Vous êtes sur la page 1sur 14

ESPA – Mention Electronique – M1 2023

Support de cours : Programmation matérielle

Chapitre 3 : Circuits combinatoires – Description en VHDL


Ce chapitre présente quelques exemples de description VHDL de circuits combinatoires.
1- Les instructions concurrentes et séquentiels de VHDL
La base d’un comportement dirigé par les évènements est la notion de processus concurrents.
Les instructions concurrentes servent à traiter l’information à temps discret. Elles sont
évaluées à chaque point de simulation logique en fonction de leur sensibilité à l’évènement
courant. Les processus sont des instructions concurrentes, l’affectation des signaux (<=), le
break ou l’assertion.
Le tableau I ci-dessous présente l’ensemble des instructions concurrentes sous VHDL
Tableau I : Instructions concurrentes

PROCESS
Un processus (process) définit une portion de code dont les instructions sont exécutées en
séquence dans l’ordre donné. Le process lui-même est une instruction concurrente, plusieurs
blocs de process dans une architecture seront exécutés simultanément.
Syntaxe:
process-name: PROCESS (sensitivity-list)
variable-declarations;
BEGIN sequential-statements;
END PROCESS process-name;

Autres instructions séquentielles


Le Tableau II présente les instructions séquentielles de VHDL

1
ESPA – Mention Electronique – M1 2023
Support de cours : Programmation matérielle

Tableau II : Instructions séquentielles

2
ESPA – Mention Electronique – M1 2023
Support de cours : Programmation matérielle

3
ESPA – Mention Electronique – M1 2023
Support de cours : Programmation matérielle

2- Description VHDL de quelques circuits combinatoires


a) Portes
La description VHDL ci-dessous représente le circuit de la Figure 1.

4
ESPA – Mention Electronique – M1 2023
Support de cours : Programmation matérielle

Figure 1 : Portes combinatoires


‘Description VHDL
library IEEE;
use IEEE.std_logic_1164.all;

entity GATE is
port(D1, D2, D3 : in std_logic;
Y1, Y2, Y3, Y4, Y5 : out std_logic);
end GATE;

architecture RTL of GATE is


signal tmp : std_logic;
begin
Y1 <= D1 nor D2;
Y2 <= not (D1 or D2 or D3);
Y3 <= D1 and D2 and not D3;
Y4 <= D1 xor (D2 xor D3);
tmp <= D1 xor D2;

5
ESPA – Mention Electronique – M1 2023
Support de cours : Programmation matérielle

Y5 <= tmp nand D3;


end RTL;

b) Multiplexeurs (mémorisation implicite)


Le circuit MUX est représenté par la Fig.2

Figure 2 : Multiplexeur

library IEEE;
use IEEE.std_logic_1164.all;
entity MUX is
port(Sel : in std_logic_vector(1 downto 0) ;
A, B, C, D : in std_logic;
Y1, Y2, Y3, Y4 : out std_logic);
end MUX;

architecture RTL of MUX is


signal tmp : std_logic ;

6
ESPA – Mention Electronique – M1 2023
Support de cours : Programmation matérielle

begin

Y1 <= A when Sel(0) = '0' else B;

p0 : process (A, B, Sel)


begin

if (Sel(0) = '0') then


Y2 <= A;
else
Y2 <= B;
end if;

if (Sel(1) = '1') then


Y3 <= A;
end if;

end process;

p1 : process (A, B, C, D, Sel)


begin
case Sel is
when "00" => Y4 <= A;
when "01" => Y4 <= B;
when "10" => Y4 <= C;
when "11" => Y4 <= D;
when others => Y4 <= A;
end case;
end process;
end RTL;

7
ESPA – Mention Electronique – M1 2023
Support de cours : Programmation matérielle

Il faut noter ici un point important : la mémorisation implicite n’est possible qu’à l’intérieur
d’un process. En effet, les instructions conditionnelles hors process (when, with … select) ne
peuvent être incomplètes d’un point de vue syntaxique. Seuls le if et le case autorisent les
branches incomplètes, donc obligatoirement dans un process.
c) Démultiplexeur – décodeur
Le fonctionnement du démultiplexeur de la Fig.3 est le suivant : si G = 0, Y est mis à 0.
L’expression (others => '0') est un agrégat. La même valeur 0 est affectée à tous les bits de Y.
Si G = 1, Y(A) = 1. On obtient bien le démultiplexeur dans sa version 1 vers 8 (3 bits
d’adresses). Il connecte G sur la sortie Y(A), A pouvant aller de 0 à 7.
Pour réaliser un décodeur, il suffit de mettre G à 1 en permanence au moment de l’utilisation
du composant.

Le chronogramme suivant montre le fonctionnement du circuit :

Figure 4 : Chronogramme du multiplexeur


Description VHDL
library IEEE;
use IEEE.std_logic_1164.all;

entity Demux_1vers8 is

8
ESPA – Mention Electronique – M1 2023
Support de cours : Programmation matérielle

port (G : in std_logic;
A : in std_logic_vector(2 downto 0);
Y : out std_logic_vector(7 downto 0) );
end Demux_1vers8;

architecture a1 of Demux_1vers8 is
begin
PROCESS (G, A) BEGIN
if (G = '0') then
Y <= (others => '0');
else

case A is
when "000" => Y <= "00000001";
when "001" => Y <= "00000010";
when "010" => Y <= "00000100";
when "011" => Y <= "00001000";
when "100" => Y <= "00010000";
when "101" => Y <= "00100000";
when "110" => Y <= "01000000";
when "111" => Y <= "10000000";
when others => Y <= "00000001";
end case;
end if;
END PROCESS;
end;

Le problème avec l’instruction case, c’est qu’il faut autant de lignes que de sorties pour décrire
le fonctionnement du circuit. On peut réécrire le démultiplexeur d’une manière plus générale,
c'est-à-dire indépendamment de sa taille, de la manière suivante :
library IEEE;

9
ESPA – Mention Electronique – M1 2023
Support de cours : Programmation matérielle

use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;

entity Demux_1vers8 is
port (G : in std_logic;
A : in std_logic_vector(2 downto 0);
Y : out std_logic_vector(7 downto 0) );
end Demux_1vers8;
architecture a1 of Demux_1vers8 is
begin
PROCESS (G, A) BEGIN
Y <= (others => '0'); -- forcément en premier
if (G = '1') then
Y(CONV_INTEGER(A)) <= '1';
end if;
END PROCESS;
end;
Y est mis à 0 en premier. Si G = 0, Y reste à 0. Si G = 1, on copie 1 sur le bit A de Y. Comme
nous sommes dans un process, il n’y a pas de conflit sur le bit A mis à 1 car c’est la dernière
instruction qui est prise en compte (mode séquentiel). Le problème avec cette description est
que l’indice du bit dans Y doit être de type entier alors que A est de type std_logic_vector. Il
faut donc utiliser une fonction de conversion définie dans le package std_logic_unsigned,
CONV_INTEGER. La conversion du std_logic_vector en entier est obligatoire. Le
fonctionnement du nouveau démultiplexeur est strictement identique à celui utilisant
l’instruction case (ainsi d’ailleurs que le nombre de portes utilisées).
Il faut aussi noter que les instructions :
if (G = '1') then Y(CONV_INTEGER(A)) <= '1'; end if;
peuvent être remplacées par :
Y(CONV_INTEGER(A)) <= G;

d) Buffer bidirectionnel trois états


Un buffer trois états ressemble fortement à un multiplexeur dans sa description .

10
ESPA – Mention Electronique – M1 2023
Support de cours : Programmation matérielle

Figure 5 : Buffer 3 états


Code VHDL
library IEEE;
use IEEE.std_logic_1164.all;

entity trois_etats is
port(E : in std_logic;
S : out std_logic;
Cde : in std_logic);
end trois_etats;

architecture comporte of trois_etats is


begin
S <= E when Cde='1' else 'Z';
end comporte ;

Un buffer bidirectionnel est un buffer trois états dont la sortie est réinjectée dans le design.

Figure 6 : Buffer bidirectionnel


library IEEE;
use IEEE.std_logic_1164.all;

11
ESPA – Mention Electronique – M1 2023
Support de cours : Programmation matérielle

entity bidir is
port(E : in std_logic;
S : out std_logic;
IO : inout std_logic;
Cde : in std_logic);
end bidir;

architecture comporte of bidir is


begin
IO <= E when Cde='1' else 'Z';
S <= IO;
end comporte ;

IO est maintenant bidirectionnelle (à la fois entrée et sortie). Si Cde = 1, IO est une sortie, si
Cde = 0 alors le buffer 3 états passe à l’état haute impédance et on peut utiliser IO comme une
entrée. Pour pouvoir écrire une valeur depuis l’extérieur sur IO, il faut que Cde soit égale à 0.
Une broche bidirectionnelle est utilisée par exemple pour lire et écrire des données dans une
mémoire de type RAM.
Pour simuler correctement un buffer bidirectionnel, il faut créer un composant externe afin de
générer un état sur IO quand ce signal est une entrée.
e) Mémoire ROM
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;

entity mem is
port (addr : in std_logic_vector(3 downto 0);
dout : out std_logic_vector(7 downto 0));
end mem;

architecture a1 of mem is

12
ESPA – Mention Electronique – M1 2023
Support de cours : Programmation matérielle

TYPE mem_data IS ARRAY (0 TO 15) OF std_logic_vector(7 DOWNTO 0);


constant data : mem_data := (
("01000000"),
("01111001"),
("00100100"),
("00110000"),
("00011001"),
("00010010"),
("00000010"),
("01111000"),
("00000000"),
("00010000"),
("00000000"),
("00000000"),
("00000000"),
("00000000"),
("00000000"), ("00000000"));
begin
dout <= data(CONV_INTEGER(addr));
end;
Le type mem_data définit un tableau (ARRAY) de 16 cases de largeur 8 bits. La constante data
qui représente le contenu de la mémoire est initialisée aux lignes 10 à 26. La ligne 29 définit le
fonctionnement de la mémoire. Elle utilise une fonction de conversion définie dans le package
std_logic_unsigned, CONV_INTEGER. En effet, l’index du tableau data doit être un nombre
entier alors que le signal data est de type std_logic_vector. La conversion std_logic_vector vers
entier est obligatoire.
Le chronogramme suivant montre le fonctionnement de la mémoire :

13
ESPA – Mention Electronique – M1 2023
Support de cours : Programmation matérielle

14

Vous aimerez peut-être aussi