Introduction au VHDL Introduction au VHDL Préambule : L'objectif de ce cours introductif est d'apprendre à décrire un circuit logique en langage VHDL (HDL pour Hardware Description Langage), mais en se limitant à des instructions simples. En année 4, un cours beaucoup plus détaillé sera proposé. Néanmoins, l'ambition du propos est d'aider l'étudiant à comprendre les principes fondamentaux du VHDL qui en font langage très particulier, à manier avec beaucoup de finesse. 1. Introduction Le VHDL est un langage de programmation dont la vocation est de donner naissance à un circuit logique et non à un programme exécutable. Ce circuit peut se matérialiser dans un CPLD (Complex Programmable Logic Device) ou plus grand encore, dans un FPGA (Field Programmable Gate Array). Un circuit logique programmable (CPLD ou FPGA) ne doit pas être confondu avec un micro-contrôleur. Le micro-contrôleur est une structure logique compliquée, figée, qui exécute des instructions rangées dans une ROM ou une RAM, les unes après les autres. L'utilisateur, via des langages de haut niveau (C, ADA, Pascal, JAVA...) ou de bas niveau (Assembleur), ne fait rien d'autre que remplir la ROM d'instructions élémentaires que le processeur exécute une à une. Un circuit programmable, est un ensemble de portes et de bascules élémentaires, intégrées dans une même puce, mais déconnectées les unes des autres. L'utilisateur, via un éditeur de schéma, ou un langage de description (Verilog, VHDL), ne fait rien d'autre que relier des portes ou des bascules nécessaires, en vue d'obtenir une structure logique souhaitée. Notons enfin, qu' un micro-contrôleur est une structure logique. Il est donc à ce titre, possible de matérialiser un tel circuit dans un circuit programmable... SFO 3MIC 1/11 Introduction au VHDL Voici de manière très simpliste, une comparaison entre un flot de conception pour un circuit programmable et celui corrspondant à un processeur : JAVA/ADA/C/Assembleur Schéma / Description VHDL - assemblage / compilation - édition de lien - synthèse - placement / routage Programmation (mise en place du code en ROM ou RAM) Programmation (mise en place des connexions) Micro-contrôleur programmé (le logiciel est implanté) FPGA ou CPLD programmé (la fonction électronique existe) Fig. 1 : comparaison des conceptions pour processeur et pour circuit logique programmable Le langage VHDL peut avoir d'autres vocations que celle de réaliser un circuit. On peut d'ailleurs distinguer deux types de descriptions VHDL : – Les descriptions VHDL synthétisables : Elles peuvent, après implémentation (synthèse, placement routage) donner lieu à un circuit logique bien réel. C'est de ce type de description que nous venons de parler. – Les descriptions VHDL non synthétisables : Elles ne peuvent pas aboutir à un circuit, à cause de l'utilisation d'instructions n'ayant aucune réalité physique. Ceci étant, ce mode de description peut être utile au démarrage d'une conception complexe (mais devra être retravaillée pour la rendre synthétisable, si l'on veut aboutir à la programmation de circuits logiques). Nous verrons également, que pour décire des stimuli (signaux de tests) lors de simulation, cette manière d'écrire est tout à fait appropriée. SFO 3MIC 2/11 Introduction au VHDL 2. Structure d'un fichier VHDL Un fichier VHDL est constitué de deux parties. La première est la description des entrées et sorties de la fonction réalisée ( Entity ). Son rôle est de définir le nom, la direction, le type et la taille des connexions d'entrées et de sortie. Exemple : Ici, on trouve 3 entrées binaires et une sortie de type bus à 4 fils. Le type utilisé est std_logic, ou std_logic_vector (pour un bus). Il peut prendre plusieurs états (autre que 0 ou 1) : Valeurs d'un std_logic : L'architecture, seconde partie du fichier VHDL décrit le fonctionnement du circuit : 'U' – Uninitialized 'X' – Forcing Unknown '1' – Forcing 1 '0' – Forcing 0 'Z' – High impedance 'W' – Weak Unknown 'H' – Weak 1 'L' – Weak 0 '-' - Don't care 3. Structuration d'une architecture, process Une architecture doit être vue, pensée comme un circuit logique. Tout comme un circuit peut se décomposer en sous-circuits, une architecture qui décrit une logique compliquée peut être décomposée en plusieurs parties. En VHDL, ces divers sous-circuits sont décrits par des process (processus). La notion de processus est centrale en VHDL. Du point de vue langage, un processus est un bloc qui contient une suite d'instructions séquentielles (au sens algorithme) qui a une durée d'exécution nulle (la notion d'exécution n'a pas de sens en VHDL) qui est en sommeil la plupart du SFO 3MIC 3/11 Introduction au VHDL temps, qui se réveille sur évènement particulier. Un processus active des sorties (selon l'algorithme décrit). Celles-ci sont mises à jour lorsque le processus retombe en sommeil, c'est à dire à la fin de son traitement. A l'intérieur d'un processus, un signal ne change donc pas d'état. Du point de vue circuit, une architecture dotées de plusieurs process peut se schématiser comme de la manière suivante : Frontière de l’entité Signal de type INOUT Architecture VHDL Architecture Arch of .. is Begin F2 F1 F3 A C Process(…) … End Process ; B Signaux de type IN Signaux de type OUT F4 liste de se n sibilité Process(…) … End Process ; Process(…) … End Process ; C<=A AND B ; End arch; Fig. 2 : Association process – structure logique Dans cet exemple, F1, F2 et F4 sont des blocs logiques lourds nécessitant une description comportementale, on utilise donc 3 processus. Par contre F3 est une fonction triviale, parfaitement définissable. avec les opérateurs logiques de base (pas besoin de processus explicite). Notons tout de même, qu'il s'agit bien d'un processus (implicite). Ces 4 ensembles sont dits concurrents car le déroulement de chacun d’eux est indépendant. L'ordre dans lequel on écrit les divers process est donc sans importance. SFO 3MIC 4/11 Introduction au VHDL Pour comprendre un peu mieux le concept, analysons de près l'architecture du compteur décrit précédemment : Process 1 On distingue dans cette description deux process. Le second est ultra simple et implicite. C'est juste la liaison du signal interne Q_int vers la sortie de l'architecture, Q. Le premier mérite une explication. Tout d'abord, il contient deux signaux dans sa liste de sensibilité. ⇒ il se réveillera sur la variation de H ou de RAZ ⇒ le signal d'entrée UP_DOWN peut toujours changer, il ne réveillera pas le process. Du point de vue électronique, il n'affectera pas directement la sortie. NB: L'entrée d'un circuit logique ne fait pas forcément partie de la liste de sensibilité, loin de là. Process 2 L'entrée RAZ est de type asynchrone. En effet, dès que son état change, elle est susceptible de mettre à 0 la sortie du process Q_int sans attendre de front d'horloge. Dès que H ou RAZ évoluent, la sortie du process Q_int est évaluée instantanément. Pour le lecteur, cette instantanéité est discutable, puisqu'il faut lire l'ensemble du process (ça prend du temps !) pour évaluer, en fin de process, la valeur de Q_int. Dès que le process est actif, il faut imaginer qu'une photo est prise de l'ensemble des signaux d'entrée du process, y compris Q_int (entrée-sortie). La nouvelle valeur de Q_int sera celle qui correspond à la dernière affectation. Par exemple, si à l'intérieur d'un process on écrit : Q_int = Q_int+1; Q_int = Q_int+1; Q_int = Q_int+1; Avec au départ Q_int = 2, alors quand le process retombe en sommeil (se termine), Q_int vaut 3 et pas 5 ! En effet, en cours de process, Qint est figé. Les premières lignes sont donc “oubliées” au profit de la dernière qui prend effet lorsque le process se rendort (si en cours de route, Q_int n'a pas été une fois encore retouchée...).. La structure if then else de l'horloge est dépourvue de else. Cela produit un effet mémoire. En effet, du point de vue du signal H, Q_int est affecté UNIQUEMENT lorsqu'il y a front montant. En dehors de cet évènement, rien n'est spécifié dans le process. Q_int demeure inchangé. On appelle cela l'effet mémoire par omission. Ici c'est voulu, mais parfois, lorsqu'on débute, cet oubli involontaire lors de la description d'un circuit logique combinatoire est catastrophique, puisqu'il crée une bascule qui n'a rien à faire là ! SFO 3MIC 5/11 Introduction au VHDL 4. Des exemples de descriptions de circuits usuels.. 4.1 Un décodage d'adresse : Version avec un process Cette version utilise un process explicite. Les 3 signaux sont donc déterminé par un algorithme (comportement attendu). Notons qu'il s'agit d'une logique combinatoire : à toute combinaison d'entrée correspond une et une seule combinaison de sortie. Ainsi, toute variation d'une entrée a une conséquence directe sur la sortie. C'est pourquoi le bus Ad apparaît dans la liste de sensibilité. Deux remarques très importantes : - Dans chaque condition, l'ensemble des 3 signaux de sortie est déteminé : pas d'effet mémoire par omission - dans le même esprit, la structure if then se finit par un else. Autrement dit, toutes les combinaisons d'entrée sont explorées. Version sans process Voici une description possible. Elle est plus élégante, nécessite moins de lignes et parfaitement adaptée à la conception de logique combinatoire. Chaque ligne décrit une sortie, et l'instruction de termine par un else, qui garantit l'aspect combinatoire. SFO 3MIC 6/11 Introduction au VHDL 4.2 Un buffer 3 états, 8 bits On retrouve ici la même construction que la précédente (adaptée à une logique combinatoire). On y observe la manière de créer, en VHDL le “fameux état HZ “ (haute impédance). Si OE (pour Output Enable) = '1' , la sortie Dout se retrouve connectée à l'entrée Din. Ce sont des bus 8 bits. Dans le cas contraire, le bus de sortie est “en l'air” au sens physique du terme, comme un interrupteur ouvert (8 en parallèle ici) . 4.3 Un multiplexeur 8 bits Ici encore, le circuit décrit est combinatoire. Il utilise la construction With Select... On peut observer que ce multiplexeur a sa sortie reliée à E2 pour les combinaisons autres que “00” et “01”. Ceci garantit l'aspect combinatoire du circuit décrit. 4.4 Une bascule RS La bascule RS, de type logique séquentielle asynchrone est décrite par un process. Sa liste de sensibilité contient les signaux R (reset) et S (set) puique les deux entrées commandent directement la sortie. NB: Comme toutes les bascules RS, il n'y a pas “d' état interdit” contrairement à l'idée reçue. Simplement, il existe en effet une combinaison qui peut paraître un peu stupide, à savoir positionner simultanément R et S à 1. Toute bascule est à Set prioritaire ou Reset prioritaire (l'une des entrées l'emporte sur l'autre). Ainsi, lorsque le cas se présente la sortie prend la valeur '1' ou '0'. Dans l'exemple, c'est le Set qui a la priorité . En effet, si les deux signaux sont à '1', le process se réveille, la structure if-elsif est évaluée, et c'est la première condition vraie qui l'emporte, à l'exclusion des autres (par définition de la structure if, elsif...). SFO 3MIC 7/11 Introduction au VHDL 4.5 Une bascule D, avec set et reset asynchrone Les entrées de la bascule sont au nombre de 4 (D, R, S et C). La dernière est l'horloge. La première est une entrée à action synchrone (son effet sur la sortie ne se fera sentir qu'au front d'horloge). C'est pour cette raison qu'elle ne fait pas partie de la liste de sensibilité. Au contraire, R et S sont à action asynchrone : elles agissent immédiatement sur la sortie. Elles font partie de la liste de sensibilité. Pour la sortie Q, l’ordre de priorité est Set, puis Reset, puis le fonctionnement en bascule D. Chronogrammes : reset Forçage set, malgré reset Copie de D 4.6 Une bascule D, avec set et reset synchrone Toutes les entrées sont à action synchrone. Ainsi, seul un front montant de C affecte la sortie, en fonction, de S, R, et D. Ici encore, on observe le même ordre de priorité. Chronogrammes : État indéterminé SFO 3MIC reset Copie de D 8/11 reset Forçage set, malgré reset Introduction au VHDL 5. Le test des descriptions VHDL Le test d'un design VHDL se fait par un fichier que l'on appelle testbench (banc d'essais), lui-même écrit en VHDL. Voici par exemple, celui qui a permis l'obtention des chronogrammes précédents (bascule D avec Set et Reset) : Entitée vide (pas d'entrée, pas de sortie). Inclusion du composant à tester (UUT : Unit Under Test) Signaux internes qui sont précisément les stimili Câblage entre les stimuli (les signaux internes), et les entrées / sorties de l'UUT Horloge écrite par une équation logique + l'instruction non synthétisable after Descriptions temporelles de chaque signal avec l'instruction after On remarque que le coeur du test est écrit avec une syntaxe non synthétisable puisque ces tests n'ont justement pas pour vocation de donner un circuit logique. NB: Après l'instruction after, le temps qui est donné est absolu, c'est à dire qu'il s'agit de dates référencées par rapport à l'origine 0. NB: Les signaux internes de test sont initialisés à 0. Ce n'est pas une obligation sauf pour l'horloge. En effet, celle-ci est décrite par une rétroaction sur elle-même, ce qui nécessite une valeur de démarrage. SFO 3MIC 9/11 Introduction au VHDL On peut aussi rédiger les stimuli en utilisant un process qui se réveille à des instants particuliers. En effet, nous avons vu que la liste de sensibilité détermine les signaux susceptibles de réveiller un process. Une autre possibilité est de garder une liste vide, mais d'utiliser à la place l'instruction wait. Voici pour exemple, un extrait du test du compteur possédant une entrée de remise à zéro et une entrée qui précise le sens de comptage, vu au chapitre 2. Horloge écrite par une équation logique + l'instruction non synthétisable after Process qui décrit la séquence temporelle de l'ensemble des signaux NB: Les valeurs de temps données dans les intructions wait for, sont relatives. Cela veut dire, dans cet exemple, que le signal RAZ passera à 0, à la date 220 + 10 = 230ns. Nous allons maintenant présenter un dernier test, un peu plus évolué, qui sert pour tester le décodeur d'adresses présenté au paragraphe 4.1. Il s'agit de réaliser un test où TOUTES les adresses possibles sont évaluées. Ceci se fait bien entendu par un compteur 16 bits que l'on réalise dans le testbench suivant : SFO 3MIC 10/11 Introduction au VHDL Architecture qui décrit le test : Compteur 16 bits Le bus Ad du décodeur d'adresses est relié à Q_int (sortie du compteur). Ceci est réalisé dans le bloc PORT MAP. Les initialisations de Q_int et H sont obligatoires ici. Sans ça, le compteur ne peut jamais démarrer. Auteur : Thierry ROCACHER SFO 3MIC 11/11