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