Le jeu d'instructions#

Nous avons toutes les pièces d'un processeur : des registres pour retenir, une mémoire pour ranger, une ALU pour calculer, des multiplexeurs pour aiguiller les données. Il nous manque une question : qu'est-ce qu'un programme, vu par le processeur ? La réponse tient en une phrase : une suite de nombres rangés dans la mémoire.

Notre processeur travaillera avec quatre registres de travail, r0, r1, r2 et r3 : ce sont ses cases de calcul, ultra-rapides, sur lesquelles portent la plupart des instructions.

Une instruction, c'est un nombre#

Un processeur ne comprend ni le français ni Python : il ne sait manipuler que des nombres. Un programme, pour lui, est une suite de nombres rangés dans des cases consécutives de la mémoire. Chacun est une instruction : un ordre élémentaire, du genre "mets la valeur 13 dans r0" ou "ajoute r1 à r0".

Pour être lisible, une instruction est découpée en champs. Le premier, le code opération (ou opcode), dit quoi faire. Les suivants désignent sur quels registres agir. Comme il y a quatre registres, il faut 2 bits pour en nommer un (00 = r0, 01 = r1, 10 = r2, 11 = r3). Sur nos 8 bits, on réserve donc les 4 bits de gauche à l'opcode, puis 2 bits pour le registre de destination Rd, et 2 bits pour le second registre Rs.

Une instruction de 8 bits découpée en trois champs : opcode 0010 (4 bits), Rd 00 (2 bits) et Rs 01 (2 bits), qui se décode en "ADD r0, r1 : r0 reçoit r0 + r1"

Une instruction se lit en trois morceaux : l'opcode (l'action), puis les deux registres concernés.#

Par convention, le premier registre est toujours la destination : c'est lui qui reçoit le résultat. Ainsi ADD r0, r1 signifie "r0 reçoit r0 + r1". C'est la même règle que dans les vrais assembleurs (x86, ARM).

Dans Logix, un composant SLICE fait exactement ce découpage : il extrait d'un mot un champ de bits choisi. Changez l'instruction ci-dessous et regardez ses trois champs apparaître.

Un petit jeu d'instructions#

La liste des instructions qu'un processeur sait exécuter s'appelle son jeu d'instructions. Voici le nôtre :

opcode

instruction

effet

0000

STOP

arrête le processeur

0001

LOAD Rd, valeur

Rd reçoit la valeur (sur 2 octets, voir plus bas)

0010

ADD Rd, Rs

Rd reçoit Rd + Rs

0011

SUB Rd, Rs

Rd reçoit Rd - Rs

0100

COPY Rd, Rs

Rd reçoit une copie de Rs

0101

OUT Rd

affiche le contenu de Rd

On retrouve nos composants : ADD, SUB font travailler l'ALU sur deux registres, COPY recopie un registre dans un autre, et LOAD fait entrer une valeur de l'extérieur.

Important

  • Un registre se nomme sur 2 bits : r0 = 00, r1 = 01, r2 = 10, r3 = 11.

  • Le premier registre d'une instruction est la destination (il reçoit le résultat). ADD r0, r1 fait donc r0 ← r0 + r1.

Une subtilité pour LOAD : la valeur à charger (par exemple 13) ne tient pas dans les 4 bits qui restent. On l'écrit donc dans l'octet suivant : LOAD occupe deux octets, l'instruction proprement dite, puis la valeur. C'est ainsi que fonctionnent les vrais processeurs : certaines instructions sont plus longues que d'autres.

Le cycle d'exécution#

Comment le processeur enchaîne-t-il les instructions ? Il répète sans fin un même cycle en trois temps. Le compteur ordinal (pc) garde l'adresse de la prochaine instruction.

Le cycle en trois étapes : Chercher (lire l'instruction pointée par le compteur ordinal), Décoder (séparer opcode et registres), Exécuter (agir puis passer à la suivante), en boucle

Le processeur répète sans fin le même cycle : chercher, décoder, exécuter.#

  1. Chercher : lire dans la mémoire l'instruction à l'adresse indiquée par pc, et faire avancer pc.

  2. Décoder : séparer l'opcode et les registres ; l'opcode détermine l'action.

  3. Exécuter : réaliser l'action, en pilotant les composants concernés.

Pour une instruction LOAD, l'étape d'exécution va simplement lire l'octet suivant (la valeur) et la ranger dans le registre, en faisant à nouveau avancer pc.

Un programme complet#

Voici un programme rangé en mémoire à partir de l'adresse 0. Il met 13 dans r0, 2 dans r1, les additionne dans r0, puis affiche le résultat.

adresse

contenu binaire

instruction

0

0001 00 00

LOAD r0, …

1

0000 1101

(valeur : 13)

2

0001 01 00

LOAD r1, …

3

0000 0010

(valeur : 2)

4

0010 00 01

ADD r0, r1

5

0101 00 00

OUT r0

6

0000 0000

STOP

En suivant le cycle, r0 prend la valeur 13, r1 prend 2, puis ADD r0, r1 met 13 + 2 = 15 dans r0, qui est affiché avant l'arrêt. Le processeur ne fait pourtant jamais rien de compliqué : il répète chercher, décoder, exécuter.

Important

  • Un programme est une suite de nombres en mémoire ; chacun est une instruction faite d'un opcode et de registres.

  • Le processeur répète sans fin le cycle chercher, décoder, exécuter, en suivant le compteur ordinal.

Exercices#

Exercice 45#

Décodez chaque instruction : donnez son nom (menu déroulant) et le numéro des registres visés (en décimal, de 0 à 3). Servez-vous du tableau du jeu d'instructions.

  1. 0010 01 11 : avec Rd = et Rs =

  2. 0100 00 10 : avec Rd = et Rs =

  3. 0101 11 00 : sur le registre

  4. 0001 10 00 : sur le registre

Exercice 46#

On exécute ce programme. Au départ, tous les registres valent 0.

adresse

instruction

0

LOAD r0, 5

2

LOAD r1, 3

4

COPY r2, r0

5

ADD r0, r1

6

OUT r0

7

STOP

Donnez le contenu des registres demandés à la fin, ainsi que la valeur affichée.

  1. r0 après ADD r0, r1 :

  2. r2 à la fin :

  3. r1 à la fin :

  4. valeur affichée par OUT r0 :

Exercice 47#

Écrivez, avec le jeu d'instructions du cours, un programme qui met 10 dans r0 et 4 dans r1, garde une copie de r0 dans r2, calcule r0 - r1 dans r0, puis affiche d'abord r0 et ensuite r2.

Exercice 48#

L'instruction ADD r0, r1 range son résultat dans r0, en écrasant l'ancien contenu de r0. Un élève veut calculer r0 + r1 tout en gardant intactes les valeurs de r0 et de r1. Expliquez comment y arriver avec les instructions du cours.