Diferență între revizuiri ale paginii „CID aplicatii 2 : Instantiere si porti logice”

De la WikiLabs
Jump to navigationJump to search
 
(Nu s-au afișat 30 de versiuni intermediare efectuate de alți 2 utilizatori)
Linia 1: Linia 1:
==Teorie: observatii generale==
 
 
Proiectarea circuitelor digitale (ce facem in acest laborator) se bazeaza pe generarea unor circuite digitale fizice. Desi se va scrie cod in limbajul Verilog, mereu trebuie avut in vedere faptul ca in spate se va genera un circuit fizic, codul nu se ruleaza pas cu pas. Aceasta fiind deosebirea fundamentala intre limbajele de descriere hardware (genereaza circuite fizice) si limbajele de programare (cod care se executa pas cu pas). Unele concepte e posibil sa semene cat si unele elemente de sintaxa cu ce ati facut la programare, dar este important sa intelegeti ca prin codul scris se deseneaza/genereaza circuite. Sau invers, pornind de la un desen, se poate face o descriere in Verilog a acestuia.
 
 
Proiectele exemplu care pot fi descarcate au fost facut in Vivado 2021.2. Daca aveti alta versiune e posibil sa va ceara sa le salvati in versiunea respectiva sau sa fie nevoie sa va faceti un proiect nou in care sa adaugati fisierele cu cod.
 
 
 
 
 
==Teorie: incapsulare si instantiere==
 
==Teorie: incapsulare si instantiere==
 
Unitatile constructive de baza din care se formeaza circuitele digitale se numesc porti logice. Acestea implementeaza functii logice si prin conectarea mai multor astfel de circuite simple complexitatea unui circuit poate creste pana la nivelul procesoarelor actuale. Pentru a putea controla cresterea complexitatii in proiectarea unui circuit de dimensiuni mari se folosesc 2 concepte cheie:  
 
Unitatile constructive de baza din care se formeaza circuitele digitale se numesc porti logice. Acestea implementeaza functii logice si prin conectarea mai multor astfel de circuite simple complexitatea unui circuit poate creste pana la nivelul procesoarelor actuale. Pentru a putea controla cresterea complexitatii in proiectarea unui circuit de dimensiuni mari se folosesc 2 concepte cheie:  
Linia 24: Linia 16:
  
  
Observatii:
+
'''Observatii:'''
  
 
1) Notatie aici: Numele modulului este scris in interior.  
 
1) Notatie aici: Numele modulului este scris in interior.  
Linia 36: Linia 28:
 
:a) "modul_2" este instantiat o singura data in tot proiecul, iar instanta se cheama "x"
 
:a) "modul_2" este instantiat o singura data in tot proiecul, iar instanta se cheama "x"
  
:b) "modul_2" are o intrare numita "in0" si o iesire numita "out"
+
:b) "modul_2" are o intrare numita "in0" si o iesire numita "out0"
  
 
:c) "modul_2" este instantiat in cadrul "modul_6"
 
:c) "modul_2" este instantiat in cadrul "modul_6"
Linia 52: Linia 44:
 
:h) La nivel de "modul_5", cele 2 instante se cheama "a" si "c".
 
:h) La nivel de "modul_5", cele 2 instante se cheama "a" si "c".
  
:i) "a" si "c" sunt 2 circuite fizice diferite chiar daca ambele sunt de tipul "modul_0". Fiind instante ale aceluiasi modul, deci identice in alcatuire, luate separat ele fac acelasi lucru. Luate in contextul lui "modul_5", "a" genereaza datele de pe firul "w1" si "c" genereaza datele pentru iesire.
+
:i) "a" si "c" sunt 2 circuite fizice diferite chiar daca ambele sunt de tipul "modul_0". Fiind instante ale aceluiasi modul, deci identice in alcatuire, luate separat ele fac acelasi lucru. Luate in contextul lui "modul_5", "a" genereaza datele de pe firul "w0" si "c" genereaza datele pentru iesire.
  
  
:j) circuitul "b" de tip "modul_1" (instantiat in "modul_5") este complet diferit de circuitul "b" de tip "modul_0" (instantiat in top). Este permis ca ele sa aibe acelasi nume (cele 2 instante) deoarece se afla in locatii diferite.  
+
:j) circuitul "b" de tip "modul_1" (instantiat in "modul_5") este complet diferit de circuitul "b" de tip "modul_0" (instantiat in top). Este permis ca ele sa aiba acelasi nume (cele 2 instante) deoarece se afla in locatii diferite.  
  
  
Linia 69: Linia 61:
 
:o) La nivelul "modul_5", firul de legatura "w1" leaga iesirea instantei "b" la intrarea instantei "c".
 
:o) La nivelul "modul_5", firul de legatura "w1" leaga iesirea instantei "b" la intrarea instantei "c".
  
Pentru claritatea desenului, respectivele intrari si iesiri nu au fost denumite. In cod este obligatoriu ca ele sa fie definite si denumite.
+
:Pentru claritatea desenului, respectivele intrari si iesiri nu au fost denumite. In cod este obligatoriu ca ele sa fie definite si denumite.
  
  
Linia 77: Linia 69:
  
 
:r) La nivelul "top", firul "in3" este conectat ca intrare pentru 3 submodule.
 
:r) La nivelul "top", firul "in3" este conectat ca intrare pentru 3 submodule.
 
 
  
 
==Teorie: testarea circuitelor==
 
==Teorie: testarea circuitelor==
Linia 88: Linia 78:
 
Generarea datelor de intrare se va face asemanator cu laboratorul 1.
 
Generarea datelor de intrare se va face asemanator cu laboratorul 1.
  
Rolul modelului ideal si al comparatorului datelor de iesire il veti avea voi, privind formele de unda din simulare.  
+
Voi veti avea rolul modelului ideal si al comparatorului datelor de iesire, uitandu-va la datele de intrare veti calcula iesirea corecta si apoi veti compara aceasta valoare cu raspunsul circuitului ce se testeaza.
 +
 
  
 
In cazul unui sistem automat, se genereaza mesaje de eroare sau mesaje ca functionarea este in regula.
 
In cazul unui sistem automat, se genereaza mesaje de eroare sau mesaje ca functionarea este in regula.
Linia 95: Linia 86:
 
Observatie: proiectarea si verificarea sunt 2 domenii diferite, firmele avand departamente separate pentru acestea.  
 
Observatie: proiectarea si verificarea sunt 2 domenii diferite, firmele avand departamente separate pentru acestea.  
  
Proiectarea/Design se ocupa cu scrierea in Verilog a modului de top si toate modulele ce se afla in acesta, avand ca scop final realizarea fizica pe placa a unui circuit.  
+
Proiectarea/Design se ocupa cu scrierea in Verilog/SystemVerilog a modului de top si toate modulele ce se afla in acesta, avand ca scop final realizarea fizica pe placa a unui circuit.  
  
 
Verificarea se ocupa de scrierea in SystemVerilog (limbaj format din Verilog cu concepte de POO) a modului de testbench si generarea de stimuli si scenarii care sa testeze functionarea design-ului.
 
Verificarea se ocupa de scrierea in SystemVerilog (limbaj format din Verilog cu concepte de POO) a modului de testbench si generarea de stimuli si scenarii care sa testeze functionarea design-ului.
Linia 102: Linia 93:
  
 
==Teorie: porti logice==
 
==Teorie: porti logice==
Portile logice folosite uzual, impreuna cu tabelele lor de adevar sunt date mai jos.
+
Portile logice folosite uzual, impreuna cu tabelele lor de adevar si reprezentarea grafica sunt date mai jos.
 +
 
 +
Se folosesc porti logice cu 1 sau 2 intrari, cele cu mai mult de 2 intrari fiind construite din acestea.
 +
 
  
Se folosesc porti logice cu 1 sau 2 intrari, cele mai mari fiind construite din acestea.
 
 
 
{| class="wikitable"
 
{| class="wikitable"
 +
! Tip !! Simbol !! Tabel de adevăr !! Tip !! Simbol !! Tabel de adevăr
 +
|-
 +
| '''Buffer/Repetor'''
 +
| [[Image:Buffer_gate.png|Buffer symbol]]
 +
|
 +
{| class="wikitable" align=right
 
|- bgcolor="#ddeeff" align="center"
 
|- bgcolor="#ddeeff" align="center"
 +
|'''INTRARE''' || '''IEȘIRE'''
 
|- bgcolor="#ddeeff" align="center"
 
|- bgcolor="#ddeeff" align="center"
| in || buffer (repetor) out || inverter (not) out
+
| A || A
 +
|- bgcolor="#ddffdd" align="center"
 +
|0 || 0
 +
|- bgcolor="#ddffdd" align="center"
 +
|1 || 1
 +
|}
 +
| '''NOT'''
 +
| [[Image:not.png|NOT symbol]]
 +
|
 +
{| class="wikitable" align=right
 +
|- bgcolor="#ddeeff" align="center"
 +
|'''INTRARE''' || '''IEȘIRE'''
 +
|- bgcolor="#ddeeff" align="center"
 +
| A || NOT A
 +
|- bgcolor="#ddffdd" align="center"
 +
|0 || 1
 +
|- bgcolor="#ddffdd" align="center"
 +
|1 || 0
 +
|}
 +
|-
 +
| '''AND'''
 +
| [[Image:and.png|AND symbol]]
 +
|
 +
{| class="wikitable" align=right
 +
|- bgcolor="#ddeeff" align="center"
 +
|colspan=2|'''INTRARE''' || '''IEȘIRE'''
 +
|- bgcolor="#ddeeff" align="center"
 +
| A || B || A AND B
 +
|- bgcolor="#ddffdd" align="center"
 +
|0 || 0 || 0
 +
|- bgcolor="#ddffdd" align="center"
 +
|0 || 1 || 0
 +
|- bgcolor="#ddffdd" align="center"
 +
|1 || 0 || 0
 +
|- bgcolor="#ddffdd" align="center"
 +
|1 || 1 || 1
 +
|}
 +
| '''NAND'''
 +
| [[Image:nand.png|NAND symbol]]
 +
|
 +
{| class="wikitable" align=right
 +
|- bgcolor="#ddeeff" align="center"
 +
|colspan=2|'''INTRARE''' || '''IEȘIRE'''
 +
|- bgcolor="#ddeeff" align="center"
 +
| A || B || A NAND B
 +
|- bgcolor="#ddffdd" align="center"
 +
|0 || 0 || 1
 +
|- bgcolor="#ddffdd" align="center"
 +
|0 || 1 || 1
 +
|- bgcolor="#ddffdd" align="center"
 +
|1 || 0 || 1
 +
|- bgcolor="#ddffdd" align="center"
 +
|1 || 1 || 0
 +
|}
 +
|-
 +
| '''OR'''
 +
| [[Image:or.png|OR symbol]]
 +
|
 +
{| class="wikitable" align=right
 +
|- bgcolor="#ddeeff" align="center"
 +
|colspan=2|'''INTRARE''' || '''IEȘIRE'''
 +
|- bgcolor="#ddeeff" align="center"
 +
| A || B || A OR B
 +
|- bgcolor="#ddffdd" align="center"
 +
|0 || 0 || 0
 +
|- bgcolor="#ddffdd" align="center"
 +
|0 || 1 || 1
 +
|- bgcolor="#ddffdd" align="center"
 +
|1 || 0 || 1
 +
|- bgcolor="#ddffdd" align="center"
 +
|1 || 1 || 1
 +
|}
 +
| '''NOR'''
 +
| [[Image:nor.png|NOR symbol]]
 +
|
 +
{| class="wikitable" align=right
 +
|- bgcolor="#ddeeff" align="center"
 +
|colspan=2|'''INTRARE''' || '''IEȘIRE'''
 +
|- bgcolor="#ddeeff" align="center"
 +
| A || B || A NOR B
 
|- bgcolor="#ddffdd" align="center"
 
|- bgcolor="#ddffdd" align="center"
 
|0 || 0 || 1
 
|0 || 0 || 1
 +
|- bgcolor="#ddffdd" align="center"
 +
|0 || 1 || 0
 +
|- bgcolor="#ddffdd" align="center"
 +
|1 || 0 || 0
 +
|- bgcolor="#ddffdd" align="center"
 +
|1 || 1 || 0
 +
|}
 +
|-
 +
| '''XOR'''
 +
| [[Image:xor.png|XOR symbol]]
 +
|
 +
{| class="wikitable" align=right
 +
|- bgcolor="#ddeeff" align="center"
 +
|colspan=2|'''INTRARE''' || '''IEȘIRE'''
 +
|- bgcolor="#ddeeff" align="center"
 +
| A || B || A XOR B
 +
|- bgcolor="#ddffdd" align="center"
 +
|0 || 0 || 0
 +
|- bgcolor="#ddffdd" align="center"
 +
|0 || 1 || 1
 +
|- bgcolor="#ddffdd" align="center"
 +
|1 || 0 || 1
 
|- bgcolor="#ddffdd" align="center"
 
|- bgcolor="#ddffdd" align="center"
 
|1 || 1 || 0
 
|1 || 1 || 0
 
|}
 
|}
 
+
| '''XNOR'''
{| class="wikitable"
+
| [[Image:xnor.png|XNOR symbol]]
 +
|
 +
{| class="wikitable" align=right
 
|- bgcolor="#ddeeff" align="center"
 
|- bgcolor="#ddeeff" align="center"
 +
|colspan=2|'''INTRARE''' || '''IEȘIRE'''
 
|- bgcolor="#ddeeff" align="center"
 
|- bgcolor="#ddeeff" align="center"
| A || B || A AND B || A NAND B || A OR B || A NOR B || A XOR B || A NXOR B
+
| A || B || A XNOR B
 
|- bgcolor="#ddffdd" align="center"
 
|- bgcolor="#ddffdd" align="center"
|0 || 0 || 0 || 1 || 0 || 1 || 0 || 1
+
|0 || 0 || 1
 
|- bgcolor="#ddffdd" align="center"
 
|- bgcolor="#ddffdd" align="center"
|0 || 1 || 0 || 1 || 1 || 0 || 1 || 0
+
|0 || 1 || 0
 
|- bgcolor="#ddffdd" align="center"
 
|- bgcolor="#ddffdd" align="center"
|1 || 0 || 0 || 1 || 1 || 0 || 1 || 0
+
|1 || 0 || 0
 
|- bgcolor="#ddffdd" align="center"
 
|- bgcolor="#ddffdd" align="center"
|1 || 1 || 1 || 0 || 1 || 0 || 0 || 1
+
|1 || 1 || 1
 
|}
 
|}
 +
|}
 +
 +
==Despre FPGA==
 +
FPGA-ul (Field-Programmable Gate Array) este un circuit programabil, capabil sa implementeze circuite definit de utilizator. El este format dintr-o matrice de blocuri programabile, interconectate intre ele printr-o serie de conexiuni la randul lor programabile.
 +
 +
 +
Cand se doreste implementarea unui circuit pe FPGA, acesta urmeaza urmatoarele etape:
  
 +
:'''Elaborarea''' este procesul prin care codul SystemVerilog este transformat intr-un circuit la nivel de porti si registre (netlist) si este independent de modelul de FPGA folosit.
  
 +
:'''Sinteza''' este procesul în care se realizează transformarea circuitului descris într-un netlist dependent de tehnologie. Se vor folosi la acest pas primitivele disponibile pe FPGA.
  
 +
:'''Implementarea''' este procesul în care se preia netlist-ul ce conține primitivele FPGA și modul lor de interconectare realizat la pasul de sinteză și se realizează maparea lor efectivă în FPGA (place and route).
  
 +
:'''Generarea Bitstream-ului''' este procesul prin care informatiile din implementare sunt asamblate intr-un singur fisier.
  
==Exemplu rezolvat: NAND2 din AND2 si NOT==
+
:'''Programarea''' este procesul prin care fisierul generat anterior este trimis efectiv catre placa cu FPGA (prin USB) unde determina modificarea valorilor si conexiunilor interne din aceasta.
 +
 
 +
 
 +
O introducere mai detaliata poate fi gasita aici : [[FPGA - Introducere]].
 +
 
 +
[[Fișier:Fpgaimg.PNG|600px]]
 +
 
 +
'''Observatii:'''
 +
* Pentru a putea controla circuitul propus si a putea vedea rezultatele, intrarile si iesirile (input si output din module) in/din acesta trebuie conectate la pini fizici ai FPGA-ului care sunt conectati la butoane/switch-uri/leduri.
 +
* Conexiunile dintre butoane/switch-uri si pinii FPGA sunt fixe. La fel si cele intre pinii FPGA si LED-uri. (in functie de PCB)
 +
* Conexiunile dintre porturile modulului ''Module'' si pinii FPGA sunt configurabile. (in functie de noi, prin fisierul XDC)
 +
* Legarea porturilor modulului ''Module'' la pinii fizici ai FPGA se realizeaza prin configurarea conexiunilor din FPGA conform contrangerilor de I/O pe care le vom mentiona in proiect, inainte de sinteza.
 +
 
 +
==Exemple==
 +
 
 +
 
 +
===Exemplul 1: Analiza circuitelor cu porti===
 +
Fie urmatorul circuit alcatuit din porti logice:
 +
[[Fișier:Mux2_schema_interna_2.png ‎| 400px]]
 +
 
 +
Se doreste exprimarea circuitului de mai sus ca formula de tip: iesire = f(intrari).
 +
 
 +
Pentru asta, abordarea consta in a porni de la iesire si a merge pas cu pas catre intrari, asa cum este exemplificat mai jos. Se vor folosi simbolurile "~" pentru NOT, "&" pentru AND, "|" pentru OR.
 +
:pas1: out0 = ?
 +
:pas2: out0 = w1 | w2
 +
:pas3: out0 = w1 | ( ? )
 +
:pas4: out0 = w1 | ( sel & in1 )
 +
:pas5: out0 = ( ? ) | ( sel & in1 )
 +
:pas6: out0 = ( in0 & w0 ) | ( sel & in1 )
 +
:pas7: out0 = ( in0 & ( ? ) ) | ( sel & in1 )
 +
:pas8: out0 = ( in0 & (~sel) ) | ( sel & in1 )
 +
 
 +
===Exemplul 2: NAND2 din AND2 si NOT===
 
In urmatorul exemplu se implementeaza o poarta NAND din o poarta AND si o poarta NOT.  
 
In urmatorul exemplu se implementeaza o poarta NAND din o poarta AND si o poarta NOT.  
  
Codul de mai jos exemplifica idea de instantiere si contine comentarii legate de sintaxa verilog necesara.
+
Codul de mai jos exemplifica ideea de instantiere si contine comentarii legate de sintaxa SystemVerilog necesara.
  
 
In mod uzual fisierele sunt denumite dupa modulul ce se afla in ele, in fiecare fisier fiind un singur modul.
 
In mod uzual fisierele sunt denumite dupa modulul ce se afla in ele, in fiecare fisier fiind un singur modul.
Linia 145: Linia 291:
 
[[Fișier:schema_exemplu_rezolvat.png ‎| 600px]]
 
[[Fișier:schema_exemplu_rezolvat.png ‎| 600px]]
  
Fisierul not_gate.v:
+
'''Descrierea portii NOT (fisierul not_gate.sv):'''
 
<syntaxhighlight lang="Verilog">
 
<syntaxhighlight lang="Verilog">
 
// comentarii cu "//" sau cu /* .... */ ;
 
// comentarii cu "//" sau cu /* .... */ ;
Linia 154: Linia 300:
 
module not_gate // cuvant cheie "module" apoi numele modulului (asemanator clase din c++)
 
module not_gate // cuvant cheie "module" apoi numele modulului (asemanator clase din c++)
 
( // intre paranteze se pune interfata (firele care intra sau ies din modul)
 
( // intre paranteze se pune interfata (firele care intra sau ies din modul)
input wire in0, // in0 este o intrare => input, in0 este fir => wire ;
+
input logic in0,         // in0 este o intrare => input
output wire out0 // out0 este o intrare => output, out0 este fir => wire
+
output logic out0 // out0 este o intrare => output
 
); // aici ";" sa nu il uitati
 
); // aici ";" sa nu il uitati
  
Linia 165: Linia 311:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Fisierul and_gate.v:
+
'''Descrierea portii AND (fisierul and_gate.sv):'''
 
<syntaxhighlight lang="Verilog">
 
<syntaxhighlight lang="Verilog">
 
module and_gate
 
module and_gate
 
(
 
(
input in0, // aici sunt 2 intrari  
+
input logic in0, // aici sunt 2 intrari  
input in1, // se poate omite "wire". default e wire daca nu e pus nimic
+
input logic in1,
output out0
+
output logic out0
 
); // nu conteaza ordinea in care sunt puse intrarile si iesirile.
 
); // nu conteaza ordinea in care sunt puse intrarile si iesirile.
 
// uzual si pentru usurinta se ordoneaza si grupeaza dupa functionalitate
 
// uzual si pentru usurinta se ordoneaza si grupeaza dupa functionalitate
Linia 181: Linia 327:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Fisierul top.v:
+
'''Descrierea modulului top (fisierul top.sv):'''
 
<syntaxhighlight lang="Verilog">
 
<syntaxhighlight lang="Verilog">
  
 
module top
 
module top
 
(
 
(
input a,
+
input logic a,
input b,
+
input logic b,
output c
+
output logic c
 
     );
 
     );
 
      
 
      
wire w0;    //declarat un fir intern de legatura  
+
logic w0;    //declarat un fir intern de legatura  
 
      
 
      
 
and_gate and_gate_0 // instantiere: nume_modul nume_instanta (asemanator int x din c/c++)
 
and_gate and_gate_0 // instantiere: nume_modul nume_instanta (asemanator int x din c/c++)
 
(
 
(
.in0(a), // la intrarea "in0" a instantei "and_gate_0"  se conecteaza firul "a"  
+
.in0(a), // la intrarea "in0" a instantei "and_gate_0"  se conecteaza firul "a" din top
 
.in1(b), // grija ca "in0", "in1", "out0" sa existe in declararea modulului "and_gate"
 
.in1(b), // grija ca "in0", "in1", "out0" sa existe in declararea modulului "and_gate"
 
.out0(w0) // grija ca "a", "b", "w0" sa existe la nivelul modulului in care se face instantierea
 
.out0(w0) // grija ca "a", "b", "w0" sa existe la nivelul modulului in care se face instantierea
Linia 218: Linia 364:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
+
Echivalent se pot folosi si "primitive" SystemVerilog pentru scrierea top-ului.
 
 
Echivalent se pot folosii si "primitive" Verilog pentru scrierea top-ului.
 
  
 
Primitivele sunt porti logice care exista deja in limbaj, folosite atunci cand se doreste o descriere structurala a circuitului.
 
Primitivele sunt porti logice care exista deja in limbaj, folosite atunci cand se doreste o descriere structurala a circuitului.
Linia 226: Linia 370:
 
In instantiere acestora, iesirea se pune prima, urmata de intrari.
 
In instantiere acestora, iesirea se pune prima, urmata de intrari.
  
Observatie: daca se doreste scrierea acestor porti de catre voi (ca mai sus), numele modulului nu trebuie sa fie un cuvant cheie ocupat de primitive.
+
'''Observatie:''' daca se doreste scrierea acestor porti de catre voi (ca mai sus), numele modulului nu trebuie sa fie un cuvant cheie ocupat de primitive.
  
Fisierul top_v2.v:
+
 
 +
'''Descrierea alternativa a modulului top (fisierul top_v2.sv):'''
 
<syntaxhighlight lang="Verilog">
 
<syntaxhighlight lang="Verilog">
 
module top_v2
 
module top_v2
 
     (
 
     (
    input a,
+
    input logic a,
    input b,
+
    input logic b,
    output c
+
    output logic c
 
     );
 
     );
 
    
 
    
Linia 245: Linia 390:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
Fiind un modul simplu, intreaga functionalitate putea fi scrisa la nivel de "top" si simplificat ca mai jos.
  
Fiind un modul simplu, intreaga functionalitate putea fi scrisa la nivel de "top" si simplificat ca mai jos.
 
  
Fisierul top_v3.v:
+
'''Descrierea alternativa a modulului top (fisierul top_v3.sv):'''
 
<syntaxhighlight lang="Verilog">
 
<syntaxhighlight lang="Verilog">
 
module top_v3
 
module top_v3
 
     (
 
     (
    input a,
+
    input logic a,
    input b,
+
    input logic b,
    output c
+
    output logic c
 
     );
 
     );
 
    
 
    
Linia 264: Linia 409:
 
Testarea circuitul se face printr-un testbench, acesta fiind:
 
Testarea circuitul se face printr-un testbench, acesta fiind:
  
Fisierul tb.v:
+
 
 +
'''Descrierea testbench-ului (fisierul top_tb.sv):'''
 
<syntaxhighlight lang="Verilog">
 
<syntaxhighlight lang="Verilog">
 
`timescale 1ns / 1ps
 
`timescale 1ns / 1ps
  
module tb(); // din/in tb nu intra si iese nimic. niciodata.
+
module top_tb(); // din/in tb nu intra si iese nimic. niciodata.
  
reg tb_a; // ce va fi intrare pentru dut, aici e declarat ca "reg", ca sa poata tine valori
+
logic a_tb;
reg tb_b;
+
logic b_tb;
wire tb_c; // ce e declarat ca iesire pentru dut, aici e declarat ca "wire" pentru ca device-ul ii va da valorile
+
logic c_tb;
  
 
top dut // instantierea modulului de tip "top" sub numele "dut"  
 
top dut // instantierea modulului de tip "top" sub numele "dut"  
 
(
 
(
.a(tb_a),
+
.a(a_tb),
.b(tb_b),
+
.b(b_tb),
.c(tb_c)
+
.c(c_tb)
 
     );
 
     );
  
 
initial
 
initial
begin // in loc de { ... } din c/c++, in Verilog se pune begin ... end  
+
begin // in loc de { ... } din c/c++, in SystemVerilog se pune begin ... end  
 
#10; // dupa 10 unitati de timp  
 
#10; // dupa 10 unitati de timp  
tb_a = 0; // tb_a ia valoarea 0
+
a_tb = 0; // a_tb ia valoarea 0
tb_b = 0;
+
b_tb = 0;
 
#10; // dupa inca 10 unitati de timp, deci in total la 20
 
#10; // dupa inca 10 unitati de timp, deci in total la 20
tb_a = 1;
+
a_tb = 1;
tb_b = 0;
+
b_tb = 0;
 
#10;
 
#10;
tb_a = 0;
+
a_tb = 0;
tb_b = 1;
+
b_tb = 1;
 
#10;
 
#10;
tb_a = 1;
+
a_tb = 1;
tb_b = 1;
+
b_tb = 1;
 
#10;
 
#10;
tb_a = 0;
+
a_tb = 0;
tb_b = 0;
+
b_tb = 0;
 
 
 
#20 $stop(); // oprirea simularii  
 
#20 $stop(); // oprirea simularii  
Linia 304: Linia 450:
 
endmodule
 
endmodule
 
</syntaxhighlight>
 
</syntaxhighlight>
 
  
 
Formele de unda rezultate din simulare se pot vedea mai jos:
 
Formele de unda rezultate din simulare se pot vedea mai jos:
Linia 317: Linia 462:
 
Apoi, din chenarul rosu se aleg semnalele si se adauga prin click dreapta->add to wave window.  
 
Apoi, din chenarul rosu se aleg semnalele si se adauga prin click dreapta->add to wave window.  
  
Pentru o mai usoara vizualizare semnalele se pot grupa asa cum se vede in chenarul mov prin click dreapta->new group.
+
Pentru o mai usoara vizualizare, semnalele se pot grupa asa cum se vede in chenarul mov prin click dreapta->new group.
  
  
Linia 323: Linia 468:
  
  
Dupa ce circuitul a fost testat in simulare se doreste punerea sa fizica pe placa.
+
'''Implementarea circuitului pe FPGA'''
  
Pentru asta se urmeaza pasii descrisi in [[Tutorial_Vivado|tutorialul Vivado]].
+
Dupa ce circuitul a fost testat in simulare, se doreste punerea sa fizica pe placa FPGA. Pentru aceasta, se tine cont de urmatoarele.
  
Proiectul complet se poate descarca de aici: [https://wiki.dcae.pub.ro/images/b/ba/W2_exemplu_nand.zip W2_exemplu_nand.zip]
+
* Pentru a controla intrarile ''a'' si ''b'' ale circuitului '''top'', va trebui sa le conectam prin intermediul conexiunilor configurabile ale FPGA-ului la pini ce sunt mai departe conectati fizic la dispozitive ce pot controla valorile semnalelor (switch-uri, butoane).
 +
* Pentru a observa valoarea iesirii, vom conecta semnalul de iesire ''c''la un dispozitiv de observare, cum ar fi un LED, care va fi aprins daca ''c'' este 1 si stins daca ''c'' este 0.
  
 +
[[Fișier:NAND2 FPGA.png | 600px]]
  
 +
Pentru a realiza conectarea porturilor modulului ''top'' la pinii fizici ai FPGA ce sunt conectati mai departe la componentele de pe placa, va trebui sa specificam in utilitarul de sinteza maparea porturilor la acestia. Maparea se realizeaza prin mentionarea codurilor pinilor la care dorim conexiunea si poata numele de '''constrangeri de I/O'''. Aceste coduri sunt mentionate in documentatia placii de dezvoltare cu FPGA (in cazul nostru, PYNQ Z2) si pot fi regasite si in pagina [[Pynq-Z2 - Pinout | PYNQ-Z2 - Pinout]].
  
 +
Conform schemei, la acest exemplu avem nevoie de codurile pinilor conectati mai departe la Switch0, Switch1 si LED0.
  
 +
'''Observatie:''' Daca intrarile si iesirile ar fi semnale pe mai multi biti, fiecare bit al intrarilor va fi conectat la cate un switch/buton si fiecare bit al iesirii va fi conectat la un LED. Acest lucru este necesar deoarece switch-urile/butoanele pot avea doar doua stari (0 si 1) si astfel pot controla un singur bit. La fel, un LED poate avea doar doua stari (0 - stins si 1 - aprins) si poate afisa starea unui singur bit.
  
==Exercitii==
+
Dupa ce ati extras codurile necesare, urmati pasii descrisi in [[Tutorial_Vivado|tutorialul Vivado]].  
Pentru urmatoarele exercitii se doreste atat testarea designurilor prin simulare cat si punerea acestora pe placa. Legat de placa, intrarile vor fi conectate la butoane iar iesirile la leduri. Se va consulta tabelul cu pini disponibili de // INSERT LINK AICI DUPA CE AVEM PLACA CLAR
 
  
Exista moduri mai rapide de a scrie functionalitatea dorita (vezi exemplu), dar tema principala a acestui laborator este instantierea asa ca sunteti rugati sa respectati desenele si sa instantiati fiecare poarta individual.
+
Dupa programarea cu succes a placii, puteti testa functionalitatea circuitului prin modficarea valorilor switch-urilor si observarea starii LED-ului.
  
 +
==Exercitii==
 +
Pentru urmatoarele exercitii se doreste atat testarea designurilor prin simulare cat si punerea acestora pe placa. Legat de placa, intrarile vor fi conectate la butoane, iar iesirile la leduri. Se va consulta tabelul cu pini disponibili ([[Pynq-Z2 - Pinout]]).
  
 +
Exista moduri mai rapide de a scrie functionalitatea dorita (vezi exemplu), dar tema principala a acestui laborator este instantierea, asa ca sunteti rugati sa respectati desenele si sa instantiati fiecare poarta individual.
  
EX 1) AND4 din AND2  
+
===Exercitiul 1: AND4 din AND2===
  
 
Acest exercitiu arata cum se construieste o poarta AND cu 4 intrari din porti AND mai simple, cu 2 intrari.  
 
Acest exercitiu arata cum se construieste o poarta AND cu 4 intrari din porti AND mai simple, cu 2 intrari.  
Linia 347: Linia 499:
 
[[Fișier:schema_and4_din_and2.png ‎| 600px]]
 
[[Fișier:schema_and4_din_and2.png ‎| 600px]]
  
 +
Pentru testarea circuitului, generati in testbench urmatoarele forme de unda (liniile punctate reprezinta 5ns):
  
 +
[[Fișier:Wavedrom_and4.png ‎| 500px]]
  
EX 2) OR4 din OR2
+
 
 +
===Exercitiul 2: OR4 din OR2===
  
 
Asemanator cu exercitiul anterior, se poate construi si o poarta or cu 4 intrari din porti or cu 2 intrari.  
 
Asemanator cu exercitiul anterior, se poate construi si o poarta or cu 4 intrari din porti or cu 2 intrari.  
 
Iesirea acesteia va fi "1" doar daca oricare din intrari (cel putin una) este "1".
 
Iesirea acesteia va fi "1" doar daca oricare din intrari (cel putin una) este "1".
 +
 +
Pentru testarea circuitului se folosesc formele de unda de la exercitiul 1.
  
 
[[Fișier:schema_or4_din_or2.png ‎| 600px]]
 
[[Fișier:schema_or4_din_or2.png ‎| 600px]]
  
  
 +
===Exercitiul 3: AND4 din AND2 aranjat pe lung (nu arbore)===
  
EX 3) AND4 din AND2 aranjat pe lung (nu arbore)
+
In multe cazuri, aceeasi functionalitate poate fi atinsa prin circuite care arata diferit.  
 
 
In multe cazuri, aceasi functionalitate poate fi atinsa prin circuite care arata diferit.  
 
 
O alta varianta de a face o poarta AND cu 4 intrari este prezentata mai jos.  
 
O alta varianta de a face o poarta AND cu 4 intrari este prezentata mai jos.  
  
 
Comparati cele 2 variante.  
 
Comparati cele 2 variante.  
 +
 +
Pentru testarea circuitului se folosesc formele de unda de la exercitiul 1.
  
 
[[Fișier:schema_and4_din_and2_v2.png ‎| 600px]]
 
[[Fișier:schema_and4_din_and2_v2.png ‎| 600px]]
 
 
  
 
+
===Exercitiul 4: AND4 din NAND2===
EX 4) and4 din nand2
 
  
 
Orice poarta logica de baza poate fi construita doar din porti NAND sau doar din porti NOR.  
 
Orice poarta logica de baza poate fi construita doar din porti NAND sau doar din porti NOR.  
Linia 377: Linia 534:
 
Tip: Incercati intai sa generati o poarta AND2 din NAND2.
 
Tip: Incercati intai sa generati o poarta AND2 din NAND2.
  
 +
Pentru testarea circuitului se folosesc formele de unda de la exercitiul 1.
  
  
EX 5) and4 pe 4b din and4 pe 1b
+
===Exercitiul 5: AND4 pe 4b din AND4 pe 1b===
  
 
Se pot face operatii logice si pe mai multi biti deodata prin punerea in paralel a mai multor porti cu o singura iesire.
 
Se pot face operatii logice si pe mai multi biti deodata prin punerea in paralel a mai multor porti cu o singura iesire.
exemplu :
+
Exemplu :
 
pentru intrarile 0011 si 1110 iesirea va fi 0010
 
pentru intrarile 0011 si 1110 iesirea va fi 0010
  
Linia 388: Linia 546:
  
 
[[Fișier:schema_and4_4b_din_and4_1b_v1.png ‎| 400px]]
 
[[Fișier:schema_and4_4b_din_and4_1b_v1.png ‎| 400px]]
 +
 +
Pentru testarea circuitului, generati in testbench urmatoarele forme de unda (liniile punctate reprezinta 5ns):
 +
 +
[[Fișier:Wavedrom_and4_4b.png ‎| 500px]]
  
 
Exista si un mod mai rapid si simplu de a scrie aceasta functionalitate, grupand intrarile si iesirile in "bus"-uri, ca in codul de mai jos.
 
Exista si un mod mai rapid si simplu de a scrie aceasta functionalitate, grupand intrarile si iesirile in "bus"-uri, ca in codul de mai jos.
Linia 394: Linia 556:
 
[[Fișier:schema_and4_4b_din_and4_1b_v2.png ‎| 600px]]
 
[[Fișier:schema_and4_4b_din_and4_1b_v2.png ‎| 600px]]
  
Fisierul and4_4b.v:
+
Fisierul and4_4b.sv:
 
<syntaxhighlight lang="Verilog">
 
<syntaxhighlight lang="Verilog">
 
module and4_4b
 
module and4_4b
 
(
 
(
input wire [3:0] in0, // in0 are 4b, de la bit 3 la bit 0 inclusiv  
+
input logic [3:0] in0, // in0 are 4b, de la bit 3 la bit 0 inclusiv  
input wire [3:0] in1, // se noteaza msb:lsb (most significant bit: least significant bit) (echivalent cu conceptul de cifra sutelor, cifra unitatilor, pt binar)
+
input logic [3:0] in1, // se noteaza msb:lsb (most significant bit: least significant bit) (echivalent cu conceptul de cifra sutelor, cifra unitatilor, pt binar)
output wire [3:0] out0
+
input logic [3:0] in2,
 +
input logic [3:0] in3,
 +
output logic [3:0] out0
 
);
 
);
 
 
assign out0 = in0 & in1;
+
assign out0 = in0 & in1 & in2 & in3;
 
 
 
endmodule
 
endmodule
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
===Exercitiul 6: Desenati schemele logice pentru urmatoarele circuite:===
  
EX 6) Desenati schemele logice pentru urmatoarele circuite:
+
'''a) Schema 1'''
 
 
a)  
 
 
 
 
<syntaxhighlight lang="Verilog">
 
<syntaxhighlight lang="Verilog">
 
module schema1 (a, b, c, d, f);
 
module schema1 (a, b, c, d, f);
input a, b, c, d;
+
input logic a, b, c, d;
output f, g;
+
output logic f, g;
 
 
wire w1;
+
logic w1;
wire w2;
+
logic w2;
 
 
 
and P1 ( w1, a, c );
 
and P1 ( w1, a, c );
Linia 428: Linia 590:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Observatie: In versiunea veche de verilog (si sa pastrat si in cea curenta), se pot specifica directiile porturilor si in exteriorul parantezelor, ca mai sus.  
+
Observatie: In versiunea veche de verilog (si s-a pastrat si in cea curenta), se pot specifica directiile porturilor si in exteriorul parantezelor, ca mai sus.  
Aceasta scriere nu este recomandata.  
+
Aceasta scriere NU este recomandata.  
 
 
  
b)
 
  
 +
'''b) Schema 2'''
 
<syntaxhighlight lang="Verilog">
 
<syntaxhighlight lang="Verilog">
 
module schema2 (a, b, c, d, f);
 
module schema2 (a, b, c, d, f);
input a, b, c, d;
+
input logic a, b, c, d;
output f;
+
output logic f;
 
 
wire w1, w2;
+
logic w1, w2;
 
 
 
nand P1 ( w1, a, b ), P2 (w2, c, d);
 
nand P1 ( w1, a, b ), P2 (w2, c, d);
Linia 446: Linia 607:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Observatie, asemanator cu c/c++, se pot face declaratii in aceasi linie a mai multor "variabile", aici fire sau instante, cum se poate vedea la w1 si w2 (ambele fiind fire) sau la P1 si P2 (ambele fiind porti nand).
+
'''Observatie:''' asemanator cu C/C++, se pot face declaratii in aceeasi linie a mai multor "variabile", aici fire sau instante, cum se poate vedea la w1 si w2 (ambele fiind fire) sau la P1 si P2 (ambele fiind porti nand).
 +
Aceasta scriere NU este recomandata.

Versiunea curentă din 22 octombrie 2024 13:53

Teorie: incapsulare si instantiere

Unitatile constructive de baza din care se formeaza circuitele digitale se numesc porti logice. Acestea implementeaza functii logice si prin conectarea mai multor astfel de circuite simple complexitatea unui circuit poate creste pana la nivelul procesoarelor actuale. Pentru a putea controla cresterea complexitatii in proiectarea unui circuit de dimensiuni mari se folosesc 2 concepte cheie:

1) incapsularea functiei dorite intr-un modul

2) instantierea unor module mai mici si asamblarea acestora pentru a forma un modul mai mare.

Incapsularea se refera la a grupa elementele ce alcatuiesc o anumita functionalitate intre-un modul. Aceste elemente pot la randul lor sa fie alte module. Instantierea (asemanator cu POO) se refera la a apela un modul deja scris pentru a fi folosit efectiv in circuitul curent. Pentru a face o analogie cu programarea, cand se declara o variabila (sau un obiect), tipul variabilei este echivalent cu modulul si numele ei este numele instantei.

Pentru a intelege aceste concepte se da circuitul de mai jos:

Schema principiu instantiere.png


Observatii:

1) Notatie aici: Numele modulului este scris in interior.

2) Notatie aici: Numele instantei este scris deasupra.

3) Idee fundamentala: prin instantierea si incapsularea unor circuite simple, mici, apar circuite mai complexe.

4) Idei esentiale (daca vreuna e neclara consultati cadrul didactic):

a) "modul_2" este instantiat o singura data in tot proiecul, iar instanta se cheama "x"
b) "modul_2" are o intrare numita "in0" si o iesire numita "out0"
c) "modul_2" este instantiat in cadrul "modul_6"


d) Modulul cel mai mare, ce cuprinde toata functionalitatea dorita a sistemului (aici "modul_6") se numeste uzual top.
e) Instanta top-ului care apare atunci cand se doreste testarea sa in simulare intr-un testbench (tb) se numeste uzual DUT (design under test)


f) "modul_0" apare instantiat de 3 ori. Circuitul final, cuprinde 3 subcircuite de tip "modul_0".
g) La nivel de top, instanta sa se cheama "b".
h) La nivel de "modul_5", cele 2 instante se cheama "a" si "c".
i) "a" si "c" sunt 2 circuite fizice diferite chiar daca ambele sunt de tipul "modul_0". Fiind instante ale aceluiasi modul, deci identice in alcatuire, luate separat ele fac acelasi lucru. Luate in contextul lui "modul_5", "a" genereaza datele de pe firul "w0" si "c" genereaza datele pentru iesire.


j) circuitul "b" de tip "modul_1" (instantiat in "modul_5") este complet diferit de circuitul "b" de tip "modul_0" (instantiat in top). Este permis ca ele sa aiba acelasi nume (cele 2 instante) deoarece se afla in locatii diferite.


k) Identic, mai multe module au o intrare numita "in_0". La sinteza circuitului nu se face confuzie intre acestea deoarece fiecare e vazut la nivelul altei instante.
l) Identic, firele de legatura "w0", "w1".


m) La nivelul "top", firul de legatura "w2" leaga iesirea "out_0" a instantei "b" la intrarea "in2" a instantei "y".
n) La nivelul "top", firul de legatura "w1" leaga iesirea "out_0" a instantei "x" la intrarea "in1" a instantei "y".
o) La nivelul "modul_5", firul de legatura "w1" leaga iesirea instantei "b" la intrarea instantei "c".
Pentru claritatea desenului, respectivele intrari si iesiri nu au fost denumite. In cod este obligatoriu ca ele sa fie definite si denumite.


p) La nivelul "top", "in0","in1","in2","in3","in4" si "out0" formeaza interfata modulului (semnalele care intra sau ies din modul).
q) La nivelul "top", "w0", "w1", "w2" sunt fire interne de legatura.
r) La nivelul "top", firul "in3" este conectat ca intrare pentru 3 submodule.

Teorie: testarea circuitelor

Pentru a se testa functionarea corecta a circuitului final, acesta este instantiat intr-un modul numit "test_bench" sau "tb". Acest modul este folosit strict in simulare. Testarea unui circuit are loc conform schemei urmatoare:

Schema principiu tb.png

Generarea datelor de intrare se va face asemanator cu laboratorul 1.

Voi veti avea rolul modelului ideal si al comparatorului datelor de iesire, uitandu-va la datele de intrare veti calcula iesirea corecta si apoi veti compara aceasta valoare cu raspunsul circuitului ce se testeaza.


In cazul unui sistem automat, se genereaza mesaje de eroare sau mesaje ca functionarea este in regula.


Observatie: proiectarea si verificarea sunt 2 domenii diferite, firmele avand departamente separate pentru acestea.

Proiectarea/Design se ocupa cu scrierea in Verilog/SystemVerilog a modului de top si toate modulele ce se afla in acesta, avand ca scop final realizarea fizica pe placa a unui circuit.

Verificarea se ocupa de scrierea in SystemVerilog (limbaj format din Verilog cu concepte de POO) a modului de testbench si generarea de stimuli si scenarii care sa testeze functionarea design-ului.


Teorie: porti logice

Portile logice folosite uzual, impreuna cu tabelele lor de adevar si reprezentarea grafica sunt date mai jos.

Se folosesc porti logice cu 1 sau 2 intrari, cele cu mai mult de 2 intrari fiind construite din acestea.


Tip Simbol Tabel de adevăr Tip Simbol Tabel de adevăr
Buffer/Repetor Buffer symbol
INTRARE IEȘIRE
A A
0 0
1 1
NOT NOT symbol
INTRARE IEȘIRE
A NOT A
0 1
1 0
AND AND symbol
INTRARE IEȘIRE
A B A AND B
0 0 0
0 1 0
1 0 0
1 1 1
NAND NAND symbol
INTRARE IEȘIRE
A B A NAND B
0 0 1
0 1 1
1 0 1
1 1 0
OR OR symbol
INTRARE IEȘIRE
A B A OR B
0 0 0
0 1 1
1 0 1
1 1 1
NOR NOR symbol
INTRARE IEȘIRE
A B A NOR B
0 0 1
0 1 0
1 0 0
1 1 0
XOR XOR symbol
INTRARE IEȘIRE
A B A XOR B
0 0 0
0 1 1
1 0 1
1 1 0
XNOR XNOR symbol
INTRARE IEȘIRE
A B A XNOR B
0 0 1
0 1 0
1 0 0
1 1 1

Despre FPGA

FPGA-ul (Field-Programmable Gate Array) este un circuit programabil, capabil sa implementeze circuite definit de utilizator. El este format dintr-o matrice de blocuri programabile, interconectate intre ele printr-o serie de conexiuni la randul lor programabile.


Cand se doreste implementarea unui circuit pe FPGA, acesta urmeaza urmatoarele etape:

Elaborarea este procesul prin care codul SystemVerilog este transformat intr-un circuit la nivel de porti si registre (netlist) si este independent de modelul de FPGA folosit.
Sinteza este procesul în care se realizează transformarea circuitului descris într-un netlist dependent de tehnologie. Se vor folosi la acest pas primitivele disponibile pe FPGA.
Implementarea este procesul în care se preia netlist-ul ce conține primitivele FPGA și modul lor de interconectare realizat la pasul de sinteză și se realizează maparea lor efectivă în FPGA (place and route).
Generarea Bitstream-ului este procesul prin care informatiile din implementare sunt asamblate intr-un singur fisier.
Programarea este procesul prin care fisierul generat anterior este trimis efectiv catre placa cu FPGA (prin USB) unde determina modificarea valorilor si conexiunilor interne din aceasta.


O introducere mai detaliata poate fi gasita aici : FPGA - Introducere.

Fpgaimg.PNG

Observatii:

  • Pentru a putea controla circuitul propus si a putea vedea rezultatele, intrarile si iesirile (input si output din module) in/din acesta trebuie conectate la pini fizici ai FPGA-ului care sunt conectati la butoane/switch-uri/leduri.
  • Conexiunile dintre butoane/switch-uri si pinii FPGA sunt fixe. La fel si cele intre pinii FPGA si LED-uri. (in functie de PCB)
  • Conexiunile dintre porturile modulului Module si pinii FPGA sunt configurabile. (in functie de noi, prin fisierul XDC)
  • Legarea porturilor modulului Module la pinii fizici ai FPGA se realizeaza prin configurarea conexiunilor din FPGA conform contrangerilor de I/O pe care le vom mentiona in proiect, inainte de sinteza.

Exemple

Exemplul 1: Analiza circuitelor cu porti

Fie urmatorul circuit alcatuit din porti logice:

Mux2 schema interna 2.png

Se doreste exprimarea circuitului de mai sus ca formula de tip: iesire = f(intrari).

Pentru asta, abordarea consta in a porni de la iesire si a merge pas cu pas catre intrari, asa cum este exemplificat mai jos. Se vor folosi simbolurile "~" pentru NOT, "&" pentru AND, "|" pentru OR.

pas1: out0 = ?
pas2: out0 = w1 | w2
pas3: out0 = w1 | ( ? )
pas4: out0 = w1 | ( sel & in1 )
pas5: out0 = ( ? ) | ( sel & in1 )
pas6: out0 = ( in0 & w0 ) | ( sel & in1 )
pas7: out0 = ( in0 & ( ? ) ) | ( sel & in1 )
pas8: out0 = ( in0 & (~sel) ) | ( sel & in1 )

Exemplul 2: NAND2 din AND2 si NOT

In urmatorul exemplu se implementeaza o poarta NAND din o poarta AND si o poarta NOT.

Codul de mai jos exemplifica ideea de instantiere si contine comentarii legate de sintaxa SystemVerilog necesara.

In mod uzual fisierele sunt denumite dupa modulul ce se afla in ele, in fiecare fisier fiind un singur modul.

Schema circuitul care se doreste a fi creat este:

Schema exemplu rezolvat.png

Descrierea portii NOT (fisierul not_gate.sv):

// comentarii cu "//" sau cu /* .... */ ;
/* 
	ca in c/c++ 
*/ 

module not_gate	// cuvant cheie "module" apoi numele modulului (asemanator clase din c++)
	( // intre paranteze se pune interfata (firele care intra sau ies din modul)
		input logic in0,         // in0 este o intrare => input
		output logic out0	// out0 este o intrare => output
	); // aici ";" sa nu il uitati

assign out0 = ~in0;	// cuvant cheie assign; 
					// semnalele de tip wire (cum e out0) iau valoare prin assign
					// ~ e semnul pentru negatie pe biti (ca in c/c++)

endmodule // cuvant cheie "endmodule". orice module se inchide cu endmodule.

Descrierea portii AND (fisierul and_gate.sv):

module and_gate
	(
		input logic in0,	// aici sunt 2 intrari 
		input logic in1,	
		output logic out0
	); // nu conteaza ordinea in care sunt puse intrarile si iesirile.
			// uzual si pentru usurinta se ordoneaza si grupeaza dupa functionalitate
			// in cazul de mai sus, am pus intai intrarile, apoi iesirile.

assign out0 = in0 & in1; // operatia propriu zisa 

endmodule

Descrierea modulului top (fisierul top.sv):

module top
	(
		input logic a,
		input logic b,
		output logic c
    );
    
logic w0;    //declarat un fir intern de legatura 
    
and_gate and_gate_0	// instantiere: nume_modul nume_instanta (asemanator int x din c/c++)
	(
		.in0(a), // la intrarea "in0" a instantei "and_gate_0"  se conecteaza firul "a" din top
		.in1(b), // grija ca "in0", "in1", "out0" sa existe in declararea modulului "and_gate"
		.out0(w0) // grija ca "a", "b", "w0" sa existe la nivelul modulului in care se face instantierea
	);    
    
not_gate not_gate_0
	(
		.in0(w0), // "w0" care iese din "and_gate_0" intra in "not_gate_0"
		.out0(c) // "c" care iese din "not_gate_0" iese din modulul "top" (e iesire in interfata de sus)
	);   // se poate scrie si ".in0(w0),.out0(c)" dar se prefera fiecare fir pe randul sau (lizibilitate si loc de comentarii pt design-uri complexe)
	// Observatie: la varianta de mai sus de instantiere, nu conteaza ordinea firelor. 

/*
not_gate not_gate_0		
	(				// se poate instantia si in forma prescurtata ca aici 
		w0,				// in acest caz se pun conexiunile in ordinea in care sunt declarate intrarile si iesirile din modul
		c	// NU se recomanda stilul asta de instantiere
	); 			// apar greseli frecvent la ordinea firelor, la numarul lor, 
*/				// mai ales daca modulul e complex si are multe intrari si intrari
 
endmodule

Echivalent se pot folosi si "primitive" SystemVerilog pentru scrierea top-ului.

Primitivele sunt porti logice care exista deja in limbaj, folosite atunci cand se doreste o descriere structurala a circuitului.

In instantiere acestora, iesirea se pune prima, urmata de intrari.

Observatie: daca se doreste scrierea acestor porti de catre voi (ca mai sus), numele modulului nu trebuie sa fie un cuvant cheie ocupat de primitive.


Descrierea alternativa a modulului top (fisierul top_v2.sv):

module top_v2
    (
	    input logic a,
	    input logic b,
	    output logic c
    );
  
wire w0;

and and_gate_0(w0,a,b);	// primitiva pentru poarta and
not not_gate_0(c,w0);  	// primitiva pentru poarta not
   
endmodule

Fiind un modul simplu, intreaga functionalitate putea fi scrisa la nivel de "top" si simplificat ca mai jos.


Descrierea alternativa a modulului top (fisierul top_v3.sv):

module top_v3
    (
	    input logic a,
	    input logic b,
	    output logic c
    );
   
assign c = ~ (a & b); // a si b, negate
   
endmodule

Testarea circuitul se face printr-un testbench, acesta fiind:


Descrierea testbench-ului (fisierul top_tb.sv):

`timescale 1ns / 1ps

module top_tb(); // din/in tb nu intra si iese nimic. niciodata.

logic a_tb;	
logic b_tb;	
logic c_tb;	

top dut	// instantierea modulului de tip "top" sub numele "dut" 
	(
		.a(a_tb),
		.b(b_tb),
		.c(c_tb)
    );

initial
begin // in loc de { ... } din c/c++, in SystemVerilog se pune begin ... end 
	#10;		// dupa 10 unitati de timp 
	a_tb = 0;		// a_tb ia valoarea 0
	b_tb = 0;
	#10;		// dupa inca 10 unitati de timp, deci in total la 20
	a_tb = 1;
	b_tb = 0;
	#10;
	a_tb = 0;
	b_tb = 1;
	#10;
	a_tb = 1;
	b_tb = 1;
	#10;
	a_tb = 0;
	b_tb = 0;
	
	#20 $stop();	// oprirea simularii 
end //end pentru initial 

endmodule

Formele de unda rezultate din simulare se pot vedea mai jos:

Exemplu rezolvat nand forme de unda.png


In chenarul verde se pot observa instantele din simulare.

Daca se doreste adaugarea de semnale noi pentru a fi vazute, se selecteaza modulul instantiat in care acestea se afla (chenar verde).

Apoi, din chenarul rosu se aleg semnalele si se adauga prin click dreapta->add to wave window.

Pentru o mai usoara vizualizare, semnalele se pot grupa asa cum se vede in chenarul mov prin click dreapta->new group.


Se observa o functionare corecta circuitului, acesta fiind o poarta NAND. El scoate "0" cand ambele semnale de intrare sunt "1" si scoate "1" in rest.


Implementarea circuitului pe FPGA

Dupa ce circuitul a fost testat in simulare, se doreste punerea sa fizica pe placa FPGA. Pentru aceasta, se tine cont de urmatoarele.

  • Pentru a controla intrarile a si b ale circuitului 'top, va trebui sa le conectam prin intermediul conexiunilor configurabile ale FPGA-ului la pini ce sunt mai departe conectati fizic la dispozitive ce pot controla valorile semnalelor (switch-uri, butoane).
  • Pentru a observa valoarea iesirii, vom conecta semnalul de iesire cla un dispozitiv de observare, cum ar fi un LED, care va fi aprins daca c este 1 si stins daca c este 0.

NAND2 FPGA.png

Pentru a realiza conectarea porturilor modulului top la pinii fizici ai FPGA ce sunt conectati mai departe la componentele de pe placa, va trebui sa specificam in utilitarul de sinteza maparea porturilor la acestia. Maparea se realizeaza prin mentionarea codurilor pinilor la care dorim conexiunea si poata numele de constrangeri de I/O. Aceste coduri sunt mentionate in documentatia placii de dezvoltare cu FPGA (in cazul nostru, PYNQ Z2) si pot fi regasite si in pagina PYNQ-Z2 - Pinout.

Conform schemei, la acest exemplu avem nevoie de codurile pinilor conectati mai departe la Switch0, Switch1 si LED0.

Observatie: Daca intrarile si iesirile ar fi semnale pe mai multi biti, fiecare bit al intrarilor va fi conectat la cate un switch/buton si fiecare bit al iesirii va fi conectat la un LED. Acest lucru este necesar deoarece switch-urile/butoanele pot avea doar doua stari (0 si 1) si astfel pot controla un singur bit. La fel, un LED poate avea doar doua stari (0 - stins si 1 - aprins) si poate afisa starea unui singur bit.

Dupa ce ati extras codurile necesare, urmati pasii descrisi in tutorialul Vivado.

Dupa programarea cu succes a placii, puteti testa functionalitatea circuitului prin modficarea valorilor switch-urilor si observarea starii LED-ului.

Exercitii

Pentru urmatoarele exercitii se doreste atat testarea designurilor prin simulare cat si punerea acestora pe placa. Legat de placa, intrarile vor fi conectate la butoane, iar iesirile la leduri. Se va consulta tabelul cu pini disponibili (Pynq-Z2 - Pinout).

Exista moduri mai rapide de a scrie functionalitatea dorita (vezi exemplu), dar tema principala a acestui laborator este instantierea, asa ca sunteti rugati sa respectati desenele si sa instantiati fiecare poarta individual.

Exercitiul 1: AND4 din AND2

Acest exercitiu arata cum se construieste o poarta AND cu 4 intrari din porti AND mai simple, cu 2 intrari. Iesirea acesteia va fi "1" doar daca toate intrarile sunt "1".

Schema and4 din and2.png

Pentru testarea circuitului, generati in testbench urmatoarele forme de unda (liniile punctate reprezinta 5ns):

Wavedrom and4.png


Exercitiul 2: OR4 din OR2

Asemanator cu exercitiul anterior, se poate construi si o poarta or cu 4 intrari din porti or cu 2 intrari. Iesirea acesteia va fi "1" doar daca oricare din intrari (cel putin una) este "1".

Pentru testarea circuitului se folosesc formele de unda de la exercitiul 1.

Schema or4 din or2.png


Exercitiul 3: AND4 din AND2 aranjat pe lung (nu arbore)

In multe cazuri, aceeasi functionalitate poate fi atinsa prin circuite care arata diferit. O alta varianta de a face o poarta AND cu 4 intrari este prezentata mai jos.

Comparati cele 2 variante.

Pentru testarea circuitului se folosesc formele de unda de la exercitiul 1.

Schema and4 din and2 v2.png


Exercitiul 4: AND4 din NAND2

Orice poarta logica de baza poate fi construita doar din porti NAND sau doar din porti NOR.

Desenati si implementati circuitul pentru o poarta AND4 din porti NAND cu 2 intrari.

Tip: Incercati intai sa generati o poarta AND2 din NAND2.

Pentru testarea circuitului se folosesc formele de unda de la exercitiul 1.


Exercitiul 5: AND4 pe 4b din AND4 pe 1b

Se pot face operatii logice si pe mai multi biti deodata prin punerea in paralel a mai multor porti cu o singura iesire. Exemplu : pentru intrarile 0011 si 1110 iesirea va fi 0010

Pentru exersarea instantierii si intelegerea circuitului din spatele operatilor multibit implementati acest circuit prin instantierea a 4 porti AND2 pe 1 bit intr-o poarta AND2 pe 4 biti.

Schema and4 4b din and4 1b v1.png

Pentru testarea circuitului, generati in testbench urmatoarele forme de unda (liniile punctate reprezinta 5ns):

Wavedrom and4 4b.png

Exista si un mod mai rapid si simplu de a scrie aceasta functionalitate, grupand intrarile si iesirile in "bus"-uri, ca in codul de mai jos. Acest mod de a grupa firele este desenat mai jos.

Schema and4 4b din and4 1b v2.png

Fisierul and4_4b.sv:

module and4_4b
	(
		input logic [3:0] in0,	// in0 are 4b, de la bit 3 la bit 0 inclusiv 
		input logic [3:0] in1,	// se noteaza msb:lsb (most significant bit: least significant bit) (echivalent cu conceptul de cifra sutelor, cifra unitatilor, pt binar)
		input logic [3:0] in2,
		input logic [3:0] in3,
		output logic [3:0] out0
	);
	
assign out0 = in0 & in1 & in2 & in3;
	
endmodule

Exercitiul 6: Desenati schemele logice pentru urmatoarele circuite:

a) Schema 1

module schema1 (a, b, c, d, f);
	input logic a, b, c, d;
	output logic f, g;
	
	logic w1;
	logic w2;
	
	and P1 ( w1, a, c );
	or P2 ( f, w1, w2, d);
	not P3 (w2, b);
	and P4 (g, w1, b, d);
endmodule

Observatie: In versiunea veche de verilog (si s-a pastrat si in cea curenta), se pot specifica directiile porturilor si in exteriorul parantezelor, ca mai sus. Aceasta scriere NU este recomandata.


b) Schema 2

module schema2 (a, b, c, d, f);
	input logic a, b, c, d;
	output logic f;
	
	logic w1, w2;
	
	nand P1 ( w1, a, b ), P2 (w2, c, d);
	and P3 ( f, w1, w2);
endmodule

Observatie: asemanator cu C/C++, se pot face declaratii in aceeasi linie a mai multor "variabile", aici fire sau instante, cum se poate vedea la w1 si w2 (ambele fiind fire) sau la P1 si P2 (ambele fiind porti nand). Aceasta scriere NU este recomandata.