Diplôme d'Ingénieur de l'IFSIC - ARA Jeux d'instructions On considère une architecture comportant 16 registres 16 bits. Le jeu d'instructions est le suivant : mnémonique et opérandes description MOV R,C Met dans les 8 bits de poids faible du registre R la constante C sur 8 bits codée dans l'instruction Décale la valeur de R2 de N bits (insertion de zéros) et stocke le résultat dans R1. N est une constante signée sur 5 bits codée dans l'instruction. Le signe de N indique le sens du décalage. Met dans R1 le résultat de R2 OP R3, où OP est une des opérations suivantes : ADD,SUB,OR,AND,XOR Lit la valeur 16 bits stockée à l'adresse mémoire R2+DEP et met la valeur dans R1. DEP est une constante signée sur 8 bits, codée dans l'instruction Écrit la valeur de R1 à l'adresse mémoire R2+DEP. DEP est une constante signée sur 8 bits, codée dans l'instruction Met la valeur du PC de l'instruction suivante dans R1 et saute à l'adresse lue dans R2 Saute à PC+DEP si R est non nul. DEP est une constante signée sur 8 bits, codée dans l'instruction. SH R1,R2,N OP R1,R2,R3 LD R1,R2,DEP ST R1,R2,DEP JMP R1,R2 BNZ R,DEP 1 Questions 1. Calculer le nombre total N d'instructions distinctes, considérant que toutes les combinaisons de registres source et destination sont valides. 2. Si on utilise un format d'instruction de longueur constante, quelle est la longueur minimum d'une instruction ? 3. Un format d'instruction de longueur variable permet-il d'obtenir une longueur moyenne d'instruction plus petite qu'un format de longueur constante ? 4. Proposer une modication minimale du jeu d'instruction qui permet un codage de longueur constante sur 16 bits (il existe plusieurs solutions acceptables). Calculer le nombre total N 0 d'instructions distinctes et vérier qu'il est compatible avec un codage sur 16 bits. 5. Un codage possible sur 16 bits serait de numéroter les instructions de 0 à N 0 − 1. Cependant, aucune architecture n'est construite de cette manière car la mise en oeuvre matérielle du décodage nécessiterait une ROM (read-only memory) très grande. Proposez un codage 16 bits pour le jeu d'instructions modié qui permette une mise en oeuvre matérielle simple du décodage (il existe plusieurs solutions acceptables). 6. L'architecture décrite jusqu'à présent ne permet d'adresser que 64 Ko de mémoire. Proposez une modication de l'architecture qui permette d'adresser 4 Go de mémoire et qui autorise la compatibilité binaire avec le jeu d'instructions décrit précédemment. Les programmes binaires écrits avec l'ancien jeu d'instruction sont toujours valides (il existe plusieurs solutions acceptables). Décrivez l'impact de cette modication sur la microarchitecture. 7. Tracez le graphe d'appel des procédures du programme suivant. Combien de contexte d'appels sont possibles pour la procédure f uncA ? TD ARA Diplôme d'Ingénieur de l'IFSIC int int { } Jeux d'instructions X = 0; funcA ( X++; return int argA ) X ∗ argA ; int funcB ( int argB ) int b ; b = funcA ( argB ) ; return b + argB ; { } int { } funcC ( int return int argC ) c; c = funcA ( argC ) ; c; int funcD ( int argD1 , int argD2 ) int d ; d = funcB ( argD1 ) + funcC ( argD2 return d ; { ); } 8. La traduction d'un programme en langage de haut niveau vers un texte en langage assembleur est le processus compilation. En utilisant le jeu d'instructions du TD, proposer un texte en langage assembleur qui réalise le programme de la question précédente. On suppose : entiers sur 16 bits argD1 et argD2 initialement stockés dans R0 et R1 adresse de début de f oncD est stockée dans PC adresse de retour stockée dans R14 pointeur de pile stocké dans R15 résultat de la fonction écrit dans R13 les registres R3 a R12 sont libres 9. Faire une critique du jeu d'instructions sur la base du programme de la question précédente. 10. Voici un simulateur pour le jeu d'instructions décrits dans ce TD. Modiez son code pour acher la trace des adresses des accès mémoires vers la mémoire (pour les instructions et les données). TD ARA 2 Diplôme d'Ingénieur de l'IFSIC Jeux d'instructions #include <s t d i o . h> #define TAILLEMEM 65536 #define NREG 16 #define PCFONC 0 #define PCFIN 0xDEAD #define PTRSTACK 0 enum t y p e _ i n s t {MOV,ADD, SUB,XOR, LD, ST , JMP,BNZ} ; struct i n s t r u c t i o n { enum t y p e _ i n s t t ; int r1 , r2 , r3 , c ; }; int pc ; int r e g [NREG ] ; int memd [TAILLEMEM ] ; struct i n s t r u c t i o n memi [TAILLEMEM] }; = { {XOR, 1 3 , 1 3 , 1 3 , 0 } , {BNZ, 1 , 0 , 0 , 6 } , {MOV, 1 3 , 0 , 0 , 1 } , {JMP, 4 , 1 4 , 0 , 0 } , {XOR, 4 , 0 , 1 , 0 } , {BNZ, 4 , 0 , 0 , 6 } , {MOV, 1 3 , 0 , 0 , 1 } , {JMP, 4 , 1 4 , 0 , 0 } , { ST, 0 , 1 5 , 0 , 0 } , { ST , 1 , 1 5 , 0 , 2 } , {ST, 1 4 , 1 5 , 0 , 4 } , {XOR, 4 , 4 , 4 , 0 } , {MOV, 4 , 0 , 0 , 6 } , {ADD, 1 5 , 1 5 , 4 , 0 } , {XOR, 4 , 4 , 4 , 0 } , {MOV, 4 , 0 , 0 , 1 } , {SUB, 0 , 0 , 4 , 0 } , {JMP, 1 4 , 2 , 0 , 0 } , {XOR, 4 , 4 , 4 , 0 } , {MOV, 4 , 0 , 0 , 6 } , {SUB, 1 5 , 1 5 , 4 , 0 } , {LD, 0 , 1 5 , 0 , 0 } , {LD, 1 , 1 5 , 0 , 2 } , {LD, 1 4 , 1 5 , 0 , 4 } , {XOR, 4 , 4 , 4 , 0 } , {ST, 1 4 , 1 5 , 0 , 0 } , { ST, 1 3 , 1 5 , 0 , 2 } , {XOR, 4 , 4 , 4 , 0 } , {MOV, 4 , 0 , 0 , 4 } , {ADD, 1 5 , 1 5 , 4 , 0 } , {XOR, 4 , 4 , 4 , 0 } , {MOV, 4 , 0 , 0 , 1 } , {SUB, 0 , 0 , 4 , 0 } , {SUB, 1 , 1 , 4 , 0 } , {JMP, 1 4 , 2 , 0 , 0 } , {XOR, 4 , 4 , 4 , 0 } , {MOV, 4 , 0 , 0 , 4 } , {SUB, 1 5 , 1 5 , 4 , 0 } , {LD, 1 4 , 1 5 , 0 , 0 } , {LD, 4 , 1 5 , 0 , 2 } , {ADD, 1 3 , 1 3 , 4 , 0 } , {JMP, 4 , 1 4 , 0 , 0 } int main ( int argc , char ∗∗ argv ) int n ,m; struct i n s t r u c t i o n i n s t ; { s c a n f ( "%d %d" ,&n,&m) ; pc = PCFONC; reg [ 0 ] = n ; r e g [ 1 ] = m; r e g [ 2 ] = PCFONC; r e g [ 1 4 ] = PCFIN ; r e g [ 1 5 ] = PTRSTACK; while ( pc != PCFIN) { i n s t = memi [ pc ] ; pc += 1 ; ( inst . t ) { MOV: r e g [ i n s t . r 1 ] &= ( − 1) ^ 2 5 5 ; r e g [ i n s t . r 1 ] |= i n s t ADD: r e g [ i n s t . r 1 ] = r e g [ i n s t . r 2 ] + r e g [ i n s t . r 3 ] ; SUB : r e g [ i n s t . r 1 ] = r e g [ i n s t . r 2 ] − r e g [ i n s t . r 3 ] ; XOR: r e g [ i n s t . r 1 ] = r e g [ i n s t . r 2 ] ^ r e g [ i n s t . r 3 ] ; LD: r e g [ i n s t . r 1 ] = memd [ r e g [ i n s t . r 2 ]+ i n s t . c / 2 ] ; ST : memd [ r e g [ i n s t . r 2 ]+ i n s t . c / 2 ] = r e g [ i n s t . r 1 ] ; JMP: r e g [ i n s t . r 1 ] = pc ; pc = r e g [ i n s t . r 2 ] ; ; BNZ: ( r e g [ i n s t . r 1 ] != 0 ) pc += i n s t . c /2 − 1; ; : p r i n t f ( "non implementee \n" ) ; pc=PCFIN ; } switch case case case case case case case case default } .c; break ; break ; break ; break ; break ; break break if break ; p r i n t f ( " r e s u l t a t : %d\n" , r e g [ 1 3 ] ) ; } return 0; 11. Quelle fonction mathématique calcule le programme exécuté par le simulateur ? TD ARA 3 Diplôme d'Ingénieur de l'IFSIC Jeux d'instructions XOR R13 , R13 , R13 BNZ R1 , 6 MOV R13 , 1 JMP R4 , R14 XOR R4 , R0 , R1 BNZ R4 , 6 MOV R13 , 1 JMP R4 , R14 ST R0 , R15 , 0 ST R1 , R15 , 2 ST R14 , R15 , 4 XOR R4 , R4 , R4 MOV R4 , 6 ADD R15 , R15 , R4 XOR R4 , R4 , R4 MOV R4 , 1 SUB R0 , R0 , R4 JMP R14 , R2 XOR R4 , R4 , R4 MOV R4 , 6 SUB R15 , R15 , R4 LD R0 , R15 , 0 LD R1 , R15 , 2 LD R14 , R15 , 4 ST R14 , R15 , 0 ST R13 , R15 , 2 XOR R4 , R4 , R4 MOV R4 , 4 ADD R15 , R15 , R4 XOR R4 , R4 , R4 MOV R4 , 1 SUB R0 , R0 , R4 SUB R1 , R1 , R4 JMP R14 , R2 XOR R4 , R4 , R4 MOV R4 , 4 SUB R15 , R15 , R4 LD R14 , R15 , 0 LD R4 , R15 , 2 ADD R13 , R13 , R4 JMP R4 , R14 TD ARA 4 Diplôme d'Ingénieur de l'IFSIC 2 Jeux d'instructions Réponses nombre de combinaisons 1. MOV R,C SH R1,R2,N OP R1,R2,R3 LD R1,R2,DEP ST R1,R2,DEP JMP R1,R2 BNZ R1,DEP Total 16 × 256 16 × 16 × 32 5 × 16 × 16 × 16 16 × 16 × 256 16 × 16 × 256 16 × 16 16 × 256 256 × 657 2. Un format de longueur xe nécessite log2 (256) + dlog2 (657)e = 18 bits par instruction. 3. Considérons tous les programmes possibles de longueur P instructions, P étant grand. Il y a N P programmes diérents. Coder ces N P programmes nécessite log2 (N P ) = P log2 (N ) bits, soit une moyenne de log2 (N ) ≈ 17.36 bits par instruction. Un codage d'instruction de longueur variable permettrait d'obtenir une longueur moyenne d'instruction légèrement plus petite qu'un format de longueur constante. 4. Les instructions LD,R1,R2,DEP et ST R1,R2,DEP ne peuvent pas être codée sur 16 bits. En eet, R1,R2 et DEP totalisent 16 bits de code. Il ne reste donc plus aucun bit pour distinguer LD de ST, sans parler des autres instructions. Pour que le jeu d'instruction puisse être codé sur 16 bits il faut nécessairement modier LD et ST. Il y a plusieurs manières possibles de modier LD et ST. Par exemple, on pourrait considérer que l'un des registres R1 ou R2 est xé implicitement. On peut aussi choisir de réduire la longueur du champ DEP. C'est cette dernière solution que nous considérons ici. Si on restreint DEP à 5 bits, on trouve que N 0 = 256 × 209, qui est compatible avec un codage sur 16 bits. Augmenter DEP à 6 bits ne permettrait pas un codage sur 16 bits 5. Pour que la mise en oeuvre matérielle du décodage soit simple, il faut que les numéros de registres et les diverses constantes soient faciles à extraire, le mieux étant qu'ils apparaissent explicitement sous forme de champs dans le code de l'instruction. Pour trouver un codage "sympathique", on peut grouper les instructions qui se ressemblent. Les instructions LD,ST et SH forment le groupe 1 (2 registres et une constante sur 5 bits). Les instructions ADD,SUB,OR,AND,XOR forment le groupe 2 (3 registres). On peut rajouter au groupe 2 l'instruction JMP, qui n'utilise que 2 registres sur les 3. Les instructions MOV et BNZ forment le groupe 3 (1 registre et une constante sur 8 bits). Le champ DEP est équivalent en longueur à 2 numéros de registre. On peut donc considérer les 8 instructions des groupes 2 et 3 comme appartenant à une même classe. On a ainsi 2 classes : la classe 1 constituée par le groupe 1 et la classe 2 constituée par les groupes 2 et 3. On utilise le bit de poids fort de l'instruction pour identier la classe. 13 des 16 bits des instructions de la classe 1 sont réservées pour les 2 registres et la constante sur 5 bits. Un bit étant réservé pour spécier la classe, il reste 2 bits, ce qui est susant pour distinguer les 3 instructions de la classe 1. Les instructions de la classe 2 utilisent 12 bits pour spécier les registres et la constante sur 8 bits. Sans compter le bit de classe, il reste 3 bits, ce qui est susant pour distinguer les 8 instructions de la classe 2. On obtient le codage suivant (par exemple) : TD ARA 5 Diplôme d'Ingénieur de l'IFSIC Jeux d'instructions LD R1,R2,DEP 0 00 DEP R1 R2 ST R1,R2,DEP 0 01 DEP R1 R2 SH R1,R2,N 0 10 N R1 R2 ADD R1,R2,R3 1 000 R1 R2 R3 SUB R1,R2,R3 1 001 R1 R2 R3 OR R1,R2,R3 1 010 R1 R2 R3 AND R1,R2,R3 1 011 R1 R2 R3 XOR R1,R2,R3 1 100 R1 R2 R3 JMP R1,R2 1 101 R1 R2 0000 MOV R,C 1 110 C R BGZ R,DEP 1 111 DEP R 6. Comme on veut obtenir la compatibilité binaire, nous devons partir du codage 16 bits obtenu à la question précédente. Le codage n'autorise que des extensions limitées au jeu d'instructions. Les seules parties du codage qui sont non utilisées sont le code interdit dont les 3 bits de poids fort sont 011 et les 4 bits de poids faible de l'instruction JMP. Nous proposons 2 solutions, mais on pourrait en imaginer d'autres. Solution 1. Une solution simple a priori est de considérer que les registres (y compris le compteur de programme PC) ont une taille de 32 bits au lieu de 16 bits. Ainsi, l'adresse contenu dans le registre R2 des instructions LD et ST permet d'adresser 4 Go. Les adresses de saut calculées par les instructions JMP et BNZ sont également des adresses 32 bits. Il faut cependant faire attention. La représentation des entiers signés n'est pas la même sur 16 et sur 32 bits. Par exemple, 0xFFFF représente −1 lorsque les entiers sont sur 16 bits et 65535 lorsqu'ils sont sur 32 bits. De plus, un ST appliqué à un registre R1 sur 16 bits écrit 2 octets consécutifs en mémoire, alors qu'il écrit 4 octets lorsqu'il est appliqué à un registre R1 sur 32 bits. Il faut donc distinguer 2 modes d'exécution, un mode 16 bits et un mode 32 bits. On peut introduire une nouvelle instruction SM (comme switch mode) pour changer le mode d'exécution de 16 à 32 bits et vice-versa. On peut utiliser le code 011.. pour représenter cette instruction. Le mode par défaut est le mode 16 bits, ce qui permet d'exécuter les programmes binaires 16 bits correctement. Concernant la microarchitecture, il faut un registre sur 1 bit pour stocker le mode d'exécution (16 ou 32 bits). Dans le mode 16 bits, les 16 bits de poids forts des registres 32 bits sont ignorés la plupart du temps, sauf pour ADD et SUB, pour lesquelles la microarchitecture doit eectuer une extension de signe (c'est-à-dire mettre les 16 bits de poids fort des registres 32 bits tous à 0 ou tous à 1 selon le signe de l'entier 16 bits) an que l'additionneur 32 bits donne le résultat attendu sur 16 bits. L'instruction ST en mode 16 bits n'écrit que les 2 octets de poids faible du registre R1. Solution 2. Une autre solution possible est de conserver des registres 16 bits mais de rajouter dans l'architecture deux registres spéciaux 16 bits, que nous appelerons ZI et ZD. ZI représente la "zone" (ou "segment") d'instructions et ZD la zone de données. Sur un accès mémoire, la microarchitecture concatène les 16 bits du registre de zone et les 16 bits d'adresse "normaux" pour former une adresse 32 bits. Pour que cela soit utile, il faut introduire des instructions permettant de modier ZI et ZD, que les instruction "normales" ne peuvent pas accéder. Nous pouvons utiliser le code 011.. pour représenter une instruction NZD R, qui copie le contenu du registre R dans le registre ZD. Pour changer la valeur de ZI, nous introduisons une instruction NZI R1,R2 qui recopie le contenu du registre R1 dans dans le registre ZI et saute à l'adresse (lue dans) R2 dans la nouvelle zone. On peut coder l'instruction NZ en utilisant le code du JMP en en mettant les 4 bits de poids faible à 0001 par exemple. Concernant la microarchitecture, la principale modication est l'ajout des registre ZI et ZD. 7. TD ARA 6 Diplôme d'Ingénieur de l'IFSIC Jeux d'instructions 8. 9. Nous pouvons remarquer que le jeu d'instructions n'est pas très ecace pour manipuler les constantes. En particulier, le principal défaut de l'instruction MOV est qu'elle ne force par les 8 bits de poids fort du registre à zéro. A cause de cela, nous avons du utiliser des XOR R,R,R. On aimerait aussi pouvoir additionner ou soustraire à un registre une constante codée directement dans l'instruction. Mais cela nécessiterait de changer complètement le codage du jeu d'instructions. 10. 11. L1 : L2 : XOR R13 , R13 , R13 BNZ R1 , 6 MOV R13 , 1 JMP R4 , R14 XOR R4 , R0 , R1 BNZ R4 , 6 MOV R13 , 1 JMP R4 , R14 ST R0 , R15 , 0 ST R1 , R15 , 2 ST R14 , R15 , 4 XOR R4 , R4 , R4 MOV R4 , 6 ADD R15 , R15 , R4 XOR R4 , R4 , R4 MOV R4 , 1 SUB R0 , R0 , R4 JMP R14 , R2 XOR R4 , R4 , R4 MOV R4 , 6 SUB R15 , R15 , R4 LD R0 , R15 , 0 LD R1 , R15 , 2 LD R14 , R15 , 4 ST R14 , R15 , 0 ST R13 , R15 , 2 XOR R4 , R4 , R4 MOV R4 , 4 ADD R15 , R15 , R4 XOR R4 , R4 , R4 MOV R4 , 1 SUB R0 , R0 , R4 SUB R1 , R1 , R4 JMP R14 , R2 XOR R4 , R4 , R4 MOV R4 , 4 SUB R15 , R15 , R4 LD R14 , R15 , 0 LD R4 , R15 , 2 ADD R13 , R13 , R4 JMP R4 , R14 // met 0 dans R13 // saute a L1 s i m=0 // r e s u l t a t =1 // retour // saute // r e s u l t a t =1 de fonction a L2 de si n=m // retour // sauve dans la pile // s a u v e m dans la pile // sauve // incremente n fonction adresse retour pointeur dans de // calcule n−1 // appelle comb ( n − 1 ,m) // decremente // restaure la valeur // restaure la valeur // restaure l ' adresse // sauve adresse // sauve comb ( n − 1 ,m) // incremente // calcule n−1 // calcule m−1 // appelle comb ( n − 1 ,m−1) // decremente // restaure // recupere // calcule // retour le de de m retour retour dans de de de 7 pile retour comb ( n − 1 ,m) comb ( n−1)+comb ( n − 1 ,m−1) i n t comb ( i n t n , i n t m) { i f ( (m= = 0 ) | | ( n==m) ) r e t u r n 1 ; r e t u r n comb ( n − 1,m) + comb ( n − 1,m− 1); } TD ARA pile pile pointeur l ' adresse pile n de pointeur le pile pointeur de pile