L'objectif de cette étude de laboratoire est de completer la conception du microprocesseur MiniArm que vous avez commencée à l'occasion du premier bureau d'étude. Il s'agit de définir le tableau des temps, d'en dériver les équations logiques et de définir l'instruction bl (Branch and Link).
Compétences visées:
- Déterminer les séquences d'opérations élémentaires nécessaires à l'exécution des instructions d'un microprocesseur.
- Synthétiser les équations du séquenceur permettant d'exécuter ces instructions.
- Modifier ces équations pour ajouter une nouvelle instruction.
- Expliquer les mécanismes mis en œuvre lors d'un appel de fonction.
Vous pouvez utiliser l'assembleur de code MiniARM (assembler.py) en ligne de commande, ou bien utiliser Eclipse avec le plug-in MiniARM
qui fonctionne sur toutes les plateformes. Consultez la section Logiciels nécessaires pour les détails d'installation.
Si vous souhaitez poursuivre le séquencement manuel que vous avez commencé lors du premier bureau d'étude, vous pouvez télécharger le kit correspondant.
1. Préliminaires
Créez sur https://gitlab-student.centralesupelec.fr un projet privé nommé 3A-PFO, en cochant la case Initialize repository with a README
. Ajoutez votre encadrant comme "maintainer" de ce projet. Vous utiliserez ce même dépôt pour tous les BEs de ce cours.
Clonez ce dépôt sur votre machine, téléchargez le kit qui vous est fourni dans le dossier correspondant et décompressez-le. Ce kit contient :
- Le fichier miniARM.circ, contenant le chemin de données du processeur.
- Le fichier assembler.py, un assembleur pour le processeur MiniArm permettant de traduire en langage machine un programme écrit dans le langage d'assemblage de MiniArm.
- Le fichier test.txt, un programme de test écrit dans le langage d'assemblage de MiniArm, vous permettant de vérifier le bon fonctionnement du processeur après avoir défini les équations du séquenceur.
- Le fichier ese1010.jar, une librairies de composants utilisés pour réaliser le chemin de données de MiniArm.
Ajouter le dossier dans git avec git add KitBE2
, faites un commit
et un push
, vérifiez que les fichiers apparaissent bien sur https://gitlab-student.centralesupelec.fr.
La description du processeur est disponible sur cette page. La documentation des composants du chemin de données (y compris les codes des opérations de l'UAL) est disponible sur cette page.
Étape intermédiaire
Dans un premier temps, vous pouvez utiliser le chemin de données du microprocesseur sans séquenceur, et séquencer manuellement l'exécution des instructions.
Pour cela, téléchargez le kit KitManu.zip, ouvrez le fichier miniARMManu.circ dans Logisim, et chargez le programme manu.mem dans la mémoire.
Ce programme exécute les instructions suivantes :
Si les registres sont initialement à 0, ce programme charge donc la valeur 1 dans r0, la valeur 2 dans r1, puis la somme de r0 et r1 dans r2. Il écrit ensuite la valeur de r2 dans le mot mémoire d'adresse var (qui est égale à 9), puis charge dans r3 le contenu de la mémoire à cette adresse. Après l'exécution de ces instructions, r2 et r3 doivent valoir 3, et le mot mémoire d'adresse 9 doit également contenir la valeur 3.
Le circuit miniARMManu.circ contient le chemin de données du processeur, sans le séquenceur. Les signaux de contrôle du chemin de données peuvent être positionnés à l'aide de boutons poussoirs et d'entrées.
Exercice :
- Pilotez manuellement le chemin de données pour exécuter les instructions de ce petit programme
- Notez dans un tableau (feuille de calcul) les séquences de signaux nécessaires pour exécuter ces instructions.
Conservez ce tableau, il vous sera utile pour déterminer les équations du séquenceur par la suite.
2. Tableau des temps
Afin de définir les équations logiques qui sont à la base du fonctionnement du séquenceur, il faut concevoir un tableau des temps permettant de déterminer les signaux à activer pour l'exécution des instructions.
Exercice 1 :
- Ecrivez le tableau des temps du séquenceur dans un fichier Excel nommé tableau-temps-miniarm.xls.
- Faites valider ce tableau par votre encadrant(e).
Vous pouvez bien entendu utiliser ce que vous avez fait dans l'étape intermédiaire en faisant le séquencement à la main.
Dans la description des actions effectuées à chaque temps, utilisez des noms symboliques pour les opérations de l'UAL (par exemple UAL=A
plutôt que UAL=0000
). Cela vous permettra de détecter plus facilement les erreurs. Vous n'utiliserez les valeurs numériques qu'au moment d'écrire les équations des 4 signaux de commande de l'UAL.
Il est conseillé de regrouper dans un même temps les actions similaires, même si cela impose de ne rien faire à certains temps pour certaines instructions. En regroupant les actions similaires, vous obtiendrez des équations plus simples et plus faciles à comprendre et à corriger.
Cette approche doit vous amener à concevoir un séquenceur en 6 ou 7 temps sans optimisation particulière.
3. Equations du séquenceur.
Une fois le tableau des temps déterminé, il faut définir les équations du séquenceur permettant de donner une valeur aux sorties du séquenceur. Ces valeurs, qui pilotent le fonctionnement du chemin de données, seront une fonction des entrées (notamment, le code de l'instruction à exécuter et les drapeaux {$N$} et {$Z$}) et les signaux d'horloge {$T_i$} et {$P_i$}.
Exercice 2 :
Dérivez les équations du séquenceur et éditez-les dans Logisim.
- Pour ce faire, cliquez sur le séquenceur et ensuite sur le texte (click to edit) de l'attribut Equations.
- Consultez, si besoin, la documentation.
Attention : ne pas modifier l'ordre des signaux dans les équations du séquenceur, car cela modifierait la disposition des pattes du composant !
4. Test
Maintenant que les équations du séquenceur sont définies, il faut tester le bon fonctionnement de MiniArm. Dans ce qui suit, vous devrez observer l'exécution du programme test.txt qui vous est fourni, afin de vérifier que toutes les instructions soient exécutées correctement.
Note : Si vous êtes sous Windows, vous pouvez utiliser directement le fichier test.mem
fourni dans le kit si vous n'arrivez pas à utiliser l'assembleur.
Ouvrez un terminal et déplacez-vous au répertoire KitBE2 en utilisant la commande cd :
cd 3A-PFO/KitBE2
Assemblez le code contenu dans le fichier test.txt en utilisant l'assembleur assembler.py comme suit :
python3 assembler.py test.txt
Pour assembler le code avec le plug-in Eclipse, renommez le fichier en test.arm afin qu'il soit reconnu comme du langage d'assemblage MiniARM.
Cela créera dans votre répertoire un fichier nommé test.mem contenant le code machine du programme de test. Si vous ouvrez ce fichier avec un éditeur de texte, vous verrez une suite d'instructions codées en hexadécimal. Un fichier test.lst est également généré pour indiquer comment le programme est placé en mémoire. Il indique pour chaque instruction du programme le code généré et l'adresse mémoire à laquelle il se trouve.
Le code en langage d'assemblage du programme de test est le suivant.
Si tout se passe bien, ce programme doit boucler sur sa dernière instruction (label @end
, à l'adresse 0x0020).
S'il s'arrête à un label de la forme @err...
, c'est que votre processeur ne fonctionne pas correctement.
Exercice 3 :
- Chargez le programme test.mem dans la mémoire RAM.
- Pour ce faire, faites un clic droit sur le composant mémoire, choisissez Load image, puis sélectionnez le fichier test.mem.
- Lancez la simulation et vérifiez que le résultat de chaque instruction soit conforme avec les commentaires du code ci-dessus.
- cochez Simulation Enabled ;
- cochez Ticks Enabled ;
- dans Tick Frequency, choisissez une fréquence suffisamment rapide (par ex., 128Hz).
- pour avancer dans le temps, utilisez le bouton {$C$} qui se trouve en bas du composant séquenceur. Cela vous permettra de voir le résultat de l'exécution d'une instruction.
- Si le résultat n'est pas celui attendu, redémarrez l'exécution du programme et testez l'instruction qui a produit l'erreur en utilisant les boutons {$S$} ou {$T$} du séquenceur, qui vous permettent d'avancer plus lentement dans le temps afin de détecter l'erreur.
- Avec {$S$}, le séquenceur avance d'un tiers de temps (par exemple, passe de {$T_1$} à {$T_1+P_1$}), puis s'arrête.
- Avec {$T$}, le séquenceur avance d'un temps (par exemple, de {$T_1$} à {$T_2$}), puis s'arrête.
Il est utile d'ouvrir le fichier test.lst dans un éditeur de texte pour suivre plus facilement l'exécution du programme.
5. Branch and Link
La possibilité de définir des fonctions est un aspect très important d'un langage de programmation, car ça permet la réutilisation d'une séquence d'instructions réalisant un calcul. Dans la mémoire, une fonction est mémorisée à partir d'une certaine adresse. L'appel d'une fonction se traduit par une instruction de saut vers l'adresse de sa première instruction. En plus, le processeur a besoin de mémoriser l'adresse de retour, c'est à dire l'adresse de l'instruction qui suit l'appel de fonction, afin de pouvoir continuer le programme une fois que la fonction a terminé sa computation.
Dans notre processeur, on utilise les registres r0, ..., r5 pour passer des valeurs à une fonction (les arguments), le registre r7 pour mémoriser l'adresse de retour et le registre r0 pour stocker le résultat de la fonction. Le programme suivant montre les instructions nécessaires afin d'appeler la fonction func.
Remarquez qu'afin d'appeler la fonction, il faut deux instructions, une instruction mov pour sauvegarder l'adresse de retour dans r7 et une instruction b pour sauter à l'adresse de la première instruction de la fonction.
On peut simplifier l'appel d'une fonction par la définition d'une nouvelle instruction que nous appelons bl (Branch and Link) :
instruction | code | imm | rx | ry | rz | ||||
---|---|---|---|---|---|---|---|---|---|
4 bits | 1 bit | 3 bits | 3 bits | 3 bits | 2 bits | ||||
bl rx fonction | 1001 | 1 | rx | ||||||
fonction |
L'instruction bl rx fonction est définie comme suit :
- rx <-- PC (par convention, rx sera toujours r7).
- PC <-- fonction
Exercice 4 :
Modifiez le jeu d'instructions du processeur pour ajouter l'instruction bl. Pour cela il faut :
- Modifier le tableau des temps pour rajouter la nouvelle instruction.
- Modifier les équations du séquenceur. Rappelez vous d'introduire un nouveau signal interne BL au séquenceur.
6. Appel de fonction
Vous allez maintenant tester le bon fonctionnement de l'instruction bl. Dans ce but, nous allons considérer la suite de Fibonacci, définie comme suit :
{$F(0) = 0$}
{$F(1) = 1$}
{$F(n) = F(n-1) + F(n-2)$}
Ci-dessous vous trouvez une possible implémentation en Python de l'algorithme permettant de calculer le terme de rang {$n$} de la suite de Fibonacci
Exercice 5 :
- Traduisez le code ci-dessus dans le language d'assemblage de MiniArm. Sauvegardez le code dans un fichier nommé fibonacci.txt.
- Rajoutez les instructions nécessaires pour appeler cette fonction dans votre code.
- Assemblez fibonacci.txt en utilisant l'assembleur fourni, ce qui créera le fichier fibonacci.mem.
- Importez fibonacci.mem dans la mémoire et testez-le.
7. Livraison
N'oubliez pas de faire les commit
et les push
sur le dépôt git à chaque modification majeure et surtout à la fin de la séance.
Votre encadrant évaluera le travail que vous avez placé dans le dossier KitBE2
ce dépôt git.