Vous êtes sur la page 1sur 18

15/01/2018 TD1 VHDL — Wikilivres

Dans ce chapitre, nous allons nous intéresser à trois problèmes différents :

la programmation de la logique combinatoire en partant des tables de vérité


la programmation de la logique séquentielle en partant des graphes d'évolutions
la programmation structurelle, c'est à dire l'assemblage de composants
Une relecture de logique combinatoire et de logique séquentielle ne fera donc aucun mal au lecteur du présent
chapitre.

Retour sur les styles de programmation


VHDL
Tout programme VHDL comporte au moins trois parties :

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 donc à l'entité :

ENTITY demo IS PORT(


a3,a2,a1,a0 : in BIT; -- 4 entrées
s1,s0 : out BIT); -- 2 sorties
END demo;
https://fr.wikibooks.org/wiki/TD1_VHDL 1/18
15/01/2018 TD1 VHDL — Wikilivres

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.

-- entité utilisée pour la présentation des styles de cette section


ENTITY demo IS PORT(
a : in BIT_VECTOR(3 DOWNTO 0); -- 4 entrées
s : out BIT_VECTOR(1 DOWNTO 0)); -- 2 sorties
END demo;

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.

Si nécessaire révisez votre algèbre de Boole, particulièrement la minimisation des expressions logiques.

Les équations concurrentes


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.

-- ******** VHDL *************


ARCHITECTURE mydemo OF demo IS
-- avec minimum de parenthèses
BEGIN
s(1) <= ( not a(3) and a(2) and not a(1) and a(0) ) OR ( a(3) and a(2) and not a(1) and a(0)
s(0) <= ( not a(3) and a(2) and not a(1) and a(0) ) OR ( not a(3) and a(2) and a(1) and a
END mydemo;

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.

Il est temps de passer au style "with select when".

Le style "with select when"


L'architecture en VHDL utilisant le style "with select when" peut s'écrire :

-- ******** VHDL *************


ARCHITECTURE mydemo OF demo IS
BEGIN
WITH a SELECT --style with select when
s <= "11" WHEN "0101", -- premiere ligne

https://fr.wikibooks.org/wiki/TD1_VHDL 2/18
15/01/2018 TD1 VHDL — Wikilivres

"01" WHEN "0110", -- deuxieme ligne


"10" WHEN "1101", -- troisieme ligne
"00" WHEN OTHERS;
END mydemo;

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 !

Explorons encore d'autres styles.

Le style "when else"


On écrirait le même programme en style "when else" :

-- ******** VHDL *************


ARCHITECTURE mydemo OF demo IS
BEGIN
-- style when else
s <= "11" WHEN a="0101" ELSE -- premiere ligne
"01" WHEN a="0110" ELSE -- deuxieme ligne
"10" WHEN a="1101" ELSE -- troisieme ligne
"00";
END mydemo;

Ce programme correspond à la table de vérité donnée plus haut dans ce chapitre.


'

Remarque : la structure "when else" ne nécessite pas des conditions mutuellement exclusives. Elle engendre alors
une architecture avec priorité. Par exemple dans

-- ******** VHDL *************


j<= w when a='1' else
x when b='1' else
0;

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.

https://fr.wikibooks.org/wiki/TD1_VHDL 3/18
15/01/2018 TD1 VHDL — Wikilivres

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"


Le style case when peut être aussi utilisé. Il est simple et ressemble au style "with select when". Voici un exemple :

-- ******** VHDL *************


ARCHITECTURE mydemo OF demo IS
BEGIN
PROCESS(a) BEGIN
CASE a is --style case when
WHEN "0101" => s <="11"; -- premiere ligne
WHEN "0110" => s <="01"; -- deuxieme ligne
WHEN "1101" => s <="10"; -- troisieme ligne
WHEN OTHERS => s <="00";
END CASE;
END PROCESS;
END mydemo;

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.

Le style "if then else"


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.

C'est aussi un style qui nécessite un PROCESS : il est appelé séquentiel dans le sens où son résultat dépend de l'ordre
d'écriture. Voici le même exemple que précédemment :

-- ******** VHDL *************


ARCHITECTURE mydemo OF demo IS
BEGIN
PROCESS(a) BEGIN
IF a="0101" THEN s <="11"; -- premiere ligne
ELSIF a="0110" THEN s <="01"; -- deuxieme ligne
ELSIF a= "1101" THEN s <="10"; -- troisieme ligne
ELSE
s <="00";
END IF;
END PROCESS;
END mydemo;

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.

https://fr.wikibooks.org/wiki/TD1_VHDL 4/18
15/01/2018 TD1 VHDL — Wikilivres

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

-- ******** VHDL *************


ENTITY adder IS PORT(
e : in BIT_VECTOR(2 DOWNTO 0); -- 3 entrées
s : out BIT_VECTOR(1 DOWNTO 0)); -- 2 sorties
END demo;
ARCITECTURE aAdder of adder IS BEGIN
With e select
s <= "00" WHEN "000",
"01" WHEN "001",
"01" WHEN "010",
"10" WHEN "011",
"01" WHEN "100",
"10" WHEN "101",
"10" WHEN "110",
"11" WHEN OTHERS;
END aAdder;

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 :

-- ******** VHDL *************


ENTITY adder IS PORT(
e : in BIT_VECTOR(2 DOWNTO 0); -- 3 entrées
s : out BIT_VECTOR(1 DOWNTO 0)); -- 2 sorties
END demo;
ARCITECTURE aAdder of adder IS BEGIN
With e select
s <= "00" WHEN "000",
"01" WHEN "001",
"01" WHEN "010",
"10" WHEN "011" | "101" | "110" ,
"01" WHEN "100",
"11" WHEN OTHERS;
END aAdder;

Ce même symbole peut être aussi utilisé dans un "case".

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
https://fr.wikibooks.org/wiki/TD1_VHDL 5/18
15/01/2018 TD1 VHDL — Wikilivres

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) :

Calcul au sens large de l'état futur


en fonction de l'état présent

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.
'

Principe à ne pas oublier :

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.

Le séquentiel simple (diagramme d'évolution) avec équations de récurrence


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.

Le séquentiel simple (diagramme d'évolution) sans équations de récurrence


Implanter un diagramme d'évolution en VHDL peut se faire de manière systématique :

ENTITY demo IS PORT(


clock : IN BIT;
q : INOUT BIT_VECTOR(1 DOWNTO 0));
END demo;

ARCHITECTURE mydemo OF demo IS

https://fr.wikibooks.org/wiki/TD1_VHDL 6/18
15/01/2018 TD1 VHDL — Wikilivres

BEGIN
PROCESS(clock) BEGIN
IF clock'EVENT AND clock='1' THEN
CASE q IS --style case when
WHEN "00" => q <="01";
WHEN "01" => q <="10";
WHEN "10" => q <="11";
WHEN OTHERS => q <="00" ;
END CASE;
END IF;
END PROCESS;
END mydemo;

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.

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;

https://fr.wikibooks.org/wiki/TD1_VHDL 7/18
15/01/2018 TD1 VHDL — Wikilivres

Assembler des composants en VHDL


Le langage VHDL est destiné aux électroniciens qui ont l'habitude d'assembler des composants électroniques simples
pour en faire d'autres un peu plus complexes etc... VHDL se doit donc de pouvoir gérer ces situations. Les composants
à assembler peuvent ou non se trouver dans des bibliothèques. Le style de programmation qui consiste à assembler
des composants s'appelle programmation structurelle. On parle aussi parfois de Netlist ou liste de connexions.

Nous allons commencer par examiner comment tout ceci s'articule.

Programme comportant plusieurs composants


Il existe plusieurs façons d'écrire un programme comportant plusieurs composants.

Quelle que 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.

Ce N et N+1 sont liés à la notion de hiérarchie expliquée dans la section suivante.

Cette programmation structurelle revient à décrire un schéma ; dans la terminologie électronique, cela s'appelle aussi
une Netlist. Nous pouvons utiliser un seul ou plusieurs fichiers pour réaliser ce type de programmation.

La notion de hiérarchie
Le style de programmation dit structurel fait appel à la notion de hiérarchie.

Décomposition hiérarchique d'un schéma

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.

Version en un seul fichier

https://fr.wikibooks.org/wiki/TD1_VHDL 8/18
15/01/2018 TD1 VHDL — Wikilivres

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.

-- fichier unique : top.vhd


ENTITY Fct IS
PORT(e0,e1,e2 : IN BIT;
s : OUT BIT);
END Fct;

ARCHITECTURE truc OF Fct IS


-- Les signaux (fils de liaison) sont déclarés avant le begin de l'architecture
SIGNAL e0e1,e2bar : BIT;
-- Les components sont déclarés avant le begin de l'architecture
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);
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).

https://fr.wikibooks.org/wiki/TD1_VHDL 9/18
15/01/2018 TD1 VHDL — Wikilivres

Câblage de composants

Pour essayer de vous faire comprendre tout cela, la figure ci-dessus vous montre comment les "PORT MAP"
fonctionnent :

remarquez que les flèches du dessin partent toujours de l'intérieur du composant (que l'on câble avec le PORT
MAP)
une sortie peut être reliée à un fil (flèche rouge) ou à une sortie du composant plus haut de la hiérarchie (flèche
mauve)
une entrée peut être reliée à un fil (flèche rouge) ou à une entrée du composant plus haut de la hiérarchie
(flèche mauve)
Il vous faut encore prendre du temps pour comprendre et assimiler cela. C'est une science exacte, aucune
dérogation. Quand le compilateur lit "e0 => e0" il ne se mélange pas les pinceaux contrairement à ce qui se passe pour
vous si vous n'y accordez pas le temps nécessaire à la compréhension.

Pour la première fois (peut-être ?), vous rencontrez un programme VHDL qui comporte plusieurs entités et plusieurs
architectures.

Un tel programme doit avoir autant d'entités que d'architectures.


Votre programme décrit une hiérarchie : des composants sont assemblés pour réaliser un grand composant.
Tous les composants assemblés sont aussi déclarés en "component".
Notre problème va être maintenant de découper ce fichier unique en plusieurs fichiers.

Version avec deux fichiers


Il est possible de couper ce fichier unique en deux après la première architecture. En effet, la majorité des
environnements de développement intégrés sont capables de gérer des écritures avec deux fichiers sans librairie
(package).

Voici le premier fichier :

-- fichier principal : top.vhd


ENTITY Fct IS
PORT(e0,e1,e2 : IN BIT;
s : OUT BIT);
END Fct;

ARCHITECTURE truc OF Fct IS


-- Les signaux (fils de liaison) sont déclarés avant le begin de l'architecture
SIGNAL e0e1,e2bar : BIT;
-- Les components sont déclarés avant le begin de l'architecture
COMPONENT et
PORT(e0,e1 : IN BIT;
s : OUT BIT);
END COMPONENT;
COMPONENT ou
https://fr.wikibooks.org/wiki/TD1_VHDL 10/18
15/01/2018 TD1 VHDL — Wikilivres

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

Le premier fichier est terminé. Il comporte une entité et une architecture.

Et voici le deuxième fichier.

-- fichier secondaire : composants.vhd


-- 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;

Le deuxième fichier est terminé, il comporte trois entités et trois architectures.

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 !

Version deux fichiers dont un package


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

https://fr.wikibooks.org/wiki/TD1_VHDL 11/18
15/01/2018 TD1 VHDL — Wikilivres

Voici en condensé comment on réalise un 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);
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;

ARCHITECTURE truc OF Fct IS


SIGNAL e0e1,e2bar : BIT;
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;

La déclaration des composants est maintenant remplacée par "USE work.mesportes.ALL;"


'

https://fr.wikibooks.org/wiki/TD1_VHDL 12/18
15/01/2018 TD1 VHDL — Wikilivres

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.

Que mettre dans les package ?


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.

Les bibliothèques usuelles


Même si vous n'avez pas l'intention d'utiliser des packages pour vos programmes vous serez bien obligé, comme on le
verra par la suite, d'utiliser les bibliothèques usuelles.

Bibliothèque standard
Le VHDL fait appel 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.

Bibliothèque IEEE-1164 standard logic


Les lignes suivantes importent la librairie IEEE-1164 standard logic.

library ieee;
use ieee.std_logic_1164.all;
https://fr.wikibooks.org/wiki/TD1_VHDL 13/18
15/01/2018 TD1 VHDL — Wikilivres

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)
1 : Niveau logique haut à basse impédance (mise à Vcc via une faible impédance)
Z : Niveau logique flottant (entrée déconnectée)
L : Niveau logique bas à haute impédance (mise à la masse via une résistance de pull-down)
H : Niveau logique haut à haute impédance (mise à Vcc via une résistance de pull-up)
W : Niveau logique inconnu à haute impédance (pouvant être 'L', 'Z' ou 'H')
X : Niveau logique inconnu (pouvant être '0', 'L', 'Z', 'H' ou '1')
U : Non défini
- : N'importe quel niveau logique (renvoie toujours true lors d'une comparaison avec les 8 autres niveaux
logiques)
On dispose de plus des fonctions rising_edge() et falling_edge(), utilisées pour synchroniser un process sur une
horloge :

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;

qui remplacent avantageusement le test classique, dont la couverture en simulation est incomplète (la transition 'X' ->
'1' étant interprétée au même titre que la transition '0' -> '1') :

if ((CLK_IN'event) and (CLK_IN = '1')) then

Bibliothèque IEEE-1164 standard logic et assemblage de composants


Jusqu'à présent nos entités utilisaient le type bit prédéfini (ou le type bit_vector) :

ENTITY demo IS PORT(


a : in BIT_VECTOR(3 DOWNTO 0);-- 4 entrées
s : out BIT_VECTOR(1 DOWNTO 0));
-- 2 sorties
END demo;

Si pour une raison ou pour une autre vous êtes obligé d'utiliser un type "std_logic" ou "std_logic_vector" de la librairie
IEEE, alors il vous faut savoir qu'il vous sera impossible de réaliser un "port map" entre un bit et un std_logic. Une
autre manière de dire les choses : si un seul composant nécessite un std_logic vous serez obligé de l'utiliser pour tous
les composants. L'entité précédente sera alors remplacée par :

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;

Ce n'est pas très compliqué sauf que pour nos assemblages de composants, chaque entité devra être précédée de

https://fr.wikibooks.org/wiki/TD1_VHDL 14/18
15/01/2018 TD1 VHDL — Wikilivres

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 :

-- fichier unique : top.vhd


library ieee;
use ieee.std_logic_1164.all;
ENTITY Fct IS
PORT(e0,e1,e2 : IN STD_LOGIC;
s : OUT STD_LOGIC);
END Fct;

ARCHITECTURE truc OF Fct IS


-- Les signaux (fils de liaison) sont déclarés avant le begin de l'architecture
SIGNAL e0e1,e2bar : STD_LOGIC;
-- Les components sont déclarés avant le begin de l'architecture
COMPONENT et
PORT(e0,e1 : IN STD_LOGIC;
s : OUT STD_LOGIC);
END COMPONENT;
COMPONENT ou
PORT(e0,e1 : IN STD_LOGIC;
s : OUT STD_LOGIC);
END COMPONENT;
COMPONENT inverseur
PORT(e : IN STD_LOGIC;
s : OUT STD_LOGIC);
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;
-- 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

https://fr.wikibooks.org/wiki/TD1_VHDL 15/18
15/01/2018 TD1 VHDL — Wikilivres

s<= NOT e;
END ainv;

Vous notez qu'en fait il n'y a pas beaucoup de changements.

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.

Et pour finir, quelques exemples


combinatoires
Le WikiBook (en) VHDL for FPGA Design fournit quelques exemples combinatoires que nous reproduisons
maintenant.

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.

Code VHDL du décodeur


Un décodeur peut simplement être décrit en VHDL.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity Decoder is
port
(
Sel : in std_logic_vector(2 downto 0);

y : out std_logic_vector(7 downto 0)


);
end Decoder;

architecture Behavioral of Decoder is


begin
y <= "00000001" when Sel="000" else
"00000010" when Sel="001" else
"00000100" when Sel="010" else
"00001000" when Sel="011" else
"00010000" when Sel="100" else
"00100000" when Sel="101" else
"01000000" when Sel="110" else
"10000000";
end architecture Behavioral;

Vous remarquez le un qui se "ballade" parmi des zéros en fonction de l'entrée de sélection ?

https://fr.wikibooks.org/wiki/TD1_VHDL 16/18
15/01/2018 TD1 VHDL — Wikilivres

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.

Le code VHDL du multiplexeur

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);

Output : out std_logic


);
end Multiplexer_VHDL;

architecture Behavioral of Multiplexer_VHDL is


begin
process (a, b, c, d, e, f, g, h, Sel) is
begin
case Sel is
when "000" => Output <= a;
when "001" => Output <= b;
when "010" => Output <= c;
when "011" => Output <= d;
when "100" => Output <= e;
when "101" => Output <= f;
when "110" => Output <= g;
when others => Output <= h;

https://fr.wikibooks.org/wiki/TD1_VHDL 17/18
15/01/2018 TD1 VHDL — Wikilivres

end case;
end process;
end Behavioral;

Remarquez les 8 entrées : une est choisie en fonction de l'entrée de sélection.

Simulation Waveform

Récupérée de « https://fr.wikibooks.org/w/index.php?title=TD1_VHDL&oldid=548324 »

La dernière modification de cette page a été faite le 24 avril 2017 à 13:31.

Les textes sont disponibles sous licence Creative Commons attribution partage à l’identique ; d’autres termes
peuvent s’appliquer.
Voyez les termes d’utilisation pour plus de détails.

https://fr.wikibooks.org/wiki/TD1_VHDL 18/18