Modélisation des processussudriaesme.free.fr/Arthur 3ème Année/Guide VHDL... · efficaces...
Transcript of Modélisation des processussudriaesme.free.fr/Arthur 3ème Année/Guide VHDL... · efficaces...
VHDL
Modélisation des processus Norme, Synthèse, Simulation, Outils
Jean-Louis FLOQUET
Jean-Louis FLOQUET Page 2 13/11/2007
Jean-Louis FLOQUET Page 3 13/11/2007
Table des matières I. À propos de ce document .......................................................................................................................9
A. Contenu................................................................................................................................................9 B. Conventions typographiques.............................................................................................................9 C. Abréviations.........................................................................................................................................9 D. Documents de référence ...................................................................................................................9
II. Introduction...........................................................................................................................................11 III. Définitions............................................................................................................................................12
A. Horloge ..............................................................................................................................................12 B. Timings...............................................................................................................................................12
1. Setup ...............................................................................................................................................12 2. Hold ................................................................................................................................................12 3. Clock to Output ............................................................................................................................12 4. Métastabilité ...................................................................................................................................12
C. Codes binaires ...................................................................................................................................13 1. CBN (Code Binaire Naturel).......................................................................................................13 2. DCB (Décimal Codé en Binaire) ................................................................................................13 3. Code de Gray.................................................................................................................................13
D. Pipeline ..............................................................................................................................................14 E. Chemin...............................................................................................................................................14
IV. Norme VHDL .....................................................................................................................................15 A. Entité ..................................................................................................................................................15
1. L’entête ...........................................................................................................................................15 2. Les déclarations .............................................................................................................................15 3. Les instructions .............................................................................................................................16
B. Architecture .......................................................................................................................................16 1. Les déclarations .............................................................................................................................16 2. Les instructions .............................................................................................................................17
C. Objets .................................................................................................................................................17 1. Signal...............................................................................................................................................17 2. Constant .........................................................................................................................................17 3. Variable...........................................................................................................................................17 4. Différences entre un signal et une variable ...............................................................................17
D. Types..................................................................................................................................................19 1. Std_logic.........................................................................................................................................19 2. Std_logic_vector............................................................................................................................19 3. Signed & Unsigned .......................................................................................................................20 4. Boolean...........................................................................................................................................20 5. Énuméré.........................................................................................................................................20 6. Record.............................................................................................................................................20 7. Integer, natural, positive, real ......................................................................................................21 8. Array ...............................................................................................................................................21 9. Record.............................................................................................................................................21 10. Personnalisé .................................................................................................................................22
E. Agents.................................................................................................................................................22 1. Process............................................................................................................................................22 2. Function .........................................................................................................................................22 3. Procedure .......................................................................................................................................23
Jean-Louis FLOQUET Page 4 13/11/2007
F. Bibliothèques IEEE..........................................................................................................................23 1. std_logic_1164...............................................................................................................................23 2. std_logic_arith & std_logic_unsigned (ou std_logic_signed).................................................23 3. numeric_std ...................................................................................................................................23 4. Conseil ............................................................................................................................................23
G. Opérateurs.........................................................................................................................................23 H. Attributs.............................................................................................................................................24
1. Attributs de types ..........................................................................................................................24 2. Attributs de signaux......................................................................................................................25 3. Attributs de tableaux ....................................................................................................................26
I. Les boucles..........................................................................................................................................26 1. if…then…else ...............................................................................................................................26 2. case…when… ...............................................................................................................................26 3. for … in … to … loop…............................................................................................................27 4. while…loop ...................................................................................................................................27 5. Generate .........................................................................................................................................28
J. Commandes ........................................................................................................................................28 1. Wait .................................................................................................................................................28
V. Structure d’un fichier VHDL ..............................................................................................................29 A. L’entête...............................................................................................................................................29 B. Bibliothèques et packages................................................................................................................29 C. L’entité................................................................................................................................................30 D. L’architecture ....................................................................................................................................30
1. Les déclarations .............................................................................................................................31 2. La description fonctionnelle........................................................................................................31
E. Fin du fichier .....................................................................................................................................31 F. Testbench ...........................................................................................................................................31
VI. Règles et conventions .........................................................................................................................33 A. Entité ..................................................................................................................................................33 B. Architecture .......................................................................................................................................33 C. Noms ..................................................................................................................................................33 D. Suffixes ..............................................................................................................................................33 E. Préfixes...............................................................................................................................................33 F. Types des signaux..............................................................................................................................34
1. Synthèse..........................................................................................................................................34 2. Simulation ......................................................................................................................................34
G. Types des constantes / generic ......................................................................................................34 H. Indentation........................................................................................................................................35
VII. Simulation ...........................................................................................................................................36 A. Testbench ..........................................................................................................................................36 B. Time et micro-time ...........................................................................................................................36
1. Définition .......................................................................................................................................37 2. Pièges classiques............................................................................................................................37
C. Horloges et signaux généraux .........................................................................................................38 D. Affectation retardée .........................................................................................................................39 E. Assert & Report ................................................................................................................................39 F. Opérateurs mathématiques avancés ...............................................................................................40 G. Procédures.........................................................................................................................................40 H. Process ...............................................................................................................................................41
VIII. Synthèse .............................................................................................................................................42
Jean-Louis FLOQUET Page 5 13/11/2007
A. Objets non synthétisables................................................................................................................42 B. Paramètres « generic » ......................................................................................................................42 C. Entrées / Sorties d’un module........................................................................................................43
1. Type « in ».......................................................................................................................................43 2. Type « out » .....................................................................................................................................43 3. Type « inout » ..................................................................................................................................43 4. Type « buffer » .................................................................................................................................44
D. Les boucles........................................................................................................................................44 1. if…then…else ...............................................................................................................................44 2. case…when....................................................................................................................................44 3. for…in…to…loop .......................................................................................................................45 4. while…loop ...................................................................................................................................46 5. Generate .........................................................................................................................................46
E. Les process ........................................................................................................................................46 1. Liste de sensibilité .........................................................................................................................46 2. Traitements ....................................................................................................................................47 3. Remarque .......................................................................................................................................48
IX. Méthodologie .......................................................................................................................................49 A. Reset ...................................................................................................................................................49
1. Généralités .....................................................................................................................................49 2. Reset asynchrone...........................................................................................................................49
B. Boucle combinatoire.........................................................................................................................49 C. Lignes à retard ...................................................................................................................................50 D. Ligne trois états ................................................................................................................................50 E. Opérateurs .........................................................................................................................................51
1. Optimisation des compteurs .......................................................................................................51 2. Additionneurs & soustracteurs ...................................................................................................52 3. Comparateurs binaires..................................................................................................................52
F. Multiplexeur .......................................................................................................................................53 G. Lecture d’une mémoire ...................................................................................................................54 H. Changement de domaine d’horloge...............................................................................................56
1. Paramètre quasi-statique ..............................................................................................................57 2. Valeur mise à jour de temps en temps.......................................................................................57 3. Flux de données ............................................................................................................................59
I. Buffer ...................................................................................................................................................59 J. Structure pipeline ...............................................................................................................................60 K. Prédiction / Auto maintient ...........................................................................................................61
1. Action a posteriori (auto maintient) ...........................................................................................61 2. Action a priori (prédiction)..........................................................................................................62 3. Remarques......................................................................................................................................63
L. Séquenceur de contrôle à N étages.................................................................................................64 X. Méthodologie avancée..........................................................................................................................65
A. Associations de plusieurs blocs mémoire......................................................................................65 B. Filtrage par moyenne glissante........................................................................................................65 C. Délai programmable.........................................................................................................................66 D. Fifo en Logic Cells ...........................................................................................................................66 E. Division par une constante .............................................................................................................68 F. Programmation de la LUT d’un Stratix .........................................................................................68
XI. Directives..............................................................................................................................................68 A. Translate On/Off.............................................................................................................................68
Jean-Louis FLOQUET Page 6 13/11/2007
B. Read Comments................................................................................................................................68 C. Preserve ..............................................................................................................................................68
XII. Outils ...................................................................................................................................................68 A. ModelSim...........................................................................................................................................68
1. Résolution temporelle ..................................................................................................................68 B. QuartusII............................................................................................................................................68
1. PLL..................................................................................................................................................68 2. Liste des codes sources ................................................................................................................68 3. Conseils de placement..................................................................................................................68
Jean-Louis FLOQUET Page 7 13/11/2007
Index 1164 .................................. 29 active ................................ 25 appel procédure .............. 40 arith................................... 29 array, dimensions............ 33 arrondi.............................. 39 ascending ......................... 24 base ................................... 24 boolean............................. 20 case when...................26, 43 clock enable..................... 45 colonne............................. 34 delayed ............................. 25 delta .................................. 18 driver ................................ 25 driving .............................. 25 driving_value................... 25 évènement .................24, 25 event ................................. 25 exponentielle ................... 39 for in to loop...... 26, 27, 44 generate......................27, 45 Gray.................................. 71 high................................... 24 horloge .......................37, 45 if then else..................25, 43 image ................................ 24 integer............................... 21 last_active ........................ 25 last_event......................... 25
last_value..........................25 left .....................................24 leftof .................................24 length................................25 load asynchrone ..............45 logarithme........................39 low ....................................24 masque .............................67 math_real .........................39 micro-time .......................18 multiplexeur........ 26, 43, 64 natural...............................21 nombres complexes........39 Output Enable ................32 partie entière....................39 pipeline .............................60 pos.....................................24 positive .............................21 pred...................................24 preserve ............................69 pull-down.........................49 pull-up ..............................49 quiet ..................................25 racine carrée.....................39 range .................................25 rapport cyclique ..............12 read comments................69 real.....................................21 reset...................................38 reset asynchrone .............45
reverse_range...................25 right...................................24 rightof ...............................24 script TCL........................71 séquenceur .......................26 seuil ...................................61 show-ahead ......................58 stable .................................25 std_logic ...........................19 std_logic_vector..............19 succ ...................................24 tabulations........................34 Tco ................ 12, 49, 55, 56 temps de propagation.....46 textio .................................41 Th......................................12 toggle ................................56 transaction................. 24, 25 translate ............................69 trigonométrie ............ 39, 41 troncature.........................39 Tsu .......................12, 55, 56 Txz ....................................49 unsigned ...........................29 val ......................................24 value..................................24 variable ...................... 47, 49 wait.......................36, 38, 40 while loop.................. 26, 44
Figures Figure 1 : Exemple d’environnement Synthèse + Simulation .............................................................11 Figure 2 : Timings d'une bascule..............................................................................................................12 Figure 3 : Correction à 1 niveau de la métastabilité ..............................................................................13 Figure 4 : Chemin.......................................................................................................................................14 Figure 5 : Problème de simulation lié au time .........................................................................................38 Figure 6 : Affectation retardée..................................................................................................................39 Figure 7 : Principe d'une ligne tri-state....................................................................................................43 Figure 8 : Ligne tri-state pilotée par A ....................................................................................................43 Figure 9 : Ligne tri-state pilotée par B.....................................................................................................43 Figure 10 : Séquenceur typique ................................................................................................................45 Figure 11 : Boucle « for » non itérative ...................................................................................................46 Figure 12 : Boucle « for » itérative ...........................................................................................................46 Figure 13 : Entrées « sensibles » d'une bascule (Stratix, Altera) ..........................................................47
Jean-Louis FLOQUET Page 8 13/11/2007
Figure 14 : Boucle combinatoire ..............................................................................................................49 Figure 15 : Ligne à retard ..........................................................................................................................50 Figure 16 : Relâchement d'un signal ........................................................................................................50 Figure 17 : Exemple de relâchements, sur Flex10K .............................................................................51 Figure 18 : Compteur.................................................................................................................................51 Figure 19 : Comparateur « Standard » 2 x 8bits .....................................................................................53 Figure 20 : Compteur optimisé 2 x 8bits ................................................................................................53 Figure 21 : Latence de lecture d'un bloc mémoire (Stratix, Altera) ....................................................55 Figure 22 : Résolution de la latence de lecture d'une mémoire ...........................................................56 Figure 23 : Passage d’un domaine d’horloge à un autre .......................................................................56 Figure 24 : Changement de domaine d'horloge.....................................................................................57 Figure 25 : Schéma logique du « toggle » ................................................................................................58 Figure 26 : Changement de domaine d’horloge (lent vers rapide) ......................................................58 Figure 27 : Changement de domaine d’horloge (rapide vers lent) ......................................................58 Figure 28 : Usage des buffers ...................................................................................................................59 Figure 29 : Buffer 1 horloge......................................................................................................................60 Figure 30 : Buffer 2 horloges....................................................................................................................60 Figure 31 : Architecture Simple................................................................................................................61 Figure 32 : Architecture pipeline..............................................................................................................61 Figure 33 : Traitement de données entre deux mémoires (a posteriori) ............................................62 Figure 34 : Traitement de données entre deux mémoires (a priori) ...................................................63 Figure 35 : Filtrage par moyenne glissante .............................................................................................66 Figure 36 : Délai programmable...............................................................................................................66 Figure 37 : Fifo en Logic Cells .................................................................................................................67
Jean-Louis FLOQUET Page 9 13/11/2007
I. À propos de ce document A. Contenu Ce document fourni une approche de base au langage VHDL de synthèse en abordant les
points suivants : � Norme VHDL (entité, architecture, types, attributs, boucles) � Règles et conventions préconisées � Principaux aspects d’une simulation � Méthodologie de synthèse
La partie dédiée à la simulation a pour objectif la mise en œuvre de vecteurs de test fiables et
efficaces vis-à-vis du code à synthétiser.
B. Conventions typographiques Aspect visuel Signification courier new Code VHDL italique Terme VHDL (port, integer…) souligné Exemple ou syntaxe VHDL.
Dans un texte, utilisé pour attirer l’attention du lecteur. gras souligné Définition importante
� Cette marque demande de porter une attention particulière.
VRAI / FAUX Valeurs booléennes
C. Abréviations ASIC Application Specific Integrated Circuit DDR Double Data Rate IEEE Institute of Electrical and Electronics Engineers I/O Input / Output FPGA Field Programmable Gate Array PCI Peripheral Component Interconnect PLL Phase Locked Loop SDR Single Data Rate SDRAM Synchronous Dynamic Random Access Memory VHDL VHSIC (Very High Speed Integrated Circuit) Hardware Descript Language
D. Documents de référence IEEE Std 1076 – 1993
Norme VHDL relative à l’année 1993 IEEE Std 1076a – 2000
Norme VHDL relative à l’année 2000 ALTERA Stratix Handbook version 3.4, janvier 2006 (référence S5V1-3.4) Notice technique des composants de la famille Stratix d’ALTERA
http://www.altera.com/literature/hb/stx/stratix_handbook.pdf
Jean-Louis FLOQUET Page 10 13/11/2007
ALTERA Application Note 42, version 4, mai 1999 (référence A-AN-042-04) Metastability in Altera Devices http://www.altera.com/literature/an/an042.pdf
ALTERA Application Note 83, version 1, avril 1997 (référence A-AN-083-01) Binary Numbering Systems http://www.altera.com/literature/an/an083_01.pdf
Jean-Louis FLOQUET Page 11 13/11/2007
II. Introduction La conception de circuits intégrés numériques complexes fait appel à des outils de simulation
et de synthèse de plus en plus puissants pour satisfaire les contraintes de qualité et de productivité imposées par le marché. La description dans un environnement informatique du circuit à concevoir est une étape incontournable et représente un investissement important qui peut être avantageusement réemployé et partagé entre concepteurs à condition d'assurer une certaine "portabilité" aux modèles structurels ou comportementaux. Sous l'impulsion du Département de la Défense Américaine, l'IEEE a normalisé en 1987 le langage de description matérielle VHDL (Very High Speed Integrated Circuits Hardware Description Language) pour tenter de répondre à ces objectifs. Initialement voué à la simulation d'ASIC, le VHDL est maintenant largement utilisé pour des applications de simulation et de synthèse logique (ASIC, FPGA, CPLD ...) Le VHDL, de par sa syntaxe, ressemble à beaucoup de langages informatiques comme le C. Mais il ne faut pas oublier que le VHDL, comme son nom l’indique, est un langage de description matérielle et que la façon même de coder va directement influencer la structure du circuit numérique.
Ce langage a été doté de nombreuses fonctionnalités non synthétisables afin de pouvoir créer un environnement de simulation le plus complet possible et s’assurer ainsi du bon fonctionnement de la partie à synthétiser. Il est essentiel de bien dissocier ces deux domaines (simulation et synthèse).
FPGASynthèse
CapteursSimulation
PCISimulation
I²CSimulation
SDRAMSimulation
Figure 1 : Exemple d’environnement Synthèse + Simulation
Jean-Louis FLOQUET Page 12 13/11/2007
III. Définitions A. Horloge Une horloge est un signal commutant à intervalle régulier et ayant un rapport cyclique fixe de
50%. Un tel signal est obtenu soit directement par une source externe au composant programmable (oscillateur, quartz) soit par une PLL interne, elle-même alimentée par la source externe.
Une horloge possède ses propres canaux de routage internes au composant et ne peut donc pas (et ne doit pas) être manipulée comme le serait un signal ordinaire.
Tout système synchrone requiert au moins une horloge pour fonctionner et chaque bascule de ce système ne peut commuter que sur l’un des deux fronts de l’horloge (on choisit généralement le front montant).
B. Timings
A
tsu th
D
Q
tco
B
A
C
B
Ck
Figure 2 : Timings d'une bascule
1. Setup Le temps de « setup », noté tsu, correspond à la durée pendant laquelle l’entrée de la bascule
doit rester stable avant le front actif de l’horloge.
2. Hold Le temps de « hold » (ou de maintient), noté th, est le temps à partir duquel l’entrée de la
bascule peut changer (l’entrée de la bascule doit donc rester stable avant cet instant). Le th est généralement nul mais peut aussi être négatif.
3. Clock to Output Le temps de « clock to output », noté tco, est le temps que met la sortie de la bascule à se
stabiliser après le front actif de l’horloge.
4. Métastabilité La sortie d’une bascule ne peut prendre que deux états : haut et bas. Pour garantir un
fonctionnement correct, le design doit respecter les timings d’entrée propres à chaque bascule (tsu et th). Si le signal d’entrée d’une bascule ne respecte pas ces conditions, la sortie de la bascule peut devenir métastable : elle oscille entre les états haut et bas pendant un bref instant pouvant suffire à générer une défaillance du système.
Jean-Louis FLOQUET Page 13 13/11/2007
Ce phénomène se résout très facilement en intercalant un registre entre la broche du composant et la logique interne. Ainsi, le signal resynchronisé est « vu » avec un cycle d’horloge de retard et les bascules internes sont protégées de toute perturbation.
D Q
clk
signal
externe
signal
resynchronisé
Figure 3 : Correction à 1 niveau de la métastabilité
Selon les conditions d’environnement, il peut s’avérer nécessaire de rajouter une seconde bascule de protection (chaînée avec la première) afin de réduire d’avantage les effets perturbants d’un signal asynchrone. Pour plus de renseignements sur ce phénomène, consulter la note d’application AN042 d’Altera.
C. Codes binaires De nombreux codes existent. Les plus utilisés sont détaillés ci-dessous. Une liste plus
complète est disponible dans la note d’application AN083 d’Altera.
1. CBN (Code Binaire Naturel) Le Code Binaire Naturel est l’équivalent binaire de notre système décimal. La position d’un
chiffre détermine sa valeur : position2 . Par exemple, le nombre décimal 46 s’écrit 101110 en binaire :
Position 5 4 3 2 1 0 Digit 1 0 1 1 1 0 Valeur 3225 = 1624 = 823 = 422 = 221 = 120 = Résultat 32 0 8 4 2 0 En effet, 2483246 +++=
2. DCB (Décimal Codé en Binaire) Chaque chiffre de notre système décimal est représenté par un groupe de 4 chiffres binaires.
Ce codage est principalement utilisé lorsque la valeur doit être affichée avec une logique de décodage réduite (horloge, compteur…).
Chaque groupe binaire peut donc prendre les valeurs de 0 à 9 (0000….1001 en binaire). Les valeurs supérieures sont toujours exclues (1010 à 1111).
En reprenant l’exemple précédent, 46 s’écrira 0100 0101.
3. Code de Gray Le code de Gray est défini de telle façon qu’un seul bit ne change lorsque la valeur
s’incrémente linéairement. Décimal 0 1 2 3 4 5 Gray 000 001 011 010 110 111
Jean-Louis FLOQUET Page 14 13/11/2007
D. Pipeline Un pipeline est une séquence d’unités fonctionnelles (des « étages ») qui effectuent une tâche
en plusieurs étapes, de la même façon que la ligne d’assemblage d’une usine. Chaque unité fonctionnelle lit des entrées et produit des sorties qui sont stockées dans des registres. Cette association permet à tous les étages de travailler en parallèle ce qui décuple la bande passante par rapport à un fonctionnement où chaque entrée aurait à subir l’intégralité des étapes avant que ne puisse entrer les données suivantes.
Le coût de cette architecture est une latence et une complexité accrues en raison du besoin de synchroniser les différents étages de façon à ce qu’ils n’interfèrent pas entre eux.
La période d’horloge minimum est déterminée par l’étage le plus lent. La plupart des microprocesseurs sont organisés autour d’un ou plusieurs pipelines. L’efficacité d’une telle structure est maximale tant que le pipeline reste saturé (tous les étages contiennent une donnée).
E. Chemin Un chemin est défini comme allant de la sortie d’un registre à l’entrée du registre suivant. Ce
chemin inclut donc : � le tco du premier registre (celui dont on utilise la sortie) � de tsu du second registre (celui dont on utilise l’entrée) � de la somme des temps de propagation (logique combinatoire) pour aller au second
registre � de la somme des temps de routage (les fils)
Reg Reg
Tco Tsur1 r2 r3lc1lc1 Figure 4 : Chemin
Le chemin critique est celui qui maximise cette somme. Par conséquent :
� il existe un unique chemin critique s’il possède à lui seul la valeur maximale � il existe plusieurs chemins critiques s’ils ont tous la même valeur
Jean-Louis FLOQUET Page 15 13/11/2007
IV. Norme VHDL Quelques points précis de la norme VHDL sont explicités dans ce paragraphe. La plupart
d’entre eux sont détaillés à des fins uniquement « théorique » et de compréhension des possibilités de ce langage. De nombreuses possibilités ne sont que rarement (voire jamais) utilisées en synthèse ni même en simulation car elles sont soit trop complexes, soit ont une alternative beaucoup plus simple à mettre en œuvre.
A. Entité L’entité d’un design est l’abstraction matérielle de base en VHDL. Elle représente une portion
d’un design matériel dont les entrées et les sorties sont parfaitement définies. Elle peut représenter un système complet, un sous-système, une carte, un composant, une macro cellule, une porte logique, ou tout autre niveau d’abstraction.
Une entité peut être décrite en un ensemble hiérarchique de blocs, chacun d’entre eux représentant une portion du design complet. Syntaxe entity name is
entity_header entity_declarative_part [begin entity_statement_part]
end [entity] [name]
1. L’entête L’entête (header) déclare les objets utilisés pour la communication de l’entité avec son
environnement. Il est constitué d’une liste de generic et d’une liste de port, chaque liste étant facultative. Un generic est une constante fixée par l’environnement (valeur purement statique), tandis qu’un port est une entrée ou une sortie de l’entité (valeur dynamique). Exemple n°1 entity PorteOU is generic
( SIZE : positive := 2 ); port ( a_in : in std_logic_vector(SIZE-1 downto 0) ; result : out std_logic );
end entity PorteOU;
Exemple n°2 entity tb_PorteOU is end entity tb_PorteOU;
2. Les déclarations Les objets suivants peuvent y être déclarés :
• subprogram (déclaration et corps) • type • subtype • constant • signal • shared variable • file
Jean-Louis FLOQUET Page 16 13/11/2007
• alias • attribute (déclaration et spécification) • disconnection • use • group (déclaration)
Exemple entity MyEntity is generic(…); port(…); type NatArray is array(1 to 2) of natural;
constant PARAM : NatArray := (45,8); end entity MyEntity;
3. Les instructions Les instructions suivantes peuvent être utilisées :
• instruction en mode concurrent • appel d’une procédure passive • process passif
Exemple entity MyEntity is port
( clk : in std_logic ; data_in : in std_logic
; load : in std_logic ; data_out : out std_logic ); begin CheckTiming(clk,data_in,load); -- appel de la procédure CheckTiming end entity MyEntity;
B. Architecture Une architecture définit le corps d’une entité et spécifie les relations entre les entrées et les
sorties de celle-ci. Syntaxe architecture name of entity_name is
architecture_declarative_part begin architecture_statement_part end [architecture] [name];
Bien que cela soit déconseillé, il est possible de définir plusieurs architectures pour une entité précise (chaque architecture possède évidemment la même interface d’entrées/sorties).
1. Les déclarations Les objets suivants peuvent y être déclarés :
• subprogram (déclaration et corps) • type • subtype • constant • signal
Jean-Louis FLOQUET Page 17 13/11/2007
• shared variable • file • alias • component • attribute (déclaration et spécification) • configuration (spécification) • disconnection • use • group (déclaration)
2. Les instructions Cette partie décrit l’organisation interne et/ou les opérations du bloc défini par l’entité.
C. Objets 1. Signal
Un signal est un objet doté d’un historique de valeurs. En simulation, on peut accéder à la valeur qu’avait ce signal à n’importe quel moment de son
passé. La présence de cet historique permet de détecter un changement de valeur du signal (la valeur
actuelle est différente de son ancienne).
2. Constant Une constant est un objet dont la valeur ne peut être changée. Une constante n’a donc pas
d’historique !
3. Variable Une variable est un objet dont la valeur peut être changée mais qui ne dispose pas d’historique
de valeurs. L’absence de cet historique empêche de détecter un changement de valeur de la variable (la
valeur actuelle est accessible mais il est impossible d’accéder à sa valeur précédente).
4. Différences entre un signal et une variable Dans un process, il existe deux façons de stocker une valeur :
- écriture dans un signal - écriture dans une variable
La valeur d’un signal est mise à jour à la fin d’un process synchrone tandis que la valeur d’une
variable est mise à jour immédiatement. La nouvelle valeur d’une variable peut donc être utilisée immédiatement après son affectation, tandis que celle d’un signal ne pourra l’être qu’au cycle suivant.
Une attente dans un process de simulation provoque la mise à jour des signaux, même si la fin du process n’est pas atteinte. Ceci amène à la définition suivante : un signal est mis à jour
Jean-Louis FLOQUET Page 18 13/11/2007
lorsque tous les micro-time (delta) ont été résolus, ce qui se produit de toute façon en sortie de process.
Dans un process synchrone, l’affectation d’un signal se traduira par un registre et celle d’une variable par autant de couches logiques qu’il y a d’affectations suivies d’un registre. L'utilisation d'une variable va donc cumuler les différents blocs de logique combinatoire et donc dégrader les performances du système.
Sign
al
signal A : std_logic_vector(7 downto 0); process(rst,clk) begin if rst='1' then A <= (others=>'0'); C <= (others=>'0'); elsif rising_edge(clk) then A <= A + 1; if A(7)='1' then C <= B1; else C <= B2; end if; end if; end process;
A
1
B1
B2
C
T1
T2
Variable
process(rst,clk) variable A : std_logic_vector(7 downto 0); begin if rst='1' then A := (others=>'0'); C <= (others=>'0'); elsif rising_edge(clk) then A := A + 1; if A(7)='1' then C <= B1; else C <= B2; end if; end if; end process;
A
1
B1
B2
C
T1
T2
Tableau 1 : Différence Signal / Variable
Dans le cas d’un signal, le temps de propagation entre les registres A et C sera égal au maximum de T1 et de T2. Par contre, dans le cas d’une variable, ce temps sera égal à la somme de T1 et de T2. La fréquence de fonctionnement du circuit en sera donc diminuée d’autant.
Jean-Louis FLOQUET Page 19 13/11/2007
D. Types 1. Std_logic
Il représente l’état logique que peut prendre un bit. État logique Signification 0 état logique bas. Correspond physiquement au 0Volt*
1 état logique haut. Correspond physiquement au 5Volts* (pour du TTL). Z haute impédance. Utilisé pour tous les signaux bidirectionnels. U état indéfini. Rien ne vient piloter ce signal X conflit. Ce signal est piloté au moins à deux endroits différents avec des valeurs
différentes. L Pull-down. Émulation d’une résistance de tirage à la masse. H Pull-up. Émulation d’une résistance de tirage au Vcc. W Conflit faible. Presque jamais utilisé. - Don’t care. Possède les mêmes propriétés que les états 0 et 1 (il pilote activement
le signal concerné), mais sans choisir aucune des deux valeurs. Cette option est surtout destinée à simplifier les équations logiques pour le synthétiseur.
Tableau 2 : États logiques * Les tensions citées ne tiennent pas compte des tolérances liées à chaque technologie Seuls les états 0, 1 et Z sont reconnus sur tous les outils de synthèse. L’état « - » peut être utilisé sur certains synthétiseurs (dépend de l’éditeur du logiciel). Tous les autres états sont non synthétisables et donc réservés exclusivement à la simulation. Ces états doivent être encapsulés par des simples cotes en VHDL : '0', '1', 'Z', …, '-'.
En simulation, ces neuf états peuvent servir en lecture (test) et en écriture (affectation). En synthèse, pour des raisons évidentes de réalité physique (transistor bloqué ou saturé), seuls les états 0 et 1 peuvent servir en écriture. Le niveau Z est réalisé grâce à une structure spécifique qui n’est présente qu’au niveau des I/O du composant ; il est donc prohibé pour un usage interne.
Pour la lecture, seuls les états 0 et 1 sont utilisables ; en effet, une haute impédance en entrée d’un transistor va permettre d’avoir une tension (quelconque) mais aucun courant ne pourra circuler. Le transistor sera donc placé dans un état imprédictible (0 ou 1) voire même oscillant (antenne).
2. Std_logic_vector C’est un vecteur de bits. Chaque bit possède évidemment les mêmes caractéristiques qu’un
std_logic. Toutes les combinaisons sont autorisées ; l’état d’un vecteur s’écrit avec des doubles cotes : "001", "10-1Z", "L10HX0"…Chaque bit doit néanmoins respecter les critères de synthèse (s’ils ont lieu de s’appliquer).
On peut aussi affecter tous les sous-éléments d’un vecteur (les bits) grâce à un opérateur unique :
MyVect <= (others=>'0'); MyVect <= (others=>'1');
Jean-Louis FLOQUET Page 20 13/11/2007
3. Signed & Unsigned Ces deux types sont de même nature élémentaire qu’un std_logic_vector mais déterminent le
type (signé ou non signé) de la valeur qu’ils contiennent.
4. Boolean Ce type ne peut prendre que deux valeurs (false et true) que l’on peut associer aux états '0' et '1'
d’un std_logic. Ceci est toujours vrai pour une simulation, mais ne l’est pas forcément après la synthèse : le synthétiseur pourrait trouver une optimisation nécessitant l’inversion de polarité de ce bit. Cette éventualité interdit donc complètement l’utilisation d’un tel type pour un signal à synthétiser (l’analyse après synthèse deviendrait d’autant plus difficile). Par contre, ce type est très fréquemment utilisé pour un generic.
5. Énuméré Ce type correspond à un vecteur contenant autant de bits qu’il y a de valeurs listées. Il permet
principalement de nommer les états d’un séquenceur. type EnumType is (idle, trsf, init, load); signal MyEnum : EnumType; case MyEnum is
when idle => instructions
when tsrf => instructions
when init => instructions
when load => instructions
end case; state1 <= '1' when MyEnum=idle else '0'; state2 <= '1' when MyEnum=tsrf else '0'; state3 <= '1' when MyEnum=init else '0'; state4 <= '1' when MyEnum=load else '0';
Chaque état du séquenceur peut alors être « extrait » en un bit qui sera à 1 s’il est dans l’état testé ou à 0 sinon.
6. Record Ce type permet d’associer plusieurs signaux (pas de contrainte sur le type de ces signaux) en
un nouveau groupe. Ce nouveau type contient donc tous les signaux définis et cela de façon unitaire (un seul signal au lieu du contenu).
Par exemple, si l’on considère un flux vidéo BT656 (flux vidéo numérique pour les standard PAL, SECAM, et NTSC). On définit alors le type YCbCrStrm de la façon suivante :
type YCbCrStrm is record -- 1 data of 8bits ok : std_logic ;-- Set if video present, unset if stream meaningless data : std_logic_vector(7 downto 0);-- Data (pixel, timing reference, or blanking) valid : std_logic ;-- Data validation enable : std_logic ;-- Clock enable (useful for CIF & slow streams) isY : std_logic ;-- Y pixel isCb : std_logic ;-- Cb pixel isCr : std_logic ;-- Cr pixel vbi : std_logic ;-- Vertical Blanking Interval SAV : std_logic ;-- SAV --> data is FF 00 00 xx video : std_logic ;-- Video --> data is Cb0 Y0 Cr0 Y1 EAV : std_logic ;-- EAV --> data is FF 00 00 xx blk : std_logic ;-- Blanking --> data is 80 10 80 10... field : std_logic ;-- Field fl : std_logic ;-- First Line fp : std_logic ;-- First pixel lp : std_logic ;-- Last pixel
Jean-Louis FLOQUET Page 21 13/11/2007
sof : std_logic ;-- Start of field eof : std_logic ;-- End of field end record YCbCrStrm;
La mise à zéro de tous les éléments inclus dans ce record s’écrit de la façon suivante : constant YCbCrStrmZero : YCbCrStrm := YCbCrStrm'('0',(others=>'0'),'0','0','0','0','0','0', '0','0','0','0','0','0','0','0','0','0');
7. Integer, natural, positive, real Ces types permettent de représenter des nombres. Lorsqu’ils sont non contraints, le système
d’exploitation conditionne la taille du codage de ces valeurs (ils seront donc codés sur 32bits ou 64bits). Toutes les opérations mathématiques sont possibles sur ces types. Un entier contraint s’écrit sous la forme integer i range n to N.
8. Array Les tableaux sont principalement utilisés pour décrire des mémoires (ROM, RAM, Fifo) ou
n’importe quelle autre structure à plusieurs dimensions.
Ce type n’est pas directement utilisable lors de la déclaration d’un signal. Il faut tout d’abord créer un nouveau type qui pourra ensuite être utilisé. type MyArrayA is array(natural range <>) of std_logic_vector(7 downto 0); type MyArrayB is array(3 downto 0) of std_logic_vector(7 downto 0);
La première méthode permet de définir un tableau de vecteur de 8bits, sans fixer le nombre d’éléments que contiendra un tel tableau (écriture plus générique). La seconde méthode définit explicitement un tableau de 4 vecteurs de 8bits chacun. Cette dernière est à privilégier lors de la création d’un type qui est parfaitement connu à l’avance. Par exemple, si l’on voulait définir un signal contenant un pixel RGB (donc trois pixels de 8bits chacun), on écrirait : type PixelRGB is array(2 downto 0) of std_logic_vector(7 downto 0);
Un tableau ne peut pas être manipulé comme le serait un vecteur : ses sous-éléments ne peuvent pas être concaténés ni subir d’autres opérations similaires. Il faut dans ce cas affecter chacun des éléments du tableau un par un (ou bien utiliser une boucle for si cela est possible). Par contre, on peut affecter la même valeur à tous ses éléments grâce à un seul opérateur : MyPixelRGB <= (others=>(others=>'0'));
9. Record Le type record permet de regrouper plusieurs données (de même type ou non) en un seul
objet qui sera ensuite beaucoup plus facile à transmettre à travers un design. Ce type est normalement bien reconnu par les outils courants (ModelSim, QuartusII) mais peut être incompatible avec d’autres. type MyRecord is record
data1 : type1;
data2 : type2;
data3 : type3;
end record MyRecord;
constant MyRecordRst : MyRecord := MyRecord’( data1 => type1_reset_value
, data2 => type2_reset_value
, data3 => type3_reset_value
);
Jean-Louis FLOQUET Page 22 13/11/2007
signal MySignal : MyRecord; MySignal <= MyRecordRst; --valeur de reset
if MySignal.data1=xxx and MySignal.data2=yyy then instructions; end if;
Chaque donnée du record se manipule comme le type auquel elle appartient.
10. Personnalisé On peut définir un nouveau type en VHDL de deux façons :
- par le mot clé subtype qui permet de conserver toutes les propriétés liées au type dont il dépend
- par le mot clé type qui crée réellement un nouveau type subtype slv8 is std_logic_vector(7 downto 0); type Pixel is std_logic_vector(7 downto 0); type PixelRGB is array(2 downto 0) of Pixel;
Dans l’exemple ci-dessus, les nouveaux types slv8 et Pixel sont équivalents (ce sont tous deux des vecteurs) mais la déclaration de slv8 est à préférer. Si un nouveau type est utilisé dans le port d’une entité, la déclaration de ce type doit être faite dans un package qui devra lui-même être appelé dans tous les fichiers utilisant ce nouveau type.
E. Agents 1. Process
Un process est un agent qui exécute des instructions et met à jour des objets. On distingue trois types de process :
• les process synchrones : le process est exécuté à chaque cycle d’horloge • les process combinatoires : le process est exécuté à chaque que l’un de signaux inclus
dans la liste de sensibilité subit un évènement • les process linéaires : le process est exécuté linéairement et peut contenir des délais
(met en pause le déroulement du process pendant un temps déterminé ou jusqu’à ce qu’une condition soit remplie)
2. Function Une function retourne une valeur en fonction des paramètres qui lui sont fournis. On distingue deux types de fonctions : les fonctions pure et impure :
• fonction pure : retourne toujours la même valeur si elle appelée avec les mêmes paramètres
• fonction impure : peut retourner une valeur différente à chaque appel, même si les paramètres qui lui sont fournis sont identiques (peut accéder à des objets non fournis en paramètres)
3. Procedure Une procedure est un agent qui reçoit des paramètres, exécute des instructions et peut mettre à
jour des objets.
Jean-Louis FLOQUET Page 23 13/11/2007
F. Bibliothèques IEEE 1. std_logic_1164
Cette bibliothèque définit les types std_logic et std_logic_vector. Il faut donc systématiquement l’inclure dans tout code source VHDL.
2. std_logic_arith & std_logic_unsigned (ou std_logic_signed) Cette paire de bibliothèques permet de réaliser très simplement toutes les opérations
arithmétiques standards. Néanmoins, ces bibliothèques ne font pas véritablement partie de la norme IEEE mais sont toutefois reconnues et utilisables par la quasi-totalité des logiciels.
Les bibliothèques std_logic_unsigned et std_logic_signed ne peuvent pas être utilisées dans la même architecture, puisqu’elles posent une condition de base opposée : la première considère que tous les std_logic_vector sont de type unsigned alors que la seconde considère qu’ils sont de type signed.
3. numeric_std Cette bibliothèque fait partie intégrante de la norme IEEE et est donc reconnue par tous les
outils. Néanmoins, son utilisation conduit à l’un des deux choix suivants : 1) utiliser les types signed et unsigned pour tous les objets sur lesquels on souhaite réaliser une
opération arithmétique, ce qui pose un problème évident pour tous les signaux d’entrée/sortie (ces deux types sont fortement déconseillé dans le port d’une entité). Les objets de type signed et unsigned peuvent alors être manipulés pour les opérations arithmétiques standards, avec la précaution laissée à l’utilisateur de vérifier la taille de tous les objets. Par exemple 32 – "0000" renvoit la valeur "0000" (le calcul est fait en ne considérant que les 4 LSB de 32, qui sont tous nuls !)
2) utiliser une double conversion std_logic_vector vers unsigned (ou signed) puis unsigned (ou
signed) vers std_logic_vector lors de l’opération. Par exemple, std_logic_vector(unsigned(Vecteur) – 14)
4. Conseil Bien que les bibliothèques std_logic_arith et std_logic_unsigned ne soient pas inclues dans la
norme IEEE, et si les règles d’écriture imposées pour le design le permettent, il est préférable de les utiliser en raison de la simplification qu’elles apportent.
G. Opérateurs Les opérateurs les plus couramment utilisés sont indiqués dans le tableau ci-dessous (liste
non-exhaustive).
+ - * / mod rem ** = /= < <= > >=
and nand or nor xor xnor &
abs not
Tableau 3 : Opérateurs usuels
Jean-Louis FLOQUET Page 24 13/11/2007
Les opérateurs de comparaison donnent des résultats « inattendus » pour des vecteurs de longueurs différentes : "000" > "00" ! Ceci est dû à la bibliothèque numeric_std et peut être évité simplement :
• soit en utilisant les bibliothèques std_logic_arith et std_logic_unsigned à la place de la bibliothèque numeric_std
• soit en surchargeant les opérateurs en question de façon à comparer des vecteurs de tailles identiques
H. Attributs 1. Attributs de types
Les attributs de types permettent d’obtenir des informations relatives à un type. Dans le tableau ci-dessous, T est un type quelconque.
Attribut Description T'base T'left Extrémité gauche de T T'right Extrémité droite de T T'low Extrémité inférieure de T T'high Extrémité supérieure de T T'ascending VRAI si T est ascendant (a to b), FAUX si descendant (a downto b) T'image(X) Représentation (sous forme de chaîne de caractères) de X T'value(X) Valeur dont la représentation est X T'pos(X) Position de l’élément X dans le signal T T'val(N) Valeur du Nième élément de T T'succ(N) Successeur. Équivalent à T’val(T’pos(X)+1) T'pred(N) Prédécesseur. Équivalent à T’val(T’pos(X)-1) T'leftof(X) Élément situé à gauche de X T'rightof(X) Élément situé à droite de X
Tableau 4 : Attributs de types type T is (A, B, C, D, E)
T'left � A
T'right � E
T'low � A
T'high � E
T'ascending � true
T'image(D) � "d"
T'value("e") � E
T'pos(B) � 2
T'val(2) � B
T'succ(B) � C
T'pred(B) � A
T'leftof(D) � C
T'rightof(D) � E
2. Attributs de signaux Les attributs de signaux permettent d’obtenir des informations relatives à un signal. Dans le
tableau ci-dessous, S est un signal quelconque.
� L’affectation d’un signal crée une transaction. Une transaction causant un changement de valeur est un évènement.
Jean-Louis FLOQUET Page 25 13/11/2007
Attribut Description
S'delayed(T) Valeur du signal au temps NOW-T S'stable(T) VRAI si et seulement si aucun évènement ne s’est produit depuis T (temps) S'quiet(T) VRAI si et seulement si aucune transaction ne s’est produite depuis T (temps) S'transaction Signal de type « bit » qui commute à chaque transaction du signal S. S'event VRAI si et seulement si un évènement se produit sur S pendant l’actuel delta*. S'active VRAI si et seulement si une transaction se produit sur S pendant l’actuel delta*. S'last_event Durée depuis le dernier évènement sur S S'last_active Durée depuis la dernière transaction sur S S'last_value Valeur de S avant le dernier évènement. S'driving FAUX si et seulement si le driver de S dans le process courant est null. S'driving_value Valeur du driver de S dans le process courant.
Tableau 5 : Attributs de signaux * delta : se reporter au § VII.B Time et micro-time, p. 36
3. Attributs de tableaux Les attributs de tableaux permettent d’obtenir des informations relatives à un tableau. Dans le
tableau ci-dessous, T est un tableau quelconque. Attribut Description
T'range Plage (de gauche à droite) T'reverse_range Plage (de droite à gauche) T'length Nombre d’éléments dans le tableau
Tableau 6 : Attributs de tableaux signal S : std_logic_vector(7 downto 0);
S'range � 7 downto 0
S'reverse_range � 0 to 7
S'length � 8
L'attribut range est très pratique pour générer des boucles for.
I. Les boucles Les boucles de test constituent un outil essentiel de description du comportement d’un signal.
Le fonctionnement de telles boucles est similaire à la plupart des langages informatiques mais avec des contraintes spécifiques puisque ici on cible une architecture matérielle prédéterminée (le CPLD, le FPGA, …). Ces fonctions auront des implémentations différentes selon la cible choisie et l’on pourra donc se permettre plus ou moins de liberté d’écriture.
1. if…then…else Syntaxe if test1 then instructions
elsif test2 then instructions
else instructions
end if;
Ce type de boucle est celui qui est le plus souvent utilisé. Une telle boucle ne sera utilisée que
dans les cas suivants :
Jean-Louis FLOQUET Page 26 13/11/2007
- soit piloter un seul signal. Si un autre signal utilise des conditions de test similaire, cet autre signal devra posséder sa propre boucle de test. D’une part, ceci permettra de simplifier une évolution du code (surtout pendant la phase d’écriture de celui-ci). D’autre part, ceci évitera de coder des conditions non souhaitées (et donc de nécessiter des ressources inutiles en synthèse).
- soit piloter plusieurs signaux. Dans ce cas, tous les signaux doivent être gérés exactement de la même façon et avoir la même signification fonctionnelle.
2. case…when… Syntaxe case A is
when … => instructions
when … => instructions
when others => instructions
end case ;
Ce type de boucle permet de coder explicitement un multiplexeur ou un séquenceur
(machines d’états). À noter que toutes les combinaisons possibles doivent être listées à l’intérieur du case. Les cas
non listés explicitement peuvent être regroupés avec le mot clé others qui apparaît forcément en dernier. En particulier, pour un std_logic_vector, il faut bien considérer les neufs états possibles de chaque bit (seulement deux en synthèse).
3. for … in … to … loop… Syntaxe
for i in A to B loop
instructions
end loop;
Ce type de boucle permet de générer automatiquement du code à l’intérieur d’un process. Ceci permet de faire appel à un indice de boucle (la variable située après le « for ») et de l’inclure par exemple dans une formule mathématique plus ou moins évoluée. Une boucle for crée l’un des deux types suivants :
- boucle itérative : le signal affecté dépend de tout ou partie de résultat en cours de calcul - boucle non itérative : le signal affecté ne dépend pas du résultat en cours de calcul
Boucle itérative Boucle non itérative
for i in 0 to 7 loop V(i+1) := V(i) and K; end loop;
for i in 0 to 7 loop S(i+1) <= S(i) and K; end loop; for i in 0 to 7 loop A(i) <= B(i) and C(i); end loop;
V étant une variable, K une constante binaire A, B, C et S étant des vecteurs.
4. while…loop Syntaxe while test loop
instructions
end loop;
Jean-Louis FLOQUET Page 27 13/11/2007
Ce type de boucle permet de créer une itération dont le nombre d’occurrences est, a priori, inconnu. Les instructions contenues à l’intérieur de cette boucle sont exécutées aussi longtemps que le test fait est vrai. Attention aux boucles infinies !!
5. Generate Syntaxe Label : for Param in Range generate
Instanciation d’une entité
Instructions concurrentes
end generate label;
Ce type de boucle a un fonctionnement totalement différent des autres boucles : il permet de
générer automatiquement (avec ou sans indice de boucle) du code VHDL. Cette méthode revient à écrire le code autant de fois le contenu de la boucle.
La principale utilisation de ce type de boucle (qui fait d’ailleurs aussi appel à la boucle for…in…to…loop) est l’instanciation de plusieurs entités identiques.
J. Commandes 1. Wait
Syntaxe wait [ until Condition ] [ for TimeExpression ]
Lorsqu’un évènement se produit sur un signal testé, la condition est réévaluée. L’attente peut être limitée à une durée prédéterminée par l’expression TimeExpression.
La commande wait until se déclenche uniquement sur front, c’est-à-dire que la condition n’est testée que lorsqu’un évènement se produit sur un signal inclus dans cette condition. Ceci implique notamment :
wait until NOW=5 us; � attente infinie
wait until busy='0'; � attend un front descendant de busy
Jean-Louis FLOQUET Page 28 13/11/2007
V. Structure d’un fichier VHDL Tout fichier VHDL commence par un entête qui contient notamment :
- le nom du plus haut niveau hiérarchique du design - le nom du fichier - l’auteur - la date de création - la date et l’heure de dernière modification - un numéro de version - une description concise du rôle et du fonctionnement du module
Le numéro de version 1.0.0 doit correspondre à une version finale et testée complètement.
Pendant la phase de développement, soit ce numéro reste constamment à 1.0.0 (avec tout de même la mise à jour de la date de dernière modification), soit il part de 0.0.0 pour arriver finalement au numéro 1.0.0. Sous l’entête, viennent la déclaration des bibliothèques et packages. Puis celle de l’entité avec deux zones distinctes :
- les paramètres statiques, appelés « generic » - les signaux d’interconnexion avec les autres modules
L’entité est suivie de l’architecture qui décrit le comportement du module VHDL. Cette
architecture est elle-même scindée en deux parties : - la déclaration des signaux internes - la description fonctionnelle du module
A. L’entête Par exemple :
----------------------------------------------------------------------------------------- -- Project : Project Name ----------------------------------------------------------------------------------------- -- Top level : project.vhd -- File : this_file.vhd -- Author : -- Organization: -- Created : 2004, January 10th -- Last update : 2004, March 12th -- Version : 1.0.0 -- Dependency : ----------------------------------------------------------------------------------------- -- Description : -----------------------------------------------------------------------------------------
B. Bibliothèques et packages Les bibliothèques et packages permettent de prédéfinir de nombreux types et opérations
VHDL (std_logic, std_logic_vector, integer, boolean,…, addition, soustraction, comparateur,…) qui seront utilisés dans la description fonctionnelle du module.
L’exemple de déclaration ci-dessous appelle la bibliothèque standard IEEE1164 ainsi que plusieurs sous-ensembles.
Jean-Louis FLOQUET Page 29 13/11/2007
library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; library work; use work.pkg.all;
Nom Fonction 1164 Types et opérations standard arith Opérations arithmétiques unsigned Considère que tous les std_logic_vector ont une représentation non signée. work Permet de faire référence à une entité précédemment compilée (valable pour
ModelSim et Quartus) work.pkg Charge le package utilisateur (s’il a été créé et est nécessaire à ce module)
C. L’entité L’entité est déclarée en deux parties : les paramètres d’une part et les signaux d’autre part. La
section relative aux paramètres (si elle existe) doit impérativement être mise avant celle des signaux. Ceux-ci peuvent en effet utiliser un ou plusieurs des paramètres de la section précédente afin d’avoir une écriture adaptable. entity my_entity is generic
( PARAM_A : integer -- description ; PARAM_B : integer -- description ); port ( rst : in std_logic -- reset asynchrone ; clk : in std_logic -- horloge ; a : in std_logic_vector(PARAM_A-1 downto 0) -- description ; b : out std_logic_vector(PARAM_B+5 downto 0) -- description
); end entity my_entity;
Si PARAM_A et PARAM_B valent respectivement 10 et 15, alors a sera un vecteur de 10bits et b un vecteur de 21bits. La fin de la déclaration de l’entité (partie soulignée) impose au compilateur d’utiliser la norme VHDL93, qui sera considérée comme la norme par défaut. Cette méthode permet notamment de générer une erreur bloquant toute compilation en VHDL87, norme qui peut dans certain cas entraîner des effets de bords / comportements indésirables. De nombreuses méthodes de simulation nécessitent la norme 93.
D. L’architecture L’architecture est scindée en deux parties:
- les déclarations - la description fonctionnelle
Ces deux parties sont séparées par un begin qu’il ne faudra pas oublier.
1. Les déclarations Cette partie est la déclaration des signaux internes permettant d’effectuer toutes les
opérations intermédiaires ainsi que les entités qui seront mappées en tant que sous module (cette seconde zone est impérative en VHDL87 et optionnelle en VHDL93).
Jean-Louis FLOQUET Page 30 13/11/2007
2. La description fonctionnelle Cette partie est la zone réellement active du code. Elle décrit le fonctionnement du module.
Elle contient à la fois la logique synchrone (process) et asynchrone (mode concurrent). architecture rtl of my_entity is
constant MyConstant : integer; signal Cnt : std_logic_vector(MyConstant-1 downto 0); signal led : std_logic;
déclarations des signaux
component sub_entity generic (… ); port (… ); end; -- on aurait pu mettre "end component sub_entity" (VHDL93)
déclarations des entités des
sous-modules
begin
séparateur
process(rst,clk) begin if rst='1' then Cnt <= (others=>'0'); elsif rising_edge(clk) then Cnt <= Cnt + 1; end if; end process;
logique synchrone
led <= Cnt(0) xor Cnt(1);
logique asynchrone
end architecture rtl; L’écriture de la fin de l’architecture (partie soulignée) impose là aussi la norme VHDL93, pour les mêmes raisons que précédemment.
E. Fin du fichier Le module ainsi décrit doit être terminé par cinq lignes de commentaires réalisant une
séparation visuelle entre ce module et le suivant, même s’il s’agit de la dernière entité du fichier. Cette séparation doit être suivie d’une ligne vide. Par exemple : --########################################################################################## --########################################################################################## --########################################################################################## --########################################################################################## --##########################################################################################
F. Testbench Le testbench est un module VHDL venant stimuler les entrées du module à réaliser et relire
ses sorties afin de valider le bon fonctionnement de celui-ci. Il est placé à la suite du module à tester* et respecte les mêmes règles que n’importe quel autre module VHDL.
La déclaration de l’entité du testbench est vide dans l’immense majorité des cas (pas d’interconnexion avec un autre module). Il devient intéressant de définir des generic (et/ou des ports) sur un testbench si l’on veut que celui-ci récupère des paramètres fournis par le simulateur. Sous ModelSim, on aurait « vsim -g<Name>=<Value> ».
� Un testbench n’est pas quelque chose d’optionnel ! Il doit être systématiquement créé pour chaque module à synthétiser, être le plus efficace possible (normalement il doit valider tous les cas possibles de fonctionnement), et donc permettre d’utiliser de façon fiable le module testé. Une absence de testbench est donc une aberration.
Jean-Louis FLOQUET Page 31 13/11/2007
library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; library work; use work.pkg.all; entity tb_my_entity is end entity tb_my_entity; architecture testbench of tb_my_entity is
déclarations
begin my_entity_inst : entity work.my_entity generic map
( PARAM_A => … , PARAM_B => … ) port map
( rst => rst , clk => clk , … );
description fonctionnelle
end architecture testbench;
* Le testbench du top-level hiérarchique doit être placé dans un fichier séparé pour deux raisons :
- il est généralement très grand (en taille de code) et sa présence dans le fichier top-level (qui lui aussi est généralement très grand) rendrait sa lecture difficile
- le simulateur compilant les deux entités simultanément, il devient impossible de faire une simulation post-route puisque l’entité de synthèse (fournie par le synthétiseur) doit être compilée avant son testbench
Jean-Louis FLOQUET Page 32 13/11/2007
VI. Règles et conventions A. Entité Le nom de l’entité de synthèse impose son nom au fichier VHDL. De nombreux
synthétiseurs ne savent trouver le fichier VHDL que s’il correspond au nom de l’entité. L’entité testbench (qui rappelons-le est toujours située dans le même fichier, sauf dans le cas du top-level) devra avoir le même nom que son entité associée, avec le préfixe tb_.
B. Architecture Une entité synthétisable aura une architecture nommée rtl, tandis que celle d’un testbench
sera nommée testbench. Ces conventions permettent d’identifier immédiatement le rôle du module, sans avoir à lire plus en détail le code. Bien que la norme VHDL permette de définir plusieurs architectures pour une seule et même entité, cette possibilité ne devra pas être utilisée.
C. Noms Pour un nom composé de plusieurs termes (par exemple un contrôleur mémoire), il y a deux
possibilités: - MemCtrl - mem_ctrl
La première solution est à privilégier puisqu’elle nécessite moins de caractères, et donc moins de place sur l’écran de l’ordinateur. Les noms (des entités, des signaux, des paramètres…) doivent être courts et explicites. Toujours dans l’exemple du contrôleur mémoire, le nom MemoryController est à bannir formellement !
D. Suffixes Les suffixes listés ci-dessous sont fixés par convention :
Suffixe Signification _n Signal actif à l’état bas _r Valeur registrée d’un signal _rr Valeur registrée deux fois d’un signal _s Registre à décalage où le signal en question entre par le LSB. _i Signal interne dirigé vers le signal sortant du même nom (sans suffixe) _x Valeur du signal un cycle avant (va généralement à une broche du composant) _xx Valeur du signal deux cycles avant _oe Output Enable _o Valeur à piloter sur le bus si l’Output Enable est actif
Tableau 7 : Suffixes
E. Préfixes Les préfixes sont utilisés pour désigner l’appartenance d’un signal à un groupe. Par exemple :
- pci_clk, pci_frame_n, pci_idsel, pci_devsel_n… - ddr_a, ddr_ba, ddr_ras_n, ddr_cas_n, ddr_we_n…
Jean-Louis FLOQUET Page 33 13/11/2007
F. Types des signaux 1. Synthèse
Seuls les types suivants pourront être utilisés, à l’exclusion de tous les autres : - std_logic - std_logic_vector - tableau de std_logic_vector - type énuméré (cf. Erreur ! Source du renvoi introuvable. Erreur ! Source du
renvoi introuvable., p. Erreur ! Signet non défini.)
Les types signed et unsigned sont « exclus » de cette liste car leur utilisation pose problème au niveau des entités : mélanger les std_logic_vector avec les signed/unsigned provoque presque systématiquement des « conflits » de types et donc des conversions de type en très grand nombre.
Pour des raisons liées au synthétiseur Quartus, il faut limiter les tableaux (array) à seulement deux dimensions (pas de tableau de tableau de vecteurs).
Type VHDL Représentation logique
std_logic
std_logic_vector
tableau de std_logic_vector
type énuméré
Tableau 8: Représentation physique des types VHDL Tous les autres types VHDL seront à considérer comme non synthétisables.
2. Simulation Aucune restriction n’est imposée ici. Le seul but étant de valider une interface elle-même
assujettie aux règles du § VI.F.1 Synthèse, p. 34. Les signaux intermédiaires devront donc permettre une écriture la plus simple et la plus rapide possible du testbench.
G. Types des constantes / generic Les constantes sont soit déclarées explicitement dans le corps des déclarations, soit
proviennent de la section « generic » de l’entité. Leur type n’est assujetti à aucune contrainte, si ce n’est un choix adapté à leur utilisation.
Jean-Louis FLOQUET Page 34 13/11/2007
H. Indentation L’indentation correcte est un aspect primordial garantissant une lecture convenable d’un
code. Il faut aussi tenir compte que la relecture d’un code peut être faite sur un autre ordinateur (voire un autre système d’exploitation) que celui où il a été saisi.
Les tabulations ne doivent être utilisées que pour créer une indentation du code et jamais pour décaler le texte d’un certain nombre de caractères. Par conséquent, elles ne peuvent être employées qu’en début de ligne. Il faut aussi privilégier un alignement vertical du texte. Ceci est l’une des raisons pour laquelle les points-virgules des sections « generic » et « port » d’une entité sont placés en début de ligne.
Certains éditeurs de texte possèdent un mode « colonne » accélérant grandement une saisie identique sur plusieurs lignes. Les points-virgules de l’entité peuvent alors être très facilement remplacés par des virgules lors de la création du « port map ».
Jean-Louis FLOQUET Page 35 13/11/2007
VII. Simulation A. Testbench Le testbench est un module VHDL venant stimuler les entrées du module à réaliser et relire
ses sorties afin de valider le bon fonctionnement de celui-ci. Il est placé à la suite du module à tester* et respecte les mêmes règles que n’importe quel autre module VHDL. Par contre, la déclaration de l’entité du testbench est vide (pas d’interconnexion avec un autre module).
� Un testbench n’est pas quelque chose d’optionnel ! Il doit être systématiquement créé pour chaque module à synthétiser, être le plus efficace possible (normalement il doit valider tous les cas possibles de fonctionnement), et donc permettre d’utiliser de façon fiable le module testé. Une absence de testbench est donc une aberration.
De la qualité du testbench dépend la rapidité de mise au point de l’entité synthétisable une
fois implémentée sur la carte. Il est donc vital de tester un maximum de cas possibles en simulation avant de lancer une synthèse. Les performances des outils actuels sont telles qu’il est quasiment toujours faisable de se passer d’une simulation post-route. library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; library work; use work.pkg.all; entity tb_my_entity is end entity tb_my_entity; architecture testbench of tb_my_entity is
déclarations
begin my_entity_inst : entity work.my_entity generic map( PARAM_A => … , PARAM_B => … ) port map( rst => rst , clk => clk , … );
description fonctionnelle
end architecture testbench;
* Le testbench du top-level hiérarchique doit être placé dans un fichier séparé pour deux raisons :
- il est généralement très grand (en taille de code) et sa présence dans le fichier top-level (qui lui aussi est généralement très grand) rendrait sa lecture difficile
- le simulateur compilant les deux entités simultanément, il devient impossible de faire une simulation post-route puisque l’entité de synthèse (fournie par le synthétiseur) doit être compilée avant son testbench
B. Time et micro-time Si sur n’importe quel écran de simulation on peut voir facilement l’évolution temporelle de
n’importe quel signal y figurant, il est impossible d’y voir des éléments temporels plus petits : les « time » et « micro-time ». Cette notion de subdivision du temps, une fois correctement maîtrisée, devient totalement transparente pour le designer. Nous allons voir ce qu’ils sont réellement et comment les ignorer.
Jean-Louis FLOQUET Page 36 13/11/2007
1. Définition Un « time » est un temps microscopique de la simulation (non visualisable sur l’écran de
simulation) et est atteint : • soit à la fin d’un process synchrone • soit par une attente explicite dans un process linéaire • soit après une affectation hors process
Un « micro-time » (ou delta) est une subdivision d’un « time » et correspond :
• soit à l’affectation d’une variable dans un process • soit à une itération d’une boucle (for…loop par exemple)
Tous les « micro-times » doivent être résolus (finis) avant que le « time » associé ne soit
lui-même achevé.
Considérons les exemples suivants :
Exemple 1 Exemple 2 process(rst,clk) begin if rst='1' then … elsif rising_edge(clk) then a <= b or c;
d <= a and b; e <= a xor d;
end if; end process;
-- hors process a <= b or c; d <= a and b; e <= a xor d;
Le premier cas ne nécessite qu’un seul time pour réaliser les trois affectations (chacune d’entre elle requiert un micro-time). On peut aboutir à cette analyse de deux façons :
� les trois affectations sont faites avant la fin du process synchrone, donc un time � le process synchrone se déroule sur le front montant de clk, donc un seul time
Le second cas nécessité quant à lui trois time puisque chaque affectation a lieu de façon
concurrente et que ces affectations ne peuvent se faire que dans l’ordre dans lequel elles sont écrites (a doit être calculé avant de pouvoir mettre à jour d, idem pour d et e).
2. Pièges classiques a. Attente
La gestion des time et micro-time est assurée par le simulateur. Mais des comportements non souhaités peuvent survenir en simulation suite à une attente prédéterminée directement exprimée en nanoseconde (ou tout autre unité de temps). En effet, la fin d’une attente peut se produire entre plusieurs « time » alors que tous les signaux ne sont pas encore calculés par le simulateur. Solution
Ceci est facilement contourné en utilisant en plus une attente du front actif de l’horloge (wait until rising_edge(clk)).
b. Affectation Une affectation concurrente (hors process) requiert un time et peut engendrer une aberration
importante si l’affection se produit sur l’horloge ou tout autre signal de la liste de sensibilité d’un process.
Jean-Louis FLOQUET Page 37 13/11/2007
Si un process basé sur la seconde horloge (résultante de l’affectation) utilise un signal généré par un process basé sur la première horloge, alors ce second process se comportera exactement comme si le front de la seconde horloge s’était produit après le front de la première. Considérons l’exemple suivant où les signaux a et b sont décrits exactement de la même façon. Leur process utilise deux horloges différentes (clk et clk2) qui sont pourtant rigoureusement identique sur l’écran du simulateur. Dans cet exemple, le signal a sera à 1 lorsque cnt vaut 13 (comportement parfaitement normal) alors que b sera à 1 en même temps que cnt vaut 12. Ce comportement non souhaité (mais normal) de b ne se produira pas en synthèse, puisque la notion de time et micro-time n’existe évidemment pas. Ceci peut évidemment aboutir à un design non fonctionnel s’il s’agit d’un signal de contrôle… clk2 <= clk; process(rst,clk) begin if rst='1' then cnt <= (others=>'0'); elsif rising_edge(clk) then cnt <= cnt + 1; end if; end process; process(rst,clk) begin if rst='1' then a <= '0'; elsif rising_edge(clk) then if cnt=12 then a <= '1'; else a <= '0'; end if; end if; end process; process(rst,clk2) begin if rst='1' then b <= '0'; elsif rising_edge(clk2) then if cnt=12 then b <= '1'; else b <= '0'; end if; end if; end process;
5 6 7 8 9 10 11 12 13 14
clk
clk2
cnt
a
b Figure 5 : Problème de simulation lié au time
� Ne jamais faire d’affectation concurrente (hors process) sur une horloge ni sur aucun autre signal figurant dans la liste de sensibilité d’un process.
C. Horloges et signaux généraux La méthode la plus simple pour générer une horloge dans un testbench nécessite seulement
une ligne de code : - la déclaration du signal d’horloge que l’on initialise (elle est de toute façon indispensable) - la commutation à intervalle régulier par une négation du signal lui-même
architecture testbench of tb_my_entity is
signal clk : std_logic := '0'; déclaration et initialisation à '0'
Jean-Louis FLOQUET Page 38 13/11/2007
autres déclarations
begin
clk <= not(clk) after 5 ns; commutation toutes les 5ns (T=10ns � F=100MHz)
autres instructions
end architecture testbench;
On peut aussi utiliser cette méthode pour générer un reset asynchrone en début de simulation. Dans ce cas, il n'y aura pas d'inversion mais seulement forçage à un état: signal rst : std_logic := '1'; rst <= '0' after 8 ns;
On pourrait tout aussi bien écrire un process pour décrire le fonctionnement de ce type de signaux, mais cela serait moins simple. Attention Pour piloter les signaux du testbench après un front actif de l’horloge, il ne faut pas écrire un wait for xx ns car on ne sait pas si cette attente va terminer juste avant ou juste après le front en question de l’horloge en raison des micro-times de la simulation. Il faut toujours insérer un wait until rising_edge(clk) ou wait until falling_edge(clk), car cela impose formellement de se positionner après le front actif de l’horloge (cf. VII.B Time et micro-time, p.36).
Par contre, il est tout à fait possible de créer une attente prédéterminée (exprimée grâce à un wait for xx ns) suivie immédiatement de l’attente du front d’horloge.
D. Affectation retardée Il est souvent pratique de pouvoir appliquer un retard sur un signal afin de simuler le
comportement physique de ce signal sur une carte. On utilise alors la commande suivante : b1 <= a after time; -- délai + filtre passe-bas b2 <= transport a after time; -- délai pur
Figure 6 : Affectation retardée
Attention à ne pas oublier le mot transport, ce qui changerait le comportement de l’affectation en un délai couplé à un filtre passe-bas. Dans ce cas, le signal est retardé du temps spécifié, mais toute transition du signal source inférieure au décalage ne sera pas reproduite en sortie.
E. Assert & Report Avant de faciliter la mise au point d’un testbench efficace (qui se doit de tester tous les cas
possibles et de s’assurer qu’il n’y a pas d’erreur dans le comportement de l’entité à tester), on peut y inclure l’une des commandes suivantes : assert FalseTest report "Message" severity level;
report "Message" severity level;
Attention, le message n’est renvoyé qui si le test est faux ! La seconde commande, associée à une boucle if, permet de simplifier son utilisation puisque dans ce cas le test est réalisé par la boucle if et non plus par la commande assert.
Jean-Louis FLOQUET Page 39 13/11/2007
Il existe quatre niveaux d'erreur : note, warning, error, failure. Ce dernier niveau permet de stopper la simulation et sera à utiliser dans les cas suivants:
- vérification permanente du comportement interne du code de synthèse nécessitant l’arrêt de la simulation en cas de défaillance
- arrêt volontaire de la simulation une fois tous les tests effectués afin de pouvoir utiliser la commande run –all de ModelSim et donc ne pas avoir à se préoccuper du temps exact nécessaire à cette simulation.
Sur des designs complexes, il est important d’ajouter des points de contrôle (grâce à cette
commande) à des endroits stratégiques du code. Par exemple, un vecteur ne devant contenir au plus qu’un seul bit à 1 doit être vérifié en permanence et un message d’erreur affiché en cas de disfonctionnement (exemple 1)
On peut aussi vérifier la cohérence d’un ensemble de paramètres generics en envoyant un simple message d’avertissement (warning) ou bien interdire la simulation et la synthèse (failure) (exemple 2). Exemple n°1 process … --synthesis translate_off if vect1="110" and vect2="001" then
report "Vect1 & Vect2 wrong value" severity error; end if; --synthesis translate_on … end process;
Exemple n°2 assert not(DPS=32 and APS/=5) report "DPS / APS mismatch!!" severity failure; --hors process
F. Opérateurs mathématiques avancés La plupart des opérateurs mathématiques évolués (partie entière, arrondi, troncature, racine
carrée, exponentielle, logarithme, trigonométrie classique et hyperbolique, nombres complexes…) ainsi que les constantes les plus répandues (pi, log(2), log(10), e et leurs dérivées) sont disponibles dans la bibliothèque standard math_real fournie avec ModelSim. library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; --synthesis translate_off
use ieee.math_real.all; appel de la bibliothèque math_real -synthesis translate_on
La liste des fonctions et constantes contenues dans cette bibliothèque est disponible dans le fichier Modeltech\docs\technotes\ieee_math.note. Cette bibliothèque n’est pas synthétisable, d’où l’utilisation des directives de synthèse (cf. § XII.B - QuartusII).
G. Procédures Une procédure permet de regrouper des commandes séquentielles et d’en faciliter l’exécution.
Une procédure peut recevoir des paramètres (entrées) et fournir optionnellement un ou plusieurs résultats (sorties). Il est impossible d’utiliser le mode buffer pour un port d’une procédure.
Par exemple, pour écrire une donnée accompagnée d’un bit d’écriture :
procedure WriteData(data : in std_logic_vector(7 downto 0)) is
déclaration optionnelle de variables internes
begin data_in <= data ;
Jean-Louis FLOQUET Page 40 13/11/2007
Wr <= '1'; wait until rising_edge(clk); data_in <= (others=>'X'); Wr <= '0'; end procedure WriteData;
La définition de cette procédure pourra être effectuée à l’intérieur même du process concerné (entre les lignes process et begin), ou sinon dans le package pour une utilisation plus globale. L’appel de la procédure se fera tout simplement par la commande ProcedureName(arguments), ce qui donnerait dans notre exemple WriteData(x"AB") pour écrire la valeur hexadécimale "AB". Si cette procédure est appelée deux fois consécutivement, le signal Wr ne sera pas remis à 0 et data_in passera directement de la première donnée à la seconde. La mise en conflit volontaire du bus de données permet de s’assurer qu’aucune donnée ne se propage lorsque Wr est à 0. Dans le cas d’une propagation, du rouge apparaîtrait (couleur d’un signal en conflit sous ModelSim). Un paramètre d’entrée d’une procédure ne doit pas être le résultat de l’affectation d’un signal faite juste avant l’appel de cette procédure, puisque la valeur d’un signal n’est mise à jour qu’à la fin du time en cours (cf. VII.B Time et micro-time, p. 36). La nouvelle valeur ne serait donc pas transmise (ou le serait au cycle suivant dans le cas de deux appels successifs de la procédure).
H. Process Tout process « non synchrone » (séquence linéaire de commandes avec éventuellement des
temps d’attente) doit impérativement se terminer par un wait afin qu’il n’y ait pas de redémarrage du process.
En effet, chacun d’entre eux ne doit être exécuté qu’une seule et unique fois pour ne pas complexifier inutilement le testbench et la mise au point de l’entité de synthèse. Prenons le cas d’un testbench contenant plusieurs de ces process ; il deviendra très vite impossible de savoir quel process en est à quelle itération, de se le mémoriser et d’observer le comportement de tous ces process dans la fenêtre du simulateur. Cela augmente la difficulté d’écriture du testbench (pour lui faire avoir le comportement souhaité), diminue son efficacité vis-à-vis de l’entité à tester et donc accroît le nombre potentiel de bugs dans celle-ci (moins de bugs corrigés).
Jean-Louis FLOQUET Page 41 13/11/2007
VIII. Synthèse La synthèse est un terme général décrivant le processus de transformation d’un modèle
comportemental à un niveau de description plus bas et plus détaillé.
Que ce soit l’écriture d’un simple compteur ou celle d’un séquenceur complexe, il faut toujours se poser la question suivante : « comment le synthétiseur va faire pour transcrire le code VHDL en un schéma logique ? ». Il ne s’agit pas là d’y répondre avec une exactitude démesurée, mais simplement de se faire une représentation schématique (et approximative) des différents blocs logiques qui seront mis en œuvre. Par exemple,
if Cnt=13 then Cnt <= Cnt + 2; elsif Cnt=21 then Cnt <= Cnt + 3; else Cnt <= Cnt + 1; end if;
�
C
N
T
+1
+2
=13
=21
+3
L’impossibilité de répondre à cette simple question doit remettre en cause la méthode d’écriture du code VHDL.
A. Objets non synthétisables Tout ce qui fait référence à des fonctions de « très haut niveau » sont non synthétisables :
- accès à des fichiers (lecture / écriture). La bibliothèque « textio » et les quelques procédures de gestion des fichiers sont donc à proscrire formellement du RTL. Ceci dépend de surcroît du système d’exploitation de l’ordinateur réalisant la simulation.
- opérateurs mathématiques et trigonométriques avancés (division, racine carrée, sinus, cosinus, logarithme, …). Ces opérateurs peuvent néanmoins être réalisés grâce à des modules plus ou moins complexes, mais en aucun cas à l’aide du seul opérateur correspondant.
- allocation dynamique de la mémoire de l’ordinateur réalisant la simulation. Cette allocation peut se faire au moyen d’un record couplé à un type access ou bien au moyen d’une liste chaînée.
B. Paramètres « generic » Les « generic » ne sont pas réellement synthétisés en tant que tels puisqu’ils ne sont en aucun
cas dynamiques : tous les « generic » doivent avoir une valeur déterminée avant la synthèse logique. Ces valeurs ne sont plus accessibles dans le design résultant, comme le serait par exemple la valeur d’un compteur.
Les « generic » peuvent être de type integer ou string, ou plus rarement de type std_logic, (ou std_logic_vector)… Les autres types statiques devront faire l’objet d’une justification valable avant leur utilisation.
Jean-Louis FLOQUET Page 42 13/11/2007
C. Entrées / Sorties d’un module Un module dispose d’une section « port » pour communiquer avec son environnement. Cette
section peut contenir un nombre quelconque de signaux. Chaque signal doit être typé selon l’un des quatre cas suivants :
- in - out - inout - buffer
1. Type « in » Ce signal est une entrée et peut être lu par ce module (et tous ses sous-modules). Il ne peut
pas être piloté sous peine de créer un conflit.
2. Type « out » Ce signal est une sortie et peut être lu par tous les modules hiérarchiquement supérieurs au
module considéré. Il ne peut pas être relu par le module qui le pilote.
3. Type « inout »
qa
outputenable
qb
outputenable
da db
Composant A Composant B
Figure 7 : Principe d'une ligne tri-state
Ce signal définit un bus tri-state (état bas, état haut, haute impédance) et doit impérativement correspondre à une broche (ou groupe de broches) physique(s) du composant. La valeur lue de ce signal n’est pas la valeur fournie qa par le système (lorsque celui-ci vient piloter la ligne trois états) mais la valeur telle qu’elle est visible sur le signal physique externe; la valeur lue peut donc différer à cause d’un conflit sur la ligne. De plus, les performances sont dégradées à cause du temps de traversée du buffer de ligne.
De façon générale, il n’est pas souhaitable de lire un tel signal lorsqu’il est activement géré mais seulement lorsqu’il est placé en haute impédance par le système et activement piloté par un autre composant présent sur cette ligne trois états.
q
outputenable
q
outputenable
d d
Composant A Composant B
Figure 8 : Ligne tri-state pilotée par A
q
output
enable
q
output
enable
d d
Composant A Composant B
Figure 9 : Ligne tri-state pilotée par B
Jean-Louis FLOQUET Page 43 13/11/2007
4. Type « buffer » Ce signal est une sortie pouvant être relue en interne, mais il type engendre des aberrations en
synthèse et est donc totalement prohibé, sauf pour la simulation bien évidemment. Pour relire un signal sortant, il suffit simplement de définir un signal interne supplémentaire,
de le gérer comme s’il s’agissait de la sortie (et il est donc possible de le relire), et enfin de piloter le signal sortant par ce nouveau signal interne. Prenons l’exemple d’un compteur : entity test is port
( rst : in std_logic ; clk : in std_logic ; cnt : out std_logic_vector(3 downto 0) ); end entity test; architecture rtl of test is signal cnt_i : std_logic_vector(3 downto 0); -- Valeur interne du compteur begin process(rst,clk) begin if rst='1' then cnt_i <= (others=>'0'); elsif rising_edge(clk) then cnt_i <= cnt_i + 1; end if; end process; cnt <= cnt_i; -- Pilote la sortie grâce à la valeur interne end architecture rtl;
D. Les boucles 1. if…then…else
Chaque branche de ce type de boucle requiert une entrée sur un multiplexeur qui sera situé entre les différents termes des équations logiques et l’entrée de la bascule D. Ainsi, une boucle if…then…elsif…else…end if génèrera un multiplexeur 3 vers 1.
Le cas par défaut (branche else), qu’il soit explicitement codé en VHDL ou non, existe toujours : s’il est non codé, il sera implémenté avec un enable ou un register feedback. Bien que la norme VHDL n’impose aucune limitation quant au nombre de branche d’une telle boucle, on se limitera à seulement 4 branches.
2. case…when La gestion d’un ou plusieurs signaux par boucle case…when doit respecter les mêmes règles
que celles énoncées pour la boucle if…then…else. Cette fois-ci, les limitations d’utilisation sont : - le nombre de conditions d’entrée (activation de l’état) - le nombre de conditions de sortie (désactivation de l’état)
Dans l’exemple suivant, l’état C possède 4 entrées et 4 sorties et sera l’état ayant les moins
bonnes performances après la synthèse (si l’on considère que tous les tests de passage d’un état à l’autre sont équivalents au niveau complexité).
Jean-Louis FLOQUET Page 44 13/11/2007
A
B
C
D
E
GF
H
IJ
Figure 10 : Séquenceur typique
Étant donné que toutes les combinaisons possibles doivent être listées dans le case, et que la simulation et la synthèse ne comptent pas le même nombre d’états pour chaque bit (9 en simulation, 2 en synthèse), il est impératif d’utiliser une écriture compatible avec les deux modes. La méthode la plus simple est d’utiliser une directive VHDL (cf. XI.A Translate On/Off p. 68, pour plus de détails) encapsulant les cas purement liés à la simulation : case A is
when "00" => instructions #0
when "01" => instructions #1
when "10" => instructions #2
when "11" => instructions #3
--synthesis translate_off when others => report "message d'erreur" severity warning; --synthesis translate_on end case;
De cette façon, les deux outils ont toutes les informations dont ils ont besoin. De plus, si un cas non prévu pour la synthèse survient en simulation, l’utilisateur en serait immédiatement informé et pourrait agir en conséquence.
3. for…in…to…loop Une utilisation itérative dégrade (par définition même) les performances et est donc à éviter, bien qu’indispensable dans certain cas. Le principal exemple où la boucle itérative est nécessaire est celui de la conversion d’un code de Gray vers un code binaire : bin(gray'high) := gray(gray'high); for i in gray'high-1 downto gray'low loop bin(i) := bin(i+1) xor gray(i); end loop;
Figure 11 : Boucle « for » non itérative
Figure 12 : Boucle « for » itérative
4. while…loop Cette boucle est strictement interdite en synthèse car l’itération engendrée par cette écriture
ne permet pas de maîtriser l’implémentation physique qui en sera faite.
Jean-Louis FLOQUET Page 45 13/11/2007
5. Generate Cette boucle faisant que générer automatiquement du code (et non pas une itération sur telle
ou telle condition), elle peut être utilisée sans aucune restriction.
E. Les process 1. Liste de sensibilité
La sortie d’une bascule D ne peut être modifiée que par l’une des conditions suivantes : - reset asynchrone (cf. Figure 13, chemin vert CLRN) - load asynchrone (cf. Figure 13, chemin vert PRN) - front de l’horloge (cf. Figure 13, chemin rouge) - clock enable (cf. Figure 13, chemin bleu)
L’entrée PRN n’est utilisée que dans de rares cas où la maîtrise complète au niveau système
(c’est-à-dire au niveau de l’ensemble du design) permet de faire une telle opération. L’entrée ENA (« clock enable ») est elle aussi peu utilisée, car le synthétiseur analyse
généralement correctement le signal répondant à sa fonctionnalité. Lorsque cette entrée est inactive, la sortie de la bascule se comporte exactement comme si l’horloge qui lui est appliquée ne subissait aucune transition. Les entrées synchrones sont alors purement et simplement ignorées. Ce signal n’est en fait déclarer que dans des cas très précis d’optimisation.
L’architecture physique du composant impose donc l’écriture suivante pour un process : process(rst,clk) begin if rst='1' then q <= '0'; elsif rising_edge(clk) then q <= d; end if; end process;
On ne pourra donc pas ajouter de signaux (données et/ou contrôle) autre que ceux énoncés ci-dessus. Concernant l’horloge, il s’agit d’une véritable horloge issue d’un oscillateur externe ou d’une PLL interne, et non pas de la sortie d’une autre bascule. Ceci reviendrait à changer de domaine d’horloge et requerrait des mécanismes spécifiques (cf. § IX. H Changement de domaine d’horloge, p. 56). Une même bascule ne peut pas travailler sur les deux fronts de l’horloge !
Jean-Louis FLOQUET Page 46 13/11/2007
Figure 13 : Entrées « sensibles » d'une bascule (Stratix, Altera)
Un process ayant une liste de sensibilité prédéterminée, il est donc totalement inutile de faire plusieurs process ayant exactement la même liste de sensibilité (il faut les regrouper en un seul). Seuls les process nécessitant une liste de sensibilité différente peuvent être écrits séparément.
2. Traitements Les performances d’un système sont directement liées à la quantité de logique combinatoire
située entre deux couches de registres. Cette logique combinatoire (LUT, Carry & Cascade représentés en orange sur la Figure 13) induit un temps de propagation supplémentaire limitant la fréquence maximale d’utilisation du composant. Plus il y a de logique combinatoire entre deux registres et moins le composant pourra fonctionner rapidement. Il faut donc impérativement effectuer de petites opérations logiques dont le résultat sera placé dans un registre avant d’utiliser à nouveau ce résultat pour une autre opération.
Performances élevées Performances moyennes/faibles A+B
A+B+1 (utilisation de la carry) A+B+C
BmA <= B – A; -- MSB=1 si BmA<0 � A>B if BmA(BmA'high)='1' then C <= D; else C <= E; end if;
if A>B then C <= D; else C <= E; end if;
if A(A'high)='1' then A <= cst – 2; else A <= A – 1; end if; if A(A'high)='1' then B <= C; end if;
if A=cst then A <= (others=>'0'); B <= C; else A <= A + 1; end if;
Jean-Louis FLOQUET Page 47 13/11/2007
Des contraintes énoncées ci-dessus découle l’interdiction des variables. En effet, une variable est mise à jour immédiatement et sera donc implémentée par le synthétiseur comme de la logique combinatoire (sans registre derrière). De même, l’horloge ne pourra jamais :
• être utilisée en tant que donnée entrant dans une équation logique (ceci reviendrait à faire entrer l’horloge dans la LUT)
• être affectée à un autre signal, même si ce nouveau signal est utilisé comme une véritable horloge. Ceci engendrerait des problèmes de simulation liés aux times et micro-times (cf. VHDL – Simulation, section Time et micro-time)
3. Remarque Il serait tentant de créer des process représentant un bloc de logique combinatoire pure (sans
registre) avec une liste de sensibilité autre que celle énoncée au paragraphe précédent. Ceci est à proscrire pour les raisons suivantes :
• réserver la structure de process aux évènements synchrones (pour la synthèse) • la liste de sensibilité doit être parfaitement décrite sous peine d’instancier des latches
et donc d’avoir potentiellement des problèmes physiques dans le composant (un latch est, fonctionnellement, équivalent à un registre mais implémenté en pure logique combinatoire)
Avec process (et risques) Sans process
process(sel,a,b,c,d) begin case sel is when "00" => mux <= a; when "01" => mux <= b; when "10" => mux <= c; when "11" => mux <= d; --synthesis translate_off when others => null; --synthesis translate_on end case; end process;
mux <= a when sel="00" else b when sel="01" else c when sel="10" else d;
La méthode sans process est plus simple et sans risque. La première méthode (avec process) sera donc interdite.
Jean-Louis FLOQUET Page 48 13/11/2007
IX. Méthodologie A. Reset
1. Généralités Bien que l’on puisse mettre n’importe quelle valeur dans la partie reset d’un process, il est
fortement conseillé de placer tous les bits à 0. Quelques signaux très spécifiques peuvent être mis à 1 dans le reset, mais à condition que cette contrainte soit liée au fait que ces signaux soient directement connectés à des composants externes nécessitant un état haut à la mise sous tension (ChipSelect*, OutputEnable*…).
En revanche, il est hors de question d’initialiser un bus interne (par exemple un compteur) avec une valeur non nulle. Un type énuméré doit être initialisé à la valeur du premier état de la liste de description qui en a été faite. En cas de besoin, il suffit simplement de changer l’ordre de cette liste de description. * : ces signaux sont généralement actifs à l’état bas.
2. Reset asynchrone Bien que ce type de reset soit le plus fréquemment rencontré, il faut garantir que le
relâchement du reset soit vu au même cycle d’horloge pour toutes les bascules (afin qu’elles « démarrent » toutes en même temps).
Pour cela, il faut resynchroniser le relâchement du reset avec une bascule D. Toutefois, il ne faut généralement pas modifier la prise en compte du reset qui doit rester asynchrone. process(rst_externe,clk)
if rst_externe='1' then
rst_interne <= '1';
elsif rising_edge(clk) then
rst_interne <= '0';
end if;
end process;
B. Boucle combinatoire Le terme boucle employé ici n’a aucun rapport avec les boucles de test. Il s’agit d’un
rebouclage de la sortie d’une porte logique vers une partie située en amont et qui intervient dans la valeur de cette sortie.
Figure 14 : Boucle combinatoire
Un tel phénomène est à éviter absolument car les portes logiques impliquées peuvent entrer dans un mode oscillatoire totalement imprédictible (temps de routage, température du composant, qualité des sources d’alimentations…).
Jean-Louis FLOQUET Page 49 13/11/2007
L’utilisation des variables en VHDL synthétisable est l’une des causes des boucles combinatoires, d’où leur interdiction en synthèse. Ce n’est pas le fait même que l’objet soit une variable, mais l’utilisation qui peut en être faite lorsque de nombreux objets sont de ce type. L’outil de synthèse Quartus signale ce problème afin d’attirer l’attention mais ne le résout en aucun cas.
C. Lignes à retard Une ligne à retard est une succession de registres dont le seul but est de délayer un signal dans
le temps (cycles d’horloge). Le transfert de registre à registre ne comporte aucune couche logique, quelle qu’elle soit. Les lignes à retard ont un rôle important dans la gestion de tout pipeline afin de suivre les différentes étapes de calcul (cf. IX.J Structure pipeline, p. 60)
4 3 2 1 05n
clk Figure 15 : Ligne à retard
Pour implémenter des lignes à retard, l’écriture suivante est conseillée : signal MySignal_s : std_logic_vector(N downto 0); … MySignal _s <= MySignal _s(MySignal _s'high-1 downto 0) & MySignal;
D. Ligne trois états De nombreux FPGA ont un tOUTCO (tCO en sortie du composant) inférieur au tXZ (temps de
passage d’un état actif à la haute impédance). Il est résulte que l’intervalle de temps compris entre ces deux paramètres va avoir un véritable rôle sur la carte. Une ligne trois états se pilote généralement de la façon suivante : a <= a_o when a_oe='1' else 'Z'; -- a_o et a_oe : std_logic
D0 D1
TOUTCO
TXZ Figure 16 : Relâchement d'un signal
Bien que le signal soit relâché pour passer en haute impédance, la nouvelle donnée apparaît un bref instant. Ceci peut être mis à profit si le signal sur la carte est tiré au Vcc ou à la masse via une résistance (pull-up ou pull-down). Dans une telle situation, le relâchement de la ligne doit s’accompagner de l’affectation du signal sortant à la valeur de repos (celle de tirage de la résistance) afin de faciliter le retour à l’état inactif de la ligne.
Jean-Louis FLOQUET Page 50 13/11/2007
Exemple process(clk) if rising_edge(clk) then if Lfsr_oe(2)='1' then a_o <= Lfsr_oe(3); a_oe <= '1'; else a_o <= '1'; a_oe <= '0'; end if; if Lfsr_oe(2)='1' then b_o <= Lfsr_oe(3); b_oe <= '1'; else b_oe <= '0'; end if; end if; end process; a <= a_o when a_oe='1' else 'Z'; b <= b_o when b_oe='1' else 'Z';
Dans cet exemple, les signaux a et b sont tirés au Vcc. La ligne de a aura de meilleures performances que celle de b, à cause d’un temps de remontée du front plus court.
Figure 17 : Exemple de relâchements, sur Flex10K
E. Opérateurs 1. Optimisation des compteurs
Lorsqu’un compteur binaire doit compter modulo 2n, aucun test logique n’est nécessaire pour le réinitialiser puisqu’il le fera de lui-même via le dépassement de capacité. Mais si l’on doit compter sur un modulo différent de 2n, il faut générer une condition telle que le compteur soit réinitialisé en temps voulu.
Considérons l’exemple d’un compteur devant générer une impulsion tous les N cycles (N étant statique, ou presque). Ici, seul l’intervalle de temps entre deux impulsions nous intéresse ; l’ordre des différentes valeurs prises par le compteur est sans importance. L’écriture « naturelle » est la suivante :
if Cnt=N-1 then Cnt <= (others=>'0'); else Cnt <= Cnt + 1; end if;
Cette écriture est équivalente à l’architecture représentée ci-dessous (Figure 18). Le chemin critique d’une telle structure passe par le comparateur (avec N-1) et le multiplexeur.
c
n
t
?
0
1
Figure 18 : Compteur
Si l’on cherche à améliorer cette architecture, il paraît évident que la fonction addition est
difficilement optimisable ; par contre, nous pouvons chercher à modifier la condition de test (le comparateur). Considérons maintenant les modifications suivantes :
- ajout d’un bit au compteur en tant que MSB - chargement de la valeur N-2 (son MSB est alors nul) - décrémentation
Le décompteur va alors prendre les valeurs (N-2), (N-1), …, 2, 1, 0, -1. Or cette dernière valeur correspond à la mise à 1 du MSB (ainsi que de tous les autres bits) et servira de condition
Jean-Louis FLOQUET Page 51 13/11/2007
de redémarrage du décompteur. Ainsi, il y aura bien eu N cycles : (N-2) cycles pour les valeurs de (N-2) à 1, plus 2 autres pour « 0 » et « -1 ».
if Cnt(Cnt'high)='1' then Cnt <= ('0' & N) – 2; else Cnt <= Cnt – 1; end if;
Une telle écriture évite d’instancier un comparateur et optimise au maximum la fréquence de fonctionnement (le compteur est directement rebouclé sur lui-même sans aucune couche de logique combinatoire supplémentaire). Quant au nombre de Logic Cells utilisées, il reste sensiblement équivalent : le gain du comparateur est compensé par l’ajout d’un soustracteur.
2. Additionneurs & soustracteurs Il faut distinguer les deux cas suivants :
1) tous les std_logic_vector de l’entité sont de type non signé 2) l’entité contient à la fois des std_logic_vector signés et non signés
1er cas
On utilise les bibliothèques suivantes : • ieee.std_logic_arith.all • ieee.std_logic_unsigned.all
L’écriture sera alors : • a <= b + c pour une addition • a <= b – c pour une soustraction
Toute tentative d’utilisation du type signé pourra aboutir à une erreur d’interprétation du synthétiseur, qui compilera quand même le code. Donc, à utiliser en toute connaissance de cause. À noter que ces deux bibliothèques ne font pas partie des bibliothèques standard du VHDL : ce sont des bibliothèques « fondeur » (fournies par Synopsis). Leur utilisation avec l’immense majorité des logiciels ne pose aucun problème, mais si certaines sociétés en interdisent l’utilisation. 2ème cas
On utilise la bibliothèque suivante : • ieee.numeric_std.all
L’écriture sera alors • a <= std_logic_vector(unsigned(b) + signed(c)), par exemple, pour une addition • a <= std_logic_vector(signed(b) – integer), par exemple, pour une soustraction
Cette seconde méthode est plus « sûre » dans le sens où l’on peut utiliser librement les deux types (signé et non signé), mais alourdi l’écriture.
3. Comparateurs binaires a. Égalité
Ce comparateur est de loin le plus utilisé. Son utilisation ne requiert presque aucune précaution. Le seul problème rencontré avec ce type de comparateur est qu’il est la plupart du temps implémenté sans la Carry Chain disponible dans les éléments logiques (LCells), mais sous la forme minimisant le nombre de LCells utilisées.
Jean-Louis FLOQUET Page 52 13/11/2007
=
=
=
=
&
A0
B0
A1
B1
A2
B2
A3
B3
A4
B4
A5
B5
A6
B6
A7
B7 Figure 19 : Comparateur « Standard » 2 x 8bits
=A0
B0
=
=
=
=
=
=
=
A1
B1
A2
B2
A3
B3
A4
B4
A5
B5
A6
B6
A7
B7 Figure 20 : Compteur optimisé 2 x 8bits
La version optimisée utilise certes plus de LCells, mais est aussi déjà environ de 15 à 20% plus rapide pour un comparateur de 8bits. Plus le comparateur est grand et plus la différence sera importante (la version standard peut nécessiter plus de 2 couches logiques).
b. Autres comparateurs De la même façon que le comparateur d’égalité peut être implémenté « en vrac » (cf.
Figure 19 : Comparateur « Standard » 2 x 8bits), les comparateurs de supériorité et d’infériorité peuvent subir le même sort. Une façon très simple d’empêcher cela est de les remplacer par une soustraction et de regarder le signe du résultat. En effet, il est excessivement rare qu’un soustracteur soit implémenté sans Carry Chain. Le signe du résultat est indiqué par son MSB. Une comparaison au sens large équivaut à un résultat positif ou nul (MSB=0) tandis qu’une comparaison au sens stricte équivaut à un résultat strictement négatif (MSB=1) :
• ( ) '0'0 =−⇔≥−⇔≤ ABMSBABBA
• ( ) '1'0 =−⇔<−⇔< BAMSBBABA Remarque
Dans de très nombreux cas, la comparaison porte entre un compteur et une constante. Prenons l’exemple d’un comparateur indiquant que le compteur est compris entre deux valeurs MIN et MAX. Bien que les deux écritures suivantes soient possibles, la seconde sera toujours privilégiée :
if Cnt>VAL0 and Cnt<VAL1 then result <= '1'; else result <= '0'; end if; 1ère écriture if Cnt=VAL0 then result <= '1'; elsif Cnt=VAL1-1 then result <= '0'; end if; 2ème écriture Si les valeurs ne sont pas des constantes mais des signaux (donc dynamiques) et que l’on se situe dans une architecture de type pipeline, le résultat sera simplement retardé d’un cycle d’horloge (ce qui ajoute un cycle de latence). if Cnt=Val0 then result <= '1'; elsif Cnt=Val1 then result <= '0'; end if; signaux / pipeline
F. Multiplexeur La fonction de multiplexage, lorsqu’elle est exprimée explicitement, peut être codée de
plusieurs façons : 1er cas, en mode concurrent res <= a when test1 else b when test2 else c;
Jean-Louis FLOQUET Page 53 13/11/2007
2nd cas, dans un process if test1 then res <= a; elsif test2 then res <= b; else res <= c; end if;
3ème cas, en mode concurrent ou dans un process res <= (a and test1) or (b and test2) or (c and test3);
Cette écriture est valable si et seulement si test1 et test2 et test3 sont mutuellement exclusifs. 4ème cas, dans un process case test is when 1 => res <= a when 2 => res <= b end case
5ème cas, mode concurrent with test select res <= a when 1, b when 2 | 3, c when others;
Il est à noter que les deux premières écritures établissent un multiplexage par priorité. Dans cet exemple, le test logique test1 est prioritaire sur le test logique test2, et ce, quel que soit le résultat de ce dernier. Voir aussi le § X.A - Associations de plusieurs blocs mémoire (page 65) pour une autre technique de multiplexage mettant en œuvre des blocs mémoire.
G. Lecture d’une mémoire Dans un FPGA, une mémoire interne ne fournit la donnée correspondant à l’adresse de
lecture que deux cycles plus tard.
Jean-Louis FLOQUET Page 54 13/11/2007
Figure 21 : Latence de lecture d'un bloc mémoire (Stratix, Altera)
Une méthode pouvant venir à l’idée serait d’initialiser un compteur en même tant que l’opération de lecture et de faire incrémenter celui-ci jusqu’à ce qu’il obtienne une valeur égale à la latence de la mémoire, ce qui validerait la lecture de la donnée. On aurait un fonctionnement comme ci-dessous :
Cycle 0
Demande de lecture
Cnt = 0 Cnt = 1 Cnt = 2
Validation de lecture
Cette solution souffre d’un défaut majeur : on ne peut débuter une nouvelle lecture tant que la donnée précédente n’est pas sortie. Or ceci est totalement incompatible avec une architecture de type « pipeline » pour laquelle ces blocs mémoires sont conçus. Il faut donc utiliser une autre
Jean-Louis FLOQUET Page 55 13/11/2007
méthode : les lignes à retard. Il s’agit tout simplement d’une succession de registres sans aucune logique combinatoire entre deux registres consécutifs : Read_r <= Read; Read_rr <= Read_r;
L’emploi d’un registre à décalage (ou ligne à retard, cf. IX.C Lignes à retard, p. 50) permet d’accéder directement à un niveau précis avec un indice (entier naturel) qu’il sera ensuite très facile d’adapter en fonction du retard voulu.
0 1 2 3
0 1 2 3
0 1 2 3
Clk
Read
RdAddr
RdData
Read_r
Read_rr
RdData_x Figure 22 : Résolution de la latence de lecture d'une mémoire
Dans la Figure 22, la donnée RdData est validée par le signal Read_rr.
H. Changement de domaine d’horloge Les mécanismes de changement de domaine d’horloge sont un aspect essentiel dans tout
design où de nombreuses fréquences peuvent être mises en jeux et interagir.
A B
Horloge 1 Horloge 2
Figure 23 : Passage d’un domaine d’horloge à un autre
En simulation, toutes les bascules commutent instantanément et peuvent lire n’importe quelle donnée sans contrainte. En fait, les bascules réelles possèdent un tco et un tsu. Ces deux paramètres diffèrent pour chaque bascule et ne sont donc pas parfaitement prévisible lors du codage.
L’impossibilité de changer trivialement de domaine d’horloge vient donc du fait qu’un front actif de l’horloge 2 peut se produire de telle façon que le tco et le tsu ne soient pas respectés :
Jean-Louis FLOQUET Page 56 13/11/2007
A1Qidéal A2 A3 A4 A5 A6 A7 A8 A9
Qréel A1 A2 A3 A4 A5 A6 A7 A8 A9
A1 A2 A3 A4 A5 A6 A7 A8 A9Didéal
A1 A2 A3 A4 A5 A6 A7 A8 A9Dréel
Horloge 1
Horloge 2
A1 A2 A3 A4 A5 A6 A7 A8
Figure 24 : Changement de domaine d'horloge
Si l’on souhaite, sur le domaine d’horloge 2, lire une donnée A provenant du domaine
d’horloge 1, plusieurs cas sont à préciser : - paramètre quasi-statique - valeur mise à jour de temps en temps - flux de données
1. Paramètre quasi-statique La donnée A est stable depuis très longtemps. Le tco et le tsu des bascules sont alors largement
dépassés. Aucune précaution n’est à prendre et la donnée A peut être lue comme si elle appartenait au domaine d’horloge 2.
Exemples :
- longueur d’une ligne vidéo - seuil de déclenchement
2. Valeur mise à jour de temps en temps La donnée DA est modifiée de temps en temps. Il suffit pour le domaine d’horloge 1 de faire
commuter un bit de contrôle (un toggle) à chaque fois que cette donnée DA est mise à jour. Le domaine d’horloge 2 va alors registrer deux fois ce signal et détecter une transition (avec un xor) sur ces deux registres qui sont désormais sur son propre domaine. La durée de détection est donc égale au temps de stabilisation du toggle plus un cycle complet d’horloge, ce qui permet à la donnée DA d’être stable et parfaitement lisible par le domaine d’horloge 2.
Le problème est certes résolu pour la donnée, mais on pourrait penser qu’il est reporté sur la détection du toggle. En fait, ce problème existe réellement mais nous importe peu. Prenons l’exemple d’un toggle passant de 1 à 0. Seule la première bascule servant à la détection est concernée (puisque la seconde lit la sortie de la première). Il y a alors trois cas possibles :
- les timings (tco et tsu) sont respectés, auquel cas le changement de domaine d’horloge s’est déroulé correctement
- les timings ne sont pas respectés mais la bascule prend quand même la valeur 0. Le changement de domaine d’horloge se produit comme si les timings avaient été respectés.
- les timings ne sont pas respectés et la bascule reste à la valeur 1. Par contre, elle prendra effectivement la valeur 0 au prochain cycle d’horloge. Le changement de
Jean-Louis FLOQUET Page 57 13/11/2007
domaine d’horloge s’est encore déroulé correctement, mais en ayant pris un cycle de plus.
Toggle A
BD CEBusy
Figure 25 : Schéma logique du « toggle »
1 2 3 4 5 6 7 8
Clk1
Toggle
D
E
Clk2
A
B
C Figure 26 : Changement de domaine d’horloge (lent vers rapide)
1 2 3 4 5 6 7 8
Clk1
Toggle
D
E
Clk2
A
B
C Figure 27 : Changement de domaine d’horloge (rapide vers lent)
Considérons maintenant la Figure 26 et la Figure 27 (les cycles numérotés sont identiques
fonctionnellement) : - L’impulsion sur C correspond à la réception d’une donnée par le domaine d’horloge 2.
Cette impulsion dure toujours un cycle - L’impulsion sur E correspond au temps global de transfert de la donnée. Sa durée est
variable. - Cycle 1 : le signal toggle commute sur le front de l’horloge Clk1 - Cycle 2 : sur l’horloge Clk2, A prend la valeur de toggle - Cycle 3 : A est recopié dans B au prochain front de Clk2 - Cycle 4 : sur l’horloge Clk1, D prend la valeur de B. Le transfert a été effectué. - Cycle 5 : identique au cycle 1 - Cycle 6 : identique au cycle 2 - Cycle 7 : identique au cycle 3 - Cycle 8 : identique au cycle 4
Jean-Louis FLOQUET Page 58 13/11/2007
3. Flux de données La méthode du toggle ne peut plus être utilisée ici, puisque la donnée change à chaque cycle.
Etant donné que la valeur d’un bus de données ne peut-être connue à l’avance, il faut transformer ce flux de telle sorte qu’il puisse subir un changement de domaine d’horloge sans être dénaturé. Le seul flux de données pouvant subir ce type d’opération est basé sur un compteur utilisant le « code de Gray ». Ce code a été établi pour que le compteur, lorsqu’il s’incrémente ou se décrémente, n’ait qu’un seul bit qui commute à chaque fois. Ainsi, on retrouve exactement le principe du toggle.
Valeur décimale 0 1 2 3 4 5 6 7 8 Code Binaire Naturel 0000 0001 0010 0011 0100 0101 0110 0111 1000 Code de Gray 0000 0001 0011 0010 0110 0111 0101 0100 1100
Il suffit donc de créer un mécanisme d’adressage linéaire des données et de traverser une
mémoire. Les données sont écrites en mémoire avec l’horloge 1 et relues avec l’horloge 2. Le changement de domaine d’horloge pour le flux de données est donc géré en totalité par la mémoire. C’est pour cela que les FIFO existent notamment. Il ne reste plus qu’à gérer les pointeurs mémoires et renvoyer quelques flags.
Chaque pointeur mémoire doit être décrit dans deux codes différents : - code binaire naturel, directement connecté à la mémoire - code de gray ayant la valeur équivalente du CBN, et permettant de la transmettre à
l’autre domaine d’horloge Il suffit simplement de garantir que la base passante (moyenne) en lecture soit plus grande que celle d’écriture (moyenne) de façon à ce que la FIFO ne se remplisse pas complètement. Se reporter à la section IX.I Buffer pour la partie relative à la gestion de la mémoire.
I. Buffer Il est très fréquent de faire appel à de petites mémoires tampon dans un système de flux de
données. Ces mémoires permettent de segmenter les différents traitements afin de faciliter la mise au point mais aussi d’utiliser différents domaines d’horloge pour chaque zone de calcul.
B
u
f
f
e
r
flux entrant
B
u
f
f
e
rpipeline
B
u
f
f
e
rpipeline
B
u
f
f
e
rpipeline
flux sortant
Figure 28 : Usage des buffers
Un buffer peut avoir deux positions distinctes :
- interface entre un module maîtrisé (le sien) et un module extérieur non maîtrisé - interface entre deux modules maîtrisés
Dans le premier cas, le manque de maîtrise de la latence (temps de réaction) du système
oblige quasi-systématiquement l’emploi d’une FIFO dite « show-ahead » où les signaux d’informations doivent avoir une latence réduite au strict minimum (niveau du buffer, plein / vide…). Ce gain de « rapidité » se traduit par un surcoût en ressources physiques (Logic Cells).
Jean-Louis FLOQUET Page 59 13/11/2007
Dans le second cas, le système est parfaitement maîtrisé par le concepteur et l’emploi d’une FIFO show-ahead est alors superflu. On utilise une simple mémoire avec une logique de contrôle réduite à sa plus simple expression :
- un compteur pour l’adresse d’écriture - un compteur pour l’adresse de lecture - un soustracteur pour le nombre de mots
Se reporter à la section IX.H.3 Flux de données pour le changement de domaine d’horloge
d’un flux de données.
WrAddr RdAddr
MémoireWrData RdData
-
UsedW Figure 29 : Buffer 1 horloge
WrAddr RdAddr
MémoireWrData RdData
- RdAddrUsedW RdAddr
Gray
WrAddr
GrayWrAddr -
UsedW
Figure 30 : Buffer 2 horloges
Que le buffer soit sur un seul domaine d’horloge ou deux, il n’y a aucun module de contrôle en plus des deux pointeurs mémoire. Ceci fait apparaître quelques contraintes qui seront très facilement contournées puisque ce buffer a pour vocation d’être dans une architecture « pipeline » et que tous les retards induits pourront être inclus dans le contrôle du pipeline :
- une donnée ne sortira que deux cycles après sa demande (un pour le registre Rd, un autre pour le registre de sortie de la mémoire)
- le nombre de mots sera en « retard » d’un cycle ou deux - la lecture d’un buffer vide ou l’écriture dans un buffer plein provoquera un
« overflow » du nombre de mots et la plupart du temps une corruption totale des données contenues (cf. IX.K.3 Remarques, p. 63)
La latence de lecture est un phénomène extrêmement facile à gérer, tandis que les
« overflow » peuvent être contournés par le fait de considérer le buffer comme étant plein dès qu’il dépasse une certaine valeur (inférieure de quelques unités à sa contenance) ou vide s’il contient trop peu de données. Se reporter au § IX.J
J. Structure pipeline Une architecture de type « pipeline » est très souvent employée car elle permet d’utiliser au
mieux les ressources d’un FPGA (qui d’ailleurs est l’un de ses atouts majeurs avec la parallélisation des calculs).
Considérons la fonction suivante : - si A+14>B, alors C=A+14 - sinon C=B
Elle pourrait s’écrire de façon très simple (cf. Figure 31), mais si l’on considère
l’implémentation physique de ceci, on aura un additionneur suivi d’un comparateur, lui-même suivi d’un multiplexeur pour enfin arriver dans le registre. Ces trois couches de logique combinatoires sont très pénalisantes en termes de performance. Dans un tel cas, il est largement préférable de scinder cette fonction en plusieurs parties de telle sorte qu’il n’y ait qu’une seule
Jean-Louis FLOQUET Page 60 13/11/2007
couche de logique combinatoire entre deux registres (cf. Figure 32). Le temps de propagation est alors approximativement divisé par trois, donc la fréquence multipliée par trois. Ce gain de performance est primordial si l’on souhaite traiter un flux ininterrompu de données. Le seul « inconvénient » est la latence engendrée (trois cycles au lieu d’un seul), qui, dans le cas du traitement d’un flux de données, est absolument négligeable comparativement aux performances obtenues.
a
b
>
14
c
Figure 31 : Architecture Simple
a
b
a1
b1
a2
b2
> gt14
c
Figure 32 : Architecture pipeline
if (a+14)>b then c <= a+14; else c <= b ; end if;
a1 <= a + 14; b1 <= b; if a1>b1 then gt <= '1'; else gt <= '0'; end if; a2 <= a1; b2 <= b1; if gt='1' then c <= a2; else c <= b2; end if;
Application La première solution fonctionne à environ 164MHz dans un Stratix 1S10C5 tandis que la seconde fonctionne à 410MHz dans le même composant, ce qui est bien conforme à ce qui était attendu…
K. Prédiction / Auto maintient Pour traiter un flux de données, il existe deux méthodes opposées :
- la première consiste à observer certains paramètres liés à ce flux et à déterminer a posteriori l’action à entreprendre
- la seconde consiste à observer des paramètres déduits (calculés) à partir de ce flux et de décider a priori de l’action à entreprendre
Ces deux méthodes ont leurs propres avantages et inconvénients.
1. Action a posteriori (auto maintient) Prenons l’exemple d’un traitement du flux se produisant entre deux zones mémoires (des
buffers). La zone de traitement des données (entre les deux zones mémoires) est appelée un pipeline.
Le calcul pourra s’effectuer si le buffer d’entrée contient suffisamment de données et que le buffer de sortie possède suffisamment de places libres pour stocker les données issues du traitement. Ces deux conditions ont un rôle identique (au niveau priorité).
Jean-Louis FLOQUET Page 61 13/11/2007
Buffer
In
Buffer
Out………
N cycles
Figure 33 : Traitement de données entre deux mémoires (a posteriori)
Malheureusement, cette solution souffre d’un problème de latence : • Si le buffer d’entrée contient trop peu de données (inférieur à un seuil prédéterminé), il
faut arrêter d’en prendre. La latence est alors égale au nombre de cycles nécessaires à effectuer la détection (généralement 2-3 cycles).
• Si le buffer de sortie a un niveau trop élevé (supérieur à un seuil prédéterminé), il faut arrêter d’y placer de nouvelles données et donc arrêter d’en prendre du buffer d’entrée. Mais les données en cours de traitement dans le pipeline ne doivent en aucun cas y rester bloquées (une donnée ne pourrait alors sortir que si N données sont présentes après, ce qui est évidemment inacceptable). La latence est alors égale au nombre de cycles nécessaires à effectuer la détection (2-3 cycles) plus le nombre de cycles N correspondant à la profondeur du pipeline !!
Si le flux a un débit constant (flux audio par exemple) et que les profondeurs des mémoires et
les seuils sont correctement adaptés, cette méthode peut être très efficace. Par contre, il va falloir tenir compte du cas où le débit s’arrête pendant de nombreux cycles (flux vidéo par exemple). En effet, le buffer d’entrée va alors contenir un petit nombre de données (inférieur au seuil fixé) et il faudra mettre en place un mécanisme permettant de récupérer ces données…
Avantages Inconvénients facilité de mise en œuvre 1) latence directement proportionnelle à la
profondeur du pipeline 2) extraction des dernières données
2. Action a priori (prédiction) Reprenons l’exemple précédent. Cette fois-ci, au lieu de « subir » l’évolution des niveaux de
remplissage des deux zones mémoire, on anticipe la quantité de données que l’on peut traiter.
Buffer
In
Buffer
Out………
N cycles
Nin
Nout
Figure 34 : Traitement de données entre deux mémoires (a priori)
Soient Nin et Nout (respectivement) le nombre de données disponibles en entrée et le nombre places disponibles en sortie. Le nombre de données transférables est donc égal à Min(Nin, Nout).
Jean-Louis FLOQUET Page 62 13/11/2007
Une fois ce nombre calculé, on démarre le traitement des données (on appellera cet ensemble une commande).
Lorsque la commande se termine, il faut simplement attendre que le niveau du buffer d’entrée soit stabilisé vis-à-vis de la sortie (c’est-à-dire que son niveau ne puisse plus diminuer). Le niveau du buffer de sortie est parfaitement prédictible puisque l’on connaissait son niveau avant la commande ainsi que le nombre de données transférer.
Ainsi, quelque soit le nombre de cycles de traitement à effectuer entre les deux zones mémoires, on peut assurer une latence relativement faible liée uniquement au temps de calcul des niveaux. De plus, on pourra extraire absolument tous les points du buffer d’entrée puisqu’il n’y a plus de notion de seuil ni d’un côté ni de l’autre. Si l’on ne souhaite pas anticiper le niveau du buffer d’entrée, il faudra insérer une pose afin que le niveau du buffer d’entrée se stabilise. Un traitement continu des données devient donc impossible et une puissance de calcul un peu supérieure sera nécessaire.
Par contre, si plusieurs buffers d’entrée sont connectés (grâce à un multiplexeur), cette méthode devient extrêmement puissante car il suffit simplement de s’interdire de traiter deux fois de suite le même buffer (si toutefois cela est possible). Le principal exemple de ceci est l’écriture (ou la lecture) de plusieurs flux de données vers une seule mémoire externe au FPGA; la bande passante de la mémoire peut être alors utilisée au maximum.
Avantages Inconvénients 1) latence faible 2) extraction de toutes les données 3) pas de notion de seuil
1) mise en œuvre plus complexe 2) difficulté de travailler en continu sans
anticiper le niveau d’entrée (cas d’un seul buffer d’entrée)
3. Remarques Quelque soit la méthode retenue pour contrôler le pipeline, il faut se souvenir de la règle
suivante qui est la plus importante dans une architecture de ce type : une fois qu’une décision devant se dérouler sur plusieurs cycles est prise, il ne faut jamais vérifier en cours de route qu’elle puisse toujours être exécutée. Tous les tests nécessaires doivent être faits avant de prendre la décision, et non pendant, sous peine de créer un contrôle redondant (nuisible en terme de surface de silicium et de performances).
Ceci implique notamment qu’un buffer ne doit jamais vérifier les opérations suivantes (et encore moins s’en protéger) :
- lecture d’un buffer vide - écriture dans un buffer plein
Ces conditions aux limites doivent être intégralement gérées par la logique de contrôle (cf. IX.L Séquenceur de contrôle à N étages, p. 64).
L. Séquenceur de contrôle à N étages On réalise un tel séquenceur avec les éléments de base suivants :
- séquenceur de contrôle simple (étage #0) - lignes à retard (étages #1 à #N-1)
Le séquenceur de contrôle, quelque soit son mode (prédiction ou auto-maintient), évolue
d’état en état et génère les commandes en fonction de son environnement sans se préoccuper du nombre d’étages (cycles d’horloge) nécessaires au calcul des données fournies en entrées.
Jean-Louis FLOQUET Page 63 13/11/2007
À chaque cycle d’horloge suivant est effectuée une opération élémentaire dans le pipeline où chaque étage est en mesure de savoir le comportement à adopter grâce aux lignes à retard issues du premier étage du séquenceur. Exemple type SeqType is (idle, load, add, sub, trsf,…); type SeqArray is array(10 downto 1) of SeqType ; signal Seq : SeqType; signal Seq_s : SeqArray; process(rst,clk) begin if rst='1' then Seq <= idle ; Seq_s <= (others=>idle); elsif rising_edge(clk) then case Seq is when … when … end case;
Seq_s <= Seq_s(Seq_s'high-1 downto 1) & Seq; -- ligne à retard du séquenceur -- Cycle 1
if Seq_s(1)=load then ReadMemory; end if;
-- Cycle 2 : traversée du registre d'entrée de la mémoire -- Cycle 3 : la donnée est placée en sortie de la mémoire (lisible au prochain cycle) -- Cycle 4 : donnée disponible en sortie de la mémoire if Seq_s(4) =add then D4 <= MemData + A; elsif Seq_s(4) =trsf then D4 <= MemData + B; else D4 <= MemData ; end if; if Seq_s(5) =sub then D5_a <= D4 – C_a; D5_b <= (D4 & '0') - C_b; else D5_a <= D4 ; D5_b <= D4 ; end if; if Seq_s(6) =load then D6 <= D5_a; elsif Seq_s(6) =trsf then D6 <= D5_b; elsif Seq_s(6)/=idle then D6 <= (others=>'0'); end if;
end if; end process;
Jean-Louis FLOQUET Page 64 13/11/2007
X. Méthodologie avancée Cette seconde partie de méthodologie s’intéresse plus particulièrement à des optimisations
plus ou moins complexes visant à tirer pleinement profit de l’architecture d’un FPGA, et notamment la famille Stratix d’Altera.
A. Associations de plusieurs blocs mémoire Il arrive fréquemment que plusieurs blocs mémoire doivent être regroupés pour former une
mémoire de capacité supérieure.
Or, pour créer un bloc mémoire, il est préférable de toujours minimiser le nombre de blocs dans le sens de la profondeur, car ceci induit un multiplexeur en sortie (c’est-à-dire qu’il faut maximiser le nombre de mots par bloc physique tout en adaptant la taille des données). Par exemple, pour stocker 1024 mots de 8bits, deux possibilités avec des blocs de 4Kbits :
512 mots
8bits
512 mots
8bits
M
U
X
1024 mots
4bits
1024 mots
4bits
8bits
Réduction du bus d’adresses Réduction du bus de données
La seconde méthode (à droite) ne nécessite aucun multiplexeur en sortie, ni décodage de
l’adresse entrante permettant d’écrire dans l’un ou l’autre bloc mémoire. Dans l’exemple ci-dessus, l’association de blocs mémoire par réduction du bus d’adresses conduit à n’utiliser qu’un bloc parmi deux, tandis que le même nombre de blocs mémoires associés par réduction du bus de données conduit à utiliser en permanence les deux blocs. Ceci permet d’économiser un multiplexeur et éventuellement un cycle d’horloge.
B. Filtrage par moyenne glissante Un tel filtrage consiste à effecteur une moyenne sur les n dernières valeurs d’un flux de
données. Ce bloc n’est constitué que d’un additionneur et d’un soustracteur dans la plupart des cas (si l’on choisit n comme puissance de 2).
Jean-Louis FLOQUET Page 65 13/11/2007
/n
Result
Input
+
-
Figure 35 : Filtrage par moyenne glissante
C. Délai programmable Implémentation d’une ligne à retard dont le délai est programmable dynamiquement. La seule limitation est la profondeur de la mémoire utilisée.
Delay
WrAddr
RdAddr
M512
ou
M4K
Data-
Figure 36 : Délai programmable
D. Fifo en Logic Cells Cette méthode d’implémentation de Fifo ne requiert aucun bloc mémoire et est donc
particulièrement adapté pour des Fifos de très faible profondeur.
Jean-Louis FLOQUET Page 66 13/11/2007
R
R
Data In
Valid
Valid
Write
Valid
Read1 0
n
n-1
n+1
Figure 37 : Fifo en Logic Cells
Pour une FIFO de 8 niveau, n ∈ [1…8]. n0=1 et n9=0 de façon à ce que les niveaux en
dehors des limites fournissent les conditions de fonctionnement. Ecriture seule Si l’on considère que le niveau (n-1) est le dernier niveau valide, la donnée est écrite au niveau n. Valid n-1 = 1 Valid n = 0 Write = 1 Le flag Valid n est mis à 1 par le procédé expliqué ci-dessous. Lecture seule Si l’on considère que le niveau (n) est le dernier niveau valide, la donnée (n) est copiée au niveau (n-1). Valid n = 1 Valid n+1 = 0 Read = 1 Lecture et écriture simultanées Si l’on considère que le niveau n est le dernier niveau valide, la donnée n est copiée au niveau (n-1) et la donnée entrante est placée en n puisque le niveau (n+1) n’est pas valide et qu’il sélectionne cette entrée sur le multiplexeur. Valid n-1 = 1 Valid n = 1 Write = 1 Read = 1
Exemple de gestion du flag Validn en VHDL -- Lecture seule if read=’1’ and write=’0’ then Valid(n) <= Valid(n+1); -- Ecriture seule elsif read=’0’ and write=’1’ then Valid(n) <= Valid(n-1); end if; end if;
Jean-Louis FLOQUET Page 67 13/11/2007
E. Division par une constante Une grande partie des divisions faisant intervenir une constante peut être remplacée par
seulement quelques additions successives. En effet, prenons l’exemple d’une division par avec une résolution de 16bits. On a :
( )
+++++++=
+++++++=
+++++++==
16
1
4
1
16
1
16
1
4
1
16
1
16
1
4
1
16
1
16
1
4
1
4096
1
1024
1
256
1
64
1
16
1
4
1
16
1
16
1
4
1
65536
1
16384
1
4096
1
1024
1
256
1
64
1
16
1
4
11010110101010100.0
3
22
16
Soit un nombre binaire A, noté A15A14A13A12A11A10A9A8A7A6A5A4A3A2A1A0.
1/4 0.25 1/16 0.0625
1er additionneur R1=A/4 + A/16
1/64 0.015625 1/256 0.00390625
2ème additionneur R2=R1 + R1/16
1/1024 0.00097656 1/4096 0.00024414
3ème additionneur R3=R2 + R2/256
1/16384 6.1035E-05 1/65536 1.5259E-05
4ème additionneur R4=R3 + R3/65536
0.33332825
A/4 A/16
1/16
1/256
A/3
1/65536
Cette méthode est particulièrement utile pour effectuer une division par un diviseur dont
l’écriture binaire est périodique : K,121,101,91,71,61,51,31
F. Programmation de la LUT d’un Stratix Il peut s’avérer, dans certains cas, de pouvoir programmer directement un élément logique.
Ceci a pour seul et unique (mais très important) avantage de pouvoir imposer exactement le mode d’implémentation de celui-ci. Le synthétiseur n’a alors plus aucune liberté et l’on retrouvera donc cet élément logique tel quel dans le composant final. Parmi les nombreux paramètres qu’il faudra fournir (mode normal / arithmétique, rôle de data3, LUT et/ou registre…), il en est un qui correspond au masque de la LUT. Ce paramètre, nommé LUT_MASK, est une chaîne de 4 caractères représentant une valeur binaire de 16 bits.
Jean-Louis FLOQUET Page 68 13/11/2007
LUT_MASK = b15 b14 b13 b12 b11 b10 b9 b8 b7 b6 b5 b4 b3 b2 b1 b0.
Si l’on affecte les coefficients suivants aux entrées a, b, c, d (les 4 entrées de la LUT) : - a ↔ 1 - b ↔ 2 - c ↔ 4 - d ↔ 8
La sortie de la LUT vaut ‘1’ si et seulement si 1842 =
+++ dcbab .
a
b
c
d
Input 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
LUT MASK=1234 � 0001 0010 0011 0100
LUT MASK=A570 � 1010 0101 0111 0000
LUT MASK=0000 (GND)
LUT MASK=FFFF (VCC)
Jean-Louis FLOQUET Page 69 13/11/2007
XI. Directives Il existe des directives VHDL permettant de donner des consignes au simulateur et/ou au
synthétiseur. Les directives de synthèse sont principalement liées à des optimisations/contraintes que souhaite l’utilisateur.
A. Translate On/Off -- synthesis translate_off
instructions non synthétisables
-- synthesis translate_on
Cette directive permet de ne pas synthétiser une portion de code. Elle est notamment utilisée pour encapsuler la totalité d’un testbench mais aussi à l’intérieur d’un code pour vérifier le bon fonctionnement d’une portion de code. Par exemple, si deux signaux (A et B) ne devaient jamais être actifs simultanément, on écrirait : -- synthesis translate_off
if A='1' and B='1' then report "A et B actifs !!" severity failure;
end if; -- synthesis translate_on
B. Read Comments -- synthesis read_comments_as_HDL on
-- instructions à synthétiser
-- synthesis read_comments_as_HDL off
Cette directive est l’inverse de la précédente. Elle permet de ne pas simuler une portion de code tout en la synthétisant. Elle est notamment utilisée pour avoir une description de très bas niveau d’un petit morceau de code tout en conservant une description simplifiée pour la simulation (et donc plus rapide en temps microprocesseur). L’écriture de très bas niveau est toujours utilisée pour imposer très précisément les ressources logiques qui doivent être utilisées et donc maîtriser les performances du design. Il est impossible d’insérer un commentaire entre cette paire de directives puisque ce sont justement les commentaires qui sont considérés comme du code VHDL.
C. Preserve signal reg1: stdlogic; attribute preserve: boolean; attribute preserve of reg1: signal is true;
Cette directive spécifie que la synthèse ne doit pas simplifier ou supprimer ce signal. Elle est généralement appliquée à un registre afin de faciliter les temps de routage.
Jean-Louis FLOQUET Page 70 13/11/2007
XII. Outils A. ModelSim Les différents codes sources d’un projet sont à lister dans la fenêtre appropriée de ModelSim.
Ils pourront ensuite faire l’objet d’une gestion automatique de ModelSim visant à ne recompiler que les fichiers le nécessitant. Il est impératif de veiller à ce que les différents fichiers soient adressés de façon relative et non absolue (../sources/file.vhd et non pas C:\projet\......\sources\file.vhd).
La mise au point d’un code source requérant de nombreuses compilations et simulations, toute la chaîne de commandes doit être exécutée par un script. Par exemple (voir la documentation en ligne de ModelSim pour la signification des options utilisées) : vcom -93 –quiet –explicit –work work ../sources/MemCtrl.vhd vsim –t ps –quiet work.tb_MemCtrl log –r * do wave_MemCtrl.do run –all
Ligne 1 : compilation de l’entité MemCtrl et de son testbench Ligne 2 : chargement de la simulation Ligne 3 : Mémorisation (par ModelSim) de tous les signaux dans le vsim.wlf. Ceci permet de rajouter un signal dans la fenêtre Wave sans avoir à relancer la simulation. Ligne 4 : chargement de la liste des signaux à visualiser Ligne 5 : lancement de la simulation, arrêt en fin de simulation (cf. § VII.E Assert & Report, p. 39)
1. Résolution temporelle Dans le cas de simulation de modèles fonctionnels vérifiant certains timings (il ne s’agit pas
ici d’une simulation post-route !), comme par exemple une barrette de SDRAM ou encore une PLL, il est nécessaire d’imposer au simulateur une résolution temporelle suffisamment fine. Étant donné que les évènements principaux se produisent à l’échelle de la nanoseconde, il faudra donc fixer cette résolution temporelle à la picoseconde.
Par exemple, les modèles de simulation des PLL pour tous les composants ALTERA requiert une granularité d’au moins 1 picoseconde (c’est-à-dire 1 ps ou plus petit).
B. QuartusII 1. PLL
Lors de la création d’une instance de PLL, la fréquence ou la période de l’horloge entrante est demandée. Étant donné qu’en simulation l’horloge est générée par la description de sa fréquence, et pour des problèmes évidents d’arrondi (F=30MHz � T≈33.333ns), il est beaucoup plus simple de décrire l’horloge entrante de la PLL à partir de sa période (choix à faire dans le MegaWizard).
Jean-Louis FLOQUET Page 71 13/11/2007
2. Liste des codes sources Tous les codes sources devant être listés pour que le synthétiseur puisse compiler le design, il
existe deux méthodes: - soit indiquer les fichiers un par un, ce qui impose de maintenir cette liste à jour dans
l’outil de synthèse, ainsi que la position relative des fichiers - soit indiquer un seul fichier contenant la totalité des codes sources. Il suffit
simplement de concaténer les sources en un nouveau fichier VHDL en utilisant la commande copy/b file1.vhd+file2.vhd design_one_file.vhd. Un script TCL (à exécuter sous ModelSim) pourra vous être fourni afin de générer automatiquement cette commande
La seconde méthode est fortement conseillée car elle offre de nombreux avantages:
- possibilité de modifications des codes sources sans perturber une synthèse - préserve les codes sources d'une fausse manipulation lors de la correction des erreurs - en cas d'archivage, ce fichier reflète la totalité du projet tel qu’il a été compilé par le
synthétiseur, même si des modifications ont eu lieu - facilité de mise en œuvre
3. Conseils de placement Les méthodes présentées ici supposent que l’utilisation de QuartusII est suffisamment
maîtrisée pour réaliser les opérations citées. Pour toute information complémentaire quant à l’utilisation de QuartusII, se reporter au site Web d’Altera où toute la documentation nécessaire pourra y être téléchargée librement.
a. LogicLock L’outil LogicLock permet de contraindre un ensemble logique (registres, entités…) à
l’intérieure d’une zone déterminée de façon à rapprocher (en terme de distance physique sur le composant ciblé) les différents éléments de cet ensemble. Cette zone, appelée « LogicLock region », peut être configurée au choix :
• pour contenir l’ensemble logique sans réserver l’espace laissé libre dans cette zone qui pourra donc être utilisée, si besoin, par d’autres éléments du design
• pour ne contenir que cet ensemble logique. L’espace laissé libre est alors perdu.
b. Conversion Binaire ↔ Gray et resynchronisation Les conversions Binaire ↔ Gray permettent de changer de domaine d’horloge. La valeur de
Gray, sur un premier domaine d’horloge, est copiée telle quelle sur un second domaine d’horloge. Il apparaît alors les contraintes suivantes :
• la différence (temporelle) entre le chemin le plus long et le chemin le plus court sur le bus reliant les deux registres de Gray doit être inférieure à la plus petite des deux périodes d’horloge
• le temps de routage moyen doit être constant entre deux « run » successifs de QuartusII
Ces deux contraintes (et notamment la seconde dans le cas d’une grande liberté de placement laissée à QuartusII) sont résolues par l’une des deux méthodes suivantes :
• faire une LogicLock Region le plus petite possible (10 x 10 LABs au maximum) contenant entre autre les deux valeurs de Gray
• ou mieux, placer manuellement les registres sur le FloorPlan
Jean-Louis FLOQUET Page 72 13/11/2007