Professional Documents
Culture Documents
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
Exemples réels
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
vhdl comportemental
Synthèse et simulation
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.
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.
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 plus de détails,
on pourra se référer à une comparaison objective de VHDL et Verilog.
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).
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
Une unité de compilation doit être écrite dans le même fichier et un même fichier
peut contenir plusieurs unités de compilation.
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
Casse
VHDL 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
Identificateurs
Ce sont les noms de variables, de signaux, de fonctions, ...
Litéraux
Ce sont des valeurs explicites :
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 (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 :
L'entité précise :
le nom du circuit
Les ports d'entrée-sortie :
o Leur nom
o 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
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 :
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 ).
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 .
B,Z => Cin, M => Les ports sont des signaux implicites dont le sens doit être
Cout); respecté. Le compilateur VHDL aurait mis une erreur si
-- dans le corps de l'architecture s'était trouvé l'instruction :
end arc3;
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 paquetage
2. Le corps du paquetage
Le contenu de la déclaration du paquetage est visible depuis l'extérieur. alors 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.
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'architecture
o 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 chapitre
Le prochain chapitre traite des types et des opérateurs de base en VHDL
PRÉAMBULE
Objectifs
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.
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 .
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 :
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);
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 :
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.
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é :
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
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 :
Notation d'agrégat
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.
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
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 fichier
end 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;
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 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.
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
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.
exemples :
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.
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
opérateurs notes
d'opérations
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
** :
exponentiation
Divers **, abs, & abs : valeur
absolue
& : concaténation
Back to Top
EN RÉSUMÉ
On a vu:
Prochain chapitre
le VHDL structurel.
PRÉAMBULE
Objectifs
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 :
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
Instanciation :
Exemple:
entity AND_3 is Dans cet exemple , 2 instances de c
port( créer une porte ET à 3
e1 : in bit; entrées.
e2 : in bit;
e3 : in bit;
s : out bit L'association des ports du composan
); à l'aide de la
end entity; clause port map.
--
architecture arc of AND_3 is
-- La syntaxe des associations est soi
signal z : bit;
component and2 1. par nom où chaque broche du co
port ( cas de inst_1
a : bit; 2. positionnelle où l'ordre des s
b : bit; broches : cas de inst_2
s : bit);
end component;
--
begin
inst1 : and2 port map (a=>e1,
b=>e2 , s=>z);
inst2 : and2 port map (z, e3, s);
end arc
Back
to
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.
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 :
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.
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- L'exemple ci-co
multplier en testant
-- et WAL_multiplier le paramètre wi
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.
configuration hiérarchique
configuration à plat
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 La configuration est vide car l'entité AND_2 n'a pas d'in
is
for arc La configuration existe toutefois car tous les composant
end for; cette méthode.
end configuration CF_AND2;
configuration CF_AND3 of AND_3 Le composant AND2 est instancié dans AND_3. A chaq
is
for arc utilisée.
for all : AND2
use configuration
work.CF_AND2;
end for;
end for;
end configuration CF_AND3;
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 immédiate
Instanciation de configuration
EXERCICES
Nous avons vu :
Exercices:
--------------------------------------------------------------------------
-----
--
--
-- 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 is
end ACCU_TEST;
--
--
architecture ARCHI of ACCU_TEST is
--
constant N : integer :=8;
signal CLK : std_logic;
signal N_RESET : std_logic;
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 :process
begin
CLK <='1';
wait for 50 ns;
CLK <= '0';
wait for 50 ns;
end process horloge;
--
---------------------------------------------------------------
-- Processus du RESET
---------------------------------------------------------------
RESET : process
begin
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 :process
variable L1 : line;
variable L2 : line;
variable L3 : line;
variable D_in : integer;
variable D_exp : integer;
variable D_out : integer;
begin
write(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);
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;
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
Objectifs
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.
Plan du chapitre
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 ?
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.
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 é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 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.
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.
end loop;
wait for 100 us; -- après 100 us on reprend le process donc pulse
va repasser à 0
end process;
Exercice :
Afficher la réponse
process(x,y)
begin
if x='1' then
z<=y;
else
z<='0';
end if;
end process;
--
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
Exercices :
Que se passe t'il si la ligne else z <='0' est omise ? Afficher la réponse
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
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 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]
Back to Top
STRUCTURES DE CONTRÔLE
Dans les processus, il est possible d'utiliser des structures de contrôle similaires à
celles du C :
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:
...
[else instruction;]
end if;
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
C :='0'
C :='0';
C :='1';
end case;
Instruction de boucle
...
L2: loop
...
...
if stop_L1 then
exit L1;
end if;
Il faut noter :
Afficher la réponse]
Back to Top
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.
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.
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 passe
MESSAGE = chaîne de caractères renseignant le fait que la condition n'a pas été remplie
NIVEAU = niveau d'erreur. Ilen existe 4 prédifinis : NOTE,WARNING, ERROR,
FAILURE
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 fonctions
2. Les procédures
Les sous-programmes font partie du domaine séquentiel et ont la même utilité 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
non modifiable (entrées) les sorties sont modifiables
d'appels
valeur
oui non
retournée
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 :
end if;
end procedure MinMax;
MinMax(x, y, z, t);
Il faut 2 fonctions min et max pour avoir léquivalent en fonction. Voici l'exemple
de min :
Exercices :
...
z := min(x, y);
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 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.
wait
listes de sensibilité
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
Résumé
Back to Top
AND3
On va voir
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
les bibliothèques
l'utilisation de signaux intermédiaires
La concaténation de signaux pour créer un bus
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.