Plus facile à lire avec un fond crème, une teinte, plus de contraste ou un texte plus grand ? Choisissez vos couleurs et votre texte, une fois pour toutes les pages.

Leçon gratuite

Lire les instructions d’un processeur (RISC-V)

Après cette leçon: Je peux lire un court programme RISC-V.

Leçon de 55 min10 commandesLab de compilation et d’architecture : gcc, flex, bison et RISC-V dans une VM

Le terminal de paiement planté

Le terminal de paiement d’une pharmacie se bloque pendant un encaissement. Son rapport d’erreur ne donne qu’une ligne : la dernière instruction exécutée, sw a1, 16(sp).

Le terminal ne contient aucun code source, seulement des instructions. Quelqu’un qui sait les lire peut dire ce que faisait le programme au moment de l’arrêt.

À la fin de cette leçon

Remarque

Je peux lire un court programme RISC-V.

Mots-clés

MotCe que ça veut direExemple
Registreune petite mémoire rapide dans le processeura0
Immédiatun nombre écrit dans l’instruction elle-même93
Chargementune instruction qui copie une valeur de la mémoire vers un registrelw
Rangementune instruction qui copie un registre vers la mémoiresw
Branchementune instruction qui peut sauter ailleurs dans le programmebne
Étiquetteun nom donné à un endroit du programmeboucle:

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

Trente-deux registres, chacun son rôle

Un processeur RISC-V de 64 bits a 32 registres de 64 bits, nommés x0 à x31. L’assembleur donne à la plupart un nom qui dit leur usage.

x0 s’appelle zero : il vaut toujours 0, et ce qu’on y écrit est perdu. Les registres a portent les entrées d’une fonction et sa réponse. Les registres t gardent des valeurs de travail de courte durée.

Exemple travaillé : les registres de la leçon

NuméroNomUsage habituel
x0zeroVaut toujours 0
x2spLe pointeur de pile : l’adresse de la pile en mémoire
x5 à x7t0 à t2Valeurs de travail
x10, x11a0, a1Entrées d’une fonction, et sa réponse dans a0
x17a7Le service que ecall demande à Linux

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

Aller dans le dossier d’architecture

Commande
cd ~/arch

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Trois formes d’instruction

La plupart des instructions nomment d’abord le registre de destination, puis l’origine des entrées.

sub a0, a0, a1 soustrait deux registres. addi t0, t0, -1 ajoute à un registre un immédiat, un nombre écrit dans l’instruction. li a0, 5 semble être une troisième sorte. C’est un raccourci : pour un petit nombre, l’assembleur écrit addi a0, zero, 5.

Chargements et rangements touchent la mémoire

Les registres sont peu nombreux : les données vivent en mémoire. RISC-V ne calcule que sur des registres. Un chargement copie de la mémoire vers un registre, un rangement fait l’inverse.

lw a4, 8(a5) charge un mot de 4 octets à l’adresse contenue dans a5, plus 8. Le loop.c du labo remplit un tableau puis l’additionne : gcc doit donc charger et ranger.

Compiler loop.c en assembleur RISC-V

Commande
riscv64-linux-gnu-gcc -O2 -march=rv64gc -S loop.c

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Trouver les chargements et le rangement

Commande
grep -E 'lw|sw' loop.s

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

La boucle colonne par colonne

Commande
grep -A 4 'L9:' loop.s

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Exemple travaillé : le C à côté du RISC-V

C dans loop.cRISC-VCe que fait l’instruction
grid[r][c] = 1;sw a3,0(a5)Écrit a3, qui vaut 1, à l’adresse contenue dans a5
sum = sum + grid[r][c];lw a4,0(a5)Lit 4 octets à l’adresse de a5 et les met dans a4
sum = sum + grid[r][c];add a3,a3,a4Ajoute le nombre au total, dans les registres
la ligne r suivanteadd a5,a5,a1Avance l’adresse de a1, qui vaut 16384 octets

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

Erreur fréquente

Attention

Beaucoup pensent que add peut additionner un nombre pris directement en mémoire. En RISC-V, c’est impossible. Seuls les chargements et les rangements touchent la mémoire. Une valeur est chargée, travaillée dans les registres, puis rangée. C’est pourquoi la somme demande lw, puis add.

Un branchement fait une boucle

Un branchement compare deux registres et saute si le test réussit. beq saute s’ils sont égaux, bne s’ils sont différents.

Une étiquette comme boucle: nomme l’endroit où sauter. Le programme suivant calcule 5 fois 3 sans multiplier. t0 part de 5, a0 reçoit 3 à chaque tour, et bne t0, zero, boucle revient en arrière tant que t0 n’est pas nul.

Écrire une boucle en RISC-V

Commande
printf '.globl _start\n_start:\n  li a0, 0\n  li t0, 5\nboucle:\n  addi a0, a0, 3\n  addi t0, t0, -1\n  bne t0, zero, boucle\n  li a7, 93\n  ecall\n' > fois.s

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

L’assembler

Commande
riscv64-linux-gnu-as fois.s -o fois.o

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Faire l’édition de liens

Commande
riscv64-linux-gnu-ld fois.o -o fois

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Le lancer dans l’émulateur

Commande
qemu-riscv64 ./fois

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Lire le résultat

Commande
echo $?

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Le relire sans raccourcis

Commande
riscv64-linux-gnu-objdump -d -M no-aliases fois

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Pour aller plus loin : une puissance de deux

Écrivez un programme RISC-V qui calcule 2 puissance 5 en doublant : partez de 1 dans a0 et faites add a0, a0, a0 cinq fois dans une boucle.

Essayez-le d’abord dans votre interpréteur. Écrivez-le ensuite avec printf, comme fois.s, puis construisez-le et lancez-le dans le labo. Le code de sortie doit être 32.

À propos de ce labo et de sa source: Lab de compilation et d’architecture : gcc, flex, bison et RISC-V dans une VM

Vous enseignez à une classe ? Proposez ce module à vos étudiants avec un guide de l'enseignant, des devoirs corrigés et un laboratoire pour chaque étudiant.