Ce petit tutoriel propose de montrer comment construire un programme pour le YASEP, pas à pas, avec un exemple simple : remplir le framebuffer avec une couleur pseudo aléatoire.
Prérequis et suppositions :
⚠ Le code ne fonctionnera pas si la fenêtre du framebuffer n'est pas ouverte ⚠
N'oubliez pas de l'ouvrir en cliquant ici puis de la lier à la même carte mémoire.
Pour remplir l'écran, il faudra balayer tous ses pixels, ce qui nécessite une boucle.
Commençons par affecter des registres à cette opération :
; R3 : un compteur ; A1 : une boucle
Note : ceci est un commentaire. Pas indispensable mais ça permet de s'y retrouver.
Ensuite, il nous faut remplir le registre A1 avec le bon nombre d'itérations. Le YASEP est configuré en 32 bits et le framebuffer en 24 bits par pixel (+ 8 bits inutilisés), il est donc possible d'accéder à 1 pixel à la fois.
Avec un framebuffer de 256*256, ça fait 65 536 pixels et il faut donc 65 536 itérations pour balayer tout le framebuffer. On décrémentera cette valeur un peu plus bas.
mov 65536 R3
Il faut aussi créer une instruction pour pouvoir reboucler au bon endroit dans le programme.
On calcule 4+PC et on met le résultat dans A1. PC étant l'adresse de l'instruction en cours, cela crée un repère qui permet de revenir à l'instruction suivante (PC+4) plus tard pour reboucler (on ajoute 4 car cette instruction est sur 4 octets, mais il peut y avoir des cas d'instruction sur 2 octets, voir cette doc).
add 4 PC A1
On décrémente ensuite le compteur
add -1 R3
Puis on remet A1 dans PC si R3 n'est pas égal à 0 (NZ : Not Zero)
mov A1 PC NZ R3
Et enfin, on bloque le processeur pour arrêter le programme quand le rebouclage est terminé.
HALT
Voici le programme complet :
; fbLFSR_1 : boucle 65536 fois .name fbLFSR_1 .profile YASEP32 ; Affectation des registres : ; R3 : compteur ; A1 : loop mov 65536 R3 add 4 PC A1 ;;;;; début de la boucle ;;;;; ; décrémente le compteur add -1 R3 ; on remet A1 dans PC si R3 n'est pas égal à 0 mov A1 PC NZ R3 ;;;;;; fin de la boucle ;;;;;; HALT
Maintenant, nous pouvons accéder au framebuffer, ce qui nécessite de gérer l'adresse des pixels ainsi que leur valeur (qui est fixe pour l'instant).
On commence par compléter l'affectation des registres :
; R1 : couleur (R : Registre simple de stockage) ; R3 : compteur ; A1 : loop ; A2 : écran (A : registre d'Adresse) ; associé à D2 (D : registre de Donnée)
On pointe ensuite A2 sur le début du framebuffer :
mov 20000h A2
Cette adresse peut changer arbitrairement, vérifier que cela correspond bien au champ "Adresse début" en haut à droite de la fenêtre du framebuffer.
On décide alors de la couleur des pixels :
Pour ça, on doit placer #00A0FF (le code HTML de la couleur) dans R1. On commence par inverser l'ordre des trois octets dans ce mot :
On passe manuellement de RVB à BVR car le YASEP est "Little Endian" et l'octet rouge est à la première position d'un pixel. La valeur de la couleur dans le registre finira donc par être 00 FF A0 00 (les deux premiers 0 ne sont pas exploités mais ils restent nécessaires pour remplir les 32 bits).
Le YASEP ne permet pas de charger 32 bits directement, il faut donc une séquence d'instructions qui chargent 16 bits chacune. On place d'abord A0 00 (dans les bits de poids faible, à droite) avec MOV puis on place (00)FF dans les bits de poids forts (à gauche) avec MOVH.
mov A000h R1 movh FFh R1 ; #00A0FF : bleu ciel
Puis on écrit la couleur dans le framebuffer avec MOV et avance au pixel suivant (4 octets plus loin) avec ADD 4 A2 :
mov R1 D2 add 4 A2
Voici le programme complet :
; fbLFSR_2 : remplit l'écran avec une couleur .name fbLFSR_2 .profile YASEP32 ; Affectation des registres : ; R1 : couleur (Registre simple de stockage) ; R3 : compteur ; A1 : loop ; A2 : écran (registre d'Adresse) ; associé à D2 (registre de Donnée) mov 65536 R3 ; adresse du framebuffer: mov 20000h A2 mov A000h R1 movh FFh R1 ; #00A0FF : bleu ciel add 4 PC A1 ;;;;; début de la boucle ;;;;; ; écrit la couleur dans le framebuffer mov R1 D2 add 4 A2 ; décrémente le compteur add -1 R3 ; on remet A1 dans PC si R3 n'est pas égal à 0 mov A1 PC NZ R3 ;;;;;; fin de la boucle ;;;;;; HALT
Toutes les subtilités mathématiques sont concentrées dans la valeur choisie pour le XOR, qu'on appelle "polynôme". Il existe des tables de valeurs valides, et comme on utilise 32 bits, on choisit une des valeurs les plus utilisées, celle du CRC32 standard : 0x04C11DB7
Pour que le générateur de nombres pseudo-aléatoires fonctionne correctement, en plus du choix d'un bon polynôme, il faut s'assurer que R1 n'est pas initialisé avec la valeur 0. La couleur "bleu ciel" convient par exemple et R1 est initialisé avec cette valeur.
Affectation des registres :
; R1 : LFSR (couleur) ; R2 : polynome ; R3 : compteur ; A1 : loop ; A2 : écran (registre d'Adresse) ; associé à D2 (registre de Donnée)
On initialise donc d'abord le polynôme du LFSR (R2) ...
mov 1DB7h R2 ; LSB movh 04C1h R2 ; MSB
C'est une valeur qui ne tient pas dans 20 bits, il faut donc la "couper en deux" et la charger dans R1 avec une séquence de 2 instructions (MOV puis MOVH).
... Et on génère un bit pseudo-aléatoire :
add R1 R1 ; décale le registre ; et met le bit de poids fort dans la retenue
Enfin, si la retenue est à 1, on XOR avec le polynome. Cela permet de générer le bit pseudo aléatoire en combinaison avec le décalage réalisé par le ADD précédent) :
xor R2 R1 CARRY
Voici le programme complet :
; fbLFSR : remplit l'écran avec ; une couleur pseudo-aléatoire .name fbLFSR .profile YASEP32 ; Affectation des registres : ; R1 : LFSR (couleur) ; R2 : polynome ; R3 : compteur ; A1 : loop ; A2 : écran (registre d'Adresse) ; associé à D2 (registre de Donnée) mov 65536 R3 ; adresse du framebuffer: mov 20000h A2 mov A000h R1 movh FFh R1 ; #00A0FF : bleu ciel ; initialise le polynôme du LFSR: mov 1DB7h R2 ; LSB movh 04C1h R2 ; MSB add 4 PC A1 ;;;;; début de la boucle ;;;;; ; génère un bit pseudo-aléatoire : ADD R1 R1 ; décale le registre et ; met le bit de poids fort ; dans la retenue ; si la retenue est à 1, alors on xor xor R2 R1 CARRY ; écrit la couleur dans le framebuffer mov R1 D2 add 4 A2 ; décrémente le compteur add -1 R3 ; on remet A1 dans PC si R3 n'est pas égal à 0 mov A1 PC NZ R3 ;;;;;; fin de la boucle ;;;;;; HALT