Constructii sintetizabile in verilog Introducere Programele verilog se împart în două categorii: cod pentru simulare și cod sintetizabil. Codul scris pentru simulare (testul) nu este sintetizabil. Codul sintetizabil poate fi simulat, dar prin intermetiul unui test. Principalele construcții sintetizabile în limbajul verilog sunt următoarele: - instanțierea de module sintetizabile - orice construcție folosind cuvântul cheie assign - blocurile always care respectă un format standard, cunoscut de către compilator Automate cu stari finite de tip Mealy Schema unui automat de tip Mealy este prezentată mai jos. Un automat de tip Mealy este format din: - registre, care sunt utilizate pentru memorarea stării curente a automatului pe durata perioadei curente a ceasului (clk) - circuite logice combinationale, care sunt utilizate pentru calcularea stării urmatoare a automatului - logica de calcul a ieșirilor automatului, care se calculează in funcție de intrări și starea curentă intrări logică pentru ieșiri logică combinatorială pentru starea următoare registru > ieșiri starea curentă ceas Figura 1. Automat cu stări finite Mealy Exemplu. Se dorește construirea unui automat Mealy ce primește la intrare variabila in și detectează tranzitiile din 0 în 1 și din 1 în 0 ale acestui semnal. Modulul are interfața următoare: module edgedetector1 (input clk, input reset, input in, output reg rout); localparam A=3'd0, B=3'd1, C=3'd2; reg out; reg [2:0] state; // Current state reg [2:0] nxtstate; // Next state
Blocul always utilizat pentru salvarea stării pe perioada curentă a semnalului de ceas este prezentat mai jos. Aceasta este o constructie sintetizabilă. Compilatorul va sintetiza variabila state intr-un registru. always @(posedge clk or posedge reset) begin if (reset) begin state = A; // Initial state rout = 0; else begin state = nxtstate; rout = out; Blocul always utilizat pentru calcularea stării urmatoare a automatului și a ieșirii acestuia este prezentat mai jos. Aceasta este o constructie sintetizabilă. Compilatorul va sintetiza blocul de cod în circuite logice combinaționale. Variabilele nxtstate și out nu vor fi sintetizate ca registre pentru că nu depind de semnalul de ceas clk. always @(*) begin nxtstate = state; out = 0; case (state) A : if (in) nxtstate = C; else nxtstate = B; B : if (in) begin out = 1; nxtstate = C; C : if (!in) begin out = 1; nxtstate = B; default : begin out = 1'bX; nxtstate = 3'bX; case Se observă ca primele doua instructiuni ale corpului always sunt două atribuiri: se setează variabilele nxtstate și out. Aceste atribuiri se numesc implicite. Dacă în vreo ramură a blocului case, vreuna dintre variabilele nxtstate și out nu este setată, atunci ea va avea valoarea atribuită la începutul blocului always de atribuirea implicită. În ramurile blocului case în care se setează aceste variabile explicit, atunci atribuirile implicite se ignoră. De exemplu, în starea B, dacă in este egal cu 1 atunci variabila out este setată la valoarea 1; altfel, variabila out este setată la valoare implicită, adica 0.
Acelasi efect se poate obține folosind pentru variabilele nxtstate și out setare prin instrucțiunea assign, dar în acest caz, aceste variabile trebuie declarate ca wire. module edgedetector2 (input clk, input reset, input in, output reg rout); localparam A=3'd0, B=3'd1, C=3'd2; wire out; reg [2:0] state; // Current state wire [2:0] nxtstate; // Next state always @(posedge clk or posedge reset) begin if (reset) begin state = A; // Initial state rout = 0; else begin state = nxtstate; rout = out; assign nxtstate = (state == A)? (in? C : B) : (state == B)? (in? C : B) : (state == C)? (!in? B: C) : 3'bX; assign out = (state == A)? 0 : (state == B)? (in? 1 : 0) : (state == C)? (!in? 1: 0) : 1'bX; module Observație: se recomanda în cazul automatelor de tip Mealy ca iesirea out să fie trecută printr-un registru rout. Automate cu stari finite de tip Moore Schema unui automat de tip Moore este prezentată mai jos. Un automat de tip Moore este format din: - registre, care sunt utilizate pentru memorarea stării curente a automatului pe durata perioadei curente a ceasului (clk) - circuite logice combinationale, care sunt utilizate pentru calcularea starii următoare a automatului - logica de calcul a iesirilor automatului, care se calculeaza numai in funcție de starea curentă a automatului
intrări logică combinatorială pentru starea următoare registru > starea curentă logică pentru ieșiri ieșiri ceas Figura 2. Automat cu stări finite Moore În continuare este prezentată implementarea exemplului dat anterior, dar cu automat de tip Moore. Singura deosebire este blocul always utilizat pentru calcularea stării următoare a automatului și a iesirii acestuia, care este prezentat mai jos. always @(*) begin nxtstate = state; out = 0; case (state) A : if (in) nxtstate = C; else nxtstate = B; B : if (in) nxtstate = D; C : if (!in) nxtstate = E; D : begin out = 1; if (in) nxtstate = C; else nxtstate = E; E : begin out = 1; if (in) nxtstate = D; else nxtstate = B; default : begin out = 1'bX; nxtstate = 3'bX; case
Simularea modulelor verilog Simularea modulelor implementate mai sus presupune crearea unui modul de test în care se instanțiază modulul testat. Modulul de test este prezentat mai jos. Prima linie este directiva timescale care stabilește durata de întârziere sau așteptare a instrucțiunii precedată de caracterul #. Urmează instanțierea modulului testat și corpul initial care descrie stimulii acestei simulări. Se mai remarcă simulatorul semnalului de ceas clk din blocul always, care, in acest caz, din 5 în 5ns inversează valoarea semnalului de ceas. `timescale 1ns / 1ps module test; reg clk, reset, in; wire rout; edgedetector1 ed (clk, reset, in, rout); initial begin clk = 0; reset = 1; in = 0; #20; reset = 0; #30; in = 1; #50; in = 0; always #5 clk = ~clk; module Simularea modulului edgedetector1 de tip Mealy este prezentata mai jos:
Aplicație: Afisaj numeric Placa de dezvoltare Nexys1 deține un afisaj numeric cu patru digiți, iar placa de dezvoltare Nexys4DDR deține un afisaj numeric cu opt digiți. Fiecare dintre cei patru (sau opt) digiți este compus din șapte segmente aranjate ca în figura de mai jos, cu un led încorporat în fiecare segment. Segmentele pot fi iluminate individual, deci 128 de combinații diferite pot fi afișate pe un digit. Cele mai interesante combinații sunt cifrele zecimale. Figura 3. Digit cu 7 segmente Anozii celor șapte segmente luminoase ale unui digit sunt legate împreună, iar catozii rămân separați, ca în figura următoare. Anodul comun al fiecărui digit are un semnal disponibil ca intrare digitală pentru afisajul numeric. Acestea sunt numerotate AN0... AN7. Cele 8 elementele catod ale unui digit sunt comune tuturor digiților și sunt denumite CA,..., CG, DP. Aceste 8 semnale sunt disponibile ca intrări digitale. Această schemă creează un afisaj multiplexat în care elementele catod sunt comunte tuturor digiților, dar pot ilumina doar segmentele digitului pentru care semnalul anod este activ. Figura 4. Afisaj numeric Pentru a ilumina un segment, intrarea anod corespunzătoare digitului de care aparține segmentul trebuie setată pe 0, iar catodul corespunzător tot pe 0.
Un circuit de control poate fi utilizat pentru a afișa un număr cu cifre diferite pe afisaj. Circuitul setează semnalele anod și combinația de segmente (ce reprezintă cifra) pentru fiecare digit în parte într-o manieră repetitivă și cu o rapiditate suficient de mare pentru a evita stingerea digiților. Daca frecvența de reîmprospătare a afisajului este mai mică de 45Hz, atunci afisajul va clipi. În continuare descriem metoda de afișare pentru patru digiți deoarece extinderea la opt digiți se poate face imediat. Pentru ca fiecare dintre cei patru digiți să apară iluminat continuu avem nevoie de o frecvență de reîmprospătare a afisajului cuprinsă intre 1KHz și 60Hz. De exemplu, pentru o frecvență de 60Hz, afisajul va fi reîmprospătat o dată la fiecare 16ms și fiecare digit va fi iluminat un sfert din acest ciclu, deci 4ms. Modulul de control trebuie să asigure combinația de segmente dorită pentru a ilumina digitul al cărui anod este activat. De exemplu, când AN0 este activat și CB și CC sunt activate, atunci cifra 1 va fi afișată pe primul digit. Apoi, când AN1 este activat și CA, CB și CC sunt activate, atunci cifra 7 va fi afișată pe digitul al doilea. Dacă AN0, CB și CC sunt activate 4ms (în timp ce AN1, AN2, AN3 sunt inactive) iar apoi A1 și CA, CB, CC sunt activate pentru 4ms și ciclăm aceste activări, atunci pe primii doi digiți va fi afișat numărul 71. Figura de mai jos ilustrează modul de afișare pentru patru digiți. Figura 5. Ilustrarea modului de afișare pe 4 digiți Pentru a implementa modulul de control al afisajului, avem nevoie de un automat cu stări finite. Pentru un afisaj cu patru digiți avem nevoie de patru stări, fiecare pentru un digit. În fiecare stare, automatul trebuie să aștepte 4ms, timp în care se ține activat anodul corespunzător digitului iluminat (iar ceilalți anozi sunt dezacvitați) și sunt setate segmentele digitului (catozii) pentru cifra dorită. Calculul intervalului de 4ms se poate face prin numărarea perioadelor oscilatorului de ceas; de exemplu, pentru o frecvență a ceasului de 50Mhz, vom avea 50000000perioade/s. Probleme propuse 1. Afișați aceeași cifră pe toți digiții afisajului numeric. 2. Afișați un număr cu cifre diferite pe afisajul numeric. 3. Afișați un ceas digital pe afișajul numeric astfel: primii doi digiți reprezintă secundele, iar următorii doi, minutele.
4. Afișați un cronometru cu numărătoare inversă (descrescător). Primii doi digiți reprezintă sutimile de secundă, iar următorii doi digiți reprezintă secundele. 5. Relizați o schemă de afișare animată ca în figura de mai jos. În fiecare din stările a, b, c, d, automatul va sta 0,5s. Figura 6. Schema de afișare animată