Ce projet a pour but d`implémenter un processeur de Harvard en

Transcription

Ce projet a pour but d`implémenter un processeur de Harvard en
EL FAHSSI Hamid DELPY Julien ELEC4 Ce projet a pour but d’implémenter un processeur de Harvard en langage
VHDL. L’intérêt de celui-ci est double : nous permettre de mettre en pratique
les connaissances théoriques que nous avons acquises, et de le faire sur un cas
réel qu’est l’implémentation d’un processeur. La construction de ce processeur
se fera par étape : nous constituerons d’abord indépendamment les unes des
autres trois entités élémentaires, vérifierons leur fonctionnement, puis les
assemblerons pour constituer le processeur Harvard dans sa totalité.
1 EL FAHSSI Hamid DELPY Julien ELEC4 SOMMAIRE
Cahier des charges
1. La mémoire de données…………………………………....….3
2. Le chemin de données……………………………………...…3
3. L'unité de contrôle………………………………………...…..4
I – L’unité de contrôle
1. Principe……………………………………………………..6
2. Test…………………………………………………………7
II – Le chemin de données
1. Principe………………………………………………….....9
2. Test……………………………………………………..…10
III – La mémoire de données
1. Principe…………………………………………………....12
2. Test………………………………………………………..12
IV – Le calculateur complet
1. Principe…………………………………………………….14
2. Test………………………………………………………...15
Conclusion……………………………………………………...17
Annexes………………………………………………………….18
2 EL FAHSSI Hamid DELPY Julien ELEC4 Cahier des charges
Comme le montre la figure précédente, le modèle de notre calculateur sera découpé en trois
entités distinctes :
1. L'unité de contrôle
2. Le chemin de données
3. La mémoire de données
L'assemblage des trois entités dans une architecture du type structurel permettra d'aboutir au
calculateur de Harvard.
1. La mémoire de données
-
La mémoire de données dispose de 216 cases mémoires de 16 bits chacune.
-
L'opération d'écriture est autorisée sur niveau haut du signal du signal MW (type bit) et
de manière asynchrone.
-
La valeur pointée par l'adresse (adr type unsigned) sera toujours disponible en lecture.
-
L'adresse du mot en lecture et en écriture est donc commune et toute valeur écrite en
mémoire modifie la valeur en sortie.
-
Le comportement de la mémoire sera décrit par un process manipulant une variable de
type tableau.
-
Les données de la mémoire seront du type signed (datain et dataout).
-
L'initialisation sera faite par lecture dans un fichier.
2. Le chemin de données
La figure suivante montre les divers composants du chemin de données.
1. Le banc de registre : il est constitué de 8 registres de 16 bits chacun. Ils agissent
comme une mémoire extrêmement rapide pour les calculs.
2. L'unité fonctionnelle : elle se charge des opérations arithmétiques, logiques ou de
simples transferts.
3. Des multiplexeurs pour aiguiller le flot de données en fonction du mot de contrôle.
-
Le Mux B permet l'aiguillage d'une constante contenue dans le mot de contrôle ou
d'une donnée B lue dans le banc de registre. Le temps de propagation du signal est de
1 ns.
-
Le Mux D permet l'aiguillage du résultat d'un traitement de l'unité fonctionnelle ou
3 EL FAHSSI Hamid DELPY Julien ELEC4 d'une donnée en provenance de la mémoire vers un registre du banc de registre. Le
temps de propagation du signal est de 1 ns.
-
Le bloc zéro fill permet d'ajuster la taille de la constante au format utilisé (il ajoute
donc 13 zéros).
-
Le banc de registre sera un tableau de 8 données de type signed. Seul un registre est
accessible à la fois en écriture. On le note D. L'écriture est synchrone à l'horloge et se
fait lorsque le signal RW est à niveau haut. La lecture de données se fait sur deux bus
distincts. Il est donc possible de sélectionner deux registres en lecture noté A et B. Les
lectures ou l'écriture dans un registre du banc de registre prend 3 ns.
-
L'unité fonctionnelle se charge des divers traitements à effectuer sur les données
présentent sur le bus A et le bus B et les écrit dans le bus D. Le traitement des
opérations prend 4 ns. Les fonctionnalités remplies en fonction des bits du mot de
contrôle sont les suivantes :
-
Les indicateurs à traiter sont les suivants. N qui prend la valeur 1 quand le résultat sur
le bus D est négatif. Z qui prend la valeur 1 quand le résultat sur le bus D est nul.
L'affectation de l'état des indicateurs prend 1 ns.
-
Les signaux rst, clk, N et Z sont de type bit.
-
Les signaux ctrlword et adr sont de type unsigned.
-
Le signal constante est de type signed.
-
Les signaux datain et dataout sont de type signed.
-
Le signal rst permettra de positionner les registres dans un état initial.
-
L'architecture sera décrite avec un modèle flot de données (affectations concurrentes).
3. L'unité de contrôle
Elle se charge de lire et décoder l'instruction en mémoire. Le décodage fournit un mot de
contrôle au chemin de données.
-
La mémoire d'instructions est une mémoire d'unsigned. Elle dispose de 216cases
mémoires de 16 bits chacune. On suppose qu'elle n'est accessible qu'en lecture et que
les instructions devront être chargées avant l'exécution. L'opération de lecture prend 3
ns. L'instruction en sortie de mémoire est appelé InstructionRegister
-
Le compteur ordinal PC fournit l'adresse de l'instruction à extraire. Il est mis à jour à
chaque cycle d'horloge. L'incrémentation ou le chargement de PC prend 1 ns.
-
Dans le cas d'un branchement conditionnel sur Z, PC reçoit la somme du PC courant et
de l'extension quand l'indicateur Z est à 1. Sinon PC est simplement incrémenté.
-
Dans le cas d'un branchement conditionnel sur N, PC reçoit la somme du PC courant
et de l'extension quand l'indicateur N est à 1. Sinon PC est simplement incrémenté
-
Dans le cas d'un saut inconditionnel, PC reçoit l'adresse de branchement.
-
Dans les autres cas, PC est incrémenté.
PL
JB
BC
Incrémentation
PC Opération
0
0
0
Saut inconditionnel
1
1
0
4 EL FAHSSI Hamid DELPY Julien ELEC4 PC Opération
PL
JB
BC
Branchement sur N (sinon Incrémentation)
1
0
1
Branchement sur Z (sinon Incrémentation)
1
0
0
-
Le signal rst replace le PC à l'adresse 0.
-
Le décodage de l'instruction se fait sur 20 bits. 16 bits constituent le mot de
contrôle :
Illustration 12: Format du mot de contrôle
Les 4 autres bits sont MW (Memory Write), PL, JB et BC. Ils sont définis par la table
suivante. Le décodage prend 1 ns.
-
Le bloc d'extension fournit le décalage d'adresse au bloc PC pour effectuer les
sauts. Il prend en entrée la concaténation des bits de poids faibles et forts du
déplacement et effectue une extension de signe pour ajuster les données sur 16
bits.
-
Le bloc de Contrôle de Branchement permet de spécifier quand un chargement est
nécessaire. La table suivante spécifie les valeurs de Ld en fonction de BC, Z et V :
= ⋅  ⋅
-
Les signaux clk, rst, V, C, N, Z et MW sont de type bit.
-
Les signaux adr et ctrlword sont de type unsigned et cste (IR[2..0]) de type signed.
-
L'architecture sera décrite avec un modèle flot de données (affectations
concurrentes).
5 EL FAHSSI Hamid DELPY Julien ELEC4 I – L’unité de contrôle
1-Principe
Nous commençons d’abord par l’unité de contrôle. Sa description est dessinée cidessous :
Il manque un élément qui n’est pas dessiné sur ce schéma : il s’agit du signal d’entrée reset
sur le bloc PC qui permettra de se remettre à l’adresse d’initialisation si le reset est mis à 1 ce
qui dès lors engendrera un écrasement des données suivantes même si elles avaient été
affectées par le passé. Ce signal est très utile, notamment pour l’initialisation au départ du
programme ou encore au cas où nous aurions atteint le maximum de la capacité mémoire
accordée ce qui nous évitera les bugs éventuels (étant donné que le nombre de données
traitées deviendrait très vite astronomique), mais aussi de n’utiliser que le dernier élément de
la mémoire (c'est-à-dire de réécrire le résultat toujours à la même adresse, la dernière
disponible dans ce cas extrême).
Rappelons avant tout le rôle de l’unité de contrôle : elle constitue le pilier central de notre
système. Son entité se présente comme suit :
entity control_unit is
generic (tPC :time:= 1 ns;
tINST :time:= 3 ns;
tdec :time:= 1 ns);
port (N,Z,V,C,clk,rst:in bit;
6 EL FAHSSI Hamid DELPY Julien ELEC4 adresse : in unsigned(15 downto 0);
ctrlword: out unsigned(15 downto 0);
mw : out bit;
constante : out unsigned(2 downto 0));
end control_unit;
Cette entité nous renseigne sur les entrées et sorties de ce bloc fonctionnel qu’est l’unité de
contrôle. Les éléments importants sont ici :
-
-
le reset (comme nous avons décrit l’intérêt plus haut)
l’adresse, selon le calcul il est intéressant de pouvoir choisir le point de départ du
calcul
le ctrlword, qui servira à définir tous les paramètres importants pour le calcul qui
s’effectuera dans le chemin de données ( le registre de destination, les registres
opérandes,le type d’opération,…)
le mw qui servira à décider si on écrit ou non dans la mémoire
2-Test
Maintenant, nous allons tester l’unité de contrôle. Nous utiliserons un fichier texte pour
définir les adresses de départ. Nous allons constituer le tableau regroupant les tests que nous
faisons (ce sont ici les résultats attendus par rapport aux valeurs entrées dans le fichiers source
texte « Meminst.txt ») :
Test
DA
AA
BA
MB
FS
MD
RW
1
2
3
4
5
6
7
011
010
010
010
111
001
001
001
011
011
001
001
000
000
010
000
000
000
000
000
000
0
0
0
0
1
0
0
0010
1011
1011
1000
1000
0001
0010
1
0
0
0
1
1
1
0
0
0
0
0
1
1
Opération à éxécuter
dans le chemin de
donnée
ADD
R3,R1,R2
NOT
R2,R3
LD
R2,datain
AND
R2,R1,R0
AND
R7,R1,R0
ADD
R1,R0, #1
ADD
R1,R0,cste
Voici nos résultats consignés dans les chronogrammes suivants :
(Chronogramme n°1)
7 EL FAHSSI Hamid DELPY Julien ELEC4 Dans cette première partie de la simulation, on note que l’incrémentation du PC (Pointer
Counter) se fait correctement étant donné qu’ici nous sommes en marche normale après bien
sûr son initialisation à 0 étant donné que le reset est mis à 1 au début. Aussi, on remarque que
comme souhaité, le changement de ce pointeur est bien synchrone. Ensuite, en comparant les
résultats du chronogramme on a bien les résultats attendus, ce qui confirme la bonne lecture
des données par le programme VHDL. Contrairement au PC, le changement de ce mot de
contrôle n’est pas synchrone : dès qu’un changement est observé au niveau de la valeur du
PC, le ctrlword est modifié après tDec, à savoir le temps de latence pour le décodeur
d’instruction.
(Chronogramme n°2) :
Dans cette seconde, on remarque que le PC, conformément à ce que l’on voulait observer, se
charge à partir de la valeur de l’adresse rangée dans la variable « adresse » au lieu de
s’incrémenter tout en restant synchrone. D’autre part, la variable « mw » passe bien à 0 quand
IR(15) et IR(14) sont tous les 2 à 1.
Ce test de l’unité valide bien sa fonctionnalité, son respect de la table de vérité, et de la
logique de calcul des variables internes (calculs dans les blocs internes comme le bloc
Extension par exemple).
8 EL FAHSSI Hamid DELPY Julien ELEC4 Passons maintenant à l’étude du chemin de données.
II – Le chemin de données
1-Principe
Voici la description du fonctionnement du chemin données :
C’est dans ce module que tout le calcul va s’effectuer : le ctrlword transmis au chemin
de donnée par l’unité de contrôle va déterminer toutes les propriétés du calcul à effectuer :
Codés sur 1 bits chacun -
Le type d’opération
Codé sur 4 bits L’adresse de destination
Codées sur 3 bits chacune L’adresse opérande A
L’adresse opérande B
Le mode de calcul (mode registre ou non)
L’état d’écriture (si l’écriture est ou non autorisé)
La sortie sélectionnée (si on récupère le calcul effectué avant ou si on charge une
valeur fournie en entrée, c'est-à-dire ici datain)
9 EL FAHSSI Hamid DELPY Julien ELEC4 2-Test
Nous allons maintenant vérifier le on fonctionnement du chemin de données en effectuant les
tests suivants et en vérifiant que la valeur obtenue est bien celle attendue avec le tableau
suivant et les données des registres chargés à partir du fichier texte ci dessous:
20
18
1
0
23
0
16
90
On a ici R0 sur la première ligne, R1 sur la deuxième et ainsi de suite jusqu’à R7. Le tableau
de test sera alors :
Test
DA
AA
BA
MB
FS
MD RW Opération
1
011
001
000
0
0010
0
1
2
001
010
011
0
1001
0
1
3
000
000
000
1
0001
1
1
4
010
001
000
1
0111
0
1
5
101
100
001
0
0101
1
0
ADD
R3,R1,R0
OR
R1,R3,R0
LD
R0,datain
MOV
R2,R1
LD
R5,datain
D_Data
100110
Dataout(B_Data
ou cste)
10010
100111
100110
Datain
Cste
010010
Cste
Datain
10010
Nous obtenons en testant avec ce tableau les chronogrammes suivants :
(Chronogramme n°3) :
10 EL FAHSSI Hamid DELPY Julien ELEC4 (Chronogramme n°4) :
En comparant les résultats donnés sur les chronogrammes et les résultats escomptés dans le
tableau nous remarquons que le système a fonctionné comme nous le désirions. Ce test a mis
en place des pièges (pour pouvoir trouver les éventuels bugs) mais le système a tout de même
fonctionné.
Par exemple, dans la premier nous affectons au registre R3 une addition de 2 autres
registre, laquelle fonctionne. Dans la seconde, on effectue un OR avec ce registre R3, ce qui
permet de vérifier si la valeur de R3 a bien été mise à jour et qu’elle n’est restée identique à
celle de départ.
D’autre part, nous vérifions aussi, dans ce troisième test, que le fait de mettre MB à 1
rend bien l’importance de la valeur de BA nulle étant donné que cette manœuvre a pour but de
charger la constante (laquelle passe dans le zero fill pour adapter sa taille) au lieu de la valeur
présente dans le registre B. Dans ce même test, nous remarquons aussi une mise à jour du
registre R0 : étant donné que notre registre de destination est R0 et que nous chargeons la
valeur de datain dedans nous devons observer un changement de la valeur de A_data, à savoir
la valeur du registre R0, avant de passer au test suivant, ce qui est effectivement le cas.
Enfin, dans le dernier test où nous testons si la mise à 0 de RW est bien prise en
compte nous validons notre attente théorique : la valeur qui a été chargée est bien la valeur de
départ du registre R1 et non pas la valeur qui lui a été affectée (donc constituant une
modification de sa valeur initiale). Une dernière remarque serait de noter une fois encore
l’intérêt du reset au début du test.
11 EL FAHSSI Hamid DELPY Julien ELEC4 Passons maintenant à la mémoire de données.
III – La mémoire de données
1-Principe
Le rôle de la mémoire de données est de gérer les entrées/sorties dans la mémoire.
Voici la description de cette entité :
2-Test
Les principales fonctionnalités à tester dans notre cas sont l’écriture conditionnée et
l’emplacement d’écriture.
(Chronogramme n°5) :
(Chronogramme n°6) :
12 EL FAHSSI Hamid DELPY Julien ELEC4 On remarque bien que la correspondance est parfaite entre l’adresse (fournit par la variable
adr) et l’emplacement où la valeur est écrite. Bien entendu, cette écriture est rendue possible
grâce à la mise à 1 de mw. Pour tester que l’écriture ne se fait pas dans le cas contraire, on
met à 0 mw : dans le second chronogramme, on voit que l’écriture dans la mémoire ne se fait
plus quand mw est mis à 0 ce qui correspond bien à ce que nous voulons pour cette entité.
Dans le cas présent nous avons-nous-mêmes donné les adresses où ranger la valeur, mais dans
la suite cela se fera à partir d’un fichier.
Testons maintenant le calculateur complet en assemblant les 3 entités codées, testées, et
configurées comme précédemment.
13 EL FAHSSI Hamid DELPY Julien ELEC4 IV – Le calculateur complet
1-Principe
Nous allons maintenant assembler les 3 blocs précédents. En voici la description
combinée :
Nous allons tester le calculateur dont les données seront toutes tirées de fichiers textes. Faire
ainsi a un grand avantage : ne pas avoir à initialiser quoi que ce soit dans le fichier de test
concernant les blocs exceptés l’horloge et le reset uniquement, ce qui réduit considérablement
le nombre d’éléments à initialiser et est confortable quant à une utilisation dans la vie de tous
les jours. Changer de fichier source est beaucoup plus rapide et souple que de changer toutes
les valeurs, et particulièrement dans notre cas car la mémoire contient 2**16 éléments.
2-Test
Testons maintenant ce calculateur :
(Chronogramme n°7) :
14 EL FAHSSI Hamid DELPY Julien ELEC4 (Chronogramme n°8) :
(Chronogramme n°9) :
(Chronogramme n°10) :
(Chronogramme n°11) :
15 EL FAHSSI Hamid DELPY Julien ELEC4 (Chronogramme n°12) :
(Chronogramme n°13) :
Etant donné que tout est chargé à partir du fichier des registres (dont on a parlé dans le
chemin de données) et des mots de contrôles (dont on a parlé dans l’unité de contrôle), on se
référera aux tests donnés dans l’unité de contrôle et aux valeurs des registres donnés dans la
partie du chemin de données.
La première chose à remarquer avec les chronogrammes précédents est que la
communication entre les blocs fonctionne : le mot de contrôle transmis (celui qui est sur les
chronogrammes) est bien celui que nous avions dans la partie de l’unité de contrôle. De
même, les calculs que nous avions prévu que le chemin de données effectuerait sans avoir pu
le vérifier puisque le lien n’était pas encore fait s’effectue bien correctement.
Par exemple, l’opération que nous avions prévu en deuxième à savoir, NOT R2,R3
s’effectue bien correctement. R3 est nul donc on doit avoir 111…111 en donnée résultante, ce
qui est bien le cas (à 28 ns). Visualiser la mémoire n’a ici pas un grand intérêt car nous avons
déjà démontré que tout se déroulait comme désiré pour peu que l’on transmette la bonne
adresse au bloc de mémoire de données. Celui-ci n’est pas présent sur les chronogrammes
mais nous les avons vérifiés nous même et on obtient bien en adresse du bloc mémoire,
l’adresse fournit par le chemin de données.
16 EL FAHSSI Hamid DELPY Julien ELEC4 Conclusion :
Ce projet nous a permis de mettre en pratique nos connaissances théorique et pratique
vues en cours et TP sur un cas réel et de développer une première expérience de la
modélisation VHDL. Nous y avons constaté que le fait de fonctionner en blocs fonctionnels
(entités élémentaires) constitue un grand gain de temps et donc une plus grande efficacité.
Tester séparément les blocs et ne les réunir qu’après les avoir vérifiés chacun à leur tour
permet une minimisation des erreurs et une plus grande clarté.
ANNEXES
17 EL FAHSSI Hamid DELPY Julien ELEC4 Listing du code VHDL :
-Unité de contrôle (entité+architecture+test):
library ieee;
USE ieee.numeric_bit.ALL;
USE ieee.std_logic_textio.ALL;
USE std.textio.ALL;
USE ieee.std_logic_1164.ALL;
entity control_unit is
generic (tPC :time:= 1 ns;
tINST :time:= 3 ns;
tdec :time:= 1 ns);
port (N,Z,V,C,clk,rst:in bit;
adresse : in unsigned(15 downto 0);
ctrlword: out unsigned(15 downto 0);
mw : out bit;
constante : out unsigned(2 downto 0));
end control_unit;
architecture beh of control_unit is
type tab is array((2**16)-1 downto 0) of unsigned(15 downto 0);
signal mb,md,rw,pl,jb,bc,ld : bit;
signal fs : unsigned(3 downto 0);
signal da,aa,ba : unsigned(2 downto 0);
signal IR : unsigned (15 downto 0);
signal pc : unsigned (15 downto 0);
signal ext : unsigned(15 downto 0);
function Meminst(i:integer) return tab is
file fd :text open READ_MODE is "Meminst.txt";
variable mem: tab;
variable NLine:natural:=0;
variable Data:std_logic_vector(15 downto 0);
variable Line:line;
begin
while not endfile(fd) loop
readline(fd,Line);
if Line'length>0 and Line(1)/='-' then
read(Line,Data);
18 EL FAHSSI Hamid DELPY Julien ELEC4 mem(NLine):=unsigned(to_bitvector(Data));
NLine:=NLine+1;
end if;
end loop;
return mem;
end Meminst;
signal Mem_Inst: tab := Meminst(0);
begin
--Branch Control : instructions de branchement -> JZ, JO, JS, JC
Ld <= '1' when ((BC='0' and Z='1') or (BC='1' and N='1') or (BC='1' and V='1') or
(BC='1' and C='1'))
else '0';
--Extension : Décalage d'adresse pour PC
Ext <= (5=>IR(8),4=>IR(7),3=>IR(6),2=>IR(2),1=>IR(1),0=>IR(0),others=>'1') when
IR(8)='1'
else (5=>IR(8),4=>IR(7),3=>IR(6),2=>IR(2),1=>IR(1),0=>IR(0),others=>'0') when
IR(8)='0';
--PC : Adresse effective
PC <= (others=>'0') after tPc when Rst = '1'
else adresse after tPc when (PL='1' and JB='1' and Clk='1' and Clk'event)
else (PC + Ext) after tPc when (PL='1' and JB='0' and Ld='1' and Clk='1' and Clk'event)
else (PC + 1) after tPc when (Clk='1' and Clk'event and (PL='0' or (PL='1' and JB='0'
and Ld='0')));
--Memoire d'instructions : Registre
IR <= Mem_Inst(to_integer(PC)) after tINST;
--Sortie Instruction Register
constante <= IR(2 downto 0);
--Decodeur d'instructions : Affectation d'un mot de contrôle
DA <= IR(15 downto 13) after tDec;
AA <= IR(12 downto 10) after tDec;
BA <= IR(9 downto 7) after tDec;
FS <= IR(5 downto 2) after tDec;
MB <= '1' after tDec when IR(15)='1'
else '0' after tDec;
MD <= '1' after tDec when (IR(13)='1')
else '0' after tDec;
RW <= '1' after tDec when (IR(14)='0')
19 EL FAHSSI Hamid DELPY Julien ELEC4 else '0' after tDec;
MW <= '1' after tDec when (IR(15)='0' and IR(14)='1')
else '0' after tDec;
PL <= '1' after tDec when (IR(15)='1' and IR(14)='1')
else '0' after tDec;
JB <= '1' after tDec when (IR(13)='1')
else '0' after tDec;
BC <= '1' after tDec when (IR(9)='1')
else '0' after tDec;
--Concaténation
ctrlword <= DA&AA&BA&MB&FS&MD&RW;
end beh;
library ieee;
USE ieee.numeric_bit.ALL;
USE ieee.std_logic_textio.ALL;
USE std.textio.ALL;
USE ieee.std_logic_1164.ALL;
-----Test----entity test is
end test;
architecture testbench of test is
component control_unit is
generic(tPC:time:= 1 ns;
tINST:time:= 3 ns;
tdec:time:= 1 ns);
port (N,Z,V,C,clk,rst:in bit;
adresse : in unsigned(15 downto 0);
ctrlword : out unsigned(15 downto 0);
mw : out bit;
constante : out unsigned(2 downto 0));
end component;
signal V,C,Z,N,clk,rst,mw : bit;
signal adresse : unsigned(15 downto 0);
signal ctrlword : unsigned (15 downto 0);
signal constante : unsigned(2 downto 0);
begin
20 EL FAHSSI Hamid DELPY Julien ELEC4 uut
:
control_unit
port
map
(Z=>Z,N=>N,V=>V,C=>C,clk=>clk,rst=>rst,adresse=>adresse,ctrlword=>ctrlword,const
ante=>constante,mw=>mw);
horloge:process
begin
wait for 20 ns;
clk<=not clk;
end process;
N<='0', '1' after 30 ns, '0' after 60 ns;
Z<='0', '1' after 50 ns, '0' after 70 ns, '1' after 100 ns;
V<='0';
C<='0';
rst <= '1','0' after 40 ns;
adresse <= "0010101110010101","1010000000101001" after 60 ns;
end testbench;
-Chemin de données (entité+architecture+test):
library ieee;
USE ieee.numeric_bit.ALL;
USE ieee.std_logic_textio.ALL;
USE std.textio.ALL;
USE ieee.std_logic_1164.ALL;
entity datapath is
generic (NB_reg : natural;
NB_data : natural;
t_reg : time:=3 ns;
t_mux : time:=1 ns;
t_ind : time := 1 ns;
t_uf : time:=4 ns);
port (rst,clk : in bit;
datain : in signed(NB_data-1 downto 0);
ctrlword : in unsigned(15 downto 0);
cste : in unsigned(2 downto 0);
dataout : out signed(NB_data-1 downto 0);
adr : out unsigned(NB_data-1 downto 0);
N,Z : out bit);
end datapath;
21 EL FAHSSI Hamid DELPY Julien ELEC4 architecture beh of datapath is
type Banc_de_Reg is array(NB_reg-1 downto 0) of signed(NB_data - 1 downto 0);
signal da,aa,ba : unsigned(2 downto 0);
signal rw,md,mb : bit;
signal fs : unsigned(3 downto 0);
function Reg(i:integer) return Banc_de_Reg is
file file_data : text open read_mode is "Reg.txt";
variable mem: Banc_de_Reg;
variable NLine:natural:=0;
variable Data:integer;
variable Line:line;
begin
while not endfile(file_data) loop
readline(file_data,Line);
if Line'length>0 and Line(1)/='-' then
read(Line,Data);
mem(NLine):= to_signed(Data,NB_data);
NLine:=NLine+1;
end if;
end loop;
return mem;
end Reg;
--Fonction d'ecriture de Ddata a l'adresse courante
function fct_mem_interne(i:natural; Reg: Banc_de_Reg; Data:signed(NB_data-1 downto 0))
return Banc_de_Reg is
variable Var_Reg: Banc_de_Reg:=Reg;
begin
Var_Reg(i):=Data;
return Var_Reg;
end fct_mem_interne;
signal mem_interne: Banc_de_Reg:= Reg(0);
signal D_data,A_data,B_data,A,B,B2,F,F2,Constant_in : signed (NB_data-1 downto 0);
signal ev:bit:='0';
begin
rw <= ctrlword(0);
md <= ctrlword(1);
fs <= ctrlword(5 downto 2);
mb <= ctrlword(6);
ba <= ctrlword(9 downto 7);
aa <= ctrlword(12 downto 10);
da <= ctrlword(15 downto 13);
22 EL FAHSSI Hamid DELPY Julien ELEC4 --Determination de l'opération a effectuer
mem_interne <= Reg(0) after t_reg when rst='1'
else fct_mem_interne(to_integer(da),mem_interne,D_data) after t_reg when
(clk='1' and clk'event and rw='1');
-- lecture des regitres A et B
A_data<=mem_interne(to_integer(aa)) after t_reg;
B_data<=mem_interne(to_integer(ba)) after t_reg;
A<=A_data;
adr<=unsigned(A_data);
-- zéro fill
Constant_in<=(2=>cste(2),1=>cste(1),0=>cste(0), others =>'0');
-- MuxB
B<=Constant_in after t_mux when mb='1'
else B_data after t_mux;
dataout<=B;
-- Unité fonctionnelle
with fs select
F<=
A after t_uf when "0000",
A+1 after t_uf when "0001",
A+B after t_uf when "0010",
A+B+1 after t_uf when "0011",
A+(not B) after t_uf when "0100",
A+(not B)+1 after t_uf when "0101",
A-1 after t_uf when "0110",
A after t_uf when "0111",
A and B after t_uf when "1000",
A or B after t_uf when "1001",
A xor B after t_uf when "1010",
(not A) after t_uf when "1011",
B after t_uf when "1100",
'0'&B(NB_data-1 downto 1) after t_uf when "1101",
B(NB_data-2 downto 0)&'0' after t_uf when "1110",
"0000000000000000" after t_uf when "1111";
--Signe
N<='1' after (t_ind) when to_integer(F)<0
else '0' after (t_ind);
--Zero
Z<='1' after (t_ind) when to_integer(F)=0
else '0' after (t_ind);
23 EL FAHSSI Hamid DELPY Julien ELEC4 D_data <= F after t_mux when md='0' else datain;
end beh;
-----Test----library ieee;
USE ieee.numeric_bit.ALL;
USE ieee.std_logic_textio.ALL;
USE std.textio.ALL;
USE ieee.std_logic_1164.ALL;
entity test_datapath is
end test_datapath;
architecture testbench of test_datapath is
component datapath
generic (NB_reg : natural;
NB_data : natural;
t_reg : time:=3 ns;
t_mux : time:=1 ns;
t_ind : time := 1 ns;
t_uf : time:=4 ns);
port (rst,clk : in bit;
datain : in signed(NB_data-1 downto 0);
ctrlword : in unsigned(15 downto 0);
cste : in unsigned(2 downto 0);
dataout : out signed(NB_data-1 downto 0);
adr : out unsigned(NB_data-1 downto 0);
N,Z : out bit);
end component;
signal rst,clk,N,Z : bit;
signal datain,dataout : signed(6 downto 0);
signal adr: unsigned(6 downto 0);
signal ctrlword : unsigned(15 downto 0);
signal cste : unsigned(2 downto 0);
signal NB_reg:natural:=8;
signal NB_data : natural :=7;
begin
uut: datapath generic map (NB_reg=>NB_reg,NB_data=>NB_data)
port
map
(rst=>rst,clk=>clk,datain=>datain,ctrlword=>ctrlword,cste=>cste,dataout=>dataout,adr=
>adr,N=>N,Z=>Z);
process
begin
24 EL FAHSSI Hamid DELPY Julien ELEC4 clk<=not clk;
wait for 20 ns;
end process;
datain <= "1101011", "0000001" after 50 ns, "0011001" after 90 ns;
rst <= '1','0' after 5 ns;
ctrlword <= "0110010000001001","0010100110100101" after 50 ns,"0000000001000111"
after 75 ns,"0100010001011101" after 100 ns, "1011000010010110" after 125 ns;
cste <= "111";
end testbench;
-Mémoire (entité+architecture+test):
library ieee;
USE ieee.numeric_bit.ALL;
USE ieee.std_logic_textio.ALL;
USE std.textio.ALL;
USE ieee.std_logic_1164.ALL;
entity memoire is
generic (NB_data:natural:=16;NB_adr:natural:=16;t_co:time:=4 ns);
port(clk,mw,rst : in bit;
datain : in signed (NB_data-1 downto 0);
adr : in unsigned (NB_adr-1 downto 0);
dataout : out signed (NB_data-1 downto 0)
);
end memoire;
architecture beh of memoire is
type tabvect is array((2**NB_adr)-1 downto 0) of signed(NB_data-1 downto 0);
--Fonction d'initialisation du tableau mémoire
function Mem(i:integer) return tabvect is
file fd :text open READ_MODE is "Memory.txt";
variable mem2: tabvect;
variable NLine:natural:=0;
variable Data:integer;
variable Line:line;
begin
while not endfile(fd) loop
readline(fd,Line);
if Line'length>0 and Line(1)/='-' then
read(Line,NLine);
25 EL FAHSSI Hamid DELPY Julien ELEC4 read(Line,Data);
mem2(NLine):= to_signed(Data,NB_data);
end if;
end loop;
return mem2;
end Mem;
begin
Fonctionnement:process(CLK)
variable memoire: bloc_RAM:=Mem(0);
begin
if(CLK='0' and CLK'event) then
if(mw='1') then
memoire(to_integer(adr)):=datain;
end if;
dataout<=memoire(to_integer(adr))after t_co;
end if;
end process;
end beh;
-----Test--------Fichier test
library ieee;
USE ieee.numeric_bit.ALL;
entity testmem is
end testmem;
architecture testbench of testmem is
component memoire is
generic(NB_data : natural := 16;
NB_adr : natural := 16;
t_co : time := 4 ns);
port(clk,mw,rst: in bit;
datain: in signed(NB_data-1 downto 0);
adr: in unsigned(NB_adr-1 downto 0);
dataout: out signed(NB_data-1 downto 0));
end component;
constant NB_data: natural :=16;
constant NB_adr: natural :=16;
constant t_co: time :=4 ns;
signal dataout,datain: signed(NB_data-1 downto 0);
signal mw,clk,rst: bit;
26 EL FAHSSI Hamid DELPY Julien ELEC4 signal adr: unsigned(NB_adr-1 downto 0);
begin
UUT:memoire generic map(NB_data=>NB_data,NB_adr=>NB_adr,t_co=>t_co)
map(clk=>clk,mw=>mw,rst=>rst,datain=>datain,adr=>adr,dataout=>dataout);
process
begin
wait for 10 ns;
clk<=not clk;
end process;
port
datain<="0000000000000101", "1111111111111111" after 80 ns, "0000000011110000"
after 100 ns, "0000000011111111" after 120 ns;
adr<="1111111111111111", "1111111111111110" after 68 ns, "1111111111111111"
after 145 ns;
mw<= '0', '1' after 25 ns,'0'after 45 ns, '1' after 85 ns,'0'after 115 ns ;
end testbench;
-Calculateur complet (entité+architecture+test):
--Librairie
library ieee;
USE ieee.numeric_bit.ALL;
USE ieee.std_logic_textio.ALL;
USE std.textio.ALL;
USE ieee.std_logic_1164.ALL;
--Entité
entity CalculateurHarward is
port(clk,rst:in bit);
end CalculateurHarward;
--Architecture : Assemblage des blocs
architecture structureCalculator of CalculateurHarward is
--Composant unité de contrôle
component control_unit is
generic (tPc:time:=1 ns;tDec:time:=1 ns;tINST:time:=3 ns);
port(clk,rst,N,Z,V,C : in bit;
adresse : in unsigned (15 downto 0);
mw : out bit;
constante : out unsigned (2 downto 0);
ctrlword : out unsigned (15 downto 0)
27 EL FAHSSI Hamid DELPY Julien ELEC4 );
end component;
--Composant Chemin de données
component datapath is
generic (NB_reg : natural:=8;
NB_data : natural:=16;
t_reg : time:=3 ns;
t_mux : time:=1 ns;
t_ind : time := 1 ns;
t_uf : time:=4 ns);
port (rst,clk : in bit;
datain : in signed(NB_data-1 downto 0);
ctrlword : in unsigned(15 downto 0);
cste : in unsigned(2 downto 0);
dataout : out signed(NB_data-1 downto 0);
adr : out unsigned(NB_data-1 downto 0);
N,Z : out bit);
end component;
--Composant Mémoire de données
component memoire is
generic (NB_data:natural:=16;NB_adr:natural:=16;t_co:time:=4 ns);
port(clk,mw,rst : in bit;
datain : in signed (NB_data-1 downto 0);
adr : in unsigned (NB_adr-1 downto 0);
dataout : out signed (NB_data-1 downto 0)
);
end component;
--Signaux internes
constant NB_data: natural:=16;
constant NB_adr: natural:=16;
constant NB_reg:natural:=8;
signal datain,dataout: signed(NB_data-1 downto 0);
signal V,C,N,Z: bit;
signal adr: unsigned(NB_adr-1 downto 0);
signal MW: bit;
signal cste: unsigned(2 downto 0);
signal ctrlword: unsigned(15 downto 0);
--Description
begin
28 EL FAHSSI Hamid DELPY Julien ELEC4 UUT1
:
datapath
port
map(clk=>clk,rst=>rst,datain=>datain,ctrlword=>ctrlword,cste=>cste,adr=>adr,dataout=
>dataout,N=>N,Z=>Z);
UUT2
:
control_unit
port
map(clk=>clk,rst=>rst,V=>V,C=>C,N=>N,Z=>Z,adresse=>adr,mw=>mw,constante=>cs
te,ctrlword=>ctrlword);
UUT3
:
memoire
port
map(clk=>clk,mw=>mw,rst=>rst,dataout=>datain,adr=>adr,datain=>dataout);
end structureCalculator;
-----Test----library ieee;
use ieee.numeric_bit.all;
--Entité
entity test_Calc is
end test_Calc;
--Architecture de test
architecture bench of test_Calc is
--Composant Calculateur
component CalculateurHarward is
port(clk,rst:in bit);
end component;
--Signaux internes
signal clk,rst:bit;
--Description
begin
UUT_System: CalculateurHarward port map(clk=>clk,rst=>rst);
process
begin
clk<=not clk;
wait for 9 ns;
end process;
rst<='1', '0' after 5 ns;
end bench;
Fichier registres (Reg.txt):
29 EL FAHSSI Hamid DELPY Julien ELEC4 20
18
1
0
23
0
16
90
Fichier mémoire (Memory.txt):
0001010000000000
0010000001011000
1100000010001000
0010000010100000
1100000010010000
0000101011001010
1100001000011100
0000000011010000
0000000100001000
1110000000111000
0000000011001000
0000000100010000
1100000010011000
0000010000000100
0000110011011000
1110000000111000
Fichier IR de l’unité de contrôle (sert pour le mot de contrôle, Meminst.txt) :
--ADD
R3,R1,R2
0110010100001001
--NOT R2,R3
0100110001101101
--LD R2,datain
0100110001101111
--AND R2,R1,R0
0100010000100001
--AND R2,R1,R0 sans ecriture
1110010000100000
--ADD R1,R0,#1
0010000001000101
--ADD R1,R0,cste
0010000001001001
30 

Documents pareils