TD6 VHDL et Simulation
VHDL est un langage de spécification, il est donc très lié à la simulation. Nous allons présenter un certain nombre de façons de simuler. La simulation dépend beaucoup des fournisseurs des simulateurs VHDL.
Test Bench = test en VHDL
Introduction
modifierNous allons commencer par deux exemples :
entity addit is port (
a,b,c: in bit;
s,r: out bit);
end addit;
architecture addit of addit is
begin
s <= a xor b xor c;
r <= ((a and b) or (c and (a xor b)));
end addit;
Si l'on veut tester cet additionneur il faut bâtir un fichier destiné à construire les signaux de tests : on appelle cela un Test Bench. On parle classiquement de test bench lorsque la simulation se réalise en VHDL (sauf pour visualiser les résultats). On prendra par exemple : fichier demo1.vhdl
entity demo1 is
end demo1;
architecture demo1 of demo1 is
signal asig,bsig,csig,sum,carry : bit;
begin
asig <= not asig after 100 ns;
bsig <= not bsig after 200 ns;
csig <= not csig after 400 ns;
ad1:entity work.addit
port map (asig,bsig,csig,sum,carry);
end demo1;
Autre exemple (séquentiel celui-là) :
entity cmpt is port (
clk: in bit;
q0,q1: inout bit);
end cmpt;
architecture cmpt of cmpt is
begin
cmpt1 : process (clk) begin
if (clk'event and clk='1') then
q0 <= not q0;
q1 <= q0 xor q1;
end if;
end process;
end cmpt;
Si l'on veut tester ce compteur il faut bâtir un fichier destiné à construire les signaux de tests. On prendra par exemple : fichier demo2.vhdl
entity demo2 is
end demo2;
architecture demo2 of demo2 is
signal clksig,q0sig,q1sig : bit;
begin
clksig <= not clksig after 10 ns;
cpt1:entity work.cmpt
port map (clksig,q0sig,q1sig);
end demo2;
Quelques autres manières de spécifier des valeurs sur les entrées :
process begin
s_en<='0';
s_d0<='1';
wait for 40 ns;
s_en<='1';
wait for 40 ns;
..
end process;
ou encore
process begin
wait for 5 ns;
s_en<='0','1' after 10 ns,'0' after 18 ns,
'1' after 25 ns; --30 ns ici
wait; --fin
..
end process;
Remarque : la plupart des simulateurs y compris celui de Warp (Aldec) acceptent ce style de test. Pour un simulateur gratuit sous Linux voir FreeVHDL
Méthodes graphiques
modifierLes méthodes graphiques sont intuitives et de ce fait très appréciées par les étudiants. Il n'empêche qu'il est facile de trouver des exemples simples qui sont bien mieux décrits par des méthodes textuelles. L'exercice 1 en fournit un exemple.
Exercice
modifierExercice 1 : Simulation textIO On donne le programme :
ENTITY Counter_1 IS end;
--library work;use work.textio.all;
library std;use std.textio.all; -- avec warp2
architecture behave of Counter_1 is
signal clk : bit:='0';
signal Count : integer:=0;
begin
process begin
wait for 10 ns;
clk <= not clk;
if( now > 340 ns) then wait; end if; -- fin
end process;
process begin
wait until (Clk='0');
if (Count=7) then Count <=0;
else Count <=Count+1;
end if;
end process;
process (Count) variable L:LINE; begin
write(L,now);write(L,STRING'(" Count= "));
write(L,Count);writeline(Output,L);
end process;
end behave;
qui donne en simulation :
20 ns Count= 1 40 ns Count= 2 60 ns Count= 3 80 ns Count= 4 100 ns Count= 5 120 ns Count= 6 140 ns Count= 7 160 ns Count= 0 180 ns Count= 1 200 ns Count= 2 220 ns Count= 3 240 ns Count= 4 260 ns Count= 5 280 ns Count= 6 300 ns Count= 7 320 ns Count= 0
On peut remarquer la façon de faire ici : un process décrit le composant à tester et deux autres process sont là pour le test.
1°) Repérer le compteur et le transformer en écrivant le process de comptage dans un style plus familier pour nous : en utilisant une liste de sensibilité et un if clk'event.
2°) Reprendre le test de l'additionneur et le transformer pour avoir une sortie affichée en texte lors de sa simulation. Comment faire pour que sa sortie sur 2 bits apparaisse en décimal (de 0 à 3) ?
3°) Réaliser un module (librairie) qui permet de tester un afficheur 7 segments sur du texte. À faire que si l'on a du temps.
1°) Remplacer le process central par :
process(clk) begin
-- wait until (Clk='0');
if clk'event and clk='0' then
if (Count=7) then Count <=0;
else Count <=Count+1;
end if;
end if;
end process;
2°)
----- Composant à tester --------
entity addit is
--generic (gen : integer := 10);
port (
a,b,c: in bit;
s,r: out bit);
end addit;
architecture aaddit of addit is
begin
s <= a xor b xor c;
r <= ((a and b) or (c and (a xor b)));
end aaddit;
------- Test Bench --------
library std;
use std.textio.all;
use WORK.addit;
entity model is
end model;
architecture struct of model is
signal asig,bsig,csig,sum,carry : bit:='0';
component addit is port (
a,b,c: in bit;
s,r: out bit);
end component;
begin
ad1: addit port map (a=>asig,b=>bsig,c=>csig,s=>sum,r=>carry);
asig <= not asig after 10 ns;
bsig <= not bsig after 20 ns;
csig <= not csig after 40 ns;
TestBench:process(sum,carry) variable L:LINE; begin
write(L,now);write(L,STRING'(" (r,s)= "));
write(L,carry);write(L,sum);
write(L,STRING'(" = "));write(L,asig);write(L,STRING'(" + ")); write(L,bsig);
write(L,STRING'(" + "));write(L,csig);writeline(Output,L);
end process;
end struct;
donne comme résultat :
Simulation time = 0 fs + 0d > r 100ns Run simulation for which time span? Simulating model to time 100 ns 10 ns (r,s)= 01 = 1 + 0 + 0 30 ns (r,s)= 10 = 1 + 1 + 0 40 ns (r,s)= 01 = 0 + 0 + 1 50 ns (r,s)= 10 = 1 + 0 + 1 70 ns (r,s)= 11 = 1 + 1 + 1 80 ns (r,s)= 00 = 0 + 0 + 0 90 ns (r,s)= 01 = 1 + 0 + 0 Simulation time = 100 ns + 0d
3°)
--library work;use work.textio.all;
library std;use std.textio.all;
PACKAGE test7seg IS
COMPONENT SeptSeg
PORT (a : IN BIT_VECTOR(6 DOWNTO 0));
END COMPONENT;
END test7seg;
ENTITY SeptSeg IS
PORT (a : IN BIT_VECTOR(6 DOWNTO 0));
END SeptSeg;
library std;use std.textio.all; --imperatif avant architecture
ARCHITECTURE aSeptSeg OF SeptSeg IS
BEGIN
process (a) variable L:LINE;
begin
write(L,now);
writeline(Output,L);
if a(0)='1' then
write(L,STRING'(" **"));
writeline(Output,L);
else
write(L,STRING'(" --"));
writeline(Output,L);
end if;
if (a(5)='1' and a(1)='0') then
write(L,STRING'("* |"));
writeline(Output,L);
write(L,STRING'("* |"));
writeline(Output,L);
elsif (a(5)='1' and a(1)='1') then
write(L,STRING'("* *"));
writeline(Output,L);
write(L,STRING'("* *"));
writeline(Output,L);
elsif (a(5)='0' and a(1)='1') then
write(L,STRING'("| *"));
writeline(Output,L);
write(L,STRING'("| *"));
writeline(Output,L);
else
write(L,STRING'("| |"));
writeline(Output,L);
write(L,STRING'("| |"));
writeline(Output,L);
end if;
if a(6)='1' then
write(L,STRING'(" **"));
writeline(Output,L);
else
write(L,STRING'(" --"));
writeline(Output,L);
end if;
if (a(4)='1' and a(2)='0') then
write(L,STRING'("* |"));
writeline(Output,L);
write(L,STRING'("* |"));
writeline(Output,L);
elsif (a(4)='1' and a(2)='1') then
write(L,STRING'("* *"));
writeline(Output,L);
write(L,STRING'("* *"));
writeline(Output,L);
elsif (a(4)='0' and a(2)='1') then
write(L,STRING'("| *"));
writeline(Output,L);
write(L,STRING'("| *"));
writeline(Output,L);
else
write(L,STRING'("| |"));
writeline(Output,L);
write(L,STRING'("| |"));
writeline(Output,L);
end if;
if a(3)='1' then
write(L,STRING'(" **"));
writeline(Output,L);
else
write(L,STRING'(" --"));
writeline(Output,L);
end if;
end process;
END aSeptSeg;
Un fichier test du style :
ENTITY transcod IS
PORT(a:IN BIT_VECTOR(3 DOWNTO 0);s:OUT BIT_VECTOR(6 DOWNTO 0));
END transcod;
ARCHITECTURE atranscod OF transcod IS
BEGIN
with a SELECT
s <="0111111" WHEN "0000",
"0000110" WHEN "0001",
"1011011" WHEN "0010",
"1001111" WHEN "0011",
"1100110" WHEN "0100",
"1101101" WHEN "0101",
"1111101" WHEN "0110",
"0000111" WHEN "0111",
"1111111" WHEN "1000",
"1101111" WHEN "1001",
"0000000" WHEN OTHERS;
END atranscod;
ENTITY test7seg IS END;
library afficheur7seg;
use afficheur7seg.all;
ARCHITECTURE atest7seg OF test7seg IS
SIGNAL e4 :BIT_VECTOR(3 DOWNTO 0);
SIGNAL s7 : BIT_VECTOR(6 DOWNTO 0);
COMPONENT SeptSeg
PORT (a : IN BIT_VECTOR(6 DOWNTO 0));
END COMPONENT;
COMPONENT transcod
PORT(a:IN BIT_VECTOR(3 DOWNTO 0);s:OUT BIT_VECTOR(6 DOWNTO 0));
END COMPONENT;
BEGIN
c1:transcod PORT MAP(e4,s7);
c2:SeptSeg PORT MAP(s7);
e4(0) <= not e4(0) after 100 ns;
e4(1) <= not e4(1) after 200 ns;
e4(2) <= not e4(2) after 400 ns;
e4(3) <= not e4(3) after 800 ns;
END;
donnera un rapport : (** : segment allumé, -- segment éteint) pas très facile à lire ...
0 ns : -- : | | : | | : -- : | | : | | : -- : 0 ns : ** : * * : * * : -- : * * : * * : ** : 100 ns : -- : | * : | * : -- : | * : | * : -- : ** : | * : | * : ** : * | : * | : ** : 300 ns : ** : | * : | * : ** : | * : | * : ** : 400 ns : -- : * * : * * : ** : | * : | * : -- : 500 ns : ** : * | : * | : ** : | * : | * : ** : 600 ns : ** : * | : * | : ** : * * : * * : ** : 700 ns ...... KERNEL: stopped at time: 1600 ns
Méthode tabulaire
modifierElle consiste à construire une table de valeurs. Un exemple sera plus parlant :
ENTITY Counter_1 IS end;
library std;
use std.textio.all;
architecture behave of Counter_1 is
signal clk : bit:='0';
signal Count : integer:=0;
type test_vector is record
clk: bit;
cnt: integer;
end record;
type test_vector_array is array(natural range<>) of test_vector;
constant test_vectors:test_vector_array := (
(clk=>'0',cnt=>0),
(clk=>'1',cnt=>0),
(clk=>'0',cnt=>0),
(clk=>'1',cnt=>1),
(clk=>'0',cnt=>1),
(clk=>'1',cnt=>2),
(clk=>'0',cnt=>2),
(clk=>'1',cnt=>3),
(clk=>'0',cnt=>3)
);
begin
process
variable i:integer:=0;
variable vector: test_vector;
variable L:LINE;
begin
wait for 10 ns;
vector := test_vectors(i);
i:=i+1; if i>8 then i:=0;end if;
clk <= vector.clk;
if Count /= vector.cnt then
write(L,now);write(L,STRING'("Erreur : "));
write(L,Count);write(L,STRING'(" <> "));
write(L,vector.cnt);writeline(Output,L);
end if;
end process;
process(clk) begin
if clk'event and clk='0' then
if (Count=7) then Count <=0;
else Count <=Count+1;
end if;
end if;
end process;
end;
La difficulté peut être avec la gestion du temps. Si vous regardez attentivement les tests vous vous apercevez qu'il faut décaler le comptage du front. J'ai essayé avec deux simulateurs (un libre et un payant) qui ont donné le même résultat.
Exercice 2
modifierReprendre le test de l'aditionneur avec une méthode tabulaire.
Voir aussi
modifier- Un simulateur en ligne peut être utilisé avec un compte Google.