Veuillez consulter cette page à partir de l'interface principale.
Tutoriel: framebuffer
yasep/tuto/tuto_fb.fr.html créé le 2012-11-18 par Laura Bécognée et Yann Guidon
version 2012-11-23
version 2013-08-04
 

Initiation à la programmation graphique avec le YASEP

Introduction

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.

Coder une boucle

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 R3 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 1

 

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 1

 

Changer la couleur du framebuffer

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 1

 

Vous devriez voir ceci sur votre écran :

 

Changer la couleur avec un LFSR

Nous allons maintenant remplir l'écran avec des pixels pseudo-aléatoires. Pour cela, on utilise un "Registre à décalage à rétroaction linéaire". La théorie mathématique est mieux expliquée sur la page Wikipedia anglaise et un article très détaillé est disponible chez UnixGarden. Le principe est réduit à un décalage et une opération XOR.

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 dans R2. C'est une valeur qui ne tient pas dans 20 bits, il faut donc la "couper en deux" et la charger dans R2 avec une séquence de 2 instructions, comme pour la couleur (MOV puis MOVH).

  mov   1DB7h R2 ; LSB
  movh 04C1h R2 ; MSB

... 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 1

 

Le résultat devrait ressembler à peu près à ça :