CID aplicatii 1 : Generare de forme de unda

De la WikiLabs

În această sesiune de aplicații vom învăța cum să generăm semnale digitale cu ajutorul limbajului Verilog. Generarea de semnale este utilizată în testarea prin simulare a circuitelor digitale. Semnalele generate sunt introduse la intrarea circuitului, observându-se apoi cum se modifică starea ieșirilor acestuia.

Proiectarea circuitelor digitale se bazează pe generarea unor circuite digitale fizice. Deși se va scrie cod în limbajul Verilog, mereu trebuie avut în vedere faptul că în spate se va genera un circuit fizic, codul nu se rulează pas cu pas, aceasta fiind deosebirea fundamentală dintre limbajele de descriere hardware (generează circuite fizice) și limbajele de programare (cod care se execută pas cu pas). Unele concepte cât și unele elemente de sintaxa este posibil să semene cu ce ați facut la programare, dar este important să înțelegeți că prin codul scris se desenează/generează circuite. Sau invers, pornind de la un desen, se poate face o descriere în Verilog a acestuia.

Proiectele exemplu care pot fi descărcate au fost implementate folosind Vivado 2021.2. Dacă aveți altă versiune este posibil să vă ceară să le salvați în versiunea respectivă sau să fie nevoie să vă faceți un proiect nou, în care să adaugați fișierele cu cod.

Noțiuni și cunoștințe necesare

Modulul de test (Testbench)

Modulul de test este un modul nesintetizabil (nu poate fi transformat într-un circuit de către utilitarul care realizează sinteza) și este folosit, așa cum sugerează și numele, în testarea circuitelor. Acest modul este folosit exclusiv în simulare. Simularea permite detecția rapidă a erorilor de implementare și corectarea acestora. Ideea generală a unui modul de test este descrisă în figura de mai jos (considerăm un circuit cu numele circuit și modulul său de test circuit_tb):

CircuitTestbench.png

După cum se vede în figura de mai sus, modulul de test conține printre altele și un generator de semnale de test. Acesta are rolul de a genera câte un semnal de test pentru fiecare intrare a circuitului. Forma acestor semnale de test este stabilită de către cel care realizează verificarea și trebuie aleasă astfel încât să detectăm cât mai multe posibile erori.

Exemple

Exemplul 1: Generarea a doua semnale digitale de 1 bit

Să se genereze două semnale digitale de 1 bit, care să aibă următoarea variație în timp (unitatea de timp este de 1ns):

CID Aplicatii1 ex1.svg

`timescale 1ns/1ps     // setăm unitatea de timp la 1ns, cu o precizie de 1ps

module waveform1();    // modulul se numește waveform1 și nu are nicio intrare și nicio ieșire. Semnalele de test generate sunt semnale interne.

reg a, b;              // cele două semnale de test sunt modificate într-un bloc de tip initial și trebuie declarate ca elemente de tip reg.

initial begin
    $monitor("time = %2d, a = %b, b=%b", $time, a, b);  // monitorizăm în consolă starea semnalelor a si b
       a = 0;          // semnalul a va avea valoarea 0 la momentul inițial de timp (la momentul t = 0)
       b = 0;          // semnalul b va avea valoarea 0 la momentul inițial de timp (la momentul t = 0)
    #1 a = 1;          // după 1ns de la momentul inițial, a se face 1
    #1 b = 1;          // după 2ns de la momentul inițial, b se face 1
    #1 a = 0;          // după 3ns de la momentul inițial, a se face 0
       b = 0;          // după 3ns de la momentul inițial, b se face 0
    #2 $stop();        // simularea este oprită
end

endmodule              // incheiem descrierea modulului de generare de semnale digitale

Observație: Atunci când un semnal are dimensiunea de 1 bit, nu va apărea nimic intre tipul acestuia și nume. Atunci când semnalul are o dimensiune mai mare sau egală cu doi biți, dimensiunea va fi descrisă sub forma [n-1:0], unde n este numărul de biți. Conform acestei descrieri, bitul n-1 este cel mai semnificativ.

reg a;           //semnal cu dimeniunea de 1 bit
reg [7:0] data;  //semnal/magistrală/bus cu dimensiunea de 8 biți

Exemplul 2: Generarea unui semnal periodic de 1 bit

Să se genereze un semnal digital periodic de 1 bit, cu perioada egală cu 2ns:

Clock wave.png

`timescale 1ns/1ps     // setăm unitatea de timp la 1ns, cu o precizie de 1ps

module waveform2();    // modulul se numește waveform2 si nu are nicio intrare și nicio iesire

reg clock;             // semnalul de test se va modifica într-un bloc initial, așadar este declarat de tip reg

initial begin
    clock = 0;                   // valoarea inițială a semnalului va fi 0 (la momentul t = 0)
    forever #1 clock = ~clock;   // forever indică faptul că ce urmează se va repeta într-o buclă continuă. 
                                 // La trecea unui timp egal cu unitatea de timp definită, semnalul clock iși va nega valoarea
end

initial begin
    #20 $stop();       // La 20 de unități de timp (aici, 20 ns), simularea se va opri. 
                       // Aici punem $stop într-un bloc separat, deoarece forever blochează blocul initial în care se află
                       // Toate blocurile initial încep la același moment de timp (t = 0) și au efect în paralel
end

endmodule

Exerciții

Exercițiul 1

Generați două semnale digitale a și b de 1 bit, astfel încât să se formeze cu ele toate cele 4 combinații posibile, după cum urmează:

   t = 0ns: a = 0, b = 0
   t = 1ns: a = 0, b = 1
   t = 2ns: a = 1, b = 0
   t = 3ns: a = 1, b = 1

Exercițiul 2

Să se genereze un semnal digital de 8 biți aliniat la fronturile crescătoare ale unui semnal periodic (semnal de ceas), ce are perioada de 2ns:

Clock and data wave.png

Observație:

  • Frontul crescător al unui semnal este definit ca tranziția dintre nivelul de 0 logic și 1 logic.
  • Spunem că un semnal este aliniat la fronturile crescătoare ale unui alt semnal dacă acesta își modifică valoarea imediat după apariția acelui front crescător. În figura de mai sus, se observă că data își schimbă valoarea imediat după fiecare front crescător al semnalului clock.

Indicații:

  • Așteptarea unui front crescător al semnalului NumeSemnal se realizează cu @(posedge NumeSemnal). Aceasta va înlocui întârzierile de tip #n folosite anterior.
  • Pentru semnalele ce se doresc aliniate la un eveniment de tip posedge, vom folosi atribuirea non-blocantă: de exemplu, data <= 1;.
  • Nu uitați! Folosirea forever pentru generarea semnalului de ceas va bloca acel bloc initial.
  • Incrementarea valorii unui semnal se poate realiza cu un bloc de tip for, inclus in blocul initial. Blocul for va avea nevoie de un contor de tip integer, declarat în afara blocului initial. Pentru mai multe detalii, consultați tutorialul de sintaxa Verilog.


Folosind indicațiile anterioare, înlocuiți al doilea bloc initial din Exemplul 2 cu următoarea secvență și completați liniile de cod lipsă:

integer index;

initial begin
    for(index = 0; index < 11; index = index + 1) begin
        //completati codul    
    end
    #20 $stop();
end

Exercițiul 3

Desenați formele de undă ale semnalelor de test a, b și c, generate cu ajutorul următoarelor două blocuri initial:

`timescale 1ns/1ps     

module waveform();    

reg a, b, c; 

initial begin
       a = 0;          
       b = 0;          
    #2 b = 1;          
    #1 a = 1;          
    #3 b = 0;          
    #3 a = 0;          
    #2 $stop();       
end   

initial begin
       c = 1;                   
    #2 c = 0;          
    #3 c = 1;                
end  
      
endmodule

Exercițiul 4

Generati un semnal digital clock cu dimensiunea de 1 bit si perioada de 2ns si un semnal digital data, cu dimensiunea de 4 biti, aliniat la fronturile crescatoare ale semnalului clock. Semnalul data va varia astfel: 0, 1, 2, 3, 0, 1, 2 ,3, 0, 1 ... . Opriti simularea dupa ce semnalul data a realizat 4 variatii complete (s-a generat secventa 0, 1, 2, 3 de 4 ori).