23
Module ENSL1 : Initiation au langage VHDL Travaux Dirig´ es Eric PERONNIN

Module ENSL1 : Initiation au langage VHDL Travaux …geii.eu/fichiers/geii/cours/td_vhdl.pdf · Dresser la table de vérité du décodeur. Décrire en VHDL le bloc ... Un aanvt goût

  • Upload
    dodiep

  • View
    222

  • Download
    1

Embed Size (px)

Citation preview

Page 1: Module ENSL1 : Initiation au langage VHDL Travaux …geii.eu/fichiers/geii/cours/td_vhdl.pdf · Dresser la table de vérité du décodeur. Décrire en VHDL le bloc ... Un aanvt goût

IUT de l'Indre

Département Génie Electrique et Informatique Industrielle

Module ENSL1 : Initiation au langage VHDL

Travaux Diriges

Eric PERONNIN

Chateauroux, le 13 octobre 2012

Page 2: Module ENSL1 : Initiation au langage VHDL Travaux …geii.eu/fichiers/geii/cours/td_vhdl.pdf · Dresser la table de vérité du décodeur. Décrire en VHDL le bloc ... Un aanvt goût

2

Page 3: Module ENSL1 : Initiation au langage VHDL Travaux …geii.eu/fichiers/geii/cours/td_vhdl.pdf · Dresser la table de vérité du décodeur. Décrire en VHDL le bloc ... Un aanvt goût

Table des matières

Exercice 1 : Décodeur binaire 4 bits vers a�cheur 7 segments . . . . . . . . . . . . . . . . . 5

Exercice 2 : Compteur/décompteur synchrone binaire 4 bits à reset asynchrone . . . . . . . 5

Exercice 3 : Unité arithmétique et logique 7 opérations . . . . . . . . . . . . . . . . . . . . . 10

Exercice 4 : Module de gestion des registres d'un processeur . . . . . . . . . . . . . . . . . . 13

Exercice 5 : Mémoire de programme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

Exercice 6 : Mémoire de données (Megawizard for Custom Megafonctions de Quartus) . . . 16

Exercice 7 : Unité d'exécution du microcontrôleur IUT . . . . . . . . . . . . . . . . . . . . . 16

Page 4: Module ENSL1 : Initiation au langage VHDL Travaux …geii.eu/fichiers/geii/cours/td_vhdl.pdf · Dresser la table de vérité du décodeur. Décrire en VHDL le bloc ... Un aanvt goût

4

Page 5: Module ENSL1 : Initiation au langage VHDL Travaux …geii.eu/fichiers/geii/cours/td_vhdl.pdf · Dresser la table de vérité du décodeur. Décrire en VHDL le bloc ... Un aanvt goût

Exercices de base

Exercice 1 : Décodeur binaire 4 bits vers a�cheur 7 segments

Objectif

A�cher les chi�res 0 à 9 et lettres allant de A à F pour représenter en hexadécimal la grandeur d'entrée

du décodeur.

Cahier des charges

Le système est totalement combinatoire. Le signal entre sous une forme vectorielle composée de 4 bits

(un std_logic_vector sur 4 bits).

Il en résulte en sortie 7 signaux scalaires représentant les di�érents segments d'un a�cheur 7 segments :

signaux a, b, c, d, e, f, g.

Travail à réaliser

• Dresser la table de vérité du décodeur.

• Décrire en VHDL le bloc fonctionnel correspondant de trois manières di�érentes.

• Tester chacune des versions du décodeur.

Exercice 2 : Compteur/décompteur synchrone binaire 4 bits à reset asynchrone

Page 6: Module ENSL1 : Initiation au langage VHDL Travaux …geii.eu/fichiers/geii/cours/td_vhdl.pdf · Dresser la table de vérité du décodeur. Décrire en VHDL le bloc ... Un aanvt goût

6

Page 7: Module ENSL1 : Initiation au langage VHDL Travaux …geii.eu/fichiers/geii/cours/td_vhdl.pdf · Dresser la table de vérité du décodeur. Décrire en VHDL le bloc ... Un aanvt goût

Problème : Processeur IUT

Ce problème propose la réalisation d'un coeur de microprocesseur tel que ceux présents dans de nombreux

microcontrôleurs. Ce processeur, désigné processeur IUT car ne reposant sur aucun modèle connu, possède

les caractéristiques suivantes :

• jeu d'instructions réduit (36 dans sa version pédagogique de base),

• mémoire de programme interne au processeur limitée à 1024 mots (10 bits d'adresse pour accéder aux

instructions),

• mémoire de données interne de 256 octets,

• calculs s'e�ectuant sur 8 bits et reposant sur l'emploi de 4 registres internes de calcul notés r0, r1, r2 et

r3(les registres sont des mémoires internes au processeur utilisées pour la réalisation de calculs divers).

Un avant goût du cours d'informatique industrielle du module I2

Introduction

Un coeur de processeur est une unité de traitement séquentielle dont le fonctionnement, rythmé par

un signal d'horloge, permet d'exécuter divers traitements élémentaires codés dans une mémoire appelée

mémoire de programme. L'ensemble des informations contenues dans la mémoire de programme constitue un

programme informatique. Les di�érents traitements élémentaires possibles reposent sur diverses instructions

pouvant nécessiter plusieurs cycles d'horloge pour être exécutées :

• a�ectations,

• opérations arithmétiques et logiques,

• comparaisons,

• sauts conditionnés ou non conditionnés vers une instruction autre que l'instruction immédiatement

suivante dans le processus séquentiel.

Ces traitements permettent de manipuler des données d'origines variées :

• mémoires internes du processeur connues sous le nom de registre,

• mémoire RAM de données adjointe au processeur et accessible en lecture et en écriture par l'intermé-

diaire des bus de données, d'adresse et de contrôle,

• mémoires de périphériques permettant des liaisons diverses avec l'environnement externe au processeur

et la réalisation de fonctions cablées spéci�ques en dehors du processeur dans le but de l'assister.

Exemple de programme - Assembleur

Voici un exemple simple de programme écrit en assembleur processeur IUT :

Page 8: Module ENSL1 : Initiation au langage VHDL Travaux …geii.eu/fichiers/geii/cours/td_vhdl.pdf · Dresser la table de vérité du décodeur. Décrire en VHDL le bloc ... Un aanvt goût

8

ad r e s s e s mnémoniques opérandes commentaires

0 mov r0 ,10 ; r0 <− 10 l e r e g i s t r e r0 r e ç o i t l a va l eur 10

1 mov r1 ,230 ; r1 <− 230

2 add r1 , r0 ; r1 <− r1 + r0

3 mov (25 ) , r1 ; l ' emplacement mémoire 25 r e ç o i t l a va l eur de r1

4 mov r2 , 17 ; r2 <− 17

5 sub (25 ) , r2 ; (25) <− (25) − r2

6 and r0 , (25) ; r0 <− r0 and (25)

7 jump 2 ; saute à l ' i n s t r u c t i o n de l ' ad r e s s e 2 : pc <− 2

Cet exemple montre un programme mettant en jeu quelques instructions du processeur IUT avec r0, r1,

r2 et la donnée située à l'adresse 25 de la ram comme opérandes. Le mnémonique mov permet de réaliser

des a�ectations, add assure des additions, sub des soustractions, and permet de réaliser un et logique bit

à bit alors que l'instruction jump permet de rompre le déroulement séquentiel en spéci�ant l'adresse de la

prochaine instruction à exécuter.

Présentation du jeu d'instructions

Le tableau présenté ci-dessous présente l'ensemble du jeu d'instructions du processeur IUT dans sa

version pédagogique de base (il est tout à fait envisageable de l'étendre en exploitant des possibilités de

codage laissées libres) :

Table 1 � jeu d'instructions du processeur IUT

Dans ce tableau, 16 colonnes numérotées de 0 à 15 représentent les 16 bits constituant le code machine

d'une instruction. Ces 16 bits sont les suivants (en partant du bit de poids fort) :

• alu (bit 15) indique si l'unité arithmétique et logique du processeur est utilisée (dans ce cas alu = '1' ).

• m1 et m0 (bits 14 et 13) précisent le mode d'adressage dans le cas où l'unité arithmétique et logique

est employée. Cela renseigne sur les opérandes mis en jeu, en particulier sur la nature de l'opérande de

destination et sur celle de l'opérande source.

� Pour m1 = '0' et m0 = '0', la destination est un registre et la source est un emplacement mémoire

de la mémoire de données.

Page 9: Module ENSL1 : Initiation au langage VHDL Travaux …geii.eu/fichiers/geii/cours/td_vhdl.pdf · Dresser la table de vérité du décodeur. Décrire en VHDL le bloc ... Un aanvt goût

9

� Pour m1 = '0' et m0 = '1', la destination est un registre et la source est une information littérale

codée sur 8 bits.

� Pour m1 = '1' et m0 = '0', la destination est un registre et la source est également un registre.

� Pour m1 = '1' et m0 = '1', la destination est un emplacement de la mémoire de données et la source

est un registre.

• op2, op1 et op0 (bits 12, 11 et 10) renseignent sur l'opération que doit réaliser l'unité arithmétique

et logique lorsque celle-ci est utilisée (les détails seront vus lors de l'étude de l'unité arithmétique et

logique au cours de l'exercice 1).

• rd1, rd0 (bits 9 et 8) indiquent le numéro de registre de destination lorsque l'instruction codée en

nécessite un.

• opérandes (bits 7 à 0) revêt di�érentes formes en fonction du mode d'adressage. La description qui suit

n'a de sens que si l'unité arithmétique et logique est utilisée :

� Pour m1 = '0' et m0 = '0', ces 8 bits donnent l'adresse dans la mémoire de données de la donnée à

exploiter comme source.

� Pour m1 = '0' et m0 = '1', les 8 bits d'opérandes fournissent l'opérande source sous la forme d'un

littéral codé sur 8 bits.

� Pour m1 = '1' et m0 = '0', seuls les bits 7 et 6 sont exploités. Ils fournissent le numéro du registre

source à utiliser lors d'une opération arithmétique ou logique.

� Pour m1 = '0' et m0 = '1', les 8 bits d'opérandes précisent l'adresse dans la mémoire de donnée de

la valeur codée sur 8 bits à exploiter comme opérande source.

Lorsque l'instruction à exécuter n'exploite pas l'unité arithmétique et logique, le découpage des 16 bits est

di�érent. Par exemple, l'instruction jump repose sur un code machine faisant apparaître le code �011111�

suivi de l'adresse de l'instruction vers laquelle e�ectuer le saut.

Codage d'un programme en langage machine

Dans la mémoire de programme, on trouve donc une liste de codes machines sur 16 bits réprésentant

chacun une instruction.

Reprenons le programme donné en exemple. A l'adresse 0, on a un mov r0,12, ce qui correspond à une

instruction de type mov rd, lit. Le code correspondant dans la mémoire de programme commencera donc

par �10100000 00001100�.

On peut appliquer cette technique de codage à chacune des instructions du programme :

ad r e s s e s codes machine mnémoniques opérandes

0 1 01 000 00 0000 1100 mov r0 ,12

1 1 01 000 01 1110 0110 mov r1 ,230

2 1 10 100 01 0000 0000 add r1 , r0

3 1 11 000 01 0001 0111 mov (25 ) , r1

4 1 01 000 10 0001 0001 mov r2 , 17

5 1 11 101 10 0001 0001 sub (25 ) , r2

6 1 00 001 00 0001 0001 and r0 , (25)

7 011111 0000000010 jump 2

Note : pour plus de lisibilité, le code machine des instructions utilisant l'unité arithmétique et logique a

été découpé par groupe de bits : le bit alu, les bits du mode d'adressage, les bits du code opération, le registre

de destination (source dans le cas d'une a�ectation vers la mémoire), puis les bits soit du registre source,

soit de l'adresse mémoire ciblée, soit du littéral à a�ecter. Dans le cas du branchement, le code machine

est proposé en 2 parties : une pour indiqué un jump et l'autre pour spéci�er l'adresse de l'instruction où

s'e�ectue le saut.

Présentation de la structure interne du microcontrôleur IUT

Pour son fonctionnement, ce processeur exploite di�érents modules interconnectés entre eux :

Page 10: Module ENSL1 : Initiation au langage VHDL Travaux …geii.eu/fichiers/geii/cours/td_vhdl.pdf · Dresser la table de vérité du décodeur. Décrire en VHDL le bloc ... Un aanvt goût

10

• une mémoire de programme qui contient les instructions à exécuter : cette mémoire possède une largeur

de 16 bits (elle renvoit des données sur 16 bits correspondant au codage d'une instruction à exécuter)

et une profondeur de 1024 mots (elle nécessite qu'on lui fournisse une adresse codée sur 10 bits). Le

�chier VHDL associé à la mémoire de programme s'appellera program_memory (étude et réalisation

pratique dans l'exercice 3).

• une mémoire de données utilisée pour stocker les variables du programme nommée data_memory et

réalisée à l'aide du MegaWizard Plug-in Manager de Quartus. Sa taille est limitée à 256 octets (bus

d'adresse et de données tous deux sur 8 bits). Voir l'exercice 4 pour plus de détails.

• l'unité arithmétique et logique nommée alu de l'exercice 1. C'est l'unité de calcul du processeur. Elle

travaille avec deux opérandes codés sur 8 bits, e�ectue une opération indiquée par le biais de 3 bits

(et, ou, ou exclusif, +, -) dont elle renvoit le résultat sur 8 bits

• le module de gestion des registres de calcul interne au processeur de l'exercice 2 (module registers).

• une unité d'exécution mettant en jeu di�érents processus. Elle constitue le module principal du pro-

cesseur.

La �gure 1 montre les liaisons entre les di�érents blocs constituant la version de base du microcontrôleur IUT

en intégrant les éléments propres au coeur de processeur ainsi que les mémoires de programme et de données.

Les di�érents exercices qui suivent proposent la réalisation progressive des éléments qui apparaîssent sur ce

schéma. Une grande importance sera donnée au test unitaire de chacun de ces modules a�n de garantir le

succès du fonctionnement de l'ensemble une fois constitué comme sur ce schéma.

Exercice 3 : Unité arithmétique et logique 7 opérations

Objectif

Réaliser la description d'une unité arithmétique et logique simple capable d'e�ectuer 7 opérations.

Cahier des charges

Le fonctionnement du système est totalement combinatoire.

Les entrées du module à réaliser sont :

• operand_a : premier opérande.

• operand_b : second opérande.

• operation : mot de 3 bits précisant l'opération à e�ectuer.

• reset : entrée de remise à 0.

• clk : entrée d'horloge du processeur.

• �ag_we : signal de validation pour la mémorisation des indicateurs c_out et z_out.

Les signaux de sortie sont :

• result : mot de 8 bits contenant le résultat de l'opération.

• c_out : indicateur de retenue sur 1 bit pour l'addition.

• z_out : indicateur sur 1 bit précisant que le résultat obtenu est nul.

Tableau des di�érentes opérations :

Page 11: Module ENSL1 : Initiation au langage VHDL Travaux …geii.eu/fichiers/geii/cours/td_vhdl.pdf · Dresser la table de vérité du décodeur. Décrire en VHDL le bloc ... Un aanvt goût

11

Figure 1 � structure du microcontrôleur IUT sous Quartus

Page 12: Module ENSL1 : Initiation au langage VHDL Travaux …geii.eu/fichiers/geii/cours/td_vhdl.pdf · Dresser la table de vérité du décodeur. Décrire en VHDL le bloc ... Un aanvt goût

12

Table 2 � tableau des opérations de l'unité arithmétique et logique

Remarques :

Avec les bibliothèques habituelles, les opérations arithmétiques sur des signaux de types std_logic_vector

ne sont pas possibles (on ne peut pas utiliser l'opérateur + de la somme avec des std_logic_vector). Par

contre, le paquetage numeric_std de la bibliothèque ieee propose des types, les types unsigned et signed,

tous deux basés sur des std_logic autorisant une conversion de ces types depuis et vers des std_logic_vector

de façon directe et pour lesquels les opérateurs arithmétiques ont été dé�nis.

L'exemple suivant montre comment les utiliser :

a r c h i t e c t u r e r t l o f exemple i s

s i g n a l a , b , c : s td_log ic_vector (7 downto 0 ) ;

begin

a <= "01001010";

b <= "11110000";

c <= std_log ic_vector ( unsigned ( a ) + unsigned (b) ) ;

end r t l ;

Dans cet exemple, on crée trois signaux a, b et c vectoriels de 8 std_logic de large.

Pour réaliser la somme de a et de b, on a recours à une double conversion. La première permet de convertir

a en unsigned et b en unsigned. Les deux unsigned résultants sont alors ajoutés puis convertis en retour en

std_logic_vector.

Est-il possible de faire plus simple ?

Bien sûr ... en utilisant un paquetage dé�nissant les additions sur les std_logic_vector !

l i b r a r y i e e e ;

use i e e e . s td_log i c_ar i th . a l l ;

use i e e e . std_logic_unsigned . a l l ;

use i e e e . std_logic_1164 . a l l ;

use i e e e . numeric_std . a l l ;

. . .

. . .

a r c h i t e c t u r e r t l o f somme i f

begin

a <= "01001010";

b <= "11110000";

c <= a + b ;

end r t l ;

Précision concernant la soustraction :

On peut réaliser la soustraction en utilisant l'addition du complément à 2 de la valeur à soustraire (ici

ce sera donc le complément à 2 de operand_b).

Travail exigé

1. Réalisation simple : modèle purement combinatoire ne prenant pas en charge la retenue et

le zero.

• Analyser le problème et proposer des idées pour le traitement.

Page 13: Module ENSL1 : Initiation au langage VHDL Travaux …geii.eu/fichiers/geii/cours/td_vhdl.pdf · Dresser la table de vérité du décodeur. Décrire en VHDL le bloc ... Un aanvt goût

13

• Coder le programme.

• Tester les di�érentes opérations à l'aide de vecteurs entrés dans un �chier de test VHDL.

2. Implémentation du zero et de la retenue.

La sortie z_out indique si le résultat d'une opération est nulle. Elle est calculée uniquement pour les

opérations 1 à 7 ce qui signi�e que son état ne doit pas changer lorsque l'opération 0 (result <= operand_b)

est sélectionnée.

La retenue c_out est calculée dans le cas des opérations arithmétiques uniquement. Lorsqu'une autre

opération est réalisée, l'état de c_out doit être conservé pour re�éter la dernière opération arithmétique

réalisée.

c_out et z_out sont donc des grandeurs mémorisées. Leur mémorisation utilise le signal d'horloge clk

d'une part et s'e�ectue lorsque l'entrée �ag_we est validée d'autre part.

Note 1 : le signal �ag_we est fourni par le module execution_unit à un moment où il est connu que les

données calculées pour c_out et z_out sont pertinentes.

Note 2 : lorsque reset = '1', les signaux c_out et z_out sont remis à 0 sans autre condition (on dit que

le reset est prioritaire).

Le calcul de c_out obéit aux équations suivantes :

• cas d'une soustraction : c_out <= operand_a7.operand_b7+operand_b7.result7+result7.operand_a7

• cas d'une addition : c_out <= operand_a7.operand_b7 + operand_b7.result7 + result7.operand_a7

Lorsque son calcul est nécessaire, z_out obéit quand à lui à l'équation suivante :

z_out <= result7.result6.result5.result4.result3.result2.result1.result0

• Implémenter ces deux indicateurs.

• Tester le fonctionnement du module �nalisé.

Exercice 4 : Module de gestion des registres d'un processeur

Objectif

Créer un module permettant de gérer les registres du futur processeur IUT.

Cahier des charges

Ce module permet de gérer 4 registres 8 bits dénommés : r0, r1, r2 et r3.

Il doit permettre de mettre à jour l'état de ces registres à partir de la sortie de l'unité arithmétique et

logique connectée à l'entrée reg_in et de conserver leurs valeurs le reste du temps.

Les entrées sont les suivantes :

• clk : horloge du processeur.

• reset : l'entrée d'initialisation du système (à la mise à 0, les 4 registres sont remis à 0 : r1 <= �00000000�

...).

• dest_reg(1..0) : mot de 2 std_logic indiquant le numéro du registre à mettre à jour (�00� pour r0 à

�11� pour r3).

• reg_in(7..0) : vecteur de 8 std_logic contenant la valeur sur 8 bits à stocker dans le registre de desti-

nation indiqué par dest_reg.

• reg_we : signal de type std_logic autorisant la mise à jour du registre spéci�é par dest_reg. Si reg_we

= '1' et qu'un front montant de l'horloge clk intervient alors le registre spéci�é par dest_reg reçoit la

valeur de reg_in.

Les sorties sont :

Page 14: Module ENSL1 : Initiation au langage VHDL Travaux …geii.eu/fichiers/geii/cours/td_vhdl.pdf · Dresser la table de vérité du décodeur. Décrire en VHDL le bloc ... Un aanvt goût

14

• r0(7..0), r1(7..0), r2(7..0) et r3(7..0) : les 4 registres 8 bits du processeur IUT dont l'état est mémorisé

dans l'attente d'une mise à jour indiquée par reg_we..

Fonctionnement :

• Le reset est prioritaire (donc asynchrone) et provoque la mise à 0 des di�érents registres.

• Lors d'un front montant d'horloge, si reg_we = '1' alors le registre dont le numéro est indiqué par

dest_reg reçoit la valeur présente sur l'entrée reg_in. Par exemple, au front montant d'horloge, si

reg_we = '1' et que dest_reg = �10� alors r2 <= reg_in.

Travail demandé

• Donner une table de vérité de synthèse du module registers.

• Décrire ce module en langage VHDL (on appellera l'entité registers et le �chier VHDL associé sera

nommé registers.vhd)

• Tester le module dans di�érents cas de �gures choisis su�samment exhaustifs.

Exercice 5 : Mémoire de programme

Il s'agit de décrire le module program_memory en langage VHDL.

Dans le respect des règles, il est bien clair que ce module devrait reposer sur une mémoire ROM telle

que celle que propose Altera dans son Megawizard. En e�et, dans le cas d'une implémentation par Quartus

avec un bloc dédié, c'est une portion de la mémoire embarquée dans le FPGA (les fameux M4K) qui sera

généralement exploitée. A contrario, la description combinatoire imposée dans cet exercice utilisera des

éléments logiques uniquement, consommant ainsi en grand nombre des portes logiques qui auraient pu servir

à toute autre chose (le but d'un M4K est exclusivement d'être exploité dans une fonction de mémoire).

Ainsi, le module program_memory est un programme VHDL combinatoire reposant sur une table de

vérité renvoyant un code machine sur 16 bits en sortie pour une adresse sur 10 bits fournie en entrée.

Dans le cas du programme fourni en exemple, la table de vérité mise en place est la suivante :

prg_address prg_data

0 1010 0000 0000 1100

1 1010 0001 1110 0110

2 1101 0001 0000 0000

3 1110 0001 0001 0111

4 1010 0010 0001 0001

5 1111 0110 0001 0001

6 1000 0100 0001 0001

7 0111 1100 0000 0010

Le codage de cette table de vérité en l'état présente un problème de lisibilité évident : qui se souviendra

que l'adresse 0 renferme une instruction mov r0, 12 ?

A des �ns d'essais et en attendant de disposer d'un logiciel assembleur capable de passer d'un source

contenant des mnémoniques à un �chier exécutable contenant une suite de codes machines, on aura très cer-

tainement besoin d'un moyen permettant de spéci�er les codes machines dans le �chier program_memory.vhd

avec davantage de souplesse.

Le code présenté ci-dessous propose une approche exploitant des constantes et l'opérateur de concaténa-

tion pour réaliser un codage plus explicite :

Page 15: Module ENSL1 : Initiation au langage VHDL Travaux …geii.eu/fichiers/geii/cours/td_vhdl.pdf · Dresser la table de vérité du décodeur. Décrire en VHDL le bloc ... Un aanvt goût

15

l i b r a r y i e e e ;

use i e e e . numeric_std . a l l ;

use i e e e . std_logic_1164 . a l l ;

use i e e e . s td_log i c_ar i th . a l l ;

use i e e e . std_logic_unsigned . a l l ;

e n t i t y program_memory i s port (

prg_address : in std_log ic_vector (9 downto 0 ) ;

prg_data : out std_log ic_vector (15 downto 0)

) ;

end en t i t y ;

a r c h i t e c t u r e r t l o f program_memory i s

constant r0 : s td_log ic_vector (1 downto 0) := "00" ;

constant r1 : s td_log ic_vector (1 downto 0) := "01" ;

constant r2 : s td_log ic_vector (1 downto 0) := "10" ;

constant r3 : s td_log ic_vector (1 downto 0) := "11" ;

constant i_reg_ram : std_log ic_vector (2 downto 0) := "100" ;

constant i_reg_reg : s td_log ic_vector (2 downto 0) := "110";

constant i_reg_l i t : s td_log ic_vector (2 downto 0) := "101";

constant i_ram_reg : s td_log ic_vector (2 downto 0) := "111" ;

constant op_mov : std_log ic_vector (2 downto 0) := "000" ;

constant op_and : std_log ic_vector (2 downto 0) := "001" ;

constant op_or : s td_log ic_vector (2 downto 0) := "010" ;

constant op_xor : s td_log ic_vector (2 downto 0) := "011" ;

constant op_add : std_log ic_vector (2 downto 0) := "100" ;

constant op_sub : std_log ic_vector (2 downto 0) := "101";

constant op_not : s td_log ic_vector (2 downto 0) := "110" ;

constant op_cmp : std_log ic_vector (2 downto 0) := "111" ;

constant i_jump : std_log ic_vector (5 downto 0) := "011111";

begin

proce s s ( prg_address )

begin

case prg_address (9 downto 0) i s

when "0000000000" =>

prg_data <= i_reg_l i t & op_mov & r0 & std_log ic_vector ( to_unsigned ( 1 2 , 8 ) ) ;

when "0000000001" =>

prg_data <= i_reg_l i t & op_mov & r1 & std_log ic_vector ( to_unsigned ( 2 3 0 , 8 ) ) ;

when "0000000010" =>

prg_data <= i_reg_reg & op_add & r1 & r0 & "000000";

when "0000000011" =>

prg_data <= i_ram_reg & op_mov & r1 & std_log ic_vector ( to_unsigned ( 2 5 , 8 ) ) ;

−−−− A vous de poursu iv re l e codage en exp l o i t an t ce s premiers exemples .

−−

when othe r s =>

prg_data <= "0000000000000000";

end case ;

end proce s s ;

end r t l ;

Travail demandé

• Ajouter le module program_memory.vhd à votre projet.

• Reprendre l'exemple fourni ci-dessous et le compléter.

• Proposer une procédure et la mettre en oeuvre pour valider le bon fonctionnement de la mémoire de

programme.

Page 16: Module ENSL1 : Initiation au langage VHDL Travaux …geii.eu/fichiers/geii/cours/td_vhdl.pdf · Dresser la table de vérité du décodeur. Décrire en VHDL le bloc ... Un aanvt goût

16

Exercice 6 : Mémoire de données (Megawizard for Custom Megafonctions de

Quartus)

Exercice 7 : Unité d'exécution du microcontrôleur IUT

Objectif

Réaliser l'unité d'exécution d'un processeur 8 bits disposant d'un jeu d'instructions réduit : le microcon-

trôleur IUT.

La réalisation de ce module va comporter de nombreuses étapes au cours desquelles di�érents processus

seront implémentés.

Présentation de l'unité d'exécution (execution_unit dans notre projet) - Fonc-

tionnement

L'unité d'exécution est le module qui va prendre en charge les instructions en provenance de la mémoire

de programme et dispatcher les informations utiles aux di�érents modules du processeur pour mener à bien

l'exécution de l'instruction. En particulier, elle comunique à l'unité arithmétique et logique ses di�érents

signaux d'entrée ; elle réalise l'interface avec la mémoire de données et elle assure la mémorisation des

registres en cas d'évolution de leur valeur lors de l'exécution d'une instruction.

Reprenons une version allégée du premier exemple de programme :

ad r e s s e s mnémoniques opérandes commentaires

0 mov r0 ,12 ; r0 <− 12 l e r e g i s t r e r0 r e ç o i t l a va l eur 12

1 mov r1 ,230 ; r1 <− 230

2 add r1 , r0 ; r1 <− r1 + r0

3 mov (25 ) , r1 ; l ' emplacement mémoire 25 r e ç o i t l a va l eur de r1

4 and r0 , (25) ; r0 <− r0 and (25)

5 jump 2 ; saute à l ' i n s t r u c t i o n de l ' ad r e s s e 2 : pc <− 2

L'exécution de ce programme s'e�ectue en de nombreuses étapes :

• Phase d'initialisation

� A la mise sous tension, une impulsion de reset est transmise au processeur IUT a�n de l'initialiser.

� Les registres (r0, r1, r2 et r3) sont tous remis à 0 ; le registre pc pour program counter est également

initialisé à 0 pour pointer vers l'instruction située à l'adresse 0 de la mémoire de programme (i.e. la

première instruction de notre programme).

� L'exécution d'une instruction s'e�ectuant systématiquement en 4 cycles d'horloge, un compteur de

cycle re�étant le niveau d'avancement dans l'exécution de l'instruction en cours est initialisé à un

état Q0 (il évoluera ensuite vers l'état Q1, puis Q2, puis Q3 pour revenir à Q0 ; le cycle se répétant

indé�niment).

• Adresse 0 : mov r0, 12

� Le compteur de cycle se trouve en Q0 et le front montant d'horloge apparaît :

∗ Le processeur charge l'instruction qui se trouve à l'adresse 0 : mov r0, 12 et incrémente immédia-

tement le compteur de programme pc (pc← pc+ 1). Note : cette instruction est stockée dans un

signal vectoriel noté instruction. On a donc instruction = �1010 0000 0000 1100�.

∗ L'unité d'exécution du processeur envoie r0 à l'operand_a de l'unité arithmétique et logique. Elle

attribue la valeur �00001100� à operand_b et transmet le code opération �000� au signal operation

de l'alu.

∗ La destination étant le registre r0, l'unité d'exécution �xe le signal dest_reg à �00� pour le module

registers.

� Au front descendant de l'horloge, le compteur de cycle passe en Q1 : rien à faire.

� Au front descendant de l'horloge, le compteur de cycle passe en Q2 : rien à faire.

� Au front descendant de l'horloge, le compteur de cycle passe en Q3 :

Page 17: Module ENSL1 : Initiation au langage VHDL Travaux …geii.eu/fichiers/geii/cours/td_vhdl.pdf · Dresser la table de vérité du décodeur. Décrire en VHDL le bloc ... Un aanvt goût

17

∗ La sortie de l'alu est dirigé vers l'entrée reg_in du module registers (dans les faits, la sortie de

l'alu sera toujours dirigée vers reg_in).

∗ Le signal reg_we est positionné à '1' pour autoriser l'écriture dans le registre r0 lors du prochain

front montant d'horloge (reg_we ne conservera cette valeur que durant ce cycle Q3).

� Au front montant d'horloge suivant, alors que le compteur de cycle est en Q3, le module registers

mémorise dans r0 la valeur présente sur reg_in.

� On repasse au Q0 au front descendant d'horloge.

• Adresse 1 : mov r1, 230

� même traitement en 4 cycles d'horloge que pour l'instruction précédente. Seul le registre de desti-

nation change (dest_reg = �01�). L'operand_b reçoit quand à lui la valeur 230 codée en binaire non

signé.

• Adresse 2 : add r1, r0

� on reprend les cycles Q0 à Q3 de l'instruction précédente en changeant ceci au cycle Q0 :

∗ operand_a reçoit la valeur stockée dans r1. operand_b reçoit la valeur présente dans r0. operation

reçoit la valeur �100� correspondant à l'addition.

∗ dest_reg reçoit �01� pour indiquer le registre de destination.

Notes :

∗ Ce sont les bits 9 et 8 du mot instruction qui renseigne sur le numéro de registre de destination.

∗ Les bits 7 et 6 du signal instruction indique le numéro du registre source.

∗ Les bits 12 à 10 du signal instruction donne le code de l'opération à réaliser dans l'unit arithmé-

tique et logique.

� Durant le cycle Q3 et uniquement pour ce cycle, l'unité d'exécution autorise l'écriture sur le registre

destination en �xant reg_we = '1'.

• Adresse 3 : mov (25), r1

� Cycle Q0, au front montant d'horloge :

∗ Le processeur charge l'instruction qui se trouve à l'adresse 3 : mov (25), r1 et incrémente immé-

diatement le compteur de programme pc (pc← pc+1). On a donc instruction = �1110 0001 0001

1001�.

∗ L'adresse 25 est transmise à la ram a�n d'accéder à la donnée qui y est stockée (pas utile dans le

cas d'un mov) et de préparer l'accès pour l'écriture du résultat qui interviendra au cycle Q3.

∗ Les données suivantes sont envoyées à l'unité arithmétique et logique :

· operand_a reçoit la donnée provenant de la ram (elle ne sera pas utile mais le traitement est le

même que pour les autres instructions faisant appel à l'unité arithmétique et logique dans le cas

d'une destination en mémoire).

Remarque : en Q0, cette donnée n'est pas nécessairement la bonne car la lecture nécessite un cycle

d'horloge supplémentaire et l'adresse vient seulement d'être fournie à la mémoire ram.

· operand_b est a�ecté par la valeur stockée dans le registre de travail r1.

· Le code operation est �xé à �000�.

� Rien de se passe au cycle Q1

� Au front descendant d'horloge durant le cycle Q2, le compteur de cycle passe en Q3 et l'autorisation

d'écriture dans la ram (ram_we = '1') est fournie à la mémoire de donnée. Cette autorisation sera

maintenue durant tout le cycle Q3.

� Cycle Q3, front montant d'horloge :

∗ Le signal result présent à la sortie de l'unité arithmétique et logique et transmis au début du cycle

Q3 à l'entrée data de la mémoire de données est mémorisée par cette même mémoire.

� Passage en Q0 au front descendant d'horloge.

• Adresse 4 : and r0, (25)

� Cycle Q0, au front montant d'horloge :

∗ Le processeur charge l'instruction qui se trouve à l'adresse 4 : mov r0, (25) et incrémente immé-

Page 18: Module ENSL1 : Initiation au langage VHDL Travaux …geii.eu/fichiers/geii/cours/td_vhdl.pdf · Dresser la table de vérité du décodeur. Décrire en VHDL le bloc ... Un aanvt goût

18

diatement le compteur de programme pc (pc← pc+1). On a donc instruction = �1000 0100 0001

1001�.

∗ L'adresse 25 est transmise à la ram a�n d'accéder à la donnée qui y est stockée.

∗ Les données suivantes sont envoyées à l'unité arithmétique et logique :

· operand_a est a�ecté par la valeur stockée dans le registre de travail r0.

· operand_b reçoit la donnée provenant de la ram.

Remarque : en Q0, cette donnée n'est pas nécessairement la bonne car la lecture nécessite un cycle

d'horloge supplémentaire et l'adresse vient seulement d'être fournie à la mémoire ram. Cependant,

operand_b étant calculé par un processus combinatoire (ni plus ni moins qu'un multiplexeur

comme nous le verrons plus loin), il prendra la valeur adéquate lorsqu'elle sera disponible à la

sortie q de la mémoire de données. La sortie result de l'unité arithmétique et logique étant elle

même décrite par un processus combinatoire, elle sera alors immédiatement mise à jour au moment

de la mise en place de la bonne valeur de l'operand_b.

· Le code operation est �xé à �001� (pour le and).

� Rien de se passe au cycle Q1

� Au front descendant d'horloge durant le cycle Q2, le compteur de cycle passe en Q3 et l'autorisation

de mise à jour des registres (reg_we = '1') est fournie au module registers. Cette autorisation sera

maintenue durant tout le cycle Q3.

� Cycle Q3, front montant d'horloge :

∗ Le signal result présent à la sortie de l'unité arithmétique et logique et transmis au début du cycle

Q3 à l'entrée data de la mémoire de données est mémorisée par cette même mémoire.

� Passage en Q0 au front descendant d'horloge.

• Adresse 5 : jump 2

� Le compteur de cycle se trouve en Q0 et le front montant d'horloge apparaît :

∗ Le processeur charge l'instruction qui se trouve à l'adresse 5 : jump 2 et incrémente immédiatement

le compteur de programme pc (pc← pc+ 1).

Note : on a instruction = �0111 1100 0000 0010�.

� Front montant d'horloge durant le cycle Q1 :

∗ l'unité d'exécution a�ecte pc avec la valeur de l'adresse à atteindre pour la prochaine instruction.

Ici, on saute à l'adresse 2 donc pc recevra la valeur 2.

� Pas de traitement supplémentaire durant les cycles restants.

La simulation temporelle du processeur exécutant ce programme donne les chronogrammes suivants :

Page 19: Module ENSL1 : Initiation au langage VHDL Travaux …geii.eu/fichiers/geii/cours/td_vhdl.pdf · Dresser la table de vérité du décodeur. Décrire en VHDL le bloc ... Un aanvt goût

19

Figure 2 � chronogrammes du processeur exécutant le programme exemple

Page 20: Module ENSL1 : Initiation au langage VHDL Travaux …geii.eu/fichiers/geii/cours/td_vhdl.pdf · Dresser la table de vérité du décodeur. Décrire en VHDL le bloc ... Un aanvt goût

20

Sur ce graphique, cycle représente cycle_counter sous la forme d'un std_logic_vector.

Conception, réalisation et test des di�érents processus du module de l'unité

d'exécution

Vue externe imposée de l'unité d'exécution

Elle est présentée �gure 3.

Figure 3 � symbôle de l'unité d'exécution

Les entrées/sorties de l'unité d'exécution sont les suivantes :

• Signaux généraux :

� clk : le signal d'horloge du processeur.

� cycle : signal de sortie sur 2 bits indiquant le numéro du cycle en cours dans le traitement d'une

instruction.

� reset : entrée de remise à 0 de l'unité d'exécution.

• Signaux réalisant l'interfaçage avec la mémoire de programme

� prg_data : entrée sur 16 bits correspondant à la donnée pointée dans la mémoire de programme.

� prg_address : sortie sur 10 bits spéci�ant l'adresse dans la mémoire de programme de la prochaine

instruction à exécuter.

• Signaux d'interfaçage avec la mémoire de données :

� ram_data : entrée sur 8 bits contenant la donnée actuellement lue dans la mémoire de données.

� ram_address : sortie sur 8 bits indiquant l'adresse de la donnée ciblée dans la mémoire de données.

� ram_we : signal binaire indiquant à la mémoire de données si une écriture doit être e�ectuée au

prochaine front montant d'horloge.

Page 21: Module ENSL1 : Initiation au langage VHDL Travaux …geii.eu/fichiers/geii/cours/td_vhdl.pdf · Dresser la table de vérité du décodeur. Décrire en VHDL le bloc ... Un aanvt goût

21

• Signaux d'interfaçage avec l'unité arithmétique et logique :

� alu_operand_a : sortie sur 8 bits fournissant l'operand_a (dit de destination) à l'unité arithmétique

et logique.

� alu_operand_b : sortie sur 8 bits fournissant l'operand_b (dit source) à l'unité arithmétique et

logique.

� alu_operation : entrée/sortie sur 3 bits spéci�ant l'opération à réaliser au sein de l'unité arithmétique

et logique.

� alu_�ag_we : sortie précisant à l'unité arithmétique et logique si les indicateurs doivent être mis à

jour.

� alu_c : entrée recevant la retenue actuellement mémorisée dans l'unité arithmétique et logique.

� alu_z : entrée recevant l'indicateur de zéro actuellement stocké dans l'unité arithmétique et logique.

• Signaux d'interfaçage avec le module de gestion des registres internes :

� r0, r1, r2, r3 : entrées reçues du module registers donnant les 4 registres internes du processeurs

(tous sur 8 bits).

� reg_we : sortie indiquant au module registers que la mise à jour d'un registre doit être réalisée au

prochain front montant d'horloge.

� dest_reg : entrée/sortie sur 2 bits spéci�ant le numéro du registre interne à mettre à jour.

Travail préparatoire

• Copier dans votre dossier ENSL1 le dossier processeur stocké dans le dossier @partage_lecture\ENSL1\

Ce dossier contient une version du projet corrigée avec les di�érents modules déjà développés jusqu'ici ainsi

qu'un �chier execution_unit.vhd contenant essentiellement la description externe du module execution_unit.

Processus numéro 1 : Séquenceur d'instruction (cycle_counter)

L'exécution d'une instruction s'e�ectue en 4 cycles d'horloge notés Q0 à Q3. A�n d'assurer le séquen-

cement de l'exécution, on doit disposer à tout instant d'un compteur à l'intérieur de l'unité d'exécution

indiquant le cycle de calcul en court.

• En vous inspirant du cours, créer un type énuméré pouvant prendre les valeurs Q0, Q1, Q2 et Q3.

• Réaliser un processus permettant de passer successivement de Q0 à Q1, de Q1 à Q2 ...... de Q3 à Q0 à

chaque front descendant de l'horloge.

Notes :

• le cycle en cours du processeur sera mémorisé dans un signal noté cycle_counter.

• le reset sera prioritaire et remettra le système dans son état Q0.

Processus numéro 2 : Processus séquentiel d'exécution des instructions

C'est le processus le plus important de l'unité d'exécution.

Il gère l'évolution du compteur de programme pc et prélève l'instruction présente sur le bus de données

de la mémoire de programme au front montant d'horloge qui intervient lorsque le compteur de cycle est à

l'état Q0.

Note : le code de l'instruction sera mémorisé dans un signal intermédiaire nommé instruction (vecteur

de 16 std_logic) et déclaré entre le mot clé architecture et son begin.

• Ajouter la déclaration du signal instruction au programme.

• Ecrire le processus de gestion de pc en tenant compte des points suivants :

� le reset est prioritaire et entraîne la mise à 0 de pc.

� Quand un front montant d'horloge se présente alors que le compteur de cycle est en Q0 :

∗ Mémoriser le signal prg_data en provenance de la mémoire de programme dans le signal interne

instruction.

∗ Incrémenter pc pour pointer vers l'instruction suivante.

Page 22: Module ENSL1 : Initiation au langage VHDL Travaux …geii.eu/fichiers/geii/cours/td_vhdl.pdf · Dresser la table de vérité du décodeur. Décrire en VHDL le bloc ... Un aanvt goût

22

� Lors d'un front montant d'horloge pendant le cycle Q2 :

∗ Tester si l'instruction en cours d'exécution est un jump.

∗ Si oui, changer la valeur de pc en imposant l'adresse indiquée dans le code instruction du jump.

� Pour l'instant, ne rien faire pour les cycles Q1 et Q3.

• Tester le fonctionnement de l'ébauche de processeur avec le programme exemple exploité jusqu'ici.

• En opérant comme pour l'instruction jump, mettre en place le décodage et l'exécution des instructions

de sauts conditionnés skipifz (on incrémente pc si z=1 ) et skipifc (incrémentation de pc si c=1 ).

Note : les instructions skipifz et skipifc seront testées plus tard.

Processus numéro 3 : Envoi des opérandes operand_a et operand_b à l'unité arithmétique et

logique

Il s'agit d'écrire un processus combinatoire (ceci implique que les sorties de ce processus reçoivent sys-

tématiquement une valeur lors du traitement du process) permettant de fournir les opérandes à l'unité

arithmétique et logique.

Note : l'exemple ci-dessous apporte une illustration sur le caractère combinatoire ou séquentiel d'un

process.

a r c h i t e c t u r e r t l o f exemple i s

s i g n a l a , b : s td_log ic_vector (3 downto 0 ) ;

begin

−− l e p roce s su s proc_1 e s t un proce s su s s é qu en t i e l car

−− s i a vaut "0101" a l o r s b e s t mémorisé

−− et ne r e ç o i t pas de nouve l l e va l eur .

proc_1 : p roce s s ( a )

begin

i f a /= "0101" then b <= a ; end i f ;

end proce s s ;

−− l e p roce s su s c i−dessous e s t combinato i re car b r e ç o i t

−− t ou jou r s une va l eur l o r s du tra i t ement du proce s su s .

p roce s s ( a )

begin

i f a = "0000" then b <= "1010"; e l s e b <= a ; end i f ;

end proce s s ;

end r t l ;

Analyse du jeu d'instructions En se référant au tableau décrivant les di�érentes instructions du pro-

cesseur IUT, on peut constater que :

• operand_a = rd et operand_b = data_ram pour les instructions mov rd,(ram) à cmp rd,(ram)

• operand_a = rd et operand_b = lit pour les instructions mov rd,lit à cmp rd,lit

• operand_a = rd et operand_b = rs pour les instructions mov rd,rs à cmp rd,rs

• operand_a = data_ram et operand_b = rs pour les instructions mov (ram),rs à cmp (ram),rs

où rd représente le registre de destination identi�é dans le code instruction par les bits 9 et 8 (�00� pour le

registre r0 ...),

où rs spéci�e le registre source identi�é dans le code instruction par les bits 7 et 6 (�00� pour le registre

r0 ...) dans le cas des instructions de la classe mov rd,rs et par les bits 9 et 8 dans le cas des instructions de

la catégorie mov (ram),rs,

et où data_ram est le mot de 8 bits à destination ou en provenance de la mémoire de données.

Travail demandé

• Dresser une table de vérité faisant apparaître :

� En entrées : les 3 bits de poids forts du code machine contenu dans le vecteur instruction.

� En sorties : operand_a et operand_b.

Page 23: Module ENSL1 : Initiation au langage VHDL Travaux …geii.eu/fichiers/geii/cours/td_vhdl.pdf · Dresser la table de vérité du décodeur. Décrire en VHDL le bloc ... Un aanvt goût

23

Notes : les sorties recevront di�érents signaux tels que data_ram, rd, rs, lit (le poids faible du code

machine instruction) ...Par ailleurs, il est possible de prélever les 3 bits de poids forts du signal

instruction en écrivant instruction(15 downto 13) dans le code VHDL.

• Décrire cette table de vérité dans un processus combinatoire.

Attention : on ne pourra pas écrire operand_a <= rd dans le programme. Il faudra utiliser les bits du signal

instruction spéci�ant rd (dest_reg en fait) pour faire le choix de r0, r1, r2 ou encore r3. La même démarche

devra être mise en oeuvre pour la source rs.

• Tester l'intégralité du processeur, observer l'évolution des signaux d'opérandes de l'unité arithmétique

et logique et véri�er leur cohérence avec le programme de test.

Processus numéro 4 : Génération du signal reg_we autorisant la mise à jour du registre de

destination

Il s'agit d'un processus combinatoire. Lorsque l'instruction en cours cible un registre appelé registre de

destination et repéré par le signal dest_reg, le signal reg_we doit être mis à '1' durant le cycle Q3 du

compteur de cycle. Le reste du temps, reg_we reçoit la valeur '0'.

Travail demandé

• Coder ce 4ième process et le tester.

Note : à ce stade, le processeur est capable de réaliser une a�ectation vers un registre.

Processus numéro 5 : Génération du signal ram_we autorisant la mise à jour d'une donnée

dans la mémoire de données

Il s'agit à nouveau d'un processus combinatoire. Lorsque l'instruction en cours cible ma mémoire de

donnée comme destination (instructions de type (ram),rs), le signal ram_we doit être mis à '1' durant le

cycle Q3 du compteur de cycle. Le reste du temps, ram_we reçoit la valeur '0'.

Travail demandé

• Coder ce 5ième process et le tester.

Note : à ce stade, le processeur est capable de mémoriser la valeur d'un registre à l'intérieur de la mémoire

de données.

Processus numéro 6 : Génération du signal �ag_we autorisant la mise à jour ds indicateurs

de l'unité arithmétique et logique

Il s'agit encore une fois d'un processus combinatoire. Lorsque l'instruction en cours utilise l'unité arith-

métique et logique, le signal �ag_we doit être mis à '1' durant le cycle Q3 du compteur de cycle. Le reste

du temps, �ag_we reçoit la valeur '0'.

Travail demandé

• Coder ce 6ième process et le tester.

Note : à ce stade, l'unité arithmétique et logique est rendue totalement fonctionnelle. Les indicateurs z et

c informent sur le résultat de certaines opérations dans l'unité arithmétique et logique et il est possible

d'exploiter les instructions de sauts conditionnés skipifz et skipifc.