Veuillez consulter cette page à partir de l'interface principale.
La structure des instructions Instructions concernées :
yasep/doc/forms.fr.html version 2014-04-30 (OK)
 

La structure des instructions dans l'architecture du YASEP

Les instructions du YASEP ont un format fixe sur 16 bits avec une extension de 16 bits par une valeur immédiate ou d'autres registres (forme étendue). Ce format est identique pour YASEP16 et YASEP32 : YASEP32 peut utiliser des instructions sur 16 bits et YASEP16 décode les instructions sur 32 bits. En fait le décodeur d'instructions varie peu entre les 2 versions, et il doit accepter les deux longueurs.

Chaque instruction peut contenir :

Ces champs et flags ne sont pas tous utilisés en même temps. Certaines combinaisons sont impossibles par construction, d'autres n'ont aucun sens, le reste peut être transformé par l'assembleur. Cependant, une grande variété d'instructions (un opcode suivi de noms de regitres, de données immédiates et d'autres flags) peut être écrite par un programmeur. Cette page explique quelles "formes d'instructions" sont disponibles, comment elles sont structurées et quand on les utilise.

 

Résumé

Une "forme d'instruction" est nommée selon son écriture en langage assembleur. C'est une séquence de lettres, désignant chacune un champ :

La structure du YASEP ne permet qu'un nombre limité de formes. Quel que soit l'opcode, les deux bits de poids faible d'une instruction du YASEP déterminent comment interpréter les champs suivants, ce qui peut donner 4 combinaisons:

   Registre source
   Source et destination
   Registre destination
   Valeur mmédiate
   Incrémentation
   Code de condition
 
 
 
 
 
 
adresse SND (opérande Négatif)
S SND OPCODE 0 0   RR ADD R1 R2
3:0 SND OPCODE 1 0   iR ADD 3 R1
DST IMM16   15:0 SN OPCODE 0 1  IRR ADD 1234h R1 R2
DST IMM20   15:0 19:16 OPCODE 0 1   IR MOV 12345h R1
DST CND code 1 up 5:0 SN OPCODE 1 1  iRR ADD -25 R2 R3 ZERO R4-
DST CND code 0 upd S SN OPCODE 1 1  RRR ADD D1+ R2 D3+ LSB0 R4

Exemples
3
1
3
0
2
9
2
8
2
7
2
6
2
5
2
4
2
3
2
2
2
1
2
0
1
9
1
8
1
7
1
6
1
5
1
4
1
3
1
2
1
1
1
0
 
9
 
8
 
7
 
6
 
5
 
4
 
3
 
2
 
1
 
0

Aux

Imm/Reg 

 Court/Long
L'ordre des champs suit les contraintes physiques : dans un circuit intégré, la lecture des deux registres sources est l'opération la plus critique du décodage car la plus lente. Les champs immédiats ou l'adresse de destination prennent moins de temps à traiter et peuvent donc se retrouver à plusieurs endroits. De plus, le chemin critique passe par l'entrée négative de l'additionneur, l'opérande SND correspondant est donc confiné une seule position dans l'instruction.

La forme étendue dispose aussi du bit auxiliaire Aux qui indique comment utiliser le champ si4 : soit comme addresse de registre (RRR), soit comme valeur immédiate signée sur 6 bits (iRR).

En plus, certains opcodes comme MOV, ayant un seul opérande, peuvent utiliser les 4 bits inutilisés d'une adresse de registre (snd) pour constituer une valeur immédiate signée sur 20 bits.

Cela porte à 6 le nombre de formes physiquement possibles, mais l'assembleur permet d'écrire encore d'autres formes, par exemple en exploitant certaines combinaisons de champs inutilisés.

 

Remarques à propos du champ Imm4

Comme le champ Imm16 de la forme longue, le champ Imm4 est considéré comme un nombre signé.

Cependant, si l'instruction fait partie du groupe SHL (rotations et décalages) alors le champ est considéré comme un nombre positif, permettant des décalages de 0 à 15 positions, pour YASEP16 et YASEP32. Pour des décalages supérieurs à 15 bits avec YASEP32, utilisez une forme longue avec Imm16 ou une forme étendue avec Imm6.

 

Où vont les résultats ?

Le YASEP écrit le résultat des opérations (si il y a lieu) dans un registre dont l'adresse est donnée par les champs snd ou dst, en fonction de la forme de l'instruction :

Ce système pourrait complexifier les développement dans un futur lointain mais il est indispensable pour conserver la compacité et l'orthogonalité des instructions. De plus, dans le chemin de données, ce qui compte vraiment (pour la performance) c'est le temps d'accès aux opérandes. Le "calcul" de l'adresse de destination peut être réalisé rapidement, en même temps que l'ALU (une bonne quinzaine de niveaux logiques). Et puisque le YASEP n'utilise pas de "bypass de pipeline" (le microYASEP attend l'écriture d'un résultat avant de le réutiliser), on peut avoir plus de liberté avec les champs et obtenir le maximum de chaque combinaison de bits. C'est l'assembleur qui va se charger de mettre les bonnes valeurs dans les bons bits.

 

Les "formes courtes"

Commençons par les formes d'instructions les plus simples. Les instructions courtes ont leur bit de poids faible égal à zéro, ce qui indique une longueur de 16 bits. Il reste juste assez de place pour un autre flag, un opcode de 6 bits et 2 champs de 4 bits.

Note : avant, ces deux champs s'appelaient src1 et src2, et on les confondait tout le temps, donc il sont renommés depuis 20090730

 

"forme courte à registres" : deux adresses de registre

ADD R2, R1 ; R1 <= R1 + R2

1
5
1
4
1
3
1
2
1
1
1
0
 
9
 
8
 
7
 
6
 
5
 
4
 
3
 
2
 
1
 
0
S SND OPCODE I/R S/L
R2 R1 ADD 0 0
 

"forme courte immédiate" : une adresse de registre et une valeur immédiate

ADD -3, R1 ; R1 <= R1 + -3

1
5
1
4
1
3
1
2
1
1
1
0
 
9
 
8
 
7
 
6
 
5
 
4
 
3
 
2
 
1
 
0
S SND OPCODE I/R S/L
-3 R1 ADD 1 0

En pratique, ces deux combinaisons peuvent être utilisées de 5 façons en langage assembleur, puisque chacun de ces champs peut être plus ou moins utile en fonction du type d'opération désirée :

 

Forme "RR" : De Registre à Registre

 ADD R1 R2   ; R2 <- R1+R2
C'est l'une des formes les plus courantes. si4 et snd donnent les adresses des deux registres contenant les opérandes. snd est aussi la destination du résultat.

 

Forme "iR" : immédiat court vers Registre

 ADD 2 R3   ; R3 <- 2+R3
Une autre forme courante. si4 donne une valeur immédiate signée sur 4 bits, donc snd sert d'adresse de registre pour l'autre opérande source ainsi que la destination.

Certaines instructions comme OUT et PUT utilisent si4 pour indiquer l'adresse de destination, mais comme c'est une valeur immédiate, elle est écrite avant le registre source.

 PUT 3 R1   ; Envoie le contenu de R1 dans le registre spécial n°3

 

Forme "R" : Registre

 NEG R1   ; en interne : R1 = -R1
C'est aussi une façon courte d'écrire que les deux champs sont le même registre. L'assembleur va correctement remplir les champs si4 et snd si cette forme est acceptable pour l'opcode désiré.

 

Forme "i" : immédiat court

 CRIT 3   ; désactive les interruptions pour les 3 instructions suivantes
Rarement utilisé mais parfois nécessaire. si4 contient la valeur immédiate et snd est ignoré.

 

Forme "ALONE" : pas d'opérande

 NOP   ; pas d'opération, tout les champs sont ignorés.
C'est un cas extrême où aucun opérande n'est nécessaire. si4 et snd sont ignorés.

 

 

Les "formes longues"

Le YASEP interprète les instructions comme ayant une longueur de 32 bits quand leur bit de poids faible est à 1. Les 16 bits de poids faible sont très similaires aux formes courtes. Le second bit de poids faible indique comment interpréter le demi-mot de poids fort :

 

"Forme longue immédiate" : Deux adresses de registres et une valeur immédiate longue

ADD 1234h, R2, R1 ; R1 <= 1234h + R2

DST IMM16   15:0 SN OPCODE E/I S/L
R1 1234h R2 ADD 0 1
3
1
3
0
2
9
2
8
2
7
2
6
2
5
2
4
2
3
2
2
2
1
2
0
1
9
1
8
1
7
1
6
1
5
1
4
1
3
1
2
1
1
1
0
 
9
 
8
 
7
 
6
 
5
 
4
 
3
 
2
 
1
 
0

Forme "IRR" : Immédiat long et Registre vers Registre

 ADD 1234h R2 R1   ; R1 <- 1234h + R2
Cette forme est assez courante. En plus de l'opérande immédiat sur 16 bits, snd fournit l'adresse du registre qui sert de deuxième opérande. dst donne la destination du résultat.

 

Forme "IR" : Immédiat long vers Registre

 GET 1234h R1   ; R1 <- SR[1234h]
Cette forme est utilisée pour les instructions GET ou MOV. Le champ snd est ignoré parce que seul DST a un sens pour l'opération. L'assembleur détecte aussi si la valeur immédiate tient dans 4 bits pour utiliser une forme courte (FORM_iR) ou longue, et optimiser la taille du code binaire.

C'est aussi utilisé par les instructions booléennes (ROP2) et l'ASU (ADD et SUB) pour simuler FORM_iR mais avec une valeur immédiate sur 16 bits. Lorsqu'il trouve le flag ALIAS_IRR, l'assembleur va utiliser FORM_IRR et mettre la même adresse de registre dans les deux champs dst et snd.

; Ces deux instructions font la même chose et sont encodées de la même manière :
 OR 1234h R1 R1               
 OR 1234h R1

Avec le YASEP32, certains opcodes peuvent aussi utiliser le champ snd pour obtenir une valeur immédiate sur 20 bits : voir le flag IMM20.

.profile YASEP32 ; Les 4 bits de poids fort sont ignorés par YASEP16
 CALL 12345h R1
 MOV 12345h R1
MOV 12345h R1 ; R1 <= 12345h

DST IMM20   15:0 3:0 OPCODE E/I S/L
R1 1234h 5h MOV 0 1
3
1
3
0
2
9
2
8
2
7
2
6
2
5
2
4
2
3
2
2
2
1
2
0
1
9
1
8
1
7
1
6
1
5
1
4
1
3
1
2
1
1
1
0
 
9
 
8
 
7
 
6
 
5
 
4
 
3
 
2
 
1
 
0

Quelques instructions, comme OUT and PUT, utilisent Imm20 comme une adresse de destination. Comme c'est une valeur immédiate, elle est écrite avant le registre source.

 PUT 12345h R1   ; Envoie le contenu de R1 dans le registre spécial n°12345h

 

Les formes étendues

Les formes dites "étendues" réutilisent la structure des formes courtes et rajoutent 16 bits pour fournir d'autres fonctionnalités :

Ces champs sont situés dans l'instruction à des positions qui facilitent au maximum le décodage des opérandes. Le champ cnd est décalé de 16 bits du champ snd et le champ dst est également décalé d'autant par rapport à si4, afin d'accélérer les opérations si le bus d'instructions est sur 16 bits seulement. D'autre part, comme les adresses de registre sources sont dans la première moitié de l'instruction, les registres peuvent être lus en premier dans la première phase de décodage de l'instruction.

"Forme Etendue à Registres" : trois adresses de registres

ADD R1, R2, R3 ; R3 <= R1 + R2

DST CND code aux upd S SN OPCODE E/I S/L
R3 0 0 0 0 R2 R1 ADD 1 1
3
1
3
0
2
9
2
8
2
7
2
6
2
5
2
4
2
3
2
2
2
1
2
0
1
9
1
8
1
7
1
6
1
5
1
4
1
3
1
2
1
1
1
0
 
9
 
8
 
7
 
6
 
5
 
4
 
3
 
2
 
1
 
0
 

Forme "RRR" : Registre et Registre vers Registre

 ADD R1 R2 R3 ; R3 <- R1+R2
si4 (R1) et snd (R2) sont tous les deux des registres sources, le résultat est écrit dans dst (R3).


La forme RR peut être assemblée sous la forme RRR si une condition est ajoutée ou si un des registres est mis à jour/incrémenté.
 

"Forme Etendue Immediate" : deux adresses de registres et un champ immédiat de 6 bits

ADD 25, R1, R3 ; R3 <= R1 + 25

DST CND code aux upd Imm6 SN OPCODE E/I S/L
R3 0 0 1 0 25 R1 ADD 1 1
3
1
3
0
2
9
2
8
2
7
2
6
2
5
2
4
2
3
2
2
2
1
2
0
1
9
1
8
1
7
1
6
1
5
1
4
1
3
1
2
1
1
1
0
 
9
 
8
 
7
 
6
 
5
 
4
 
3
 
2
 
1
 
0
 

Form "iRR" : imm6 et Registre vers Registre

 ADD 25 R1 R3 ; R3 <- R1+25
La valeur immédiate de Imm6 (25) et la valeur du registre indiqué par snd (R1) sont les opérandes de l'addition, dont le résultat est écrit dans dst (R3).


La forme iR peut être assemblée sous la forme iRR si une condition est ajoutée, ou si l'immédiat ne tient pas sur 4 bits, ou si un des registres est mis à jour/incrémenté.
 

 

Codes de conditions

Les instructions étendues du YASEP disposent de 7 bits pour définir la condition (ou le prédicat) qui valide (ou non) l'écriture du résultat de l'instruction courante. Ils permettent d'encoder trois types de conditions :

Tables des conditions

cnd={1..15}
Fonction Neg=0 Neg=1
00 NZ (Registre[cnd]!=0) ZERO (Registre[cnd]=0)
01 BIT1 (Shadow[cnd]!=0) BIT0 (Shadow[cnd]=0)
10 LSB1 / ODD (Registre[cnd] impair) LSB0 / EVEN (Registre[cnd] pair)
11 MSB1 / NEGATIVE (Registre[cnd] négatif) MSB0 / POSITIVE (Registre[cnd] positif)

cnd=0 (PC)
Fonction Neg=0 Neg=1
00 Always (défaut) Never (réservé)
01 BIT1 (Shadow[0]!=0) BIT0 (Shadow[0]=0)
10 CARRY / NO_BORROW (Retenue à 1) NO_CARRY / BORROW (No Carry)
11 EQ (flag Égal à 1) NEQ (flag Égal à 0)

L'encodage est tel que la condition "toujours" (ALWAYS) est représentée avec tous les bits à 0.

Toutes les conditions peuvent être inversées par le bit Neg. Donc on peut coder le prédicat "jamais" en inversant la condition "toujours" (qui est celle par défaut).

Le registre "shadow" est encore indéterminé. Pour l'instant, on considère qu'il s'agit d'une copie locale du registre R1 mais on pourra le changer avec un SR pour indiquer s'il s'agit d'un port d'entrées-sorties ou d'autres choses encore.

ADD R1,R2,R3 LSB0 R4 ;Si R4 est pair alors R3 <= R1 + R2

DST CND code aux upd S SN OPCODE E/I S/L
R3 R4 101 0 0 R2 R1 ADD 1 1
3
1
3
0
2
9
2
8
2
7
2
6
2
5
2
4
2
3
2
2
2
1
2
0
1
9
1
8
1
7
1
6
1
5
1
4
1
3
1
2
1
1
1
0
 
9
 
8
 
7
 
6
 
5
 
4
 
3
 
2
 
1
 
0

 

Auto-updates

L'utilisation des bits restants pour l'auto-update a été figée le 2014-01-31. Certains codes peuvent encore évoluer mais le format ne bougera plus. Voir les justifications à Definition of the auto-update fields.

Aux = 0 (si4=registre)
00 01 10 11
00 NOP SND+,SI4+,DST+ SI4- SI4+
01 SND-,SI4- SND+,SI4+ SND- SND+
10 DST-,SI4- DST+,SI4+ DST- DST+
11 DST-,SND- DST+,SND+ CND- CND+
Aux = 1 (si4=Imm6)
00 NOP (aucune modification)
01 SND+ (incrémente la source)
10 DST+ (incrémente la destination)
11 CND- (décrémente la condition)

Les implémentations du YASEP qui ne prennent pas en charge cette fonctionnalité doivent déclencher une exception si elles décodent autre chose que NOP. Ce n'est pas un fonctionnalité critique pour le microYASEP par exemple.

Ces bits sont interprétés en fonction du bit Aux, car il serait inutile de modifier si4 si celui-ci contient une valeur immédiate. Il reste seulement 4 ou 2 bits disponibles mais les combinaisons retenues sont les plus utiles en pratique et devraient augmenter la densité du code.

La pré-incrémentation et la pré-décrémentation ne sont pas proposées à cause de leur complexité architecturale. Si une adresse est pré-calculée avant d'exécuter l'opcode, à l'intérieur d'une même instruction :
- cela augmente la latence de l'instruction car la mémoire doit être lue et peut retarder le reste de l'exécution durant de nombreux cycles
- l'adresse générée pourrait déclencher une faute d'accès à la mémoire et il n'y a pas de moyen de stopper l'exécution d'une instruction en plein milieu ni de reprendre l'opération partielle ensuite.

Les règles implicites de modification sont les suivantes :

Certaines combinaisons de modifications produisent des cas particuliers :

  • Le résultat d'un calcul a priorité sur les modifications donc si un registre normal R est modifié en tant que destination, la modification est ignorée (ou déclenche une exception)
  • ADD R1 R2 R3+  ; R3 ne sera pas incrémenté et contiendra la somme de R1 et R2
  • Si un même registre est modifié en tant que plusieurs sources, ou source et destination, une seule modification sera prise en compte
  • ADD R1+ R1+ R2   ; n'incrémentera R1 qu'une seule fois
    ADD D1+ D2+ D1+  ; A1 sera incrémenté une seule fois

    Il en résulte que le champ DST ne peut modifier que les registres A, et seulement de manière implicite en adressant son registre D.

    Utilisation

    Il n'est pas possible d'atteindre la sophistication d'un PDP11 ou d'un DSP mais les programmes économisent des instructions courtes d'incrémentation ici et là. En particulier, il est possible de faire un saut relatif conditionnel tout en décrémentant un compteur avec une seule instruction, comme à la fin d'une boucle :

    MOV 50, R1 ; initialise le compteur à 50
    MOV 0, R2  ; initialise l'accumulateur
    
      ADD R1 R2 ; ajoute le compteur à l'accumulateur
    ADD -2 PC NZ R1- ; Si R1 n'est pas à zéro alors
                     ;   - décremente R1
                     ;   - saute de 2 octets en arrière

    Une boucle, ou un bloc à sauter, peut donc contenir jusqu'à 8 instructions longues ou 16 instructions courtes, sans nécessiter d'opération ou de registre supplémentaire.

    Les registres pointeurs peuvent aussi être incrémentés automatiquement lorsque leur registre de donnée est accédé. Il est ainsi facile de recopier ou de modifier un bloc de données :

    MOV 50, R1 ; initialise le compteur à 50
    MOV 2345h, A1    ; initialise la source
    MOV 6789h, A2    ; destination
    
      MOV D1+ D2+    ; recopie un mot
    ADD -4 PC NZ R1- ; Si R1 n'est pas à zéro alors
                     ;   - décremente R1
                     ;   - saute de 4 octets en arrière

    L'accès à la pile est aussi facilité, les instructions PUSH et POP sont émulées simplement. Puisqu'il n'y a pas de pile dédiée, il est même possible d'implémenter des langages à piles multiples tels que FORTH.