FPGA: Verilog, lo “slang” degli HDL

FPGA Verilog

L'unica alternativa al VHDL è il Verilog, un Hardware Description Language con delle caratteristiche molto differenti, ma con lo stesso ruolo all'interno dell'intricato mondo dell'elettronica: descrivere sistemi digitali da poter realizzare sfruttando la potenza di circuiti programmabili ad alto livello di integrazione: FPGA. Ma quali sono le differenze tra i due linguaggi? Cosa hanno in comune? Ma soprattutto: quale dei due linguaggi è il migliore? Attraverso questo articolo avrete tutte (o quasi) le risposte di cui avete bisogno.

Sono in molti a conoscere il VHDL, il linguaggio di descrizione hardware per eccellenza nel nostro paese. Sono tuttavia in pochi a sapere che il Verilog non ha proprio nulla da invidiare al VHDL.

A livello concettuale valgono tutte le considerazioni fatte per il VHDL (indipendenza tecnologica, semplicità di descrivere sistemi complessi, etc.), quindi eviterò di dirvi cos'è il Verilog (potete accontentarvi di sapere che è un HDL),  per cui entriamo subito nel merito, partendo anche in questo caso dalla sua storia.

Come nasce il Verilog?

Verilog nasce come linguaggio di modellizzazione hardware, brevettato dalla Gateway Design Automation. Ma solo con l'acquisizione da parte di Cadence del sistema di automazione di Gateway, il Verilog è diventato in tutto e per tutto di proprietà Cadence, che ha iniziato a commercializzare sia il linguaggio che i simulatori. Nel 1991 Cadence ha organizzato Open Verilog International (OVI), un gruppo di lavoro nato per formare un Language Reference Manual (LRM) all'altezza delle richieste del mercato.

E' stato poi formato un nuovo gruppo di lavoro, IEEE 1364, al fine di rendere Verilog uno standard IEEE e poter competere con il VHDL, già standardizzato nel 1987, come potete vedere nel precedente articolo.

In seguito molti simulatori sono stati realizzati, e con il passare del tempo, i tempi di compilazione sono andati riducendosi sempre più. Ed anche il linguaggio negli anni ha subito notevoli evoluzioni. Nell'allegato potete vedere lo stato del Verilog fino al 2005, quindi con il Verilog 2001 come ultimo aggiornamento.

In realtà è stato poi realizzato l'ultimo aggiornamento nel Verilog-2005, che contiene alcune feature utili, ma nessuna modifica strutturale del linguaggio.

Nel 2009 è stata poi effettuata la fusione tra il Verilog-2005 e un superset di istruzioni Verilog, System-Verilog, al fine di migliorare le possibilità di simulazione e modellizzazione attraverso il Verilog, rendendolo molto più simile, per molti aspetti, ad un linguaggio di programmazione software (linguaggio C, per la precisione). Tale fusione ha portato al SystemVerilog2009, attualmente la versione più aggiornata del linguaggio. Si parla di un prossimo inserimento di un nuovo set di istruzioni per dare la possibilità di descrivere anche modelli analogici, ma per ora niente di concreto.

Quali sono le caratteristiche del Verilog?

Così come per il VHDL, anche per il Verilog vale il concetto che di tutorial in giro ne esistono, e non penso sia il caso di fare un corso qui in questo articolo, visto che non si impara un linguaggio attraverso un articolo. Per cui cercherò solo di mostrarvi una strada da percorrere, che poi solo la buona volontà e l'impegno possono permettervi di percorrere fino in fondo. Allego a tal proposito il quarto capitolo della mia tesi per darvi delle indicazioni varie, mentre in questo link potete trovare il reference language manual, che sicuramente vi può essere d'aiuto.

Quello di cui vi parlerò saranno le peculiarità di questo linguaggio, il primo approccio, alcune differenze fondamentali con il VHDL.

Ribadisco l'importanza del concetto di indipendenza tecnologica, valido anche per il Verilog.

Anche ora possiamo immaginare ogni sistema come una combinazione input-operazioni-output, ma questa volta la struttura base, anzichè l'entity, sarà il "module", modulo.

Ogni modulo è costituito dall'interfaccia verso l'esterno (input e output) e dalla parte funzionale (operazioni).

Per descrivere un modulo in Verilog si procede secondo la scrittura che segue:

module name_module (in1, in2, out1, out2 ...);
input in1, in2, ... ;
output out1, out2, ... ;

...
...

endmodule;

Ciò che subito salta all'occhio è una struttura meno rigida, più user-friendly, rispetto al suo competitor, e soprattutto molto più vicino ad un linguaggio software quale il C. Andando avanti con l'articolo questo aspetto verrà fuori molto di più.

Una differenza che vorrei sottolineare subito sta anche nel fatto che stiamo parlando di un linguaggio case-sensitive, tranne solo per 2 parole chiave, cioè 'z' o 'Z', 'x' o 'X'. Questo aspetto mette in chiaro subito una cosa: il Verilog vuole distinguersi dal VHDL, e sembra quasi in questo modo voler fare l'esatto contrario proprio per rimarcarlo.

Altra differenza fondamentale è l'utilizzo della logica a 4 valori (e non a 9)  per tutti i segnali. Nel template mostrato sopra, vediamo come i segnali non vengano dichiarati.

Preciso che il valore 'x'  sia un valore indeterminato, ed un segnale può assumerlo qualora non sia stato ancora inizializzato oppure quando esiste un conflitto di assegnazione. Il valore 'z' invece corrisponde all'alta impedenza, che viene usata nei bus bidirezionali o condivisi.

Queste caratteristiche appena descritte spiegano il motivo per cui mi sono permesso di definire il Verilog come lo "slang" degli HDL: un linguaggio meno schematico, meno rigido e più vicino al modo di parlare comune. E questa peculiarità è senza dubbio il punto di forza di questo linguaggio, ma forse anche la causa dei suoi "difetti".

Un esempio pratico può aiutare ad entrare meglio nel merito del suo utilizzo:

module flip_flop (q, d, clk)
input d, clk;
output q;
reg q;
always @(posedge clk)
    q <=d;
endmodule;

Un'osservazione che vi pongo è la mancanza della dichiarazione delle librerie all'inizio della descrizione del modulo.

Il concetto di libreria in Verilog non esiste! 

Questo è possibile perché il Verilog è un linguaggio con preprocessore, come anche il linguaggio C, ossia i compilatori interpretano i termini chiave estrapolandone le funzioni che definiscono. E' proprio un concetto differente, dovuto alle sue origini: il Verilog è nato come linguaggio di modellizzazione e simulazione, per cui le sue funzioni sono necessariamente parte integranti del linguaggio. Il VHDL invece, nato per descrivere sistemi, si è dovuto poi adattare alla compilazione e alla simulazione attraverso le librerie.

Altra osservazione: si nota di nuovo la struttura meno rigida del linguaggio vedendo l'utilizzo del processo always.

La parola chiave "always" descrive infatti quello che in VHDL è il Process. Con il simbolo @ andiamo ad introdurre la sensitivity list, e senza begin, nè end, ci troviamo un processo che genera un flip-flop con una riga di codice.

E' chiara la vicinanza alla descrizione verbale: a voce io direi che un flip flop "ad ogni (always) fronte di salita (posedge) del segnale di clock porta l'ingresso in uscita (q<=d)". Traduzione uno-a-uno, forse ancor più semplice oserei dire.

Preciso subito che questa mancanza di begin e end è possibile perchè viene utilizzata una sola istruzione per descrivere il processo, ma è un segnale di come questo linguaggio abbia l'obiettivo di essere vicino all'utilizzatore.

Altra grande differenza, che possiamo notare in parte anche nell'esempio, sta nell'utilizzo dei segnali interni. In verilog distinguiamo due tipi di segnali: variabili (reg) e net, i quali possono essere di più tipologie, tra cui le più comuni sono senza dubbio i wire, ma anche wor, wand, trireg.

I segnali di tipo net possono essere identificati con una connessione elettrica, per cui vanno pilotati attraverso una porta logica, un modulo o un'espressione algebrica affinchè non si mettano in alta impedenza. Per assegnarle viene utilizzato il comando assign.

I segnali di tipo reg invece sono più assimilabili al concetto di registro o flip-flop, ossia vengono assegnate una volta e mantengono quel valore fino ad una successiva assegnazione. Per essere assegnati hanno bisogno di blocchi procedurali, quali always oppure initial.

Per rendere meglio l'idea, tornando alla differenziazione tra descrizione Behavioural Gate-level, vista nell'articolo precedentenel primo caso si userà il reg, nel secondo caso si userà il net

Il blocco Initial, al contrario di always, serve a inizializzare i segnali. Per la precisione, si definisce un blocco procedurale initial, con all'interno delle assegnazioni, e queste verranno eseguite una sola volta all'avvio del sistema. Se esistono più initial, questi verranno eseguiti in modo concorrente, ma sempre una sola volta, entrambi all'avvio del sistema.

Il blocco procedurale Always invece viene ripetuto sempre e, per evitare che la simulazione diventi infinita, bisogna mettere delle condizioni temporali (sensitivity list), così come i process.

E' possibile anche inserire delle condizioni temporali internamente al processo, come nell'esempio seguente:

module clock_generator;
reg clk=0;

always
#10 clk = ~clk;   //ogni 10 nano secondi invertiamo il segnale clk

endmodule

Nessuno ha da obiettare???

Nell'altro articolo ho insistito molto sul fatto di ricordarvi sempre che abbiamo a che fare con un linguaggio Hardware, non Software. Ma allora come è possibile che in Hardware noi inseriamo una condizione temporale del tipo "dopo 10 nanosecondi"???

Esatto, non è possibile: questo costrutto non è sintetizzabile. Ma vi ricorderete che vi ho anche detto come queste regole non siano però valide nel momento della costruzione del testbench. Beh, ecco a voi un classico esempio di un driver che simula il comportamento di una sorgente di clock esterna all'FPGA (come ad esempio un oscillatore, oppure un generatore di forme d'onda).

Faccio notare come questo tipo di processo esiste anche in VHDL, ma come per il resto ha una struttura un po' più rigida.

Ora vi parlo del concetto di sequenzialità in Verilog.

Tutto quanto compreso all'interno delle parole begin e end, è eseguito in modo sequenziale. Per ottenere la concorrenzialità tra assegnazioni, c'è bisogno del costrutto fork-join

module fork;
event event1, event2;         //questo tipo di segnale non assume valori,
                              //ma possiamo forzargli degli eventi
reg a, b, c, d;

always #10 -> event1;    // ogni 10 ns forzo un evento sul segnale event1
always #15 -> event2;    // ogni 15 ns forzo un evento sul segnale event2

initial begin
   a=0; b=0; c=0; d=0;
end

initial begin
   fork
      @event1; @event2; a=~a;
   join
end
initial begin
   @event1; @event2; b=~b;
end
initial begin
   @event2; @event1; c=~c;
end

always begin
   @event2; @event1; d=~d;
end

endmodule
Perchè sia chiaro questo esempio, allego un immagine di simulazione:
 
Nel primo caso vediamo come il segnale "a" prenda il suo valore finale immediatamente, perchè le istruzioni comprese tra fork e join sono concorrenti. Cosa diversa accade a "b", che prende il suo valore finale dopo un evento di event1 seguito da un evento di event2. Per quanto riguarda la variabile "c", vediamo come ci sia l'attesa di un evento di event2, quindi del secondo evento di event1, e solo dopo c prende il valore '1'.

E' chiaro a questo punto il comportamento di "d".

Altra importante differenza rispetto al suo competitor sta nell'istanza di altri componenti. Nel VHDL viene utilizzata un tipo di istanza detta "indiretta", ossia è necessario dichiararne il component prima di poterla richiamare. In Verilog invece viene utilizzata l'istanza "diretta", non è necessario definire un modulo (o una primitiva) prima di usarlo.

Segue un esempio esplicativo:

module half_adder (a, b, sum, cout)
input a,b;
output sum,cout;

xor u1(sum,a,b);      // xor è una primitiva fornita dal linguaggio
and u2(cout,a,b);     // and è una primitiva fornita dal linguaggio

endmodule
module full_adder (s, cout, op1, op2, cin);
output s, cout;
input op1, op2, cin;
wire s1, cout1, cout2;
half_adder ha1(.sum(s1), .cout(cout1), .a(op1), .b(op2) );
half_adder ha2(.sum(s), .cout(cout2), .a(s1), .b(cin) );

xor g3(cout, cout1, cout2);

endmodule
In questi due moduli è rappresentata l'istanza diretta sia delle primitive che di altri moduli realizzati. Perché questa venga riconosciuta, è sufficiente che il modulo da istanziare sia stato compilato nella cartella di lavoro.
Altra caratteristica da conoscere è senz'altro la modalità di assegnazione dei segnali. Esistono 2 modalità di assegnazione, denominate: blocking e non-blocking. L'assegnazione blocking (a = b) viene usata nelle descrizioni procedurali, in cui l'assegnazione ha effetto immediato (logica combinatoria).
L'assegnazione di tipo non-blocking (a <= b)  invece si utilizza in tutti i processi di tipo RTL (Register Transfer Level). Per cui possiamo associarlo alla logica sequenziale.
A questo punto non vorrei essere ripetitivo, per cui vi rimando di nuovo al link sul VHDL per i consigli elargiti, sono davvero gli stessi.

Aggiungerei anche ...

Il Verilog è nato per modellizzazione e simulazione, ed a questo abbiamo visto essere decisamente più orientato. Allora ci aspettiamo una facilità ancora maggiore nella realizzazione di testbench!
Ed infatti è proprio così: basti pensare al SystemVerilog!
Il System Verilog è stato fuso al Verilog per affiancare al linguaggio di Cadence una nuova caratteristica, che possiamo definire Hardware Verification Language.  Grazie al System Verilog, ora abbiamo un linguaggio object-oriented, che permette di avere una maggior facilità di costruire sistemi non sintetizzabili ma al solo scopo di simulare i nostri modelli.
Non sono le uniche modifiche apportate al linguaggio ma senza dubbio le numerose feature aggiunte al concetto di verifica dei sistemi sono il grande passo avanti permesso grazie al System Verilog.
Il concetto può essere approfondito sul seguente link.

E quindi???

A questo punto sono certo che tutti si chiedano: ma insomma è meglio il VHDL o il Verilog?
Beh, potrei usare un paragone profano per rendere l'idea: è meglio Maradona o Pelè? Messi o Cristiano Ronaldo?
La questione è la stessa, ed è davvero difficile rispondere all'unanimità quale linguaggio sia meglio dell'altro, perchè entrano in gioco preferenze personali, esigenze differenti.
Per darvi una panoramica, vi parlerò in breve del risultato della mia tesi. L'obiettivo era di effettuare un confronto tra i 2 linguaggi, un po' a livello generale ma soprattutto orientato alla realizzazione di un encoder vocale di tipo PCM.
Quello che è emerso, senza dilungarmi troppo è stato questo:
1 - La scrittura del codice ha premiato la maggiore scorrevolezza del Verilog, il quale senza dubbio è più vicino all'utilizzatore;
2 - La scrittura del testbench ha di nuovo premiato il linguaggio di Cadence, per i motivi di cui si è parlato finora.
3 - I tempi di compilazione e simulazione hanno invece dato ragione al VHDL
4 - La sintesi del linguaggio, ossia la conversione in porte logiche e registri, hanno mostrato una maggiore attenzione del VHDL all'utilizzo di risorse hardware, con il risultato che la percentuale di FPGA utilizzata attraverso il VHDL è stata minore (in modo non trascurabile) rispetto a quella utilizzata descrivendo il sistema con il Verilog.
Premettendo che i risultati sono vincolati a quell'esempio, ed a quell'epoca specifica, a questo punto però una domanda sorge spontanea: come si fa a decidere a livello generale se è più importante avere minore occupazione di hardware oppure impiegare meno tempo a realizzare il sistema???
E' più importante riuscire a simulare il sistema in modo approfondito in modo da ridurre gli errori successivi oppure ridurre lo spazio occupato in modo da minimizzare i possibili problemi di timing???
C'è chi dice che oramai l'FPGA sia talmente grande che una differenza in area utilizzata non rappresenta di certo un problema (io dico: dipende da cosa ci vuoi mettere dentro, io ne ho viste di FPGA piene fino quasi all'ultima porta logica...)
C'è chi preferisce invece ottimizzare l'hardware utilizzato per tutti i vantaggi che ne seguono. Ma anche a questo si può obiettare: con il tempo risparmiato nella scrittura del codice e nei testbench posso trovare anche soluzioni per ottimizzare l'hardware!
Io dico: se conosci il VHDL, puoi benissimo usare il VHDL. Se conosci il Verilog, puoi senza problemi utilizzare il Verilog e, alla fine, i pregi e i difetti si vanno ad equiparare. Certamente nessuno dei due vi impedirà di realizzare e verificare il vostro sistema, per quanto complesso esso sia.

 

Quello che hai appena letto è un Articolo Premium reso disponibile affinché potessi valutare la qualità dei nostri contenuti!

 

Gli Articoli Tecnici Premium sono infatti riservati agli abbonati e vengono raccolti mensilmente nella nostra rivista digitale EOS-Book in PDF, ePub e mobi.
volantino eos-book1
Vorresti accedere a tutti gli altri Articoli Premium e fare il download degli EOS-Book? Allora valuta la possibilità di sottoscrivere un abbonamento a partire da € 2,95!
Scopri di più

5 Comments

  1. Marven 18 dicembre 2013
  2. Tiziano.Pigliacelli Tiziano.Pigliacelli 18 dicembre 2013
  3. Andres Reyes Andres Reyes 18 dicembre 2013
  4. vincenzo.deidda.5 18 dicembre 2013
  5. Tiziano.Pigliacelli Tiziano.Pigliacelli 29 dicembre 2013

Leave a Reply

Raspberry Pi 3 GRATIS! (Win10 compatibile)

Fai un abbonamento Platinum (EOS-Book + Firmware), ricevi in OMAGGIO la RASPBERRY 3, inviaci il tuo progetto e OTTIENI IL RIMBORSO