cour vhdl

68
PRÉAMBULE Remarque préliminaire : ce cours n'est pas un manuel complet de vhdl. C'est plutôt une introduction aux bases de vhdl. Nous y avons inclus ce qui nous semble important, en laissant de côté les possibilités les plus complexes. Il part aussi du principe que vous avez suivi le cours sur les HDL en général . Plan du cours Ce cours est séparé en chapitres. Il est conseillé de les suivre dans l'ordre, même si ce n'est pas une nécessité absolue. Accueil Vous trouverez dans ce chapitre l'introduction au cours, le plan du cours, une FAQ, et un Changelog. La FAQ ne vous sera probablement utile qu'après avoir suivi le cours... Temps estimé : 10 minutes + autant que vous le souhaiterez pour la FAQ Exemples réels Quelques exemples valant mieux qu'un long discours, ce chapitre vous plonge directement dans le langage. Les exemples clefs sont présentés, chacun introduisant une construction nouvelle. Ces exemples sont à étudier attentivement. Temps estimé : 1 heure 30 minutes Organisation du langage Ce chapitre traite de l'organisation du langage : en entité de compilation d'un côté et en bibliothèques de résultats de l'autre. Types de données, expressions Avant de voir comment on écrit un modèle vhdl, il faut étudier les types de données disponibles, les expressions disponibles ainsi que leur taille. En deux mots, les types

Upload: sam

Post on 30-Jun-2015

555 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: cour vhdl

PRÉAMBULE

Remarque préliminaire : ce cours n'est pas un manuel complet de vhdl. C'est plutôt une introduction aux bases de vhdl. Nous y avons inclus ce qui nous semble important, en laissant de côté les possibilités les plus complexes. Il part aussi du principe que vous avez suivi le cours sur les HDL en général.

Plan du cours

Ce cours est séparé en chapitres. Il est conseillé de les suivre dans l'ordre, même si ce n'est pas une nécessité absolue.

Accueil

Vous trouverez dans ce chapitre l'introduction au cours, le plan du cours, une FAQ, et un Changelog.La FAQ ne vous sera probablement utile qu'après avoir suivi le cours...Temps estimé : 10 minutes + autant que vous le souhaiterez pour la FAQ

Exemples réels

Quelques exemples valant mieux qu'un long discours, ce chapitre vous plonge directement dans le langage. Les exemples clefs sont présentés, chacun introduisant une construction nouvelle. Ces exemples sont à étudier attentivement. Temps estimé : 1 heure 30 minutes 

Organisation du langage

Ce chapitre traite de l'organisation du langage : en entité de compilation d'un côté et en bibliothèques de résultats de l'autre. 

Types de données, expressions

Avant de voir comment on écrit un modèle vhdl, il faut étudier les types de données disponibles, les expressions disponibles ainsi que leur taille. En deux mots, les types et expressions utilisables, et les pièges à éviter.Temps estimé : 1 heure. 

vhdl structurel

Présentation des éléments structurels de vhdl. Ou, plus simplement, comment écrire et instancier des composants, comment les relier.Temps estimé : 30 minutes.  

Page 2: cour vhdl

vhdl comportemental

Présentation des éléments fonctionnels de vhdl. Ou, plus simplement, comment décrire la fonction d'un composant.Temps estimé : 1heure 45 minutes

Synthèse et simulation

Présentation des différentes sémantiques. Ou, plus simplement, comment écrire du vhdl synthétisable.Temps estimé : 30 minutes 

 

En pratique

Chaque chapitre est séparé en sous-partie. Vous pouvez naviguer dans les chapitres et sous-parties à l'aide du menu en haut de page.Les icônes en bas de page vous permettent de passer au chapitre précédent ou suivant, ou de revenir à l'accueil du site sur les HDL.

Un enseignant se tient à votre disposition pendant les heures de cours, mais vous pouvez toujours nous contacter par courrier électronique.

Dernier détail, merci d'utiliser un navigateur acceptant les CCS et le javascript (firefox, mozilla, ...)

Bon courage !

Back to Top

HISTORIQUE RAPIDE

VHDL (VHSIC Hardware Description Langage) est un langage de description de matériel, c'est-à-dire un langage utilisé pour décrire un système numérique matériel, comme, par exemple, un flip-flop (bascule D) ou un microprocesseur. Il peut modéliser un système par n'importe quelle vue, structurelle ou comportementale, à tous les niveaux de description.

De plus il peut servir non seulement à simuler un système mais aussi à le synthétiser, c'est-à-dire être transformé par des logiciels adaptés (synthétiseurs) en une série de portes logiques prêtes à être gravées sur du silicium.

VHDL est l'un des trois grands langages de description de matériel utilisés majoritairement dans l'industrie, avec VHDL et SystemC. Chaque langage a ses propres avantages et inconvénients, ainsi que ses spécificités. Pour

Page 3: cour vhdl

plus de détails, on pourra se référer à une comparaison objective de VHDL et Verilog.

Le langage standard IEEE VHDL a été développé par le Groupe d’Analyse et de Standardisation VHDL (VASG, pour “VHDL Analysis and Standardization Group”). Larry Saunders est le coordinateur de VASG. La société CLSI (CAD Langage Systems Inc.), représentée par le Docteur Moe Shahdad et M. Erich Marschner a préparé une série d’analyses et de recommandations dont a été tirée en Février 1986 la version 7.2 de VHDL, point de départ du futur standard. La collaboration de CLSI au projet était financée par un contrat passé avec l’Air Force Wright Aeronautical Laboratories, représentée par le Docteur John Hines. Le standard définitif a été adopté vers le milieu de l’année 1987. La dernière version date de 2002 mais ce cours présente le langage dans la version 1993, correspondant au standard IEEE 1076-1993, qui est supporté par de nombreux outils de simulation et synthèse. Pour en savoir plus : http://vhdl.org

Page 4: cour vhdl

PRÉAMBULE

Principes d'utilisation du langage

Pour simuler ou effectuer la synthèse logique d'un modèle VHDL, il faut d'abord le compiler (on dit analyser pour le VHDL) . Les résultats d'analyse sont stockés dans une bibliothèque. Avant analyse Il faut donc préciser au compilateur la bibliothèque dans laquelle sera rangé le résultat. Dans un programme VHDL, on peut ainsi faire référence à un objet préalablement analysé en prenant soin de préciser dans quelle bibliothèque se trouve l'objet.

Une fois la compilation terminée, il faut effectuer l'édition de lien (on parle d'élaboration pour le VHDL). L'élaboration s'effectue sur la description structurelle de plus haut niveau hierarchique (l'équivalent du schéma au plus haut niveau).

La simulation peut alors s'effectuer sur le résultat de l'élaboration (rangé dans la bibliothèque spécifiée avant élaboration).

Structure du langage

L'analyse d'un modèle VHDL peut s'effectuer sur des parties du code ou "unités de compilation". Il existe 5 types d'unités de compilation :

L'entité  L'architecture Le paquetage Le corps du paquetage La configuration

L'entité et l'architecture sont des unités de compilation  obligatoires pour décrire un modèle. Les autres unités sont optionnelles mais quasiment indispensables pour concevoir des gros circuits nécessitant une méthode de conception efficace.

Une unité de compilation doit être écrite dans le même fichier et un même fichier peut contenir plusieurs unités de compilation. 

Page 5: cour vhdl

L'objectif de ce chapitre est de vous présenter les conventions lexicales de VHDL, les bibliothèques et les unités de compilation  (à part la configuration qui sera vue dans le chapitre sur le VHDL structurel)

Plan du chapitre

Conventions lexicales    Caractères utilisables, casse, ...

Bibliothèques     Où sont stockés les résultats

Entité     La vue externe du circuit

Architecture     La vue interne du circuit

Paquetage   Les objets communs

Résumé

Back to Top

CONVENTIONS LEXICALES

Les conventions lexicales de vhdl sont les mêmes que celles utilisées en C. Un code vhdl est composé d'une suite d'éléments :

commentaires délimiteurs nombres chaînes de caractères identificateurs mots-clefs

CasseVHDL est insensible à la casse. Un mot en majuscule est identique à un mot en minuscule. Il est cependant conseillé d'avoir des règles d'écriture cohérentes. Par exemple, les mots reservés du langage peuvent être en majuscule et les autres mots en minuscule.

Commentaires Les commentaires doivent être inclus dans le code, pour augmenter la lisibilité et la documentation. Ils commencent par 2 tirets (--) en se terminent en fin de ligne

Page 6: cour vhdl

Il est impératif de documenter vos codes, à l'école comme en entreprise.

Identificateurs Ce sont les noms de variables, de signaux, de fonctions, ...

Ils ne peuvent contenir que des lettres, des chiffres et le "underscore"  _ . Ils doivent commencer par une lettre. Ils ne peuvent pas contenir d'espace. Les mots-clefs du langage ne peuvent pas être utilisés comme

identificateurs.

ExpressionsElles se terminent par un point virgule ;

LitérauxCe sont des valeurs explicites :

67 est un littéral pour le type entier '0' est un littéral pour un bit "001"     O"562"    X"FF1" sont des littéraux pour les vecteurs de bits "chaine" est un littéral de type chaine de caractères  null est un litéral pointeur

Back to Top

BIBLIOTHEQUES

Les bibliothèques permettent à plusieurs concepteurs de travailler ensemble sur le même projet et rendent le langage indépendant du système d’exploitation de la machine hôte.

La création de la bibliothèque ne fait pas partie du langage VHDL Chaque outil VHDL a donc ses propres règles de création..  Par exemple avec le simulateur ModeSim il faut créer la bibliothèque avec cette commande :

vlib BIB

L'accès à la bibliothèque fait partie du langage VHDL. Pour accéder  à la bibliothèque BIB il est nécessaire de la déclarer :

library BIB;

La bibliothèque par défaut est WORK . WORK est aussi le nom symbolique de la bibliothèque dans laquelle sont stockés les résultats. La bibliothèque STD est une bibliothèque standard fournie avec le langage , elle contient des définitions des types et des fonctions de base

Page 7: cour vhdl

(integer, BIT, BOOLEAN,...) dans le paquetage STANDARD et des fonctions sur les caractères dans le paquetage TEXTIO.  

Par défaut, les bibliothèques STD et WORK n’ont pas besoin d’être déclarées pour être utilisables. Tout se passe comme si un programme VHDL commençait toujours par :

library STD;library WORK;

Il est très pratique d'utiliser les paquetages  des bibliothèques ce qui permet d'utiliser des objets (constantes, fonctions, composants,...) qui peuvent être définis dans une bibliothèque différente de celle en cours. C'est le cas des bibliothèques standards comme l'IEEE qui définit des types et objets normalisés compris  par les outils de synthèse.

Pour utiliser le contenu d’un paquetage, il faut déclarer la bibliothèque dans laquelle il se trouve (sauf, éventuellement, si c’est WORK) et le paquetage :

use BIBLIOTHEQUE.PAQUETAGE.all;

ou, si l’on ne veut pas utiliser tout le paquetage mais un seul objet :

use BIBLIOTHEQUE.PAQUETAGE.OBJET;

  

Back to Top

ENTITE

L'entité est la description de l'interface du circuit . Elle correspond au symbole dans les représentations schématiques :

symbole de l'additionneur 1 bit

L'entité précise :

le nom du circuit Les ports d'entrée-sortie :

o Leur nomo Leur direction (in, out, inout,...)o Leur type (bit, bit_vector, integer, std_logic,...)

Les paramètres éventuels pour les modèles génériques

Page 8: cour vhdl

L'écriture de l'entité pour l'additioneur 1 bit fa peut être la suivante . Il faut noter la déclaration préalable de la bibliothèque IEEE et des paquetages qui permet d'utiliser le type std_logic. (std_logic_1164) et des fonctions arithmétiques (numeric_std).

library ieee;use ieee.std_logic_1164.all;use ieee.numeric_std.all;--entity fa is port ( a, b, cin : in std_logic; s, cout : out std_logic );end entity;

Back to Top

ARCHITECTURE

L'architecture est la description interne du circuit. Elle est toujours associée à une entité. Une même entité peut avoir plusieurs architecture. Le mécanisme de configuration (décrit dans le VHDL structurel) permet d'indiquer l'architecture rattachée à une entité. L'exemple suivant montre un schéma de l'additionneur 1 bit fa et 2 architectures possibles écrites en VHDL :

       

architecture arc1 of fa is-- signal resultat : unsigned(1 downto 0);--begin-- resultat <= ('0' & a) + ('0' & b) + ('0' & cin); s <= resultat(0); cout <= resultat(1);

architecture arc2 of fa is--begin-- s <= a xor b xor cin; cout <= (a and b) or ((a xor b)--end arc1;--

Page 9: cour vhdl

--end arc1;

             

VHDL = langage déclaratif et typéVHDL est un langage très déclaratif qui permet au compilateur d'effectuer des vérifications poussées et fiabiliser ainsi l'écriture d'un modèle.

Dans une architecture il est nécessaire de déclarer les objets utilisés et leur type avant la zone décrivant l'architecture (le corps de l'architecture situé entre begin ... end ).

Parmi les objets très utilisés, figurent les composants (correspondent effectivement aux composants dont on a besoin dans l'architecture pour une description structurelle) et les signaux (equipotentielles reliant les instances de composants et les instructions "concurrentes" et).

Les ports déclarés dans l'entité sont des signaux utilisables dans l'architecture, il ne faut pas les redéclarer.

L'exemple ci-dessous illustre l'architecture d'un additionneur 1 bit avec les signaux A, B , Cin (qui sont des ports donc des signaux implicites) , le signal Si et le composant MAJ .

Le schéma équivalent de l'additionneur 1 bit peut être le suivant avec 1 composant MAJ et 2 portes XOR qui peuvent être codées d'une façon comportementale. 

Le code VHDL correspondant :

entity FA isport (

A, B, Cin : in bit;

S, Cout : out bit );end entity;

Entité de l'additioneur 1 bit FA

architecture arc3 of fa is--

La partie déclarative de l'architecture, avant le mot clé begin, permet de déclarer le signal SI et le composant

Page 10: cour vhdl

signal SI : bit;--component MAJport ( X,Y,Z : in bit;

M : out bit);end component;

MAJ.

begin--p1 : process(SI, Cin) begin

S <= SI xor Cin; end process;--SI <= A xor B;--inst_MAJ : MAJ port map (

X => A, Y => B,Z => Cin, M => Cout);--end arc3;

Dans le corps de l'architecture (entre begin et end) se

trouvent les 3 types d'instructions concurrentes de VHDLqui peuvent être écrites dans n'importe quel ordre :

Un processus avec le mot clé process Une instruction concurrente d'affectation S <=

SI xor Cin ( on dit S reçoit Si xor Cin) Une instruction d'appel de composant

(instanciation) ou un nom d'instance est donné (INST_MAJ) de façon à pouvoir appeler plusieurs composants du même type

Les ports  sont des signaux implicites dont le sens doit être respecté. Le compilateur VHDL aurait mis une erreur si dans le corps de l'architecture s'était trouvé l'instruction :Cout <= S and B  car S est une sortie qui ne peut pas

servir d'entrée.

 

     

Back to Top

Back to Top

PAQUETAGE

Le paquetage est une collection d'objets réutilisables. Il se compose de 2 unités de compilation :

1. La déclaration du paquetage2. Le corps du paquetage

Le contenu de la déclaration du paquetage est visible depuis l'extérieur. alors

Page 11: cour vhdl

que le corps décrit la fonction des objets nécessaires à l'utilisation du paquetage. Lorsqu'une unité de compilation utilise un paquetage, la déclaration de celui-ci doit être analysée en premier. Le corps du paquetage n'est pas toujours nécessaire.

Exemple de déclaration de paquetagepackage PAQ is--subtype MOT is bit_vector(7 downto 0);type RAM is array (natural range <>) of MOT;subtype MRAM is RAM(0 to 1023);--constant N_BITS : positive;constant REL : natural := 8;--component BRIQUE

generic (N : positive := 12);

port ( A,B : in bit;

S : out bit);end component;--function MIN(A,B,C : integer) return integer;--end package PAQ;

Le paquetage PAQ est déclaré avec le mot clé package.

Des nouveaux types type et sous-types subtype

sont déclarés.Dans cet exemple on déclare le type MOT qui est un vecteur de 8 bit, un type RAM qui est un tableau de MOT et un sous type MRAM qui est une RAM de 1024 MOTS.

Des constantes  "constant" N_BITS et REL sont

déclarées. N_BITS est un entier > 0 "positive" et REL

est un entier naturel "NATURAL" et est initialisée à la

valeur 8.

Le composant "component" BRIQUE est déclaré ici en

précisnat ces ports et paramètres. La déclaration d'un composant permet son instanciation dans l'architecture de façon à effectuer une description structurelle

Le sous-programme ou fonction "function" MIN est

déclarée dans le paquetage. La description de la fonction ser effectuée dans le corps du paquetage.

Exemple de corps de paquetagepackage body PAQ is--constant N_BITS := 16;--function MIN(A,B:integer) return integer isbegin

if (A<B) thenreturn A;elsereturn B;end if;

Le corps du paquetage  "package body" permet de

décrire les sous-programmes et d'initialiser les constantes.

La constante N_BITS est initialisée ici. Elle aurait pu être utilisée localement au corps du sous programme sans être visible de l'extérieur.

Les fonctions peuvent être surchargées en nom ou en type. Ici 2 fonctions MIN sont décrites , l'une avec 2

Page 12: cour vhdl

end if;end MIN;--function MIN(A,B,C : integer) return integer isbegin

return MIN(A, MIN(B,C));end MIN;--end package body PAQ;

entrées et l'autre avec 3 entrées utilisant celle à 2 entrées.

Back to Top

EN RÉSUMÉ

On a vu

Les bibliothèques o permettent de stocker les résultats et de les réutiliser.o certaines sont par defaut WORK et STD, d'autres sont standard

IEEE, d'autres sont personnelles. L'entité

o Elle décrit l'interface du circuit avec le monde extérieur.o Il faut spécifier les ports, leur sens et leur type.o Les paramètres d'un circuit générique sont déclarés dans l'entité.

L'architectureo Décrit l'intérieur du circuit , en structurel (schéma) ou en

comportemental ou les 2.o Avant de les utiliser dans le corps de l'architecture, il faut déclarer

les objets et les types (signaux, composants, constantes,fonctions,...).

Prochain chapitreLe prochain chapitre traite des types et des opérateurs de base en VHDL

Page 13: cour vhdl

PRÉAMBULE

Objectifs

VHDL est un langage typé où il est obligatoire de spécifier le type des objets utilisés. Le tableau ci dessous illustre la classification des types du langage VHDL :

L'objectif de ce chapitre est de vous présenter les types et les opérateurs. A l'issue de ce chapitre, vous serez en mesure de choisir le meilleur type pour l'objet que vous voulez modéliser.

Page 14: cour vhdl

Plan du chapitre.

Types entiers   C'est le type de base, sur 32 bits

Types énumérés   Les types Booléens et bits  font partie de cette catégorie.

Types tableau   Indispendables pour représenter des vecteurs, des matrices, des mémoires.

Types fichiers  Servent à effectuer des tests en lisant et/ou générant des données contenues dans ces fichiers.

Autres types     Une vue d'ensemble des autres types définis dans les bibliothèques standards.

Attibuts     Permettent de consulter les caractéristiques des types ou d'objets déclarés. Il est possible de déclarer ses propres attributs.

Opérateurs     La palette d'opérateurs standards.

IEEE     Bibliothèque utilisée par tous les outils de synthèse et permettant de travailler sur des types logiques à 9 états.

Résumé

Remarque importante

Ce chapitre, comme tous les chapitres sur la syntaxe des langages, est un peu indigeste. Il vaut mieux le voir comme une référence, une page à laquelle vous pourrez vous rapporter tout au long du cours, ou en cas de problème. Par contre, il est conseillé de l'avoir lue au moins une fois, pour garder en tête où se trouvent les pièges éventuels.

Back to Top

TYPES ENTIERS

Le type entier integer prédéfini dans le paquetage standard STD permet de définir des nombres signés sur 32 bits entre -2-31 et 231 - 1  . 

Page 15: cour vhdl

Un sous type subtype permet de déclarer un type héritant des propriétés du type père.

Il existe 2 "sous types" subtype associés à INTEGER : les entiers naturels et les entiers positifs. Leur déclaration dans le paquetage STD est la suivante :

subtype natural is integer range 0 to integer'high;subtype positive is integer range 1 to integer'high

Notez que

1. range permet d'indiquer l'intervalle 2. 'HIGH indique la plus grande valeur du type INTEGER, c'est un

attribut de type

Les types entiers servent à définir des indices de tableaux et de boucles. Pour cela il est intéressant de les restreindre de façon à contrôler les débordements.Par exemple on peut déclarer :

subtype UN_A_DIX is natural range (1 to 10);subtype DIX_A_UN is natural range (10 downto 1);

Il s'agit d'objets compatibles entre eux mais avec un ordred'indexation différent.Il est donc possible d'effectuer des opérations entre ces objets En revanche si on avait déclaré :

type UN_A_DIX is natural range (1 to 10);type DIX_A_UN is natural range (10 downto 1);

Les 2 types étant indépendants, une opération entre des objets UN_A_DIX et DIX_A_UN  aurait  causé une erreur de compilation.    

Back to Top

TYPES ENUMERE

Un type énuméré est un type défini par une énumération exhaustive :

type COULEURS is (ROUGE, JAUNE, BLEU, VERT, ORANGE);

Page 16: cour vhdl

L'ordre de déclaration est important. Lors de l'initialisation d'un signal de type enuméré T, le signal prend la valeur T'LEFT.Par exemple un signal de type COULEURS sera ROUGE en début de simulation.

Dans le paquetage STANDARD de la bibliothèque STD, plusieurs types énumérés sont définis :

type boolean is (FALSE, TRUE);type bit is ('0', '1');type severity_level is (NOTE, WARNING, ERROR, FAILURE);type character is ( NUL, SOH, STX, ETX,..., '0','1', ...);

Notez que la valeur d'un bit est équivalente à un caractère et est toujours entre quotes : '0' et  '1'  différents des entiers 0 et 1.

Dans le paquetage STD_LOGIC_1164 de la bibliothèque IEEE, le type STD_ULOGIC est défini par :

type std_ulogic is ('U', 'X, 'O', '1', 'Z', 'W', 'L', 'H', '-');

Ce permet d'avoir 9 états significatifs de la logique. Ces états illustrent les cas où le signal est soumis à de multiples affectations. Dans ce cas chaque valeur à un niveau de priorité.La liste suivante donne la signification de ces 9 valeurs en commençant par la valeur de plus grande priorité :

Au démarrage les signaux sont dans un état inconnu 'U'. 'X' indique un conflit, le signal est affecté d'un côté à '1' et d'un

autre à '0'. '0' et '1' correspondant aux valeurs booleennes du signal. 'Z' correspond à l'état haute 'impédance". 'W' est la valeur d'un signal relié à 2 résistances de tirage, une

tirant à 0 et l'autre à 1. 'H' et 'L'  sont des valeurs d'un signal relié respectivement à une

résistance de tirage à 1 et à 0. '-' est un état indifférent. Utile pour décrire les tables de vérité.

Le type énuméré est aussi très utile pour définir les états d'une machine à états d'une façon symbolique, sans avoir à définir le codage.

Back to Top

TYPES TABLEAU

Page 17: cour vhdl

Les types TABLEAU ou array sont des collections d'objets de même type, indéxés par des entiers ou des énumérés.

Exemples :

type bus is array (0 to 31) of bit;type RAM is array (0 to 1024, 0 to 31) of bit;type PRIX is ranger 0 to 1000;type COULEURS is (BLANC, BLEU, VERT, ROUGE, JAUNE, NOIR, ARC_EN_CIEL);type PRIX_PEINTURES is array (COULEUR range BLANC to NOIR) of PRIX;

Un tableau peut avoir une taille inconnue donc non contraint, par exemple le type BIT_VECTOR de la bibliothèque STD est  un tableau de dimension 1 (vecteur) de taille quelconque :

type bit_vector is array (natural range <>) of bit;

et le type STD_ULOGIC_VECTOR de la bibliothèque IEEE :

type std_ulogic_vector is array (natural range <>) of std_logic_vector;

La contrainte de taille est alors exprimée dans la déclaration de l'objet :

signal toto bit_vector(31 downto 0);signal titi std_ulogic_vector(7 downto 0);

Il faut noter que l'indexation peut être MSB en tête (31 downto 0) , la plus courante, ou LSB en tête (0 to 31). Attention, une affectation de signaux vectoriels ayant des indexations différente provoque une inversion des composantes du signal.  La valeur d'un vecteur peut être représentée dans une base différente : "001100" = 0"14" = X"0C" 

Il peut y avoir des tableaux de tableaux ou des tableaux à plusieurs dimensions; Les affectations diffèrent quelque peu comme illustré dans l'exemple suivant :

type TAB1 is array(0 to 2) of bit_vector(7 downto 0);type TAB2 is array(0 to 3, 1 to 8) of bit;signal A : TAB1;signal B : TAB2;--begin--tableau de tableau A(0) <="01001111"; A(2)(5) <= '1';-- tableau à 2 dimensions B(3,5) <= '0';--end exemple;

Page 18: cour vhdl

 Notation d'agrégat

Cette notation permet d'initialiser les tableaux facilement.Exemple :

type OPTYPE is (ADD,SUB,MUL,DIV,BRA);type T is array ( 1 to 10) of OPTYPE;signal A : T;--A <= (ADD,SUB,MUL,DIV,BRA);A <= (ADD,SUB,5=>BRA,4=>DIV,3=>MUL);A <= (ADD,2|4=>SUB,others => DIV);--

Cet exemple illustre l'affectation par position et à la position par dénomination. Notez l'utilisation de la clause 'others' pour compléter automatiquement les valeurs du tableau.

Back to Top

TYPES FICHIERS 

Les types fichiers FILE permet l'échange de données entre l'extérieur et le simulateur VHDL. Il est utilisé principalement pour créer des fichiers de test ou TESTBENCH de modèles.

Le paquetage TEXTIO de la bibliothèque STD définit un type fichier texte TEXT et des procédures pour accéder aux lignes du fichier et aux chaînes dans la ligne.  Pour l'utiliser il est nécessaire de le déclarer en début de fichier :

use STD.TEXTIO.ALL;

Un fichier peut être soit en lecture soit en écriture mais pas les 2 en même temps.L'exemple commenté suivant illustre 2 processus permettant respectivement de lire le fichier "entrees.dat" et d'écrire les résultats dans "sorties.dat" :

LECTURE: process variable L: line; -- le type LINE est un pointeur file ENTREES: text open READ_MODE is "entrees.dat"; -- fichier spécifié variable A: bit_vector(7 downto 0); -- variables à lire variable B: natural range 0 to 11;begin readline(ENTREES, L); -- lecture d'une nouvelle ligne dans le fichier read(L, A); -- lecture dans la ligne du 1er symbole => BIT VA <= A; -- utilisation pour la simulation read(L, B); -- lecture dans la ligne du 2ème symbole => entier

Page 19: cour vhdl

VB <= B; -- utilisation pour la simulation wait for 20 ns; -- attente de 20 ns;end process LECTURE;--ECRITURE: process(S) variable L: line; file SORTIES: text open WRITE_MODE is "sorties.dat";begin write(L, S); -- écriture de S dans la ligne write(L, string'(" à t = ")); -- écriture de texte dans la ligne write(L, now);-- écriture du temps de simulation dans la ligne writeline(SORTIES, L); -- écriture de la ligne dans le fichierend process ECRITURE;

Back to Top

 

AUTRES TYPES

Types réels

 Il existe un type réel prédéfini REAL. Il permet de représenter des nombres entre -1.0E+38 à 1.0E+38. Il n'est pas synthétisable.Voici quelques exemples d'affectation d'un signal de type réel :A <= 1.0;B <= 5.9E10;C <= -8.5E20;

Notez la présence obligatoire du point.

Types physiques

VHDL permet de définir des types physiques pour représenter une grandeur physique, comme le temps, la tension, etc... 

Un type physique est la combinaison d'un type entier et d'un système d'unité.Le type TIME, est le seul type physique prédéfini :

type time is range $- to $+ -- l'intervalle dépend de la machineunits fs; ps = 1000 fs; ns = 1000 ps; us = 1000 ns; Ms = 1000 us; sec = 1000 ms; min = 60 sec; hr = 60 min;end units;

Page 20: cour vhdl

Les simulateurs VHDL utilsent la fonction now, de la bibliothèque STD , qui retourne le temps physique de type TIME.

Type STRING

Ce type permet de définir les chaînes de caractères.  Il est définit comme un tableau d'éléments de type CHARACTER dans la bibliothèque STD.

type string is array (positive range <>) of character;--"ceci est une chaîne de caractère"

Type enregistrement RECORD

Ce type permet de définir un objet dont les composantes sont hétérogènes.

type OPTYPE is (MOV, ADD, SUB, JMP, CALL)type INSTRUCTION is record-- OPCODE : OPTYPE; ADR : bit_vector(7 downto 0); OP2 : bit_vector(7 downto 0);--end record;

L'affectation d'un objet de type RECORD  peut s'effectuer de différentes façons :

signal INST1 : INSTRUCTION;signal INST2 : INSTRUCTION:--begin--INST1 <= (MOV, "00011100", X"FF");INST2.ADR <= X"8A";--end;

Les RECORD sont très utiles pour les entités dont les ports peuvent être amenés à changer en nombre et en type. Les ports sont alors de type RECORD et ne changent pas. En cas de modification il suffit de modifier le contenu du type RECORD plutôt que de modifier les ports dans les entités.

Type pointeur ACCESS

Les pointeurs sont peu utilisés en VHDL car on leur préfère les tableaux indicés qui peuvent être synthétisables, à la différence des pointeurs.  Nous  ne les étudieront pas dans ce cours. 

Back to Top

Page 21: cour vhdl

ATTRIBUTS

Il s'agit de caractéristiques de types ou d'objet qu'il est possible d'utiliser dans le modèle. Ils sont représentés de cette façon :

<OBJET>'<ATTRIBUT>

Il existe des attributs sur les types, sur les objets de type tableau  et sur les signaux. 

Il est possible de créer ces propres attributs. Certains outils de synthèse en tirent profit pour passer des arguments de synthèse.

Attributs sur les types 

L'exemple suivant illustre les principaux attributs de type :

type COULEUR is (BLEU, ROUGE, VERT);--COULEUR'left renvoie BLEUCOULEUR'right renvoie VERTCOULEUR'pos(BLEU) renvoie 0COULEUR'val(0) renvoie BLEUCOULEUR'succ(BLEU) renvoie ROUGECOULEUR'pred(ROUGE) renvoie BLEU

 

Attributs sur les objets de type tableau

exemples :

type MOT is bit_vector(7 downto 0);type TAB is array (4 downto 0) of MOT;signal NOM : MOT;signal TABLEAU : TAB;

MOT'LEFT renvoie 7;MOT'LENGTH renvoie 8;TABLEAU'RIGHT renvoie 0;TABLEAU'RANGE renvoie 4 downto 0;

Ces attributs sont très utiles pour créer des indices ou pour écrire des sous-programmes manipulant des tableaux de taille variable.

Attributs sur les signaux

Ils servent à indiquer les caractéristiques d'évolution temporelle des signaux.Exemples :

Page 22: cour vhdl

CLK'EVENT renvoie un BOOLEAN indiquant si le signal CLK a changé.CLK'DELAYED(1 ns) est un signal identique à CLK décalé de 1 ns.

Attributs définis par le concepteur

Ils permettent d'associer des caractéristiques propres aux objets. Certains outils de synthèse ont leurs propres attributs pour rentrer des contraintes de synthèse dans le code.L'exemple suivant défini le brochage de certains signaux.   Exemple :ATTRIBUTE NUMERO_BROCHE : POSITIVE;ATTRIBUTE NUMERO_BROCHE of ENTREE1 is 12;ATTRIBUTE NUMERO_BROCHE of ENTREE2 is 17;

Back to Top

OPERATEURS

Les opérateurs prédifinis en VHDL sont classiques. Ils ne portent que sur les types prédéfinis, BOOLEAN, BIT, INTEGER. Il faut donc définir une surcharge d'opérateur lorsqu'il s'agit d'effectuer des opérations sur un nouveau type. 

Il faut noter l'absence du xnor et la différence entre REM et MOD pour exprimer le reste de la division.

Type d'opérations opérateurs notes

Logiques and, or, nand, nor, xor, not

Relationnels =, /=, < , <=, > , <=

Arithmétique *, / , mod, rem 

(A rem B) a le signe de A(A mod B) a le signe de B

Divers **, abs, &

** : exponentiationabs : valeur absolue& : concaténation

Back to Top

EN RÉSUMÉ

On a vu:

La diversité des types  VHDL les attributs

Page 23: cour vhdl

les opérateurs

Prochain chapitre

le VHDL structurel.

PRÉAMBULE

Objectifs

La description structurelle d'un circuit complexe en vhdl présente de nombreux avantages :

 Une architecture hiérarchique compréhensible : il est plus simple de séparer un circuit en un ensemble de blocs plus petits, ayant des fonctions bien identifiées. Ces blocs pourront alors être décrits sous forme comportementale, ou bien à leur tour être séparés en blocs encore plus simples.

Une synthèse logique efficace : la synthèse est un processus lent (en terme de temps de calcul). Plus un bloc est gros et complexe, plus sa synthèse prendra du temps. Il vaut donc

Page 24: cour vhdl

mieux travailler sur des blocs plus petits, plus simples à synthétiser, et rassembler le tout à la fin.

L'objectif de ce chapitre est de voir précisément comment coder une représentation structurelle d'un circuit, autrement dit :

comment déclarer des blocs (qu'on appellera composant) comment utiliser un composant (qui devient une "instance") et

déclarer la façon dont il est  connecté. comment choisir l'architecture d'un composant quand il y en a

plusieurs (configurations)

Plan du chapitre

Eléments de base    qu'est-ce qu'un composant, que contient-il ?

Déclaration et instanciation des composants     comment déclare-t-on un composant  (déclaration) et comment l'appeler pour le connecter (instanciation) ?

Composants génériques     VHDL offre la possibilité d'avoir des composants génériques comme par exemple un compteur sur N bits où N est un paramètre qu'il faut indiquer au moment de l'instanciation. Comment fait on pour passer des paramètres à ce type de composants

Configurations     VHDL offre la possibilité d'avoir plusieurs scénarios d'architecture pour un même composant. Comment configurer le composant ?

Exercices

Back to Top

ELÉMENTS DE BASE

VHDL permet l'assemblage de "composants" ce qui constitue une description structurelle. Ce composant peut être appelé plusieurs fois dans un même circuit. Pour différencier ces mêmes composants, il est nécessaire de leur donner un nom d'"instance". L'appel d'un composant se dit aussi "instanciation" 

De façon à instancier un composant il est nécessaire de connaître  :

Le prototype du composant (ses ports d'entrée et de sortie). La directive component peut être utilisée à cette fin. 

A quelle entité et architecture est lié chaque instance de composant. Ce lien peut être connu grâce à l'unité de configuration.

Page 25: cour vhdl

Il est important de noter  :

La déclaration du composant (directive component ) est redondante textuellement avec celle de l'entité associée mais permet :

1. Une compilation indépendante entre l'entité associée au composant et le circuit utilisant le composant.

2. La conception descendante. Le composant peut être déclaré avant l'entité associée.

La configuration est une unité de compilation optionnelle, très utile pour les gros circuits. Par exemple pour accélérer la simulation , un même composant peut être associé à un couple entité/architecture détaillé et synthétisable ou un autre couple plus abstrait et plus rapide à simuler. Pour ne pas utiliser de configuration, une règle fréquente est  d'utiliser le même nom pour le composant et l'entité associée, c'est le cas pour ModelSim et les outils de synthèse FPGA.

La description structurelle est  nécessaire pour simuler un circuit dont les vecteurs stimulis sont eux mêmes issus d'un modèle VHDL. Le modèle de plus haut niveau fait donc appel au circuit à tester (Device Under Test) et d'un générateur de stimulis. Ces deux objets sont instanciés dans un même circuit, généralement appelé "testbench" (mais ce n'est pas une obligation) qui est autonome : il n'aura pas d'entrées ni de sorties.

Exemple : le circuit top, servant à simuler le circuit  "module a" doit être autonome : son entité n'a pas d'entrée ni de sortie.

Cas particulier de la simulation : circuit "top" sans entrée ni sortie

Back to Top

DÉCLARATION ET INSTANCIATION DES COMPOSANTS

Page 26: cour vhdl

Déclaration

Le mot clé component sert à déclarer le prototype d'interconnexion. La syntaxe est presque identique à celle de l'entité :

component AND_2 port ( a : in bit; b : in bit; s : out bit);end component;

Pour créer rapidement un composant, une opération copier/coller de l'entité en enlevant le litéral "IS" suffit.

Instanciation :

L'instanciation d'un composant se fait dans le corps de l'architecture de cette façon :

<NOM_INSTANCE>:<NOM_COMPOSANT> port map(LISTE DES CONNEXIONS);

Exemple:

entity AND_3 is port( e1 : in bit; e2 : in bit; e3 : in bit; s : out bit );end entity;--architecture arc of AND_3 is--signal z : bit;component and2

port (a : bit;b : bit;s : bit);

end component;--begin inst1 : and2 port map (a=>e1, b=>e2 , s=>z);

Dans cet exemple , 2 instances de composant "and2" sont appelées pour créer une porte ET à 3entrées.

L'association des ports du composants aux signaux de l'instance se fait à l'aide de la clause port map.

La syntaxe des associations est soit

1. par nom où chaque broche du composant est associée à un signal : cas de inst_1

2. positionnelle où l'ordre des signaux correspond à l'ordre des broches : cas de inst_2

Page 27: cour vhdl

inst2 : and2 port map (z, e3, s);end arc

 

Backto  

GENERICITE

Déclaration

Un composant peut être générique en définissant les paramètres qui seront vus comme des constantes à chaque instance de composant. Il est ainsi possible de n'avoir qu'un seul composant  pour différentes instances ayant des paramètres différents. Dans la déclaration du composant, la clause generic sert à passer les paramètres au composant. Dans l'exemple suivant, l'entier positif N indique le nombre de bits de l'additionneur.

component ADD generic

(N : positive range 0 to 16);

port(A: in std_logic_vector(N-1 downto 0);B: in std_logic_vector(N-1 downto 0);S: out std_logic_vector(N-1 downto 0));

end component;

Le paramètre N permet dedimensionner la taille de l'additionneur, il est déclaré avec la clause generic

De même l'entité associée au composant doit comporter la clause generic pour déclarer le(s) paramètre(s)

Page 28: cour vhdl

entity ADD is generic

(N : positive range 0 to 16);

port(A: in std_logic_vector(N-1 downto 0);B: in std_logic_vector(N-1 downto 0);S: out std_logic_vector(N-1 downto 0));

end entity ADD;

 

Instanciation :

L'instanciation d'un composant se fait dans le corps de l'architecture de cette façon :

architecture arc of mult iscomponent ADD generic (N : positive range 0 to 16); port (A: in std_logic_vector(N-1 downto 0);B: in std_logic_vector(N-1 downto 0);S: out std_logic_vector(N-1 downto 0));end component;signal OP1,OP2,S std_logic_vector(N-1 downto 0);. . .--begininst_ADD : ADD generic map(N=>12);port map(A=>OP1, B=>OP2,S=>S);. . .end arc;

La clause generic mapdans l'instanciation du composant ADD permet de fixer la valeur duparamètre.

Instanciation de multiples composants

Les paramètres ne sont parfois pas suffisants pour écrire un code générique : on peut aussi vouloir instancier un nombre variable de composants (en fonction d'un paramètre, par exemple). Ceci est fait au moyen des mots-clef for generate..et if generate.   Exemple 1 : on veut décrire un multiplieur générique, tel que :

L'architecture Carry Lookhead (CLA) est utilisée s'il doit manipuler des nombres de largeur inférieure à 8 bits, 

L'architecture en arbre de Wallace est utilisée sinon.

Page 29: cour vhdl

L'exemple ci-dessous fait appel à la clause IF GENERATE en testant le paramètre width. Notez que :

1. le ELSE n'existe pas (oubli de VHDL ?)  et qu'il faut refaire un 2ème IF.

2. l'instruction IF GENERATE a besoin obligatoirement d'une étiquette

use work.pack.all; -- paquetage où sont déclarés les composants CLA-multplier-- et WAL_multiplier

entity multiplier isgeneric(

width : positive :=8;);port(a : in signed(width-1 downto 0);b : in signed(width-1 downto 0);product : out (2*width-1 downto 0));end entity;-- architecture arc of multiplier is--begin-- CLA_gen : if width < 8 generate inst_cla : CLA_multiplier generic map (width) port map(a, b, product);--end generate CLA_gen;--WAL_gen : if width >= 8 generate inst_wal : WAL_multiplier generic map (width) port map(a, b, product); end generate WAL_gen;--end arc;--

L'exemple ci-contre fait appel à la clauseen testantle paramètre width

Notez que :1. le ELSE

n'existe pas (oubli de VHDL ?)faut refaire un 2ème

2. l'instruction a besoin obligatoirement d'uneétiquette

Exemple 2 : l'exemple classique de l'additionneur n bits... On utilise ici une boucle FOR GENERATE pour instancier automatiquement les différentes primitives ainsi que les noeuds les connectant entre elles. Notez qu'il n'est pas nécessaire de déclarer la variable de boucle mais que l'instruction FOR GENERATE nécessite une étiquette.

entity Nbit_adder is generic( SIZE = 4); port (

Page 30: cour vhdl

a,b : in unsigned(SIZE-1 downto 0); ci : in std_logic; sum : out unsigned(SIZE-1 downto 0); co : out std_logic);end entity;--component FA port(A,B,Cin : in std_logic; S, Cout : out std_logic);end component;--architecture arc of Nbit_adder is--signal c :unsigned(SIZE downto 0);;--begin--C(0) <= Cin;co <= C(SIZE);--G: for I in 0 to N-1 generate inst: FA port map(A(I), B(I), C(I), sum(I), C(I+1));end generate G;--end arc;

Back to  

LA CONFIGURATION

VHDL dispose d'un mécanisme appelé "configuration" permettant d'associer une instance de composant à un couple entité/architecture. La configuration est une unité de compilation à part, tout comme l'entité et l'architecture. Pour la plupart des outils , la configuration est optionnelle. Le lien composant/entité s'effectue généralement en imposant un nom de l'entité identique à celui du composant, et le lien entité/architecture s'effectue soit en considérant la dernière architecture compilée, soit l'outil impose une architecture unique.

La configuration est donc l'unité de compilation de plus haut niveau car elle permet l'élaboration de l'ensemble (l'édition de liens) pour pouvoir simuler. Son intérêt apparaît pour gérer des gros circuits où plusieurs architectures sont possibles pour une même entité. C'est la cas quend il existe des modèles d'abstraction différentes, ce qui est très utilisé pour les méthodes de conception "top down" . Par exemple une équipe peut avoir des modèles abstraits de tous les blocs de façon à accélérer les temps de simulation et travailler sur plusieurs architectures du bloc à concevoir.

Il existe plusieurs façons de configurer un projet :

configuration hiérarchique configuration à plat

Page 31: cour vhdl

configuration immédiate instanciation de configuration

Configuration hiérarchique

Pour chaque entité, une configuration est créée. Dans chaque configuration, la clause use configuration est utilisée pour les instances de composant de niveau inférieur.

configuration CF_AND2 of AND_2 is for arc end for;end configuration CF_AND2;

La configuration est vide car l'entité AND_2 n'a pas d'instances de composant. La configuration existe toutefois car tous les composants utilisés doivent avoir une configuration dans cette méthode.

configuration CF_AND3 of AND_3 is for arc for all : AND2 use configuration work.CF_AND2; end for; end for;end configuration CF_AND3;

Le composant AND2 est instancié dans AND_3. A chaque instance la configuration

                                                                                         

Pour les gros circuits, il est fortement recommandé d'utiliser ce type de configuration car c'est la plus simple à maintenir.

Configuration à plat

Elle peut être unique et indique les liens entité/architecture explicitement avec la clause use entity(architecture). Elle est utilisée pour des circuits simples car il n'est pas nécessaire d'avoir des fichiers de configuration au niveau hiérarchique inférieur.

configuration CF_AND3_APLAT of AND_3 is for arc for i1 : AND2

use entity work.AND2(a1); end for; for i2 : AND2

use entity work.AND2(a2); end for; end for;end configuration CF_AND3_APLAT;

Configuration immédiate

Page 32: cour vhdl

Les associations entité/architecture des composants peuvent être déclarés directement dans l'architecture avant le corps de l'architecture. Elle est réservée aux petits circuits pour des essais de différentes architectures.

architecture arc of TOP is for all : AND2 use configuration work.CF_AND2; end for; for inst_block1 : compo use entity work.ctr(arc); end for;begin I1 : AND2 port map (...); I2 : AND2 port map (...); inst_block1 : compo port map (...);end arc;

Instanciation de configuration

Dans ce cas , il n'est pas nécessaire de déclarer de composant et l'instanciation se fait en spécifiant le couple entité/architecture. La conception dans ce cas est nécessairement "bottom-up" et non "top-down" car il faut obligatoirement avoir concçu les entités appelées au niveau le plus haut.

architecture arc of TOP isbegin I1 : entity work.and2(arc1) port map (...); I2 : entity work.ctrl(arch) port map (...);end arc;

Cette méthode ne nécessite pas de configuration. Elle est la plus simple mais peut être aussi moins adaptée aux gros circuits du fait de la conception "bottom up" uniquement.

Back to Top

EXERCICES

Nous avons vu :

comment déclarer un composant comment instancier un composant comment instancier un composant générique comment les relier (en utilisant la clause port map et generic

map)

Faisons tout de suite des exemples !

Page 33: cour vhdl

Exercices:

1. Codez un additionneur générique de 2 nombres non signés sur n bits.  Afficher la réponse

library ieee;use ieee.std_logic_1164.all;use ieee.numeric_std.all;--entity GEN_ADD is generic ( n : postive :=8

); port ( A : in unsigned(n-1 downto 0); B : in unsigned(n-1 downto 0); S : out unsigned(n-1 downto 0) );end GEN_ADD;--architecture RTL of GEN_ADD is--begin--S <= A + B;--end RTL;----

Notez l'utilisation de la bibliothèque IEEE, permettant d'utiliser le type std_logic (paquetage std_logic_1164 et le sous type unsigned (paquetage numeric_std).

2. Codez un registre générique de n bits.   Afficher la réponse

library ieee;use ieee.std_logic_1164.all;use ieee.numeric_std.all;--entity GEN_REG is generic ( n : integer :=8 ); port ( CLK : in std_logic; NRST : in std_logic; EN : in std_logic; D : in unsigned(n-1 downto 0);

Notez l'utilisation de la bibliothèque IEEE, permettant d'utiliser le type std_logic (paquetage std_logic_1164 et le sous type unsigned (paquetage numeric_std).

Page 34: cour vhdl

Q : out unsigned(n-1 downto 0) );end GEN_REG;--architecture RTL of GEN_REG is--begin--SYNC : process(CLK,NRST) begin if NRST='0' then Q <= (others => '0'); elsif (CLK'event and CLK='1')then if en='1' then Q <= D; end if; end if; end process sync;--end rtl;--

3. Codez en VHDL structurel un accumulateur n bits à l'aide du registre générique et de l'additionneur générique. Afficher la réponse

library ieee;use ieee.std_logic_1164.all;use ieee.numeric_std.all;--entity ACCU is port ( CLK : in std_logic; NRST : in std_logic; EN : in std_logic; D : in unsigned(7 downto 0); Q : out unsigned(7 downto 0) );end ACCU;--architecture RTL of ACCU is--constant N : integer := 8; --default valuesignal Q_int : unsigned(7 downto 0);signal D_int : unsigned(7 downto 0);----begin--INST_REG : entity work.GEN_REG(RTL) generic map (N=>n) port map(CLK=>CLK,NRST=>NRST,EN=>EN,D=>D_int,Q=>Q_int);INST_ADD : entity work.GEN_ADD(RTL) generic map (N=>n) port map(A=>D,B=>Q_int,S=>D_int);Q <= Q_int;

Notez l'utilisation de la bibliothèque IEEE, permettant d'utiliser le type std_logic (paquetage std_logic_1164 et le sous type unsigned (paquetage numeric_std).

Page 35: cour vhdl

--end RTL;--

4. Ecrivez un testbench simple pour tester l'accumulateur par simulation.Afficher la réponse

--------------------------------------------------------------------------------- ---- FILE : ACCU_TEST.VHD ---- Related files : ACCU.VHD ---- ---- Author(s) : J-L DANGER ---- ---- Project : TUTORIEL METHODE ---- ---- ---- Description : testbench du composant accu ---- ---- Copyright GET-ENST 2004 ---- ----------------------------------------------------------------------------------- Modifications : -----------------------------------------------------------------------------------library ieee;use ieee.std_logic_1164.all;use ieee.numeric_std.all;--use std.textio.all;----use WORK.ACCU_PACK.ALL;--entity ACCU_TEST isend ACCU_TEST;----architecture ARCHI of ACCU_TEST is--constant N : integer :=8;signal CLK : std_logic;signal N_RESET : std_logic;

Page 36: cour vhdl

signal EN : std_logic;signal D : signed(N-1 downto 0);signal Q : signed(N-1 downto 0);file VECT : text open READ_MODE is "./simu/accu_test_in.dat";file EXP : text open READ_MODE is "./simu/accu_test_exp.dat";file RESULT : text open WRITE_MODE is "./simu/accu_test_out.dat";------begin------EN <= '1';------------------------------------------------------------------- Processus d'horloge---------------------------------------------------------------horloge :processbegin CLK <='1'; wait for 50 ns; CLK <= '0'; wait for 50 ns;end process horloge;------------------------------------------------------------------- Processus du RESET---------------------------------------------------------------RESET : processbegin N_RESET <= '0'; wait until CLK'event and CLK='0'; N_RESET <= '1'; wait;end process RESET;------------------------------------------------------------------- Processus de génération des données à partir d'un fichier---------------------------------------------------------------DATA :processvariable L1 : line;variable L2 : line;variable L3 : line;variable D_in : integer;variable D_exp : integer;variable D_out : integer;beginwrite(L3,string'(" temps entrée attendu resultat"));write(L3,LF);writeline(RESULT,L3); loop wait until CLK'event and CLK='0'; readline(VECT,L1); read(L1,D_in); readline(EXP,L2); read(L2,D_exp); D <= to_signed(D_in,N); write(L3,now,field=>10); write(L3,D_in,field=>8); write(L3,D_exp,field=>8);

Page 37: cour vhdl

write(L3,to_integer(Q),field=>9); if to_integer(Q) /= D_exp then write(L3,string'(" => erreur à cette ligne")); end if; writeline(RESULT,L3); assert (to_integer(Q)=D_exp) report "comparaison fausse" severity failure; assert (endfile(VECT)=FALSE) report "fin de simulation" severity failure; end loop;end process;------------------------------------------------------------------- instanciation de ACCU-----------------------------------------------------------------INST_ACCU : entity WORK.ACCU(RTL) port map (CLK=>CLK,NRST=>N_RESET,EN=>EN, D=>D,Q=>Q);--end ARCHI;

5. Compilez les circuits et simulez le tesbench avec ModelSim. Déboguez si nécessaire

 

Back to Top

EN RÉSUMÉ

On a vu dans ce chapitre comment déclarer, instancier et relier les composants entre eux.

L'objectif du prochain chapitre est de savoir comment décrire le contenu d'un composant, son fonctionnement

PRÉAMBULE

Page 38: cour vhdl

Objectifs

Passons maintenant aux descriptions comportementales. Dans ce type de descriptions, il y a plusieurs niveaux. 

Nous allons ici étudier les principales descriptions : 

celle au niveau des équations booléennes, appelée aussi parfois flot de données. Ce type de représentation modélise les circuits combinatoires, non pas en instanciant des portes, mais sous forme d'équations booléennes.

Pour les circuits séquentiels, il faudra faire appel à un niveau plus abstrait, appelé RTL.

Les objectifs de ce chapitre sont de comprendre :

Les différences entre instructions concurrentes et séquentielles. Les processus et les différences entre variables et signal. Les structures de contrôle utilisées dans les processus. Les affectations concurrentes des signaux, les raccourcis d'écriture. Les différents types de délais dans les affectations. Comment vérifier une propriété par les assertions. Les différents types de sous-programmes.

Plan du chapitre

Instructions concurrentes et séquentielles VHDL utilise aussi bien les 2 types pour coder le comportement d'un circuit. Quelle différence ?

Processus et synchronisation Comment démarrer un processus ?

Variables et signaux Comment utiliser ces 2 types d'objets dans un processus ?

Stuctures de contrôle Là où vhdl rejoint le C.

Affectations concurrentes Comment écrire une équation sans passer par un processus ?

Affectations et délais Pour modéliser le temps. Attention, piège.

Assertions Comment vérifier une propriété et envoyer un message associé en cours de simulation ?

Sous-programmes Comment créer des fonctions et des procédures ?

Page 39: cour vhdl

Fonctions de résolution Quelle valeur prend un signal affecté dans plusieurs processus ?

Résumé

Back to Top

INSTRUCTIONS CONCURRENTES ET SEQUENTIELLES

Comme tout langage de description de matériel, le VHDL décrit des structures par assemblage d'instructions concurrentes dont l'ordre d'écriture n'a aucune importance, contrairement aux instructions séquentielles qui sont exécutées les unes après les autres, comme c'est la cas du C.

VHDL offre cependant la possibilité d'utiliser des instructions séquentielles, plus naturelles pour l'homme, par le biais de processus process. Les processus peuvent avoir leurs propres variables locales variable . 

Les objets manipulés par les instructions concurrentes sont les signaux signal qui disposent chacun d'un échéancier de façon à effectuer une simulation d'instructions concurrentes sur une machine séquentielle (l'ordinateur).

Il existe 3 principales instructions concurrentes :

1. Les processus, qui offrent la possibilité d'utiliser des instructions séquentielles.

2. Les instanciations de composants (étudiées aux chapitre précédent à propos du VHDL structurel)

3. les affectations concurrentes de signaux, qui peuvent être conditionnelles

Il existe également les assertions et les procédures concurrentes qui ont la même syntaxe que les assertions et procédures séquentielles (étudiées en fin de ce chapitre) mais utilisées en dehors  des processus.

Back to Top

PROCESSUS ET SYNCHRONISATION

 Les différentes tâches d'un programme vhdl s'exécutent en parallèle les unes des autres. Ces tâches sont appelées processus. Toutes les instructions concurrentes sont en fait des processus mais la déclaration

Page 40: cour vhdl

explicite de processus par le mot clé process permet de construire sa propre instruction par le biais d'instruction séquentielles internes au processus. Un processus peut avoir des variables locales. Le fonctionnement du processus est régi par les règles suivantes :

1. Un processus est une boucle infinie , lorsqu'il arrive à la fin du code, il reprend automatiquement au début 

2. Un processus doit être sensible des points d'arrêt de façon à le synchroniser.  La synchronisation est donc indiquée par un point d'arrêt qui est  évènement particulier. Il existe 2 types de points d'arrêts :

o Le processus est associé à une "liste de sensibilité" qui contient une liste de signaux qui réveillent le processus lors d'un changement d'un des signaux. Sa syntaxe est process(liste de signaux)

o Le processus a des instructions d'arrêt wait dans sa description interne. Le wait est sensible soit à un signal soit à un temps physique

3. Les variables sont internes au processus et sont affectées immédiatement, contrairement aux signaux qui eux ne sont pas affectés directement mais par le biais de leur échéancier qui est mis à jour en fin de processus avec la nouvelle valeur et le temps d'affectation qui correspond à un delta-cycle après le signal ayant réveillé le processus.

Synchronisation des processus par WAITL'instruction WAIT permet de mettre des points d'arrêt dans le corps du processus. La syntaxe de l'instruction est la suivante :wait [on S1,S2,...] [until CONDITION] [for DUREE] où

S1 et S2 sont des signaux, CONDITION est une expression générant un booléen, et DUREE est le temps physique d'attente.

L'instruction WAIT n'est pas synthétisable avec la condition de durée. Elle est très utile pour les testbench pour générer précisément des formes de vecteurs d'entrée.L'exemple suivant génère une trame de 10 impulsions espacées de 100 microsecondes.

trame : process -- le processus peut avoir une étiquette, ici "trame"

-- il n'y a pas de liste de sensibilité donc il faut des "wait"

pulse <= '0'; -- pulse est à 0 en début de trame

for i in 0 to 9 loop -- on génère 10 impulsions larges de 2 périodes d'horloge

wait until clk'event and clk='1';

Page 41: cour vhdl

pulse <= '1';

wait until clk'event and clk='1'

pulse <= '0';

end loop;

wait for 100 us; -- après 100 us on reprend le process donc pulse va repasser à 0

end process;

Exercice :

Ecrivez un processus permettant de générer un train d'impulsions toutes les microsecondes : pas d'impulsion, puis une impulsions de100 ns puis une impulsions de 200ns, jusqu'à 1 microseconde comme le montre la figure ci-dessous.

Afficher la réponse

Synchronisation des processus par liste de sensibilité

La liste des signaux réveillant le processus est indiquée dans la liste de sensibilité suivant cette syntaxe : process(liste de sensibilité). Cette  méthode

est tout à fait équivalente à celle consistant à utiliser un wait on liste à la

fin du corps du processus. L' exemple suivant permet de coder la logique combinatoire.

process(x,y)

begin

if x='1' then

z<=y;

Page 42: cour vhdl

else

z<='0';

end if;

end process;

--

De quelle fonction s'agit-il ? Afficher la réponse

Notez la présence dans la liste de sensibilité des entrées uniquement.

Attention un processus correspondra à de la logique combinatoire seulement si :

 la liste de sensibilité contient TOUTES les entrées, sinon la fonctionnalité n'est pas respectée car l'entrée omise  ne réveille pas le processus

 Il faut traiter TOUS les cas dans le chemin de contrôle, sinon il y a implicitement mémorisation de la sortie pour les cas non traités

Si ces règles ne sont pas respectées, le processus est séquentiel.

Exercices :

Que se passe t'il si y est omis de la liste de sensibilité ? Afficher la réponse

Que se passe t'il si la ligne else z <='0' est omise ? Afficher la réponse

Codez la fonction multiplexeur à 2 entrées :o avec les opérateurs logiques Afficher la réponse

o avec un processus combinatoire Afficher la réponse

Pour fiabiliser le processus séquentiel , nous avons vu qu'il était fortement recommandé de fonctionner en mode synchrone, c'est à dire avec l'utiliation d'un horloge qui échantillonne le calcul. Autrement dit un processus séquentiel synchrone a une liste de sensibilité qui se réduit simplement à l'horloge. Les signaux codés dans ce processus seront donc des sorties de bascule D. S'il est impératif d'initialiser les bascules (cas des machines à états), le reset asynchrone peut être employé. Dans ce cas il faut le rajouter dans la liste de sensibilité car il est prioritaire

Page 43: cour vhdl

sur l'horloge quand il est actif. La syntaxe générique d'un bloc de logique séquentiel est donc la suivante:

process(clk, n_reset)

--

begin

if n_reset='0' then

sortie <= (others=>'0'); -- tous les bits de sortie sont initialisés à 0 par le reset

elsif clk'event and clk='1' then

liste d'instructions codant "sortie"

end if;

end process;

--

Exercice : 

Donnez une description d'une bascule D possédant un reset synchrone (qui remet la bascule à zéro s'il est à l'état bas lors d'un front montant de l'horloge) [Afficher la réponse]

Back to Top

SIGNAUX VS VARIABLES

Les signaux sont équivalents à des variables globales assurant les communications entre processus. Ils sont équivalents à des équipotentielles si le code est synthétisable. Les signaux ne sont pas mis à jour tout de suite mais à la fin du processus avec un delta-cycle de retard par rapport au signal ayant déclenché le processus. Les signaux sont

Page 44: cour vhdl

affectés avec l'instruction <= qui se dit aussi "reçoit"  plutôt que "égal" car le signal va recevoir cette valeur en fin de processus avec un delta-cycle de retard.   

Les variables sont locales à chaque processus et sont mises à jour immédiatement.  Elles sont très utiles pour effectuer un codage séquentiel classique comme avec le langage C. Les variables sont déclarées juste avant le corps du processus et sont affectées avec l'instruction d'affectation immédiate := de façon à bien ne pas confondre avec l'instruction <= "reçoit" pour les signaux. Les variables gardent leur valeur quand le processus est terminé.

Dans l'exemple suivant, a,b,c sont des signaux et x une variable. Enfin de processus, a et b vont prendre la valeur a+1 après un delta-cycle alors que c prendre la valeur a après un delta-cycle.

process (a)

variable x : std_logic;

begin

x := a+1;

a <= a+1;

b <= x;

c <= a;

end if;

end process;

--

Exercice: Ecrivez un processus qui effectue la multiplication de 2 signaux a et b. Si le résultat de la multiplication dépasse le seuil c alors la sortie prend la valeur c. Afficher la réponse]

Page 45: cour vhdl

Back to Top

STRUCTURES DE CONTRÔLE

Dans les processus, il est possible d'utiliser des structures de contrôle similaires à celles du C :

les instructions de test (if, case) les boucles (loop, for loop, while loop)

Instruction IF   L' instructions IF reposent sur le test d'une  condition qui génère un booléen. Si celui ci est "TRUE"  l'instruction qui suit est exécutée

Syntaxe du IF:

if condition1 then instruction;

[elsif condition2 then instruction;]

...

[else instruction;]

end if;

Pour coder un processus combinatoire, l'utilisation du ELSE est obligatoire de façon à traiter toutes les combinaisons (sinon il y a mémorisation donc c'est da la logqiue séquentielle)

Instruction CASE L' instructions CASE reposent sur le test d'un signal ou d'une variable. En fonction de la valeur, une instruction spécifique est exécutée

Syntaxe du CASE :

case A is

Page 46: cour vhdl

when -7 => B := 10;

C :='0'

when -3 => B :=15;

C :='0';

when others => B :=2;

C :='1';

end case;

Pour coder un processus combinatoire, l'utilisation du when others est obligatoire de façon à traiter toutes les combinaisons (sinon il y a mémorisation donc c'est da la logqiue séquentielle)

Instruction de boucle

L1: for i in 0 to 10 loop

...

L2: loop

...

L3 : while non _stop_L3 loop

...

exit L2 when stop_L2;

next L3 when suite_L3;

Page 47: cour vhdl

if stop_L1 then

exit L1;

end if;

end loop L3;

end loop L2;

end loop L1;

Il faut noter :

1. Les indices de boucles (ici i pour L1) ne sont pas à déclarer2. Les étiquettes de boucles (L1,L2,L3) sont optionnelles3. L'excution peut être altérée avec les clauses next et exit

 Exemple : la boucle loop de cet exemple permet de compter le nombre de bits à 1 d'un signal.

library ieee;use ieee.std_logic_1164.all;use ieee.numeric_std.all;--entity nb_un is

port(a : in unsigned(7 downto 0);s : out unsigned(3 downto 0)

);end entity;--architecture rtl of nb_un isbeginprocess(a)variable x : unsigned (3 downto 0);beginx:= (others => '0');for i in 0 to 7 loop

x := x + ('0' & a(i));end loop;s <= x;end process;end rtl;

Le paquetage IEEE.numeric.std permet d'avoir accès aux fonction arithmétiques sur les types vecteurs non-signés unsigned ou signés signed.

Remarquez que l'addition se fait en concaténant chaque bit avec '0' car l'opérateur + du paquetage n'opère pas sur un

bit simple.

Page 48: cour vhdl

 Exercice : Ecrivez un processus calculant la parité d'un signal sur n bits.

Afficher la réponse]

 

Back to Top

AFFECTATIONS CONCURRENTES DE SIGNAUX

Ces affectations sont des instructions concurrentes au même titre que les processus et les instanciations de composants. Le codage comportemental d'une architecture repose sur l'utilisation  de ces 3 types d'instructions concurrentes qui peuvent apparaître dans n'importe quel ordre. Une instruction concurrente est équivalente à un processus et correspond à un raccourci d'écriture pour éviter le verbosité du processus.Exemple :

Architecture avec processus Architecture avec affectation concurrente

architecture arc of adder isbeginprocess(A,B,Cin)begin S <= A xor B xor Cin;

architecture arc of adder isbegin S <= A xor B xor Cin;end arc;

Affectation concurrente conditionnelle

Il existe également des instruction concurrentes conditionnelles  permettant d'effectuer des raccourcis d'écriture pour remplacer des processus simples à base de  IF et CASE

Exemples :

Architecture avec processus Architecture avec affectation concurrente

architecture arc of adder isbeginprocess(A,B,Cin) begin if A = '0' then S <= B xor Cin; elsif B = '0' then S <= not(Cin);

architecture arc of adder isbeginS <= B xor Cin when A = '0' else not Cin when B = '0' else Cin;

Page 49: cour vhdl

else S <= Cin; end if;end process;end arc;

architecture arc of MUX isbeginprocess(SEL)begin case SEL is when 0 => sortie <= A; when 1 => sortie <= B; when 2 => sortie <= C; when others => sortie <= D; end case;end process;end arc;

architecture arc of MUX isbeginwith SEL select sortie <= A when 0, B when 1, C when 2, D when others;end arc;

Pour les fonctions combinatoires, il est souvent plus prudent d'utiliser les affectations concurrentes plutôt que les processus où il est possible d'omettre un signal d'entrée dans la liste de sensibilité.Il faut toutefois avoir un chemin de contrôle exhaustif et toujours avoir la clause else ou when others pour ne rien omettre.

Back to Top

AFFECTATIONS ET DÉLAIS

VHDL permet de spécifier des délais dans les affectations. 

Il existe deux types d'affectations avec délai :

affectation avec délai inertiel :  x <= 3 after 2 ns; ou plus explicitement x <= inertial 3 after 2 ns;

affectation avec délai de transport : x = transport 3 after 2 ns;

Le type inertiel permet de "filtrer" les variations de X trop courtes par rapport au délai de la transaction. Par exemple si x est à 1 pendant 1ns, l'affectation x <= 3 after 2 ns; ne changera pas la forme d'onde de x qui restera à 0.

Contrairement au mode inertiel , le type transport n'opère pas de  "réjection des parasites". Il respecte les temps de propagation mais est certainement moins réaliste que le mode inertiel.

Page 50: cour vhdl

 

Back to Top

ASSERTIONS

Les assertions permettent de vérifier une propriété et générer un message d'erreur si cette propriété n'est pas vérifiée.La syntaxe est la suivante :assert CONDITION[report MESSAGE][severity NIVEAU];où CONDITION =  condition générant un booleén. Cette condition doit être vraie

pour que rien ne se passeMESSAGE = chaîne de caractères renseignant le fait que la condition n'a pas été

remplieNIVEAU = niveau d'erreur. Ilen existe 4 prédifinis : NOTE,WARNING, ERROR, FAILURE

Les assertions peuvent font aprtie du domaine séquentiel (dans un processus) ou du domaine concurrent

exemple :

assert NOW < 10 ms -- NOW est une fonction renvoyant le temps physique    report "Fin de simulation"    severity failure

Back to Top

SOUS-PROGRAMMES

IL existe 2 types de sous-programmes:

1. Les fonctions2. Les procédures

Les sous-programmes font partie du domaine séquentiel et ont la même utilité

Page 51: cour vhdl

que pour les autres langages de programmation : regrouper les instructions qu'on utilise souvent. Les procédures font peuvent être appelées aussi bien dans le domaine séquentiel que concurrent La différence entre fonctions et procédures sont les suivantes:

fonction procédure

paramètres d'appels

non modifiable (entrées) les sorties sont modifiables

valeur retournée

oui non

syntaxe

function F(A: unsigned(3 downto 0))return std_logic is...begin...end function F;

procedure P(A: in unsigned(3 downto 0))            S : out std_logic ) is...begin...end procedure P;

  Par rapport à la fonction, La procédure permet d'avoir plusieurs sorties, mais à condition de déclarer les entrées et les sorties comme dans une entité ou composant.   Exemples :

Fonction de calcul de minimum et maximum en procédure.

procedure MinMax( a,b : in unigned (7 downto 0); min : out unsigned(7 downto 0);

max : out unsigned(7 downto 0)) isbegin if (a < b) then

min <= a;max <= b;

elsemin <= b;max <= a;

end if;end procedure MinMax;

Page 52: cour vhdl

MinMax(x, y, z, t);

Il faut 2 fonctions min et max pour avoir léquivalent en fonction. Voici l'exemple de min :

Exercices :

function min (a,b : unsigned(7 downto 0) return unsigned(7 downto 0) is  varaiable min : unsigned(7 downto0); beginif (a < b) then

min := a;else

min := b;end if;return min;endfunction

...

z := min(x, y);

Trouvez le code de la fonction comptant le nombre de bits à 1 dans un nombre de 8 bits.

Back to Top

EN RÉSUMÉ

Ce chapitre vous a présenté les façons de décrire la fonctionnalité des processus, c'est-à-dire leur description comportementale.

Les descriptions comportementales ne s'opposent pas aux description structurelles. Elle se complètent : on adopte une description structurelle pour séparer un bloc en sous-systèmes simples, qui eux seront décrits comportementalement.

pour de la logique combinatoire ayant une expression simple : affectation concurrente

Page 53: cour vhdl

pour le la logique séquentielle, ou combinatoire ayant une expression complexe :  processus 

Les processus s'exécutent en parallèle les uns des autres, mais leur déroulement interne est séquentiel. Ils peuvent utiliser la plupart des structures de contrôle du C.

Les processus always s'exécutent en boucle, et nécessitent donc un point d'arrêt pour que le temps puisse s'écouler. Il en existe trois :

wait  listes de sensibilité

L'objectif du prochain chapitre est de faire la différence entre les constructions synthétisables, et celles spécifiques à la simulation..

PRÉAMBULE

Objectifs

Plutôt que de long discours, voici quelques exemples de modules écrits en VHDL. Chaque exemple introduit un nouveau type de construction / type de donnée.

Pour chaque exemple, passez la souris sur le code pour avoir des explications sur la façon dont il est construit.

Plan du chapitre

combinatoire : AND3 additionneur complet 1 bit additionneur complet 4 bit bascule D compteur 8 bits registre à décalage simulation

Page 54: cour vhdl

Résumé

Back to Top

AND3

On va voir

structure d'un module simple affectations concurrentes 

Commençons par le plus simple des modules ou presque : une porte combinatoire AND à trois entrées. En VHDL, les modules sont appelés "entités" (mot-clef entity). Voici une description possible d'une porte AND à 3 entrées.

Passez la souris sur les différents éléments du code pour avoir des explications sur la signification de chaque instruction

ADDITIONNEUR COMPLET 1 BIT

Nous allons voir

les bibliothèques  l'utilisation de signaux intermédiaires La concaténation de signaux pour créer un bus 

Voici une description possible d'un additionneur complet 1 bit.

Rappel : un additionneur complet 1 bit a trois entrées (a, b, et cin la retenue entrante), et deux sorties (le bit de somme s et le bit de retenue sortante cout).

Page 55: cour vhdl
Page 56: cour vhdl

ADDITIONNEUR 4 BITS

On va voir

comment instancier un composant (ou comment faire du schéma en textuel) 

comment relier des composants entre eux 

VHDL, comme tous les HDL, permet de décrire les système sous forme structurelle. C'est-à-dire, au lieu de décrire un gros système dans un seul gros fichier, de le séparer en sous-systèmes (sous-modules), eux-mêmes subdivisés en sous-modules, jusqu'à obtenir des modules facilement compréhensibles.

Nous allons ici décrire un additionneur 4 bits en assemblant des additionneurs 1 bit. On aurait aussi pu décrire la fonctionnalité de l'additionneur 4 bits (par opposition à sa structure), cela sera vu à la fin de cet exemple-ci.

On suppose ici que le code de l'additionneur 1 bit vu précédement est disponible dans un fichier à part.

Page 57: cour vhdl