Le LANGAGE VHDL et les
CPLD
Le langage VHDL a été créé pour décrire des systèmes numérisés destinés à une implantation dans des circuits logiques programmables (PLD, FPGA, ASIC). Il remplace la saisie de schéma traditionnelle. La plupart des outils de développement autorise les 2 types de saisie.
Le langage VHDL est en principe standardisé. Chaque outil de développement dispose cependant de bibliothèques spécifiques.
Les exemples fournis dans ce cours ont été testés et simulés avec l’outil ALTERA MaxPlus+2.
Pour développer une application de logique programmable, il faudra
suivre la démarche ci-dessous :
- L’étape de vérification permet de valider la syntaxe
du programme. La " netlist " est un fichier contenant la description de
l’application sous forme d’équations logiques.
- Lors de l’étape de simulation fonctionnelle, on valide l’application,
indépendamment de l’architecture et des temps de propagation du
futur circuit cible.
- L’étape de routage génère les informations permettant
d’intégrer l’application dans le circuit choisi. Une " rétro
annotation " est effectuée dans la " netlist " : les temps de propagation
du composant cible y sont pris en compte.
- Lors de la simulation temporelle, on peut évaluer les performances de l’application générée.
1- Un exemple simple
Le texte ci-dessous décrit un circuit nommé " ex1 ", dont le schéma est le suivant :
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
ENTITY ex1 IS -- commentaires
PORT ( -- déclaration des entrées/sorties physiques
a, b, c : IN STD_LOGIC ;
s1, s2 : OUT STD_LOGIC -- pas de point virgule
) ;
END ex1 ;
ARCHITECTURE numero1 OF ex1 IS -- description de l’application
BEGIN
s1 <= a AND b ;
s2 <= (NOT a) OR (a AND b AND c) ;
END numero1 ;
Conclusion:
- Les 2 instructions s1 <= … et s2 <= ….. sont " concurrentes " : l’ordre dans lequel elles sont écrites n’a pas d’importance, puisqu’au final, il s’agit d’associer des portes logiques. On dit que VHDL est un langage à exécution parallèle. Le terme " exécution " n’est d’ailleurs pas très bien choisi : ici, contrairement à un programme écrit en PASCAL ou en C, rien ne sera jamais exécuté. Il faudra toujours garder ceci à l’esprit chaque fois qu’on écrira un texte VHDL.
- VHDL ne distingue pas les majuscules des minuscules. Dans ce cours, les mots réservés du langage seront écrits en majuscules.
- Les bibliothèques déclarées au départ permettent d’utiliser les types " STD-LOGIC " définis depuis 1993.
- " l’ENTITY " est la boîte avec ses entrées et ses sorties physiques. " L’architecture " contient la description du fonctionnement de la boîte et possède son propre nom.
- Il existe une priorité entre opérateurs. Le plus simple est d’utiliser des parenthèses.
- Les autres opérateurs sont : XOR (ou exclusif), NAND, NOR,
& (concaténation), + (addition), - (soustraction), * (multiplication),
/ (division).
2- Description structurelle ou comportementale
On pourrait décrire l’exemple précédent sous la forme suivante :
ARCHITECTURE numero2 OF ex1 IS
BEGIN
s1 <= ‘1’ WHEN (a=’1’ AND b=’1’ ) ELSE ‘0’ ;
s2 <= ‘1’ WHEN (( a=’0’) OR (a=’1’ AND b=’1’ AND c=’1’)) ELSE ‘0’ ;
END numero2 ;
Conclusion:
- numéro1 est une description structurelle :elle est très proche d’une saisie de schéma.
- numéro2 est une description comportementale. Le schéma logique équivalent ne se déduit pas immédiatement.
- En logique combinatoire, il faut TOUJOURS prévoir toutes les
lignes de la table de vérité (ici, il ne faut pas omettre
ELSE). Sinon, le compilateur VHDL génèrera une fonction séquentielle
de mémorisation (on peut le vérifier en omettant le " ELSE
" de l’exemple précédent).
Exemple: multiplexeur:
![]() |
LIBRARY ieee;
USE ieee.std_logic_1164.all; USE ieee.std_logic_arith.all; ENTITY ex1 IS PORT ( e0, e1, c :IN STD_LOGIC ; s : OUT STD_LOGIC ) ; END ex2 ; ARCHITECTURE archi OF ex2 IS BEGIN s <= e0 WHEN c = ‘0’ ELSE e1; END archi; |
Les parenthèses sont inutiles ici, le compilateur repère
les mots réservés.
3- Notion de signal
Un signal est un STD_LOGIC ou un bus interne, permettant un calcul intermédiaire.
On reprend ici le premier exemple :
![]() |
ARCHITECTURE numero3 OF ex1 IS
SIGNAL x : STD_LOGIC ; BEGIN s1 <= a AND b ; x <= a AND b AND c ; s2 <= (NOT a) OR x ; END numero3 ; |
4- Bus et nombres, opérateurs de test, opérateurs
arithmétiques
Exemple:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
ENTITY combi1 IS
PORT (
a :IN STD_LOGIC_VECTOR(3 DOWNTO 0); -- bus 4 fils
b :IN STD_LOGIC_VECTOR(3 DOWNTO 0);
S : OUT STD_LOGIC_VECTOR(11 DOWNTO 0); -- bus 12 fils
T : OUT STD_LOGIC_VECTOR(7 DOWNTO 0) -- bus 8 fils
);
END combi1;
ARCHITECTURE archi OF combi1 IS
ALIAS op1:STD_LOGIC_VECTOR (3 DOWNTO 0) IS S(3 DOWNTO 0);
ALIAS op2:STD_LOGIC_VECTOR (3 DOWNTO 0) IS S(7 DOWNTO 4);
BEGIN
op1 <= a AND b;
op2 <= a OR "1010";
T <= a & b; -- concatenation
S(8) <= '1' WHEN a > b ELSE '0';
S(9) <= '1' WHEN a = "0000" ELSE '0';
S(10) <= '1' WHEN a = "0011" ELSE '0';
S(11) <='1' WHEN a<= "1001" ELSE '0';
END archi;
Conclusion:
- Les types " STD_LOGIC " et " STD_LOGIC_VECTOR " sont utilisés pour effectuer des opérations logiques.
- Via la déclaration " ALIAS ", on effectue des calculs sur une partie des bus.
- On peut accéder aux bus bit par bit.
- L’opérateur " DIFFERENT DE " s’écrit /=
- 3 DOWNTO 0 peut être remplacé par 0 TO 3.
Exemple:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
ENTITY combi2 IS
PORT (
a :IN INTEGER RANGE 0 TO 15; -- bus 4 fils
b :IN INTEGER RANGE 0 TO 15;
U : OUT INTEGER RANGE 0 TO 15;
Y : OUT STD_LOGIC_VECTOR(2 DOWNTO 0); -- bus 3 fils
T : OUT INTEGER RANGE 0 TO 31 -- bus 5 fils
);
END combi2;
ARCHITECTURE archi OF combi2 IS
BEGIN
U <= a - 4;
T<= a + b;
Y(2) <= '1' WHEN a<=12 ELSE '0'; -- a exprimé en base 10
Y(1) <= '1' WHEN a > b ELSE '0';
Y(0)<= '1' WHEN a = 16#a# ELSE '0'; -- a exprimé en base 16
END archi;
Conclusion:
- Les entiers sont utilisés pour effectuer des opérations arithmétiques.
- Chez ALTERA, seules les multiplications ou divisions par une puissance de 2 sont autorisées.
- Les tests possibles sont les mêmes qu’avec les " STD_LOGIC "
et les " STD_LOGIC_VECTOR ".
5- IF … ELSE - Notion de process
Exemple: multiplexeur 1 voie parmi 4:
![]() |
LIBRARY ieee;
USE ieee.std_logic_1164.all; USE ieee.std_logic_arith.all; ENTITY combi3 IS PORT ( c :IN INTEGER RANGE 0 TO 3; e : IN STD_LOGIC_VECTOR(3 DOWNTO 0); s : OUT STD_LOGIC ); ARCHITECTURE archi OF combi3 IS BEGIN PROCESS(c) BEGIN IF (c = 0) THEN s<= e(0); ELSIF (c = 1) THEN s<= e(1); ELSIF (c = 2) THEN s<= e(2); ELSE s<= e(3); END IF; END PROCESS; END archi; |
Conclusion:
- La notion de PROCESS sera précisée un peu plus tard.
- Plusieurs instructions peuvent être écrites entre THEN et ELSE ou ELSIF.
- Comme vu précédemment, il faut envisager tous les cas possibles, sinon il y aura génération d’une fonction registre.
- La liste de signaux inscrits entre parenthèses après le mot PROCESS se nomme la liste des sensibilités. Elle contient tous les signaux dont un changement d’état influe sur les signaux calculés dans le PROCESS.
- On peut effectuer un test sur plusieurs conditions :
PROCESS ( a, b)
BEGIN
IF (a = ‘1’ AND b = ‘0’) THEN ………
- Les signaux testés peuvent être
- des INTEGER par exemple IF a = 3
- des STD_LOGIC par exemple IF a = ‘0’
- des STD_LOGIC_VECTOR par exemple IF a = " 00100001 "
- On peut ajouter, dans le test, autant de parenthèses que nécessaire à la compréhension et à la lisibilité.
6- CASE
Le même exemple:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
ENTITY combi4 IS
PORT (
c :IN INTEGER RANGE 0 TO 3;
e : IN STD_LOGIC_VECTOR(3 DOWNTO 0);
S : OUT STD_LOGIC
);
END combi4;
ARCHITECTURE archi OF combi4 IS
BEGIN
PROCESS(c)
BEGIN
CASE c IS
WHEN 0 => s<= e(0);
WHEN 1 => s<= e(1);
WHEN 2 => s<= e(2);
WHEN 3 => s<= e(3);
END CASE;
END PROCESS;
END archi;
Conclusion:
- Comme vu précédemment, il faut envisager tous les cas possibles, sinon il y aura génération d’une fonction registre.
- Si un cas n’est pas listé, on utilise WHEN OTHERS => ……
- Les tests possibles sont les mêmes qu’avec IF
- On peut écrire autant d’instructions que nécessaires entre => et WHEN.
- On peut au sein d’un CASE introduire un IF ou inversement :
Exemple: multiplexeur une voie parmi 4 avec entrée de validation:
![]() |
LIBRARY ieee;
USE ieee.std_logic_1164.all; USE ieee.std_logic_arith.all; ENTITY combi5 IS PORT ( val : IN STD_LOGIC; c :IN INTEGER RANGE 0 TO 3; e : IN STD_LOGIC_VECTOR(3 DOWNTO 0); s : OUT STD_LOGIC ); END combi5; ARCHITECTURE archi OF combi5 IS BEGIN PROCESS(c, val) BEGIN IF ( val = '0' ) THEN s<='0'; ELSE CASE c IS WHEN 0 => s<= e(0); WHEN 1 => s<= e(1); WHEN 2 => s<= e(2); WHEN 3 => s<= e(3); END CASE; END IF; END PROCESS; END archi; |
7- Boucle et variable de boucle
On peut effectuer une itération via une instruction de boucle et un compteur de boucle. La variable de boucle est purement virtuelle, elle ne correspond à rien de physique dans le futur circuit et ne doit pas être déclarée.
Exemple: codage de données:
Le cahier des charges est le suivant :
s0 = a0
pour i>0 Si = ai . ai-1 + /ai
. /ai-1
|
LIBRARY ieee;
USE ieee.std_logic_1164.all; USE ieee.std_logic_arith.all; ENTITY combi6 IS PORT ( a: IN STD_LOGIC_VECTOR(3 DOWNTO 0); s : OUT STD_LOGIC_VECTOR(3 DOWNTO 0) ); END combi6; ARCHITECTURE archi OF combi6 IS BEGIN PROCESS BEGIN s(0) <= a(0); FOR i IN 1 TO 3 LOOP S(i)<= (a(i) AND a(i-1)) OR ( NOT a(i) AND NOT a(i-1)); END LOOP; END PROCESS; END archi; |
8- Notion de variable
On peut utiliser une variable (en générale entière), pour effectuer des calculs intermédiaires. Cette variable ne correspond à rien de physique. Elle est utilisée par le compilateur pour synthétiser la logique de l’application.
Exemple: un autre codage de données:
Le cahier des charges est le suivant : le nombre S en sortie indique, en binaire, le nombre de signaux d’entrée à 1.
Si a = 1001 alors S = 010
Si a = 1100 alors S = 010
Si a = 1111 alors S = 100
|
LIBRARY ieee;
USE ieee.std_logic_1164.all; USE ieee.std_logic_arith.all; ENTITY combi7 IS PORT ( a: IN STD_LOGIC_VECTOR(3 DOWNTO 0); S : OUT INTEGER RANGE 0 TO 4 ); END combi7; ARCHITECTURE archi OF combi7 IS BEGIN PROCESS (a) VARIABLE resultat : INTEGER; BEGIN resultat := 0; FOR i IN 0 TO 3 LOOP IF (a (i) = '1') THEN resultat := resultat + 1; END IF; END LOOP; s <= resultat; END PROCESS; END archi; |
Conclusion:
- Cet exemple pourrait aussi être décrit via une table de vérité grâce à l’instruction CASE.
- On peut ici préciser la notion de PROCESS: le compilateur prend en compte la totalité du PROCESS, et génère la logique correspondante. On peut faire cohabiter plusieurs PROCESS dans un même programme VHDL. Ils deviennent " concurrents ": les logiques correspondantes sont générées indépendamment l’une de l’autre.
Exemple:
On cherche à intégrer dans un circuit logique programmable deux des exemples précédents :
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
ENTITY combi8 IS
PORT (
a: IN STD_LOGIC_VECTOR(3 DOWNTO 0);
t : OUT INTEGER RANGE 0 TO 4;
c :IN INTEGER RANGE 0 TO 3;
e : IN STD_LOGIC_VECTOR(3 DOWNTO 0);
s : OUT STD_LOGIC
);
END combi8;
ARCHITECTURE archi OF combi8 IS
BEGIN
PROCESS (a)
VARIABLE resultat : INTEGER;
BEGIN
resultat := 0;
FOR i IN 0 TO 3 LOOP
IF (a (i) = '1') THEN resultat := resultat + 1; END IF;
END LOOP;
t <= resultat;
END PROCESS;
PROCESS(c)
BEGIN
CASE c IS
WHEN 0 => s<= e(0);
WHEN 1 => s<= e(1);
WHEN 2 => s<= e(2);
WHEN 3 => s<= e(3);
END CASE;
END PROCESS;
END archi;
9 – Le problème des " glitches "
Il s’agit d’impulsions parasites générées lorsque des portes situées sur le même étage de logique ont des temps de propagation différents, et lorsque plusieurs entrées changent d’état en même temps.
On peut observer ces impulsions sur les résultats de simulation des 2 exemples précédents.
Exemple:
Remède :
On ne cherche en général pas à supprimer ces impulsions
parasites. La tendance actuelle est de synchroniser toutes les sorties
via des bascules D, à une fréquence d’horloge suffisamment
faible pour rendre les " glitches " " invisibles ", et suffisamment rapide
pour satisfaire aux exigences temporelles de l’application.
1- Bascule D LATCH
Si ena = 0, la sortie q est figée. Si ena = 1, la sortie q recopie l’entrée d. |
LIBRARY ieee;
USE ieee.std_logic_1164.all; USE ieee.std_logic_arith.all; ENTITY seq1 IS PORT ( d,ena : IN STD_LOGIC; q: OUT STD_LOGIC ); END seq1; ARCHITECTURE archi OF seq1 IS SIGNAL test: STD_LOGIC ; BEGIN PROCESS (ena,d) BEGIN IF ena = '1' THEN test <= d; ELSE test <= test; END IF; END PROCESS; q <= test; END archi; |
Remarque:
On ne peut pas effectuer le traitement directement avec le signal q.
Le passage par le signal interne test est nécessaire.
2- Bascule D " Edge Triggered "
Au front d’horloge, la sortie q recopie l’entrée d. Entre 2 fronts d’horloge, la sortie q est figée. |
LIBRARY ieee;
USE ieee.std_logic_1164.all; USE ieee.std_logic_arith.all; ENTITY seq2 IS PORT ( d, h: IN STD_LOGIC; q: OUT STD_LOGIC ); END seq2; ARCHITECTURE archi OF seq2 IS SIGNAL test: STD_LOGIC ; BEGIN PROCESS BEGIN WAIT UNTIL h='1'; test <= d; END PROCESS; q <= test; END archi; |
Conclusion:
Ici, l’exécution du PROCESS est suspendue jusqu’au passage de 0 à 1 du signal d’horloge.
Le PROCESS ne comporte pas de liste de sensibilités.
Bascule D avec entrées de prépositionnement asynchrones
:
Si prn = cln = 1, la bascule fonctionne comme précédemment. Si cln = 0, la sortie q est mise à 0, indépendamment des autres entrées. Si cln = 1 et prn = 0, la sortie q est mise à 1, indépendamment des autres entrées. |
LIBRARY ieee;
USE ieee.std_logic_1164.all; USE ieee.std_logic_arith.all; ENTITY seq3 IS PORT ( d, h: IN STD_LOGIC; Prn, Cln : IN STD_LOGIC; q: OUT STD_LOGIC ); END seq3; ARCHITECTURE archi OF seq3 IS SIGNAL test: STD_LOGIC ; BEGIN PROCESS ( Prn, Cln, h) BEGIN IF Cln = '0' THEN test <= '0'; -- Clear prioritaire ELSIF Prn = '0' THEN test <= '1'; ELSIF h'EVENT AND h = '1' THEN test <= d; ELSE test <= test; END IF; END PROCESS; q <= test; END archi; |
Conclusion:
- Ici, pour pouvoir définir une liste de sensibilités, on n’a pas utilisé l’instruction WAIT.
- L’instruction IF h’EVENT AND h = ‘1’ permet de détecter un front d’horloge. Il est nécessaire de préciser s’il s’agit d’un front montant ou descendant.
3- Registre parallèle
C’est une extension directe des applications précédentes.
Au front d’horloge, le bus de sortie q recopie le bus d’entrée d. Entre 2 fronts d’horloge, le bus de sortie q est figé. |
LIBRARY ieee;
USE ieee.std_logic_1164.all; USE ieee.std_logic_arith.all; ENTITY seq4 IS PORT ( h: IN STD_LOGIC; d : IN STD_LOGIC_VECTOR (7 DOWNTO 0); q: OUT STD_LOGIC_VECTOR (7 DOWNTO 0) ); END seq4; ARCHITECTURE archi OF seq4 IS SIGNAL test: STD_LOGIC_VECTOR (7 DOWNTO 0) ; BEGIN PROCESS BEGIN WAIT UNTIL h='1'; test <= d; END PROCESS; q <= test; END archi; |
Conclusion:
On pourra, sur le modèle des différentes bascules D, définir
un registre de type LATCH, ou bien des entrées de prépositionnement
asynchrones.
Suppresion des " glitches " générés par de la logique combinatoire, par synchronisation des sorties sur un signal d’horloge:
On reprend l’exemple COMBI7 :
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
ENTITY seq5 IS
PORT (
a: IN STD_LOGIC_VECTOR(3 DOWNTO 0);
h: IN STD_LOGIC;
S : OUT INTEGER RANGE 0 TO 4
);
END seq5;
ARCHITECTURE archi OF seq5 IS
SIGNAL tampon : INTEGER RANGE 0 TO 4;
BEGIN
PROCESS (a) -- description conforme à l’exemple COMBI7
VARIABLE resultat : INTEGER;
BEGIN
resultat := 0;
FOR i IN 0 TO 3 LOOP
IF (a (i) = '1') THEN resultat := resultat + 1; END IF;
END LOOP;
tampon <= resultat;
END PROCESS;
PROCESS -- synchronisation
BEGIN
WAIT UNTIL h = '1';
s <= tampon;
END PROCESS;
END archi;
Conclusion :
Les " glitches " ont disparu !
Les sorties changent d’état au front d’horloge.
4- Compteur
Les compteurs décrits ci-dessous reposent sur le principe suivant :
- La sortie du compteur est prise à la sortie d’un registre parallèle.
- L’entrée de ce registre est commandée par le résultat d’une addition : la sortie du registre +1.
Un premier compteur 3 bits simple, sans remise à 0, construit
sur le modèle de SEQ2 :
|
LIBRARY ieee;
USE ieee.std_logic_1164.all; USE ieee.std_logic_arith.all; ENTITY seq6 IS PORT ( h: IN STD_LOGIC; q: OUT INTEGER RANGE 0 TO 7 ); END seq6; ARCHITECTURE archi OF seq6 IS SIGNAL test: INTEGER RANGE 0 TO 7; BEGIN PROCESS BEGIN WAIT UNTIL h='1'; test <= test+ 1; END PROCESS; q <= test; END archi; |
Un deuxième compteur 3 bits, avec remise à 0 asynchrone,
construit sur le modèle de SEQ3 :
![]() |
ENTITY seq7 IS
PORT ( h, Cln: IN STD_LOGIC; q: OUT INTEGER RANGE 0 TO 7 ); END seq7; ARCHITECTURE archi OF seq7 IS SIGNAL test: INTEGER RANGE 0 TO 7; BEGIN PROCESS (Cln, h) BEGIN IF Cln = '0' THEN test <= 0; ELSIF h'EVENT AND h = '1' THEN test <= test + 1; ELSE test <= test; END IF; END PROCESS; q <= test; END archi; |
Conclusion :
A partir de ces 2 modèles et des outils combinatoires, on pourra multiplier les options : compteur/décompteur, compteur prépositionnable, compteur DCBN, signalisation de fin de comptage etc …
Les sorties du système sont des fonctions combinatoires des bits d’état.
L’état futur du système est calculé par une fonction combinatoire dépendant de l’état actuel et des entrées.
Une entrée de remise à 0 asynchrone est prévue, permettant le retour à l’état initial à tout moment.
Si nécessaire, les sorties du système peuvent être resynchronisées sur l’horloge, via un registre.
Exemple :
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
ENTITY seq8 IS -- machine d'états
PORT ( h, x, y, z, init : IN STD_LOGIC;
a, b, c : OUT STD_LOGIC);
SIGNAL etat: STD_LOGIC_VECTOR (2 DOWNTO 0);
BEGIN
WAIT UNTIL h = '1';
CASE etat IS
WHEN "000" => IF init = '1' OR x = '0' THEN etat <= "000";
ELSE etat <= "001";
END IF;
WHEN "001" => IF init ='1' THEN etat <= "000";
ELSIF y = '1' THEN etat <= "011";
ELSE etat <= "010";
END IF;
WHEN "010" => IF init ='1' THEN etat <= "000";
ELSIF z = '1' THEN etat <= "100";
ELSE etat <= "010";
END IF;
WHEN "011" => IF init ='1' THEN etat <= "000";
ELSIF z = '1' THEN etat <= "100";
ELSE etat <= "011";
END IF;
WHEN "100" => IF init ='1' THEN etat <= "000";
ELSE etat <= "100";
END IF;
WHEN OTHERS => etat <="000"; -- pour envisager les etats non décrits
END CASE;
END PROCESS;
a <= '1' WHEN etat = "010" OR etat = "011" ELSE '0'; -- Equation des sorties
b <= '1' WHEN etat = "001" OR etat = "100" ELSE '0';
c <= '1' WHEN etat = "001" OR etat = "011" OR etat = "100" ELSE '0';
END archi;
Le même exemple en définissant un " type état " :
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
ENTITY seq9 IS -- machine d'états
PORT ( -- autrement
h, x, y, z, init : IN STD_LOGIC;
a, b, c : OUT STD_LOGIC
);
END seq9;
ARCHITECTURE archi OF seq9 IS
TYPE STATE_TYPE IS (s0,s1,s2,s3,s4);
SIGNAL etat : STATE_TYPE;
BEGIN
PROCESS
BEGIN
WAIT UNTIL h = '1';
CASE etat IS
WHEN s0 => IF init = '1' OR x = '0' THEN etat <= s0;
ELSE etat <= s1;
END IF;
WHEN s1 => IF init ='1' THEN etat <= s0;
ELSIF y = '1' THEN etat <= s3;
ELSE etat <= s2;
END IF;
WHEN s2 => IF init ='1' THEN etat <= s0;
ELSIF z = '1' THEN etat <= s4;
ELSE etat <= s2;
END IF;
WHEN s3 => IF init ='1' THEN etat <= s0;
ELSIF z = '1' THEN etat <= s4;
ELSE etat <= s3;
END IF;
WHEN s4 => IF init ='1' THEN etat <= s0;
ELSE etat <= s4;
END IF;
WHEN OTHERS => etat <=s0; -- pour envisager les etats non décrits
END CASE;
END PROCESS;
-- Equation des sorties
a <= '1' WHEN etat = s2 OR etat = s3 ELSE '0';
b <= '1' WHEN etat = s1 OR etat = s4 ELSE '0';
c <= '1' WHEN etat = s1 OR etat = s3 OR etat = s4 ELSE '0';
END archi;
Il serait plus prudent, dans l’exemple précédent de traiter l’entrée d’initialisation init de manière asynchrone, en prévoyant un signal reset sur les bascules :
Le graphe d’états se simplifie comme ci-dessous :
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
ENTITY seq10 IS -- machine d'états
PORT ( -- avec reset asynchrone
h, x, y, z, init : IN STD_LOGIC;
a, b, c : OUT STD_LOGIC
);
END seq10;
ARCHITECTURE archi OF seq10 IS
TYPE STATE_TYPE IS (s0,s1,s2,s3,s4);
SIGNAL etat : STATE_TYPE;
BEGIN
PROCESS (h,init,x,y,z,etat)
BEGIN
IF init ='1' THEN etat<=S0; --Reset asynchrone
ELSIF h'EVENT AND h='1' THEN
CASE etat IS
WHEN s0 => IF x = '0' THEN etat <= s0;
ELSE etat <= s1;
END IF;
WHEN s1 => IF y = '1' THEN etat <= s3;
ELSE etat <= s2;
END IF;
WHEN s2 => IF z = '1' THEN etat <= s4;
ELSE etat <= s2;
END IF;
WHEN s3 => IF z = '1' THEN etat <= s4;
ELSE etat <= s3;
END IF;
WHEN s4 => etat <= s4;
WHEN OTHERS => etat <=s0; -- pour envisager les etats non décrits
END CASE;
ELSE etat<=etat;
END IF;
END PROCESS;
-- Equation des sorties
a <= '1' WHEN etat = s2 OR etat = s3 ELSE '0';
b <= '1' WHEN etat = s1 OR etat = s4 ELSE '0';
c <= '1' WHEN etat = s1 OR etat = s3 OR etat = s4 ELSE '0';
END archi;
LIGNE 3 ETATS
La ligne S1 ci-dessous, peut-être utilisée
1- Comme une entrée , on a alors S2 = S1 + c. Le buffer 3 états doit être placé en haute impédance via la commande CS (à 0).
2- Comme une sortie , on a alors S1 = a.b, et S2 = a.b + c. Le buffer
3 états doit être placé en basse impédance via
la commande CS (à 1).
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
LIBRARY altera;
USE altera.maxplus2.all; -- contient la primitive TRI
ENTITY trivhd IS
PORT (
a,b,c,CS :IN STD_LOGIC;
S2 : OUT STD_LOGIC;
S1: INOUT STD_LOGIC
);
END trivhd;
ARCHITECTURE archi OF trivhd IS
SIGNAL X: STD_LOGIC;
BEGIN
S2 <= S1 OR c ;
X <= a AND b;
Mon_buffer : TRI PORT MAP (x, cs, S1); -- utilisation de la primitive TRI
END archi; -- on passe les paramètres spécifiés dans la doc
-- on peut retrouver la déclaration de la primitive dans
-- c:\maxplus2\vhdl93\altera\maxplus2.vhd