Cours VHDL Complet
Langage de Description Materielle
Chapitre 1 : Introduction au VHDL
Presentation du langage de description materielle
1.1 Qu'est-ce que le VHDL ?
Historique
- 1981 : Projet lance par le Departement de la Defense americain (DoD)
- 1987 : Premiere normalisation IEEE 1076-1987
- 1993 : Revision majeure IEEE 1076-1993
- 2008 : IEEE 1076-2008 (VHDL-2008)
- 2019 : IEEE 1076-2019 (version actuelle)
Pourquoi utiliser VHDL ?
Documentation
Code auto-documente
Simulation
Test avant fabrication
Synthese
Generation de circuits
Reutilisable
IP cores portables
Standard IEEE
Independant du fabricant
Industriel
Utilise mondialement
1.2 VHDL vs Verilog
| Critere | VHDL | Verilog |
|---|---|---|
| Origine | DoD americain (1983) | Gateway Design (1984) |
| Syntaxe | Proche de Ada/Pascal | Proche de C |
| Typage | Fortement type | Faiblement type |
| Verbeux | Plus verbeux | Plus concis |
| Usage Europe | Tres repandu | Moins utilise |
| Usage USA/Asie | Utilise | Dominant |
Chapitre 2 : Structure d'un Programme VHDL
Entity, Architecture et composants
2.1 Les Unites de Conception
Un programme VHDL est compose de plusieurs unites de conception :
┌─────────────────────────────────────────────────────────┐ │ FICHIER VHDL │ ├─────────────────────────────────────────────────────────┤ │ ┌─────────────────┐ │ │ │ LIBRARY │ Bibliotheques utilisees │ │ │ USE │ Packages importes │ │ └─────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────┐ │ │ │ ENTITY │ Interface (ports E/S) │ │ │ (Boite noire) │ Vue externe du composant │ │ └─────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────┐ │ │ │ ARCHITECTURE │ Implementation (comportement) │ │ │ (Contenu) │ Vue interne du composant │ │ └─────────────────┘ │ └─────────────────────────────────────────────────────────┘
2.2 Declaration des Bibliotheques
-- Bibliotheque standard IEEE library IEEE; use IEEE.STD_LOGIC_1164.ALL; -- Types std_logic use IEEE.NUMERIC_STD.ALL; -- Types signed/unsigned -- Anciennes bibliotheques (a eviter) -- use IEEE.STD_LOGIC_ARITH.ALL; -- use IEEE.STD_LOGIC_UNSIGNED.ALL;
NUMERIC_STD au lieu de STD_LOGIC_ARITH pour les operations arithmetiques. C'est la norme moderne.
2.3 L'Entity (Entite)
L'entity definit l'interface externe du composant : ses ports d'entree et de sortie.
entity nom_entite is generic ( -- Parametres generiques (optionnel) N : integer := 8 ); port ( -- Entrees clk : in std_logic; reset : in std_logic; data_in: in std_logic_vector(N-1 downto 0); -- Sorties data_out: out std_logic_vector(N-1 downto 0); valid : out std_logic ); end entity nom_entite;
Modes des Ports
| Mode | Description | Lecture | Ecriture |
|---|---|---|---|
in |
Entree uniquement | Oui | Non |
out |
Sortie uniquement | Non | Oui |
inout |
Bidirectionnel | Oui | Oui |
buffer |
Sortie avec relecture | Oui | Oui |
2.4 L'Architecture
L'architecture decrit le comportement interne ou la structure du composant.
architecture behavioral of nom_entite is -- Zone de declaration signal sig_interne : std_logic; constant MAX_VAL : integer := 255; begin -- Zone des instructions concurrentes -- Affectation simple data_out <= data_in; -- Process (sequentiel) process(clk, reset) begin if reset = '1' then valid <= '0'; elsif rising_edge(clk) then valid <= '1'; end if; end process; end architecture behavioral;
2.5 Exemple Complet : Porte AND
-- Fichier: porte_and.vhd library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity porte_and is port ( A : in std_logic; B : in std_logic; Y : out std_logic ); end entity porte_and; architecture dataflow of porte_and is begin Y <= A and B; end architecture dataflow;
Chapitre 3 : Types de Donnees
Types scalaires, composites et conversion
3.1 Types Scalaires de Base
| Type | Description | Exemple |
|---|---|---|
bit |
Valeurs '0' ou '1' | signal s : bit := '0'; |
boolean |
TRUE ou FALSE | signal b : boolean := true; |
integer |
Entiers 32 bits | signal i : integer := 42; |
natural |
Entiers >= 0 | signal n : natural := 10; |
positive |
Entiers > 0 | signal p : positive := 1; |
real |
Flottants (simulation) | constant pi : real := 3.14; |
character |
Caracteres ASCII | constant c : character := 'A'; |
time |
Durees (simulation) | constant T : time := 10 ns; |
3.2 Types std_logic (IEEE 1164)
Le type std_logic est le plus utilise en synthese car il modelise les 9 etats possibles d'un signal numerique.
| Valeur | Signification | Synthetisable |
|---|---|---|
'0' |
Niveau bas force | Oui |
'1' |
Niveau haut force | Oui |
'Z' |
Haute impedance | Oui |
'X' |
Inconnu force | Non |
'U' |
Non initialise | Non |
'-' |
Don't care | Oui |
'L' |
Niveau bas faible | Non |
'H' |
Niveau haut faible | Non |
'W' |
Inconnu faible | Non |
-- Declaration de signaux std_logic signal bit_unique : std_logic; signal bus_8bits : std_logic_vector(7 downto 0); signal bus_ascend : std_logic_vector(0 to 7); -- Affectation de valeurs bit_unique <= '1'; bus_8bits <= "10101010"; -- Binaire bus_8bits <= x"AA"; -- Hexadecimal bus_8bits <= (others => '0'); -- Tous a zero
3.3 Types signed et unsigned
library IEEE; use IEEE.NUMERIC_STD.ALL; -- unsigned : entier non signe (0 a 2^N-1) signal compteur : unsigned(7 downto 0); -- 0 a 255 -- signed : entier signe (complement a 2) signal valeur : signed(7 downto 0); -- -128 a +127 -- Operations arithmetiques compteur <= compteur + 1; -- Increment valeur <= valeur - 10; -- Soustraction
3.4 Conversions de Types
signal slv : std_logic_vector(7 downto 0); signal u : unsigned(7 downto 0); signal s : signed(7 downto 0); signal i : integer; -- std_logic_vector vers unsigned/signed u <= unsigned(slv); s <= signed(slv); -- unsigned/signed vers std_logic_vector slv <= std_logic_vector(u); slv <= std_logic_vector(s); -- integer vers unsigned/signed u <= to_unsigned(i, 8); -- 8 = nombre de bits s <= to_signed(i, 8); -- unsigned/signed vers integer i <= to_integer(u); i <= to_integer(s);
CONVERSIONS DE TYPES EN VHDL
┌─────────────────┐
│ integer │
└────────┬────────┘
│ to_unsigned(i, N)
│ to_signed(i, N)
▼
┌─────────────────┐
│ unsigned/signed │ ◄────► Arithmetique (+, -, *, /)
└────────┬────────┘
│ std_logic_vector(u)
│ unsigned(slv) / signed(slv)
▼
┌─────────────────┐
│std_logic_vector │ ◄────► Logique (and, or, not)
└─────────────────┘
Chapitre 4 : Operateurs
Operateurs logiques, arithmetiques et relationnels
4.1 Operateurs Logiques
| Operateur | Description | Exemple |
|---|---|---|
not |
NON logique | Y <= not A; |
and |
ET logique | Y <= A and B; |
or |
OU logique | Y <= A or B; |
nand |
NON-ET | Y <= A nand B; |
nor |
NON-OU | Y <= A nor B; |
xor |
OU exclusif | Y <= A xor B; |
xnor |
NON-OU exclusif | Y <= A xnor B; |
4.2 Operateurs Arithmetiques
-- Necessitent NUMERIC_STD pour unsigned/signed signal a, b, c : unsigned(7 downto 0); c <= a + b; -- Addition c <= a - b; -- Soustraction c <= a * b; -- Multiplication (attention taille!) c <= a / b; -- Division (non synthetisable!) c <= a mod b; -- Modulo c <= a rem b; -- Reste c <= abs(a); -- Valeur absolue c <= -a; -- Negation
4.3 Operateurs Relationnels
-- Comparaisons (resultat : boolean) if a = b then -- Egalite if a /= b then -- Difference if a < b then -- Inferieur if a <= b then -- Inferieur ou egal if a > b then -- Superieur if a >= b then -- Superieur ou egal
4.4 Operateurs de Decalage
-- Decalages logiques (remplissage par '0') c <= a sll 2; -- Shift Left Logical (x4) c <= a srl 2; -- Shift Right Logical (/4) -- Decalages arithmetiques (conserve le signe) c <= a sla 2; -- Shift Left Arithmetic c <= a sra 2; -- Shift Right Arithmetic -- Rotations c <= a rol 2; -- Rotate Left c <= a ror 2; -- Rotate Right -- Alternative avec NUMERIC_STD c <= shift_left(a, 2); c <= shift_right(a, 2);
4.5 Concatenation et Selection
signal a : std_logic_vector(3 downto 0); signal b : std_logic_vector(3 downto 0); signal c : std_logic_vector(7 downto 0); -- Concatenation avec & c <= a & b; -- c = a(3..0) & b(3..0) c <= "0000" & a; -- Extension a 8 bits -- Selection de bits a <= c(7 downto 4); -- Bits de poids fort b <= c(3 downto 0); -- Bits de poids faible -- Bit unique signal bit : std_logic; bit <= c(5); -- Bit numero 5
Chapitre 5 : Logique Combinatoire
Instructions concurrentes et affectations
5.1 Affectation Simple
-- Affectation directe (concurrente) Y <= A and B; Z <= A or B or C; W <= not (A xor B);
5.2 Affectation Conditionnelle (when...else)
-- Multiplexeur 2:1 Y <= A when sel = '0' else B; -- Multiplexeur 4:1 Y <= A when sel = "00" else B when sel = "01" else C when sel = "10" else D; -- Comparateur egal <= '1' when A = B else '0';
5.3 Affectation Selective (with...select)
-- Multiplexeur 4:1 avec with...select with sel select Y <= A when "00", B when "01", C when "10", D when "11", '0' when others; -- Decodeur 7 segments with digit select segments <= "1111110" when "0000", -- 0 "0110000" when "0001", -- 1 "1101101" when "0010", -- 2 "1111001" when "0011", -- 3 -- ... etc "0000000" when others;
5.4 Exemple : Additionneur 4 bits
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity additionneur_4bits is port ( A : in std_logic_vector(3 downto 0); B : in std_logic_vector(3 downto 0); Cin : in std_logic; Sum : out std_logic_vector(3 downto 0); Cout : out std_logic ); end entity; architecture behavioral of additionneur_4bits is signal result : unsigned(4 downto 0); begin result <= ('0' & unsigned(A)) + ('0' & unsigned(B)) + ("0000" & Cin); Sum <= std_logic_vector(result(3 downto 0)); Cout <= result(4); end architecture;
Chapitre 6 : Logique Sequentielle
Process, bascules et registres
6.1 Le Process
Le process est un bloc d'instructions sequentielles execute quand un signal de sa liste de sensibilite change.
-- Syntaxe generale process(signal1, signal2, ...) -- Liste de sensibilite -- Declarations locales (variables) begin -- Instructions sequentielles end process; -- Process avec label (recommande) mon_process: process(clk, reset) begin -- ... end process mon_process;
6.2 Bascule D (Flip-Flop)
-- Bascule D avec reset asynchrone process(clk, reset) begin if reset = '1' then Q <= '0'; elsif rising_edge(clk) then Q <= D; end if; end process; -- Bascule D avec reset synchrone process(clk) begin if rising_edge(clk) then if reset = '1' then Q <= '0'; else Q <= D; end if; end if; end process; -- Bascule D avec enable process(clk, reset) begin if reset = '1' then Q <= '0'; elsif rising_edge(clk) then if enable = '1' then Q <= D; end if; end if; end process;
6.3 Compteur
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity compteur_8bits is port ( clk : in std_logic; reset : in std_logic; enable : in std_logic; count : out std_logic_vector(7 downto 0) ); end entity; architecture behavioral of compteur_8bits is signal cnt : unsigned(7 downto 0); begin process(clk, reset) begin if reset = '1' then cnt <= (others => '0'); elsif rising_edge(clk) then if enable = '1' then cnt <= cnt + 1; end if; end if; end process; count <= std_logic_vector(cnt); end architecture;
6.4 Registre a Decalage
entity shift_register is generic (N : integer := 8); port ( clk : in std_logic; reset : in std_logic; shift_en : in std_logic; data_in : in std_logic; data_out : out std_logic_vector(N-1 downto 0) ); end entity; architecture behavioral of shift_register is signal reg : std_logic_vector(N-1 downto 0); begin process(clk, reset) begin if reset = '1' then reg <= (others => '0'); elsif rising_edge(clk) then if shift_en = '1' then reg <= reg(N-2 downto 0) & data_in; -- Decalage gauche end if; end if; end process; data_out <= reg; end architecture;
Chapitre 7 : Machines a Etats Finis (FSM)
Moore et Mealy
7.1 Types de Machines a Etats
Machine de Moore
Sorties dependent uniquement de l'etat courant
Machine de Mealy
Sorties dependent de l'etat ET des entrees
MOORE MEALY
┌─────────────┐ ┌─────────────┐
│ │ │ │
───►│ Etat │──► Sorties ───►│ Etat │───┐
│ courant │ │ courant │ │
│ │ │ │ │
└──────┬──────┘ └──────┬──────┘ │
│ │ ▼
│ Entrees │ Sorties
▼ ▼ ▲
┌─────────────┐ ┌─────────────┐ │
│ Logique │ │ Logique │───┘
│ d'etat │ │ d'etat │
└─────────────┘ └─────────────┘
7.2 Machine de Moore - Exemple
library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity fsm_moore is port ( clk : in std_logic; reset : in std_logic; start : in std_logic; done : in std_logic; busy : out std_logic; ready : out std_logic ); end entity; architecture behavioral of fsm_moore is -- Definition des etats type state_type is (IDLE, RUNNING, FINISHED); signal state, next_state : state_type; begin -- Process 1: Registre d'etat (sequentiel) process(clk, reset) begin if reset = '1' then state <= IDLE; elsif rising_edge(clk) then state <= next_state; end if; end process; -- Process 2: Logique de transition (combinatoire) process(state, start, done) begin case state is when IDLE => if start = '1' then next_state <= RUNNING; else next_state <= IDLE; end if; when RUNNING => if done = '1' then next_state <= FINISHED; else next_state <= RUNNING; end if; when FINISHED => next_state <= IDLE; when others => next_state <= IDLE; end case; end process; -- Process 3: Logique de sortie (Moore: depend de l'etat) process(state) begin case state is when IDLE => busy <= '0'; ready <= '1'; when RUNNING => busy <= '1'; ready <= '0'; when FINISHED => busy <= '0'; ready <= '0'; when others => busy <= '0'; ready <= '0'; end case; end process; end architecture;
Chapitre 8 : Testbench et Simulation
Verification du design
8.1 Structure d'un Testbench
library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity tb_compteur is -- Pas de ports pour un testbench! end entity; architecture test of tb_compteur is -- Composant a tester component compteur_8bits port ( clk : in std_logic; reset : in std_logic; enable : in std_logic; count : out std_logic_vector(7 downto 0) ); end component; -- Signaux de test signal clk_tb : std_logic := '0'; signal reset_tb : std_logic := '0'; signal enable_tb : std_logic := '0'; signal count_tb : std_logic_vector(7 downto 0); constant CLK_PERIOD : time := 10 ns; begin -- Instanciation du DUT (Device Under Test) DUT: compteur_8bits port map ( clk => clk_tb, reset => reset_tb, enable => enable_tb, count => count_tb ); -- Generation de l'horloge clk_tb <= not clk_tb after CLK_PERIOD/2; -- Process de stimuli stimulus: process begin -- Reset initial reset_tb <= '1'; wait for 20 ns; reset_tb <= '0'; -- Activer le compteur wait for 10 ns; enable_tb <= '1'; -- Compter pendant 200ns wait for 200 ns; -- Desactiver enable_tb <= '0'; wait for 50 ns; -- Fin de simulation report "Simulation terminee"; wait; end process; end architecture;
8.2 Assertions
-- Verifications dans le testbench process begin wait for 100 ns; -- Assert simple assert count_tb /= "00000000" report "Erreur: compteur devrait avoir compte!" severity ERROR; -- Assert avec note assert false report "Valeur du compteur: " & integer'image(to_integer(unsigned(count_tb))) severity NOTE; wait; end process;
Chapitre 9 : Synthese et Implementation
Du code au circuit
9.1 Regles de Codage Synthetisable
- Utiliser uniquement
std_logicetstd_logic_vector - Eviter les boucles
whileetforavec limites variables - Pas de
waitdans le code synthetisable - Pas de
realoutime - Toujours specifier le cas
othersdans lescase - Initialiser les signaux dans le reset, pas a la declaration
- Un seul signal d'horloge par process
Chapitre 10 : Projets Pratiques
Applications completes
10.1 Diviseur de Frequence
entity clock_divider is generic (DIV_FACTOR : integer := 50000000); -- 50MHz -> 1Hz port ( clk_in : in std_logic; reset : in std_logic; clk_out : out std_logic ); end entity; architecture behavioral of clock_divider is signal counter : integer range 0 to DIV_FACTOR-1 := 0; signal clk_div : std_logic := '0'; begin process(clk_in, reset) begin if reset = '1' then counter <= 0; clk_div <= '0'; elsif rising_edge(clk_in) then if counter = DIV_FACTOR-1 then counter <= 0; clk_div <= not clk_div; else counter <= counter + 1; end if; end if; end process; clk_out <= clk_div; end architecture;