yasep/docs/registers.html version 2009-08-08
Retour à la page d'accueil
Traduction : Laura Bécognée   version anglaise :

 

Les registres de YASEP

L'architecture YASEP comprend 16 registres, nommés R0 R1 R2 R3 R4 NPC A0 D0 A1 D1 A2 D2 A3 D3 A4 D4 et répartis en 4 types (et demi). C'est un peu plus compliqué qu'une architecture RISC classique mais cela réduit le nombre d'opcodes en leur permettant de remplir de nombreuses fonctions différentes.

 

Les registres "normaux"

R0, R1, R2, R3 et R4 sont des registres normaux. Comme dans les autres architectures, ils sont lus et écrits sans déclencher d'action implicite.

; Exemple 1
 MOV 1234h R2   ; écrit la valeur 1234h dans le registre R2
; Exemple 2
 ADD 4 R1       ; R1 <- R1 + 4
; Exemple 3
 ADD 32 R1 R3   ; R3 <- R1 + 32

On les utilise pour contenir les résultats intermédiaires des calculs, les compteurs de boucles, les paramètres d'appel aux fonctions...

 

Les registres "Adresse"

A0, A1, A2, A3 et A4 sont des registres d'adresse. Ils contiennent l'adresse où une donnée sera lue ou écrite. Ils peuvent être mis à jour (incrémentés ou décrémentés) par les instructions de forme étendue, afin d'accéder facilement à des données contigües.

 

Les registres de "Donnée"

D0, D1, D2, D3 et D4 sont des registres de donnée, associés aux registres d'adresse : A0 est lié à D0, A1 à D1 etc. YASEP maintient toujours la cohérence entre les registres d'adresse et de donnée afin de préserver la relation Dx=memoire[Ax] :

; Exemple 1
 MOV 1234h A1    ; pointe A1 vers l'addresse 1234h ==> D1 contient la valeur à cette adresse.
 ADD D1 R0       ; ajoute le contenu de la mémoire à l'adresse 1234 au registre R0.
; Exemple 2
 MOV 1234h A3    ; pointe A3 vers l'adresse 1234h ==> D3 contient la valeur à cette adresse.
 ADD D3 R2       ; ajoute le contenu de la mémoire à l'adresse 1234 au registre R2.
; Exemple 3
 ADD 1234h R1 A4 ; additionne R1+1234h et met le résultat dans A4 ==> D4 contient la valeur à cette adresse.
 ADD R0 D4       ; lit le mot situé à l'adresse [R1+1234h],
                  ; ajoute la valeur de R0 et réécrit le résultat à la même adresse.

En conjonction avec les fonctions d'incrémentation et décrémentation, ces registres peuvent réaliser des piles. Par convention, A4 est le pointeur de pile et D4 est le sommet de la pile, mais rien n'empêche de créer 2 ou 3 piles, ou bien de réaliser la pile standard avec d'autres registres

Attention : TOUS les accès à la mémoire sont alignés sur les frontières naturelles des mots.

; Exemple 1 (lecture en mémoire)
 MOV 1231h A0    ; pointe A0 vers l'addresse 1231h (impaire donc non alignée)
 LSB D0 R2       ; Extrait l'octet à l'adresse 1231, duplique le bit de signe et écrit le résultat dans R2.
; Exemple 1 bis (YASEP32 seulement)
 MOV 1232h A1    ; pointe A1 vers l'addresse 1232h (non alignée sur une frontière de mot)
 LSH D1 R1       ; Extrait le demi-mot à l'adresse 1232, duplique le bit de signe et écrit le résultat dans R1.

; Exemple 2 (écriture en mémoire)
 MOV 1231h A2    ; pointe A2 vers l'addresse 1231h (impaire donc non alignée)
 SB R2 D2        ; prend l'octet de poids faible en R2, insère le resultat dans l'octet de poids fort de D2.
; Exemple 2 bis (YASEP32 seulement)
 MOV 1232h A3    ; pointe A3 vers l'addresse 1232h (non alignée sur une frontière de mot)
 SH R0 D3        ; prend le demi-mot de poids faible en R0, insère le résultat dans le demi-mot de poids fort de D3.

 

Le registre "Next PC"

Le dernier registre est le plus spécial : NPC est le pointeur vers l'instruction suivante. Il est automatiquement incrémenté après chaque nouvelle instruction, et peut être lu et sur-écrit par toutes les instructions.

On peut remarquer que les instructions de YASEP sont encodées sur 2 ou 4 octets et que toutes les adresses ont une granularité d'un octet. De plus, les instructions sont toujours à des adresses paires, donc le bit de poids faible des adresses d'instructions est toujours implicitement à 0. Lorsqu'une instruction écrit dans NPC, le bit de poids faible de la valeur est ignoré, et une adresse impaire sera comprise comme une adresse paire (arrondie par défaut).

Le bit de retenue ("Carry flag")

Comme NPC est toujours pair, son bit de poids faible est inutile. On l'utilise pour stocker la retenue de la dernière instruction ADD ou SUB executée. Le bit de retenue est mis à 1 lorsqu'une addition dépasse la largeur des registres :

; R1 = 5678h avec YASEP16
 ADD CDEFh R1 R2  ; R2 <- 5678h + CDEFh = 12467h > FFFFh donc "carry" mis à 1
 ADD 1234h R1 R2  ; R2 <- 5678h + 1234h = 68ACh <= FFFFh donc "carry" mis à 0

Le bit "carry" peut ensuite être testé par une instruction conditionnelle :

 ADD 1234h R1       ; R1 <- R1 + 1234h
 ADD 5 R2 LSB0 NPC  ; Si le bit de poids faible de NPC (carry) est égal à 0,
                     ; alors on additionne R2 et 5

L'instruction SUB est basée sur l'addition et donc utilise le même bit de retenue que ADD. Cependant, pour SUB, la valeur du bit est inversée, ce dernier est à 1 lorsque la soustraction n'a pas généré de retenue :

; R1 = 4h
SUB 3 R1 ; R1 = 3 - 4 = -1 ==> carry=0
SUB 4 R1 ; R1 = 4 - 4 = 0  ==> carry=1
SUB 5 R1 ; R1 = 5 - 4 = 1  ==> carry=1

Seules les instructions marquées par le flag "CHANGE_CARRY" peuvent changer le bit de retenue. Les deux autres instructions dotées de cet attribut sont CMPU et CMPS, qui sont comme l'instruction SUB mais qui n'écrivent pas le résultat de la soustraction. Toutes les autres instructions préserveront ce bit, même lorsqu'elles écrivent dans NPC. La retenue peut donc être testée de nombreux cycles après l'exécution de ADD/SUB/CMPU/CMPS, même après des appels ou des retours de fonctions. La seule manière de forcer la valeur de la retenue est d'utiliser astucieusement les instructions CMPU ou CMPS, avec des opérandes qui donneront toujours le même résultat :

; mettre la retenue à 0 :
 CMPU R1, R1  ; R1 est égal à R1 donc le flag ne peut pas être à 1.
; mettre la retenue à 1 :
 CMPU 0, NPC  ; NPC est (quasiment) toujours supérieur à 0 donc la retenue est forcément à 1.