Sunteți pe pagina 1din 11

Fundamentele Calculatoarelor 2018 - 2019 Laborator 4

Laborator 4
1. Comparator în Verilog

Dacă se dă un pătrățel, am discutat laboratorul trecut că trebuie să știm să scriem


codul aferent în Verilog după regulile de mai jos.

Reguli de bază pentru orice pătrățel


1) Pătrățel - când vedem un pătrățel scriem module și endmodule
2) Nume pătrățel - după module scriem numele pătrățelului, în cazul nostru vom
scrie numele arithmetic
3) Intrări - specificăm între paranteze ca input toate intrările
4) Ieșiri - specificăm între paranteze ca output toate ieșirile

În acest sens, dacă dorim să scriem codul pentru pătrățelul de mai jos:

Vom scrie următorul cod :

module comparator ( // lista de porturi


input a,b, // intrari
output ls,eq,gt // iesiri
);

endmodule

Dar se întâmplă deseori să nu avem intrări pe un singur bit ca în cazul de mai


sus, ci pe mai mulți biți, de exemplu pe 3 biți, astfel încât pătrățelul va fi :
Fundamentele Calculatoarelor 2018 - 2019 Laborator 4

Și codul asociat lui va avea o singură modificare: faptul că intrările a și b nu sunt


pe 1 bit, ci sunt pe 3 biți numerotați cu 0, 1 și 2.

module comparator ( // lista de porturi


input [2:0] a,b, // intrari
output ls,eq,gt // iesiri
);

endmodule

Funcționalitatea acestul pătrățel va fi descrisă cu un bloc always. Trebuie


reținut faptul că de obicei folosim blocuri always în design și blocuri initial în
testbench. Observăm că apare cuvântul cheie reg în lista de porturi pentru ieșirile ls,
eq și gt deoarece lor li se atribuie valori în interiorul unui bloc always .

module comparator ( // lista de porturi


input [2:0] a,b, // intrari
output reg ls,eq,gt // iesiri
);

always @ ( a, b ) begin
ls = a < b;
eq = a == b;
gt = a > b;
end

endmodule

Vom crea un proiect cu numele laborator_4_project și în fișierul de tip Verilog


comparator.v pe care îl creăm vom avea scris codul de mai sus. După scrierea codului
se va salva fișierul dând click pe butonul Save sau utilizând combinația de taste Ctrl+S.
Se verifică salvarea fișierului uitându-ne dacă mai apare steluța în dreptul numelui
fișierului sau nu. După salvare vom compila fișierul dând click pe butonul Compile All.
Fundamentele Calculatoarelor 2018 - 2019 Laborator 4

Vom crea și un fișier comparator_tb.v care va conține testbench-ul asociat


design-ului din fișierul comparator.v .

Reamintim faptul că testbench-ul înconjoară design-ul ( numit DUT în acest caz)


și are 3 mari etape: monitor, generare stimuli și instanțierea DUT-ului .

Testbench-ul va conține următorul cod:

module comparator_tb;
wire [2:0] a_tb, b_tb; // intrari in DUT
wire ls_tb, eq_tb, gt_tb; // iesiri din DUT

initial begin // Monitor


$monitor(”@%0d a=%b b=%b ls=%b eq=%b gt=%b”,
$time, a_tb, b_tb, ls_tb, eq_tb, gt_tb);
end

// Instantiere DUT
comparator myInstance ( a_tb, b_tb, ls_tb, eq_tb, gt_tb);

initial begin // Generare stimuli

end
endmodule

Intrările în DUT și ieșirile din DUT le declarăm ca wire la început pentru că


pornim de la pătrățelul nostru căruia îi construim un testbench.
Fundamentele Calculatoarelor 2018 - 2019 Laborator 4

Etapa monitor conține ca de obicei: timpul, intrările și ieșirile din DUT. De


acum înainte vom utiliza @%0d pentru a indica timpul curent al simulării frumos ( a se
observa faptul că %0d va afișa timpul curent al simulării fără spații inutile).

Trebuie reținut faptul că între ghilimele putem scrie orice pentru că este un șir
de caractere, ca urmare nu afectează compilatorul, dar ne afectează pe noi, astfel încât
utilizăm un format specific pentru funcția sistem $monitor astfel încât să vedem ce
tipărește într-un mod cât mai ordonat și ușor de citit.

În etapa de instanțiere a DUT-ului putem să ținem minte ordinea porturilor


din design ca la momentul instanțierii DUT-ului în testbench să nu mai scriem :

comparator myInstance ( // Instantiere DUT


.a(a_tb),
.b(b_tb),
.ls(ls_tb),
.eq(eq_tb),
.gt(gt_tb)
);

Și să folosim următoarea variantă:

comparator myInstance ( a_tb, b_tb, ls_tb, eq_tb, gt_tb);

Trebuie să avem mare grijă cu acest mod de instanțiere. În acest laborator vom
utiliza această metodă de instanțiere pentru a vedea că funcționează, dar după acest
laborator vom utiliza prima variantă de instanțieri pentru a evita erori.

Adevărul este că această variantă de instanțiere ne ajută la cantitatea de cod


scrisă și este mai rapidă, dar probabilitatea să apară erori este mult mai mare deoarece
daca cineva va modifica ordinea din design a porturilor ( de exemplu scrie portul b
înaintea portului a) , atunci trebuie modificată ordinea și la instanțierea din testbench,
în caz contrar porturile vor fi conectate ca în desenul de mai jos.
Fundamentele Calculatoarelor 2018 - 2019 Laborator 4

Pentru etapa generării de stimuli ne vom gândi la o cronogramă ( diagramă de


timp) care să testeze design-ul, după care vom scrie codul de generare de stimuli conform
cronogramei.

Pentru a testa design-ul ne vom gândi la a verifica dacă funcționează corect în


cazul în care a este mai mic ca b, apoi în cazul în care a este egal cu b și în final cazul
în care a este mai mare ca b. În consecință vom da valori la a_tb și b_tb astfel încât
să ne verifice toate cele 3 situații.

Putem da valori într-un format specific Verilog x’yZ în care x este numărul de
biți pe care vom reprezenta numărul Z ( și este opțional deoarece Verilog va ști pe
câți biți trebuie să reprezinte numărul Z), y este baza sistemului de numerație în care
îl scriem pe numărul Z, iar Z = zn-1...zi...z1z0 este un număr format din cifre în
baza y .
Fundamentele Calculatoarelor 2018 - 2019 Laborator 4

Pentru a scrie valoarea 13 putem scrie în Verilog: 13, 4’d13, 4’b1101, 4’hd
și chiar și ’d13 pentru că spuneam că specificarea numărului de biți este opțională.

Se vede destul de clar pe cronograma de mai sus că atunci când avem


a_tb = 3’b000 și b_tb = 3’b110 avem semnalul ls_tb pe 1 ( adică este sus) asta
însemnând că a_tb este mai mic decât b_tb. În mod similar funcționează și pentru
semnalele eq_tb și gt_tb care semnifică egalitatea, respectiv relația mai mare.

Având cronograma de mai sus, putem scrie foarte ușor generarea de stimuli în
testbench astfel :

module comparator_tb;
reg [2:0] a_tb, b_tb; // intrari in DUT
wire ls_tb, eq_tb, gt_tb; // iesiri din DUT

initial begin // Monitor


$monitor(”@%0d a=%b b=%b ls=%b eq=%b gt=%b”,
$time, a_tb, b_tb, ls_tb, eq_tb, gt_tb);
end

// Instantiere DUT
comparator myInstance ( a_tb, b_tb, ls_tb, eq_tb, gt_tb);

initial begin // Generare stimuli


// blocul initial incepe tot timpul de la 0ns
a_tb = 3’b000;
b_tb = 3’b110;
// cu #1 avansam timpul de la 0ns la 1ns
#1;
// la 1ns avem a_tb=3’b011 si b_tb=3’b011
a_tb = 3’b011;
b_tb = 3’b011;
#1; // la 2ns avem a_tb=3’b111 si b_tb=3’b100
a_tb = 3’b111;
b_tb = 3’b100;
#1; // avansam la 3ns pentru ca acolo se termina simularea
end
endmodule

După scrierea codului, salvăm, compilăm și apoi simulăm testbench-ul. După ce


se „transformă” ModelSim-ul pentru simulare, ne asigurăm că vedem fereastra Objects
și apoi selectăm fereastra Objects și apăsăm combinația de taste Ctrl+A și apoi Ctrl+W
pentru a adăuga semnalele în fereastra Wave .
Fundamentele Calculatoarelor 2018 - 2019 Laborator 4

Apăsăm pe butonul Run -All și apoi vedem semnalele în fereastra Wave selectând
fereastra respectivă și apăsând tasta F pentru Zoom Full. Desigur, vedem și în fereastra
Transcript mesajele tipărite de funcția sistem $monitor.

Dacă am avut grijă la cum am generat stimulii pentru DUT, cronograma după
care ne-am orientat o vedem în fereastra Wave.
Fundamentele Calculatoarelor 2018 - 2019 Laborator 4

2. Exerciții propuse

a) Având dat design-ul comparatorului, să se rescrie blocul always astfel:

always @ (*) begin


if(a < b) begin
ls = 1;
end else begin
ls = 0;
end

if(a == b) begin
eq = 1;
end else begin
eq = 0;
end

if(a > b) begin


gt = 1;
end else begin
gt = 0;
end
end

După rescrierea design-ului, să se simuleze din nou. Pentru o altă simulare a


aceluiași design cu același testbench dacă avem încă pornită simularea anterioară
salvăm codul modificat, compilăm codul și nu mai pornim încă o dată simularea pentru
că ea este deja pornită.

După recompilarea codului pur și simplu apăsăm pe butonul Restart


care va reporni simularea luând astfel în considerare noile fișiere modificate și compilate
și pornind simularea aceluiași testbench încă o dată.

O altă alternativă este să accesăm meniul Simulate și dăm click pe


Simulate → Restart... , dar se consideră mai simplă varianta cu butoanele.
Fundamentele Calculatoarelor 2018 - 2019 Laborator 4

După cererea de repornire a simulării, se va afișa o întrebare a ce anume dorim


să repornim, fiind selectat implicit totul. Noi dăm click doar pe OK și apoi rulăm apăsând
butonul Run -All .
Fundamentele Calculatoarelor 2018 - 2019 Laborator 4

b) Se va rescrie design-ul astfel :

module comparator (
input [2:0] a,b,
output ls,eq,gt
);

assign ls = a < b;
assign eq = a == b;
assign gt = a > b;

endmodule

Atribuirile în Verilog sunt de 2 tipuri: procedurale și continue. Regula de aur


este că atribuirile procedurale se fac în blocuri always și initial și se fac doar la
variabile de tipul reg, adică variabile care au memorie, în timp ce atribuirile continue
se fac cu instrucțiuni de tipul assign și se fac doar la variabile de tipul wire, adică
variabile fără memorie, care doar transmit în mod continuu valoarea care li se atribuie.

A se observa faptul că ls, eq și gt nu mai sunt declarate ca fiind de tip reg


pentru că ar da eroare - atribuirea continuă se poate face doar la variabile de tip wire!
Se va reporni simularea cu noul cod salvat și compilat pentru a verifica faptul că
funcționează în mod identic cu restul variantelor.

c) Se va rescrie codul din design astfel :

module comparator (
input [2:0] a,b,
output ls,eq,gt
);

assign ls = (a < b) ? 1 : 0 ;
assign eq = (a == b) ? 1 : 0 ;
assign gt = (a > b) ? 1 : 0 ;

endmodule

Avem un nou operator ?: care se numește operatorul condițional și funcționează


exact ca o instrucțiune if . În cadrul unui bloc always sau initial putem folosi
instrucțiuni if, dar instrucțiunile assign acceptă doar expresii și operatorul
condițional. Astfel putem introduce logică de tipul instrucțiunii if în atribuiri continue
cu assign.
Fundamentele Calculatoarelor 2018 - 2019 Laborator 4

Pentru a înțelege mai bine, codul de mai jos

assign ls = (a < b) ? 1 : 0 ;

se poate traduce ca fiind :

if (a < b) begin
ls = 1;
end else begin
ls = 0;
end

Se va salva și compila codul și se va reporni simularea pentru a vedea cum


funcționează.

d) Se vor face modificări în testbench la partea de generare de stimuli, dând diferite


valori lui a_tb și b_tb și modificând întârzierile, punând întârzieri în plus sau
ștergând toate întârzierile pentru a vedea ce se întâmplă cu simularea dacă se
modifică într-un anumit fel generarea de stimuli. Se pot da valori foarte mari la
a_tb și b_tb pentru a vedea ce se întâmplă.

CONGRATS !!!
Tocmai ai învățat să descrii în două feluri diferite
funcționalitatea unui pătrățel!

S-ar putea să vă placă și