01 - Mini-processeur
Simuler l’exécution d’un jeu d’instructions
Objectifs du TP
Dans ce TP, vous allez simuler le fonctionnement d'un processeur avec trois registres et un nombre réduit d’instructions, qui parcourt des fichiers .asm. Vous allez travailler et vous habituer avec les chaînes de caractères en Kotlin.
Théorie nécessaire
Instructions du processeur
Comme vous avez appris au cours, les processeurs ne travaillent pas avec les langages de haut niveau. En réalité, ils ont un ensemble d’instructions simples, spécifiques à chaque architecture, qu’ils peuvent executer (et c’est le but du compilateur de transformer le code haut-niveau dans des tels instructions).
Registres
Les registres sont des composantes du processeur dans lequels on peut stocker des données. Pensez au registres comme des unités très petites de memoire (en fonction de processeur, on peut avoir des registres sur 8, 16, 32 ou même 64 bits). L’accès au registres est très vite, donc dans un programme usuel on peut les utiliser pour des valeurs qu’on utilise fréquemment. Dans un programme d’assemblage, on utilise les registres directement, en écrivant leurs noms, comme les variables dans les langages de haut-niveau.
; Exemple de code dans langage d'assemblage
; ax, bx et cx sont des registres
mov ax, bx
add bx, cx
div cx
Syntaxe de base
La syntaxe pour une instruction en langage d’assemblage est: instruction [opérande 1, opérande 2, ..]
.
Le nombre d'opérandes dépend de l’instruction. Chaque ligne contient une seule instruction et ses opérandes.
Pour plusieurs informations sur le langage d’assemblage, consultez les liens dans la séction “Sources”!
Exercice
Pour le TP d’aujourd’hui, vous allez recevoir des fichiers .asm contenant des instructions de processeur que vous devez executer. C’est à vous de parcourir les fichiers, aussi que d’écrire l’implantation pour chaque instruction nécessaire.
Le processeur a trois registres, A
, B
et C
dans lesquels on peut garder que des valeurs entières (Int
). Au debut du chaque programme, les registres ont la valeur 0. Les instructions demandées sont:
Instruction | Opérandes | Description | Exemple |
---|---|---|---|
mov | reg1, reg2/val | Copie val ou la valeur située en reg2 dans reg1 . Equivalent en programmation reg1 = reg2 ou reg1 = val | mov A, 2 |
add | reg1/val1, reg2/val2 | Fait la somme entre la valeur située en reg1 ou val1 et la valeur située en reg2 ou val2 et met le résultat dans le registre C. Equivalent en programmation C = reg1 + reg2 | add A, B |
sub | reg1/val1, reg2/val2 | Fait la différence entre la valeur située en reg1 ou val1 et la valeur située en reg2 ou val2 et met le résultat dans le registre C. Equivalent en programmation C = reg1 - reg2 | sub A, B |
mul | reg1/val1, reg2/val2 | Fait le produit entre la valeur située en reg1 ou val1 et la valeur située en reg2 ou val2 et met le résultat dans le registre C. Equivalent en programmation C = reg1 * val2 | mul A, B |
div | reg1/val1, reg2/val2 | Fait la division entre la valeur située en reg1 ou val1 et la valeur située en reg2 ou val2 et met le quotient dans le registre C. Equivalent en programmation C = reg1 / val2 | div A, B |
cmp | reg/val | Compare la valeur située en A avec val ou la valeur située en reg et met le résultat dans le registre C. Le résultat de la comparaison est -1 si la valeur de A est plus petite que val ou que celle du reg , 1 si elle est plus grande, ou 0 si les deux sont égales. Equivalent en programmation C = reg1.compareTo(reg2) | cmp 7 |
print | reg/val | Affiche sur une ligne de la sortie standard la valeur située en reg ou val . Equivalent en programmation print(reg) | print A |
Examples
; 1. Calculer et afficher la somme et la différence entre deux nombres (dans notre cas, 47 et 38)
mov A, 47 ; on met le premier nombre dans le registre A
mov B, 38 ; on met le deuxième nombre dans le registre B
add A, B ; on fait la somme entre les deux nombres (sachant que le résultat se trouve maintenant dans le registre C)
print C ; on affiche la somme
sub A, B ; on fait la différence entre les deux nombres (toujours sachant que le résultat se trouve maintenant dans le registre C)
print C ; affiche la différence
; 2. Calculer le reste de la division entre deux nombres (dans notre cas, 41 et 6)
mov B, 41 ; on met le premier nombre dans le registre B
mov A, 6 ; on met le deuxième nombre dans le registre A
div B, A ; on fait la divison (sachant que le résultat se trouve maintenant dans le registre C)
; Pour calculer le reste, on multiplie le diviseur avec le quotient et on soustrait le résultat du dividende.
mul C, A ; le produit entre le diviseur et le quotient
sub B, C ; on fait la différence entre le dividende initial et le produit calculé par nous
print C ; on affiche le reste de la division (qui se trouve dans le registre C)
Conseils avant de commencer
- Dans les fichiers du TP, regardez les contenus d’un fichier .asm. Observez la syntaxe d’un programme entier.
- Commencez par parcourir un fichier et afficher ses lignes individuellement (partagez les lignes en utilisant la fonction
split()
). - Ensuite, pour chaque ligne, séparez l’instruction et ses opérandes.
- Implantez les instructions
- Enfin, executez le programme.
Pendant ce TP, vous ne pouvez pas utiliser des expressions régulières que pour la fonction split()
. On va travailler avec les expression régulières dans un TP prochain.
Sources
- Un simulateur d'un processeur avec des addresses sur 8 bits : 8 bit processor
- The Art of Intel x86 Assembly - Chapitre 6: The 80x86 Instruction Set