Un livre de Wikilivres.
Une relecture de logique combinatoire et de logique séquentielle ne fera donc aucun mal au lecteur
du présent chapitre.
■ la première est la déclaration de la ou des bibliothèques que l'on va utiliser par la suite,
■ la deuxième est une entité dont l'objectif est de définir quelles sont les entrées et les sorties ainsi
que leurs noms,
■ la troisième est une architecture dont l'objectif est de décrire le fonctionnement.
'
Remarque : la bibliothèque est associée à l'entité qui la suit, et à cette entité seulement. Si un fichier source comporte
plusieurs entités, il faudra déclarer autant de fois les bibliothèques qu'il y a d'entités !
Dans ce chapitre, nous allons revenir sur les programmes VHDL correspondants au combinatoire et
au séquentiel simple. La table de vérité, élément central du combinatoire, sera donc notre point de
départ.
Table de vérité
La table de vérité est l'outil de spécification idéal pour la logique combinatoire. Cette section se
contente donc d'explorer comment écrire des programmes VHDL qui décrivent du combinatoire
spécifié par une table de vérité.
Nous présentons la technique des BIT_VECTOR ainsi que l'ensemble des styles de programmation.
Imaginons que l'on ait la table de vérité (4 entrées 2 sorties) suivante :
Table de vérité
Entrées Sorties
a3 a2 a1 a0 s1 s0
0 1 0 1 1 1
0 1 1 0 0 1
1 1 0 1 1 0
(ce qui n'est pas mentionné dans cette table correspond à 00 en sortie)
Une table de vérité permet de repérer les entrées (à gauche) et les sorties (à droite). Elle correspond
http://fr.wikibooks.org/wiki/TD1_VHDL 10/07/2014
TD1 VHDL — Wikilivres Page 2 sur 19
donc à l'entité :
Si l'on peut utiliser cette déclaration on lui préfèrera souvent l'utilisation des "BIT_VECTOR". On y
gagne parfois en simplicité d'écriture quand on utilise certains styles de combinatoire. Ce n'est pas le
cas avec les équations mais avec le "with select when" décrit plus loin.
L'écriture de cette entité utilise comme indiqué précédemment des "BIT_VECTOR". Une
conséquence importante est que ce qui est noté a3 dans la table de vérité sera noté a(3) en VHDL.
L'utilisation de "DOWNTO" au lieu de "TO" permet de garder le poids faible (indicé 0) à droite. Ce
n'est pas nécessaire, mais un débutant est trop habitué à cette convention pour qu'on se permette de la
changer maintenant.
Il est toujours possible de partir d'une table de vérité, et d'utiliser des tableaux de Karnaugh pour en
déduire des équations simplifiées. Ces équations peuvent être transcrites simplement en VHDL.
Malheureusement, VHDL est un langage qui utilise beaucoup parenthèses car l'opérateur ET n'est
pas prioritaire sur l'opérateur OU. En fait il n'y a aucune priorité dans les opérateurs VHDL. Ces
parenthèses peuvent constituer un frein à l'apprentissage du langage, mais si vous faites bien
attention à utiliser systématiquement des formes conjonctives ou disjonctives vous verrez que
finalement il ne faut pas tant de parenthèses que cela !
'
Remarques :
■ Comme dans tout langage, il vaut mieux utiliser trop de parenthèses que pas assez.
■ Si vous ne voulez pas simplifier vos équations, il est possible de laisser ce travail au compilateur VHDL.
http://fr.wikibooks.org/wiki/TD1_VHDL 10/07/2014
TD1 VHDL — Wikilivres Page 3 sur 19
C'est le style que l'on privilégiera lorsqu'une table de vérité est fournie. Pourquoi ? Parce que ce style
a les mêmes propriétés que la table de vérité. Une table de vérité est sensée représenter toutes les
possibilités sur ses entrées, et le style "with select when" fait la même chose puisqu'il se termine
OBLIGATOIREMENT par un "WHEN OTHERS;". Pour être complet on va quand même présenter
d'autres styles dans la suite de ce paragraphe.
'
Remarques :
■ le style "with select when" devient vite fastidieux quand le nombre d'entrées augmente. Le nombre de lignes étant
une puissance de deux du nombre d'entrée on a déjà 64 lignes pour six entrées. Pour remédier à cette augmentation
vous pouvez regrouper les lignes qui donnent la même sortie dans le when. Mais, attention, le séparateur est alors | et
non OR ou AND !
■ prenez le temps de faire la correspondance entre une table de vérité et une écriture "with select when" : ce qui est à
gauche de la table de vérité passe à droite après le when et inversement !
Remarque : la structure "when else" ne nécessite pas des conditions mutuellement exclusives. Elle engendre alors une
http://fr.wikibooks.org/wiki/TD1_VHDL 10/07/2014
TD1 VHDL — Wikilivres Page 4 sur 19
les conditions ne sont pas mutuellement exclusives. Pour vous en convaincre, essayer de répondre à la question : que
se passe-t-il quand a=1 et b=1 simultanément ? On ne pourrait pas d'emblée utiliser une structure "with select when"
qui nécessite des conditions absolument exclusives. En tout cas si on veut le faire, il faut choisir une réponse à la
question précédente, ce qui revient à choisir une priorité.
Remarquez aussi l'écriture compacte de cet exemple donné en VHDL. Une table de vérité nécessiterait quatre
variables "a", "b", "x" et "w" comme entrées soit 16 lignes.
Passons maintenant à un style appelé séquentiel. Contrairement à ce que cet adjectif "séquentiel"
pourrait suggérer, ce style est destiné aussi à décrire du combinatoire.
Le style case when peut être aussi utilisé. Il est simple et ressemble au style "with select when".
Voici un exemple :
Ce programme correspond encore à la table de vérité donnée plus haut dans ce chapitre.
'
Remarque : en combinatoire comme en séquentiel, le style "case when" nécessite un process... et un process est suivi
par une liste de sensibilité qui correspond aux entrées en combinatoire. Il est impossible d'écrire un "CASE" sans
process même en combinatoire.
Passons maintenant au style le plus emblématique du VHDL. Son grand problème est sa
ressemblance avec l'algorithmique.
Il nous est impossible d'interdire ce style surtout plus tard en séquentiel. Il faut cependant éviter le
plus possible de l'utiliser tant que l'on reste débutant. Il a des propriétés diaboliques : un if sans else
créera automatiquement un élément de mémorisation, c'est à dire de la logique séquentielle.
http://fr.wikibooks.org/wiki/TD1_VHDL 10/07/2014
TD1 VHDL — Wikilivres Page 5 sur 19
C'est aussi un style qui nécessite un process est le "if then else" :
Remarquez le constructeur "elsif" sans "e" et en un seul mot. Il est très pratique car ne nécessite pas
de "end if" contrairement au "else if" en deux mots.
Essayez de vous convaincre de lire ce style comme une table de vérité pour le moment.
Conclusion
La découverte des nombreux styles de programmation en VHDL déconcerte le débutant à juste titre.
Pour maîtriser le combinatoire, seuls les deux premiers styles sont absolument nécessaires. Il vous
faut donc apprendre comment écrire une équation en VHDL et comment transformer une table de
vérité en "with select when".
L'apprentissage du style "if then else" s'avère assez catastrophique chez les débutants car amène une
confusion avec la structure de contrôle correspondante des langages algorithmiques.
Exercice 1
Ecrire un programme VHDL pour un additionneur 1 bit avec un style "with select when".
Solution de l'exercice 1
Il existe un moyen non intuitif de rassembler les lignes qui sortent "10". Je parle de moyen non intuitif
car les étudiants qui me demandent comment on fait me proposent soit un OR, soit un AND pour faire
cela... mais ce n'est ni l'un ni l'autre :
http://fr.wikibooks.org/wiki/TD1_VHDL 10/07/2014
TD1 VHDL — Wikilivres Page 6 sur 19
Cet exercice termine nos rappels sur la programmation de la logique combinatoire en VHDL. Nous
allons aborder maintenant la logique séquentielle (ce qui nous prendra plusieurs chapitres).
Le séquentiel
Définition
La logique séquentielle est caractérisée par un calcul au sens large de l'état futur en fonction
de l'état présent, tout cela au rythme de fronts d'horloges.
Pourquoi parle-t-on de calcul au sens large ? Parce qu'il ne s'agit pas forcément d'un calcul réalisé
par un opérateur connu (comme l'addition, la soustraction, ...) mais éventuellement d'un calcul
réalisé par une équation booléenne.
Nous utiliserons le schéma ci-dessous pour rappeler cette définition (de calcul au sens large) :
On a omis la partie séquentielle dans ce schéma. Elle n'est pas difficile à ajouter si, comme déjà
souvent indiqué ailleurs, on se rappelle que l'état présent est une sortie de bascule D, tandis que l'état
futur en est une entrée.
'
http://fr.wikibooks.org/wiki/TD1_VHDL 10/07/2014
TD1 VHDL — Wikilivres Page 7 sur 19
■ L'ensemble des sorties des bascules D correspondent toujours à l'état présent (noté EP dans la figure ci-dessus).
■ L'ensemble des entrées des bascules D correspondent toujours à l'état futur (noté EF dans la figure ci-dessus).
Il existe de nombreux outils de descriptions du séquentiel. Dans cette section nous utiliserons le plus
simple d'entre eux : le diagramme dévolution. Nous aurons l'occasion d'en aborder d'autres dans le
TD4.
Ce problème a déjà été traité dans le cours Logique séquentielle au chapitre Diagrammes
d'évolution, équations de récurrence, où l'on apprend à transformer un diagramme d'évolution en
équations de récurrences. Cela se fait très simplement à l'aide d'un tableau état présent/état futur.
Il est important de maîtriser les équations de récurrences même si souvent, on peut les éviter comme
le montre la section suivante.
Vous pouvez remarquez la détection d'un front d'horloge par "IF clock'EVENT AND clock='1'
THEN". Comme déjà indiqué le case est entouré par un process. La liste de sensibilité du process
(ce qu'il y a entre parenthèses derrière le mot clef process) est au moins constituée par l'horloge.
'
Remarque générale : Le style "case when" est au séquentiel ce que le style "with select when" est au combinatoire :
tous les deux permettent d'éviter les équations (combinatoires ou de récurrences).
Deuxième remarque : Si vous concevez un diagramme d'évolution comme un calcul (au sens large) de l'état futur à
partir de l'état présent, vous êtes sur la bonne voie... Sinon, forcez-vous à le faire. Comme vous pouvez le remarquer,
ce calcul au sens large ne s'écrit pas forcément à l'aide d'un opérateur mais ici à l'aide d'une série de conditions dans un
case.
http://fr.wikibooks.org/wiki/TD1_VHDL 10/07/2014
TD1 VHDL — Wikilivres Page 8 sur 19
Exercice 2
Réaliser un compteur GRAY sur 3 bits en utilisant ces deux méthodes. Un compteur GRAY génère
un code GRAY sur front d'horloge : la suite des états du diagramme d'évolution suit un code Gray.
Solution de l'exercice 2
Un compteur Gray possède une entrée d'horloge et une sortie sur n bits. Ici, l'énoncé fixe n à 3.
-- compteur Gray
ENTITY cmptGray IS PORT (
clock: IN BIT;
q : OUT BIT_VECTOR(2 DOWNTO 0));--conforme aux conseils Xilinx
END cmptGray;
ARCHITECTURE mydemo OF cmptGray IS
SIGNAL s_q : BIT_VECTOR(2 DOWNTO 0);
BEGIN
PROCESS(clock) BEGIN
IF clock'EVENT AND clock='1' THEN
CASE s_q IS --style case when
WHEN "000" => s_q <="001";
WHEN "001" => s_q <="011";
WHEN "011" => s_q <="010";
WHEN "010" => s_q <="110";
WHEN "110" => s_q <="111";
WHEN "111" => s_q <="101";
WHEN "101" => s_q <="100";
WHEN OTHERS => s_q <="000";
END CASE;
END IF;
END PROCESS;
q <= s_q;
END mydemo;
Quelque soit la méthode, vous commencez par compter les composants différents et vous en obtenez
N. Si vous avez deux composants ET, vous ne le comptez qu'une seule fois. Il vous faudra un couple
entité architecture par composant. Par exemple, le schéma ci-contre comporte N=3 composants (ET,
OU, NON). Vous aurez à écrire autant de couples entité - architecture qu'il y a de composants plus
un couple entité - architecture pour la description globale. Vous aurez donc N+1 couples.
http://fr.wikibooks.org/wiki/TD1_VHDL 10/07/2014
TD1 VHDL — Wikilivres Page 9 sur 19
La notion de hiérarchie
Nous avons repris dans cette figure, la figure originale à gauche, pour la transformer et
progressivement montrer la hiérarchie (sur deux niveaux seulement). Nous ne réaliserons pas
systématiquement cette transformation dans nos schémas : il vous faudra la réaliser dans votre tête.
En effet, ajouter le nom des entrées et sorties de chaque composant peut vite rendre un schéma
illisible !
Chaque rectangle dans cette figure représente une entité. Nous avons ajouté dans nos rectangles bleu
clairs le nom des entrées et des sorties (ce qui diminue la lisibilité du schéma). Ces petits rectangles
bleus sont assemblés pour en faire un quatrième plus gros (de couleur grise). On a donc bien un gros
rectangle composé de 3 petits. Le grand rectangle gris représente le haut de la hiérarchie tandis que
les bleus représentent le bas. La hiérarchie peut encore continuer...et les rectangles bleus devenir eux
-mêmes composés par d'autres...
Arrêtez vous ici tant que vous n'avez pas compris. Aller plus loin nécessite de comprendre cette
notion de hiérarchie.
L'utilisation d'un seul fichier se fait en déclarant des signaux et des composants avant le begin de
l'architecture globale. Voici l'exemple de la figure ci-dessus.
http://fr.wikibooks.org/wiki/TD1_VHDL 10/07/2014
TD1 VHDL — Wikilivres Page 10 sur 19
PORT(e0,e1 : IN BIT;
s : OUT BIT);
END COMPONENT;
COMPONENT inverseur
PORT(e : IN BIT;
s : OUT BIT);
END COMPONENT;
BEGIN
i1:et PORT MAP(e0=>e0,e1=>e1,s=>e0e1);
i2:inverseur PORT MAP(e=>e2,s=>e2bar);
i3:ou PORT MAP(e0=>e0e1,e1=>e2bar,s=>s);
END truc;
-- comme expliqué plus bas vous pouvez couper ici
-- Voici la description des composants
ENTITY et IS
PORT(e0,e1 : IN BIT;
s : OUT BIT);
END et;
ARCHITECTURE aet OF et IS
BEGIN
s<=e0 AND e1;
END aet;
ENTITY ou IS
PORT(e0,e1 : IN BIT;
s : OUT BIT);
END ou;
ARCHITECTURE aou OF ou IS
BEGIN
s<=e0 OR e1;
END aou;
ENTITY inverseur IS
PORT(e : IN BIT;
s : OUT BIT);
END inverseur;
ARCHITECTURE ainv OF inverseur IS
BEGIN
s<= NOT e;
END ainv;
Apprenez à lire les "PORT MAP". Le signe "=>" doit être lu est relié à. Ce qui est à gauche de ce
signe appartient toujours au composant que l'on est en train de câbler, et ce qui est à droite peut être
soit un signal (c'est à dire un fil) soit une entrée ou sortie du composant supérieur (dans la
hiérarchie).
Câblage de composants
Pour essayer de vous faire comprendre tout cela, la figure ci-dessus vous montre comment les
"PORT MAP" fonctionnent :
http://fr.wikibooks.org/wiki/TD1_VHDL 10/07/2014
4 ; 2345 = >: $ ;; ;<
!
" #
$! #
!
" #
$! #
!
%
& '
science exacte(
$& ) *+ ,- +* $ .
# / #
&
0" 1!( $ 2345
&
6 $
&
2 $
7 $
&
**&
8 "
&
(
$ $
.
:$!&
2
7
BEGIN
i1:et PORT MAP(e0=>e0,e1=>e1,s=>e0e1);
i2:inverseur PORT MAP(e=>e2,s=>e2bar);
i3:ou PORT MAP(e0=>e0e1,e1=>e2bar,s=>s);
END truc;
-- comme expliqué plus bas vous pouvez couper ici
7??
&C:: &$?C:?4 ; 2345 ;+?+@?A+ ;B
D
TD1 VHDL — Wikilivres Page 12 sur 19
Quel est l'intérêt de couper les fichiers ? Tout simplement pour avoir des fichiers moins grands !
Tout ce qui a été mis au point peut se trouver dans un fichier séparé auquel on ne touche plus !
On désire regrouper les composants que l'on va assembler dans une bibliothèque. VHDL utilise
plutôt le mot package pour décrire ce que l'on appelle une bibliothèque.
Comme dans tout langage de programmation, la notion de librairie est associée à la programmation
séparée, c'est à dire en plusieurs fichiers. Voici donc un exemple utilisant deux fichiers.
Réalisation du package
-- fichier : composants.vhd
PACKAGE mesportes IS
COMPONENT et
PORT(e0,e1 : IN BIT;
s : OUT BIT);
END COMPONENT;
COMPONENT ou
PORT(e0,e1 : IN BIT;
s : OUT BIT);
END COMPONENT;
COMPONENT inverseur
PORT(e : IN BIT;
s : OUT BIT);
http://fr.wikibooks.org/wiki/TD1_VHDL 10/07/2014
TD1 VHDL — Wikilivres Page 13 sur 19
END COMPONENT;
END mesportes;
-- l'entête du package est terminée
ENTITY et IS
PORT(e0,e1 : IN BIT;
s : OUT BIT);
END et;
ARCHITECTURE aet OF et IS
BEGIN
s<=e0 AND e1;
END aet;
ENTITY ou IS
PORT(e0,e1 : IN BIT;
s : OUT BIT);
END ou;
ARCHITECTURE aou OF ou IS
BEGIN
s<=e0 OR e1;
END aou;
ENTITY inverseur IS
PORT(e : IN BIT;
s : OUT BIT);
END inverseur;
ARCHITECTURE ainv OF inverseur IS
BEGIN
s<= NOT e;
END ainv;
Et le fichier principal
Qu'est-ce qui change dans le fichier principal ? Le voici, essayez de deviner avant de lire plus loin.
-- top.vhd
USE work.mesportes.ALL;
ENTITY Fct IS
PORT(e0,e1,e2 : IN BIT;
s : OUT BIT);
END Fct;
Remarque : les lecteurs peu habitués aux environnements de développement intégrés peuvent se demander comment
le compilateur va retrouver "mesportes" puisque l'instruction "USE work.mesportes.ALL;" ne fait référence à aucun
nom de fichier ! C'est la notion de projet qui nous sauve. Le compilateur n'a pas besoin de lire "work", le répertoire de
travail par défaut en complet (ce qui pourrait prendre un temps fou) pour trouver le package "mesportes". En fait votre
projet sera composé de deux fichiers top.vhd et composants.vhd qui contient ce package et ce qui n'est pas trouvé dans
top.vhd est cherché dans composants.vhd.
http://fr.wikibooks.org/wiki/TD1_VHDL 10/07/2014
TD1 VHDL — Wikilivres Page 14 sur 19
Il n'y a aucun standard sur les contenus des packages du type ci-dessus. Chaque constructeur propose
son propre package pour programmer ses composants ce qui pose des problèmes de portabilité. A
noter quand même une initiative avec LPM (Library of Parameterized Modules), initiative d'Altera
mais non suivie par Xilinx.
Bibliothèque standard
Le VHDL fait appelle de manière implicite à une bibliothèque dite standard. Celle-ci défini
plusieurs types de base :
■ boolean
■ bit
■ character
■ severity_level
■ integer
■ real
■ time
■ delay_length
■ now
■ natural
■ positive
■ string
■ boolean_vector
■ bit_vector
■ integer_vector
■ real_vector
■ time_vector
■ file_open_kind
■ file_open_status
■ foreign
Les seuls types utilisés jusqu'à maintenant sont les « bit » et « bit_vector ». Un bit prend seulement
deux valeurs et ne permet pas de gérer le trois états par exemple. IEEE propose en supplément une
bibliothèque appelée std_logic.
library ieee;
use ieee.std_logic_1164.all;
Cette bibliothèque déclare les types std_logic et std_logic_vector dont les valeurs acceptées sont :
■ 0 : Niveau logique bas à basse impédance (mise à la masse via une faible impédance)
http://fr.wikibooks.org/wiki/TD1_VHDL 10/07/2014
;< < 8 9 :
— =
haut à basse impédance
flottant
bas à haute impédance
pull-down
haut à haute impédance
pull-up
inconnu à haute impédance
!!" !!
!!
#
inconnu
!$!" !!" !!" !!
!!
% Non défini
& N'importe quel niveau logique
'
true
!
(
)
*
"
,-
+
+
-
WIKI: process(CLK_IN) is
begin
if rising_edge(CLK_IN) then
-- Les instructions suivantes seront exécutées à chaque front montant du signal CLK_IN
end if;
end process WIKI;
1
! , 2
2
+
2
2 3444"
!
+ +
2
2
5 % . -
+ 6
!
!
+ 5
library ieee;
use ieee.std_logic_1164.all;
ENTITY demo IS PORT(
a : in STD_LOGIC_VECTOR(3 DOWNTO 0);-- 4 entrées
s : out STD_LOGIC_VECTOR(1 DOWNTO 0));
-- 2 sorties
END demo;
->>5B=
=5
>B=>;< < $>$?>@$A
+
TD1 VHDL — Wikilivres Page 16 sur 19
précédée de
library ieee;
use ieee.std_logic_1164.all;
Voici donc une version complète un seul fichier utilisant la librairie IEEE-1164 standard logic de
l'exemple d'assemblage de composants donné plus haut dans ce chapitre :
BEGIN
i1:et PORT MAP(e0=>e0,e1=>e1,s=>e0e1);
i2:inverseur PORT MAP(e=>e2,s=>e2bar);
i3:ou PORT MAP(e0=>e0e1,e1=>e2bar,s=>s);
END truc;
-- Voici la description des composants
library ieee;
use ieee.std_logic_1164.all;
ENTITY et IS
PORT(e0,e1 : IN STD_LOGIC;
s : OUT STD_LOGIC);
END et;
ARCHITECTURE aet OF et IS
BEGIN
s<=e0 AND e1;
END aet;
library ieee;
use ieee.std_logic_1164.all;
ENTITY ou IS
PORT(e0,e1 : IN STD_LOGIC;
s : OUT STD_LOGIC);
END ou;
ARCHITECTURE aou OF ou IS
BEGIN
s<=e0 OR e1;
END aou;
library ieee;
use ieee.std_logic_1164.all;
ENTITY inverseur IS
PORT(e : IN STD_LOGIC;
s : OUT STD_LOGIC);
END inverseur;
ARCHITECTURE ainv OF inverseur IS
BEGIN
s<= NOT e;
END ainv;
http://fr.wikibooks.org/wiki/TD1_VHDL 10/07/2014
TD1 VHDL — Wikilivres Page 17 sur 19
Prenez donc l'habitude d'utiliser les std_logic en lieu et place de bit. Cela s'avère absolument
nécessaire dès qu'il y a un compteur comme on le verra dans un prochain chapitre.
Décodeur
Définition
On appelle décodeur un circuit positionnant une sortie en fonction d'une entrée de sélection : la
sortie peut être positionnée à un parmi des zéros ou, à l'inverse, à zéro parmi des uns.
Pour ceux qui connaissent le démultiplexeur, un décodeur est un démultiplexeur avec une entrée
fixée (soit à 0 ou soit à 1). Cette entrée étant fixée, il n'est absolument pas nécessaire de la dessiner.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity Decoder is
port
(
Sel : in std_logic_vector(2 downto 0);
Vous remarquez le un qui se "ballade" parmi des zéros en fonction de l'entrée de sélection ?
http://fr.wikibooks.org/wiki/TD1_VHDL 10/07/2014
TD1 VHDL — Wikilivres Page 18 sur 19
Simulation Waveform
Le multiplexeur
Définition
Le multiplexeur est un interrupteur plusieurs positions commandé par une entrée de sélection.
L'entrée qui est électriquement reliée à la sortie est choisie parmi plusieurs possibilités.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity Multiplexer_VHDL is
port
(
a, b, c, d, e, f, g, h : in std_logic;
Sel : in std_logic_vector(2 downto 0);
http://fr.wikibooks.org/wiki/TD1_VHDL 10/07/2014