[Suivant] [Précédent] [Fin] [Niveau supérieur]
Au cours de ce TP vous allez :
Conseils :
Bien que le sujet du TP concerne plus le coeur d’exécution du microprocesseur que son environnement d’utilisation, nous présentons ici le système complet implanté sur la maquette de test. Le système proposé se compose :
Quelques autres périphériques ne sont pas représentés sur le schéma 19.1
Remarque : il y a quelques différences par rapport à la leçon sur le microprocesseur portant sur les noms des signaux :
Les caractéristiques principales de notre microprocesseur sont les suivantes :
Le tableau 19.2 résume le jeu d’instruction du microprocesseur.
|
Nous vous conseillons de vous familiariser avec le jeu d’instructions et les codes associés du microprocesseur en étudiant le programme verif_globale qui servira de jeu de test de simulation pour le microprocesseur.
Le coeur, comme illustré à la figure 19.2 est composé de quelques registres, d’une unité de calcul, d’un compteur de programme et d’une unité de contrôle. Tous les registres du microprocesseur sont pilotés par l’horloge sclk (comme horloge système, system clock en anglais) et remis à zéro par l’état bas du signal reset_n.
Le compteur de programme (8 bits) sert à stocker l’adresse de l’instruction courante.
Le signal load_PC est prioritaire par rapport au signal inc_PC.
Cette unité contient la machine à état permettant de gérer les unités du processeur. Elle est donc en charge de séquencer les différents cycles d’une instruction (chargement d’une instruction, chargement de l’opérande, puis exécution) et de générer les signaux de contrôle des différents blocs, sans oublier, bien sûr, le signal ram_write de validation d’écriture en mémoire.
Ce bloc regroupe en fait les quatre registres suivants :
Tous ces registres fonctionnent de la même façon : l’entrée xxx est mémorisée sur le front montant de l’horloge si l’enable correspondant (load_xxx) est à 1.
Ce multiplexeur permet de choisir qui, de l’adresse "pointeur programme" PC ou de l’adresse de données AD, doit être envoyé sur le bus d’adresse ram_addr de la mémoire. Le choix de l’un ou de l’autre dépend de l’état courant de fonctionnement du microprocesseur. De manière générale, lorsque le microprocesseur va chercher une instruction en mémoire, PC est sélectionné, et lorsque le microprocesseur va traiter une donnée en mémoire, AD est sélectionné. Le choix est contrôlé par le signal sel_adr.
Nous représenterons ce choix par l’équation suivante :
ram_addr[7:0] = sel_adr * AD[7:0] + !sel_adr * PC[7:0]
Ce bloc prend comme opérandes le contenu de l’accumulateur et le bus de donnée de la RAM, et effectue dessus l’opération indiquée par I. Selon le type d’opération,
Le signal reset_n permet de réinitialiser le fonctionnement du microprocesseur. Au premier cycle d’horloge suivant le passage à 1 du signal reset_n, le microprocesseur va chercher la première instruction du programme à exécuter qui se trouve implicitement à l’adresse "0" de la mémoire.
L’exécution d’une instruction s’effectue systématiquement en trois cycles d’horloge.
Le graphe de la machine à état est rappelé dans la figure 19.3 (toutes les sorties ne sont pas indiquées).
Pendant le premier cycle (IF pour "instruction fetch") deux opérations sont réalisées simultanément.
Pendant le deuxième cycle (AF pour "address fetch") deux opérations sont réalisées simultanément.
Remarque : pour simplifier, inc_PC est systématiquement mis à 1. En cas de saut, le bloc PC considerera le signal load_PC comme étant prioritaire.
Le troisième cycle correspond à l’exécution proprement dite de l’instruction. L’opération réalisée dépend de l’instruction stockée dans le registre d’instruction I. Dans tous les cas, le contenu de la mémoire à l’adresse déterminée par le pointeur stocké dans AD au cycle précédent, est lu de la mémoire et placé sur le bus d’entrée ram_data (sel_adr = 1).
Le chronograme 19.4 permet de résumer les différents cas.
Vous venez de lire les spécifications d’un petit micro-processeur, appelé nanoprocesseur, destiné à synthétiser de douces mélodies. Comme tout projet bien spécifié, différentes équipes ont pu travailler de façon indépendante à la conception des différents modules. Ainsi, la carte contenant les différents composants électroniques et acoustiques est prête, un programme assembleur de test et un autre générant de doux sons sont déja écrits, le schéma global est terminé ainsi que les sous-blocs ALU, REG, MEMOIRE.
Hélas, lors de la phase final d’intégration, le chef de projet réalise, tardivement, il est vrai, que les équipes
chargées des blocs PC et CTR ont fait un travail de tellement piètre qualité, qu’il juge préférable de les
reconcevoir complètement.
A vous de jouer...
Vous avez jusqu’à présent travaillé avec des schémas. Sans renier l’utilité des schémas pour des circuits simples ou pour donner une vue d’ensemble d’un système, il faut quand même avouer qu’ils ne se prêtent pas tellement à la réalisation de circuits complexes : vous vous imaginez placer et relier entre eux les quelques 80.000 bascules D d’un Pentium, ainsi que les centaines de milliers de portes autour d’eux ? Nous non...
C’est pour faciliter la description de circuits complexes que les langages de description de matériel ont été
inventés. Ces langages représentent les circuits sous forme textuelle.
Ils peuvent représenter :
Vous allez réaliser ce circuit à l’aide de l’un de ces langages : Verilog. Il en existe d’autres (VHDL, SystemC,
Confluence, ...), mais Verilog a quelques gros avantages :
Le but n’est pas de faire de vous des gourous de Verilog (ça viendra plus tard), mais plutôt de vous en donner
suffisament de bases pour que vous puissiez vous débrouiller.
Allez tout d’abord faire un tour sur la page Verilog en 12 minutes, pour en avoir un petit aperçu !
La première étape consiste bien évidemment à déterminer le fonctionnement exact de ce bloc à partir des spécifications globales.
Remarque : vous pouvez vous reporter à la leçon sur le processeur (8) pour vous aider...
Puis, à partir de ces spécifications, il faut en écrire le code Verilog. Vous trouverez dans le répertoire des
sources (src) :
Lancez votre éditeur de texte favori, par exemple : xemacs src/pc.v & , puis complétez le code du
PC.
Lorsque vous pensez avoir quelque chose qui tient la route, simulez-le en lançant, depuis le répertoire
nanoproc : make simu_pc . Après un certain temps, le simulateur doit vous afficher : "le bloc PC fonctionne",
et la fenêtre de chronogrammes doit avoir la même tête que la figure 19.5.
Si le simulateur vous donne une erreur, c’est que votre code Verilog comporte une erreur de syntaxe.
Fermez le simulateur, corrigez-la, et relancez la simulation. Si les chronogrammes ne sont pas assez grands,
vous pouvez zoomer à l’aide des icônes
. Vous pouvez aussi zoomer sur une partie précise avec l’icône
.
De nouveau, il faut commencer par extraire des specifications le comportement exact de la machine à états, en déduire une architecture, et la coder en Verilog.
Cette machine à états ne comportant que 3 états qui s’enchaîne dans un ordre fixe, elle sera codée en one-hot. L’état courant sera donc stocké dans trois registres, qu’on appelera cycle[2:0], dont l’en-tête a déjà été écrite.
Vous aurez à compléter le code de ces trois registres, c’est-à-dire à déterminer ce qui leur sera affecté au front montant de l’horloge, selon l’état des entrées, et de reset_n...
Le calcul des sorties est un bloc purement combinatoire. Vous aurez donc à déterminer ce qui est affecté aux différentes sorties en fonction des entrées et de l’état courant (cycle[2:0]). Si l’équation est simple, vous donnerez à la sortie en question un type wire (à déclarer au bon endroit), et vous l’affecterez avec un assign sortie_xxx = .... ; Si l’équation est moins simple, vous utiliserez les instructions évoluées de Verilog, en :
La simulation du bloc CTR sera une simulation globale du microprocesseur et de sa RAM !
Vous pouvez vérifier le bon fonctionnement de CTR en simulant directement le système complet (nanoprocesseur + mémoire) avec un programme de test. Ce programme, nommé verif_globale permet d’exécuter toutes les instructions du nanoprocesseur.
Pour cela, vous avez deux options : la simulation (virtuelle) et l’exécution pas-à-pas sur la maquette.
Placez vous dans le répertoire nanoproc, et lancez la simulation de l’ensemble avec le programme verif_globale : make simu Au bout d’un certain temps, le simulateur ouvre une fenêtre de chornogrammes qui doivent avoir la même tête que ceux en figure 19.7.
Ces chronogrammes sont disponibles en version plus grande en cliquant ici.
Nous avons inclus dans ces chronogrammes les signaux nécessaires à la compréhension de ce qui se passe dans
le processeur :
Pour suivre les chronogrammes, il est conseillé de se rapporter à la page du programme de test verif_globale,
et de suivre le déroulement du programme cycle par cycle.
Il est également possible de comparer vos chronogrammes à des chronogrammes de référence. Pour
cela :
Par exemple, ces chronogrammes (visibles seulement depuis la version HTML) mettent en évidence le
dysfonctionnement provoqué par le bug suivant :
assign load_PC = cycle[2] && ( I==13 || ( I== 14 && !C ) || ( I== 15 && !Z ) ); (la logique
correcte étant assign load_PC = cycle[1] ...).
Lors la simulation est correcte, vous pouvez aussi suivre le déroulement du programme "en vrai", sur la maquette de test.
Pour cela, il faut tranformer le code Verilog en une liste de portes (netlist) compréhensible par le FPGA. Ceci est fait au moyen des même programmes que ceux que vous avez utilisés au dernier TP.
Placez-vous dans le répertoire nanoproc , et lancez la compilation des sources Verilog en une liste de portes
pour le FPGA : make Si la compilation s’est terminée sans erreurs, lancez la programmation du FPGA (après
avoir mis la maquette sous tension...) : make program Le FPGA doit commencer à exécuter le programme de
vérification.
Il y a deux modes d’exécution de ce programme de test :
Vous pouvez suivre l’état de certain signaux du processeur :
Ici aussi, il est recommandé de suivre l’exécution du programme pas à pas, en vérifiant chaque étape à l’aide de la page du programme de test verif_globale.
Pour finir le test de votre processeur, nous vous proposons de lui faire jouer un petit morceau de "musique".
Pour cela, appelez un enseignant qui branchera un haut-parleur sur votre maquette. Puis lancez la
compilation du processeur en lui passant en argument le programme musical : make chicken.
Programmez le FPGA : make program
Pour les plus rapides, voici quelques sujets d’investigation...
[Suivant] [Précédent] [Début] [Niveau supérieur]
Pour revenir au sommaire des supports du cours ENI.
Page maintenue par Jean Provost
Dernière modification:23 août 2006