FPGA: Introduzione e basi di VHDL

vhdl_image

Siamo arrivati finalmente ad una fase fondamentale di questo corso: il VHDL. Il linguaggio di descrizione hardware più utilizzato in Italia ci permetterà di utilizzare le FPGA fino al più nascosto transistor. Mettetevi comodi: che la lezione abbia inizio!

Questo articolo è un appuntamento chiave per chi vuole apprendere l'utilizzo di FPGA: da questo articolo in poi, chi possiede una evaluation board con FPGA, e una licenza per utilizzare i tool di sviluppo, potrà iniziare a vedere led accendersi, e i più coraggiosi, potranno già provare a comunicare con un PC o con altre schede.

Ma cos'è il VHDL?

Il VHDL è un HDL (ci risiamo con le sigle!). HDL sta per Hardware Description Language, cioè Linguaggio di Descrizione dell'Hardware. Questo è il punto chiave di tutto: come accennato nel primo articolo del corso, è un linguaggio che ha il compito di descrivere un sistema elettronico digitale in termini di Hardware che lo compone, quindi porte logiche, flip-flop, multiplexer e così via.

Si interpone un po' tra i linguaggi software ed i vecchi metodi di descrizione di un sistema digitale. Infatti ha un livello di astrazione molto maggiore rispetto agli schematici (si può anche descrivere il sistema a livello di porte logiche, ma per sistemi complessi sarebbe davvero complesso!) ma comunque tutto quello che viene descritto resta vincolato all'Hardware, ed in quanto tale, deve essere descritto pensando all'Hardware.

Gode tuttavia di una caratteristica importante: l'indipendenza tecnologica. Vuol dire che per descrivere un sistema attraverso un linguaggio HDL non devo sapere necessariamente su che tipo di Hardware andrò poi a implementare il sistema.

Riportandovi un po' al precedente articolonon ci interessa se il sistema verrà implementato su una Stratix 10 o su una Virtex 7, o su una XP2 della Lattice Semiconductor, o anche su una CPLD.

In particolare il VHDL (Dove V sta per VHSIC, cioè Very High Speed Integrated Circuit) è il linguaggio HDL più datato e che ancora mantiene caratteristiche uniche nel suo genere.

Ma per conoscere il VHDL, come sempre, bisogna iniziare dal suo passato.

Come nasce il VHDL?

Il VHDL è il risultato del progetto di ricerca denominato VHSIC sui circuiti integrati iniziato negli anni '80 dal dipartimento di Difesa degli USA. I costi dovuti ai rifacimenti iniziavano ad essere pesanti, anche perché le tecnologie erano accompagnate da scarsa documentazione o descritte in linguaggi diversi, e non sempre compatibili.

Si pensò quindi ad linguaggio che fosse ad ampio range di descrizione, indipendente dalla tecnologia, e soprattutto inequivocabile.

Allora esistevano linguaggi gate-level, quali Abel e PalAsm, che si dimostrarono però inadeguati alla descrizioni di sistemi con complessità sempre maggiore.

Nacque inizialmente per la sola documentazione, per descrivere sistemi in modo che il passaggio di informazioni per il Dipartimento di Difesa fosse, appunto, inequivocabile.

Presto venne utilizzato anche per le simulazioni, quindi per la sintesi e l'implementazione grazie alla sua robustezza.

La prima versione standard del VHDL fu definita nel 1987 da IEEE (Institute of Electrical and Electronics Engineers), divenendo lo standard IEEE 1076. Con lo standard IEEE 1164, è stato introdotto, in aggiunta ai già esistenti boolean, binary, integer, un tipo di dato che ha portato una svolta al linguaggio e alla sua capacità di descrivere sistemi: la logica a '9' valori, ossia il tipo standard logic (abbreviato nella scrittura con std_logic). Questo tipo ha la caratteristica di descrivere caratteristiche di segnali prettamente Hardware: Uninizializated ('U'),   Strong Drive Unknow Value ('X'),  Strong Drive High Value ('1'),  Strong Drive LowValue ('0'), High Impedance ('Z'), Weak Drive Unknow Value ('W'), Weak Drive High Value ('H'), Weak Drive Low Value ('L'), Don't Care ('-').

Successivi aggiornamenti, nella piena compatibilità con lo standard precedente,  hanno apportato migliorie, maggiore elasticità e costrutti in più che danno al progettista degli strumenti utili per accellerare e migliorare la scrittura del codice, anche per i testbench.

Non entrerò in questo livello di dettaglio in questo articolo, cercherò solo di darvi delle basi da cui partire affinché possiate essere autonomi.

Passiamo ora alla parte pratica...

Siamo alla parte più interessante.

In un articolo pubblicato tempo fa, e che vi consiglio di sfogliare, viene detto che fare un corso completo su VHDL qui è un po' inutile, esistono vari tutorial ben fatti in giro per il Web! Io credo che sia vero, oltretutto è molto difficile fare un corso di VHDL in un articolo... Ma vi allego un capitolo della mia tesi universitaria che parla proprio del VHDL, in modo da avere a portata di mano tutte le indicazioni che vi vorrei dare e che non posso inserire per non dilungarmi troppo.
Tra l'altro vi consiglio anche questo link, che vi permette di accedere allo standard del 1993 che contiene tutto ciò di cui avrete bisogno anche per il futuro.
A questo punto però non posso darvi il manualetto e dirvi "vedetevela voi...", per cui ho selezionato alcuni argomenti chiave per aiutarvi con il primo approccio al linguaggio.
E' inutile aggiungere che, se avrete delle domande, non fatevi problemi, se saprò rispondere vi assisterò in ogni difficoltà.

Inizierò con il dirvi che il VHDL si basa su una struttura input-operazioni-output, tipica di ogni circuito, ed ogni sistema descritto sarà un insieme di tante strutture/sottosistemi di questa tipologia.

Per definire un sottosistema si dovranno quindi descrivere:

  1. la sua interfaccia esterna;
  2. il suo funzionamento interno.

In VHDL il modello di un sistema/sottosistema è detto design entity ed è costituito da due parti: una entity (che descrive l'interfaccia) ed una architecture (che descrive il funzionamento interno).

Entity <name_entity> is

port(   ...;
        ...;
        ...);

end <entity> <name_entity>;

Architecture <name_arch> of <name_entity> is
...
begin
...

end <architecture> <name_architecture>;
Le porte vanno dichiarate descrivendo il tipo di segnale che la caratterizza, oltre che la tipologia di porta (in, out, inout, ... ).
Ecco un esempio pratico:
library IEEE;

use IEEE.std_logic_1164.all;


entity MUX is

port (
              a, b, c, d        : in  STD_LOGIC;
              ctrl              : in  STD_LOGIC_VECTOR(1 DOWNTO 0);
              a_rst             : in  STD_LOGIC;
              clk               : in  STD_LOGIC;
              q                 : out   STD_LOGIC);
end MUX ;

architecture BEHAVIOURAL of  MUX is
signal q_1 : STD_LOGIC;
begin
   MUX_proc:   PROCESS( a, b, c, d, ctrl )

      CASE ctrl IS

          WHEN   "00"  =>
                q_1 <= a;
         WHEN   "01"   =>
                 q_1 <= b;
         WHEN   "10"   =>
                q_1 <= c;
         WHEN   "11"   =>

                q_1 <= d; 

         end CASE;
    end PROCESS;

    TEMPORIZER_proc: PROCESS(a_rst, clk)
    begin
       if a_rst = '1' then
          q <= '0';
       elsif rising_edge (clk) then
          q <= q_1;
       end if;
    end PROCESS TEMPORIZER_proc;

end BEHAVIOURAL;
Questo listato descrive un Multiplexer. Premetto che il VHDL è un linguaggio CASE-INSENSITIVE, le maiuscole che vedete nel codice le ho inserite un po' per mettere in risalto alcune parole chiave (in realtà ci sono alcuni casi in cui le maiuscole sono fondamentali, come per i valori che un segnale di tipo std_logic può assumere, ossia 'Z', 'H', 'X', ... come spiegato sopra).
La descrizione delle porte è chiara:   nome_porta    :    tipo_porta     tipo_segnale;
Il tipo di segnale definito come STD_LOGIC rappresenta la logica a '9' valori di cui sopra, mentre con STD_LOGIC_VECTOR si identifica un bus di segnali di tipo STD_LOGIC.
Ci sono 3 tipologie di architetture: RTL, BEHAVIOURAL o miste.
Premesso che il nome dell'ARCHITECTURE è libero, e anzichè BEHAVIOURAL potevamo scrivere qualunque cosa, ma il concetto che volevo esprimere è:
  • con BEHAVIOURAL si intende la descrizione attraverso il comportamento del modulo;
  • con RTL si intende una struttura modulare composta dall'istanza di altri sottomoduli;
  • miste vuol dire che possiamo usarle anche entrambe in un unico file (anche se in alcuni ambiti è richiesto nello specifico di separare RTL e BEHAVIOURAL).

Si vede bene come il codice riportato sopra sia di tipo BEHAVIOURAL.

Osserviamo ora la struttura PROCESS: rappresenta l'essenza di ogni BEHAVIOURAL in VHDL.

Si presenta sotto la forma:

(etichetta : ) Process ( sensitivity list )

   begin

    ...

   end process (etichetta); 
La cosa fondamentale è capire bene il significato della sensitivity list. Un processo va dichiarato specificando la lista di tutti i segnali che, modificando il proprio stato, modificano immediatamente i segnali di uscita. Ad esempio: se ho una porta and a 4 ingressi, ognuno dei 4 ingressi può avere il potere di modificare l'uscita in alcune situazioni; per cui tutti gli ingressi andranno nella sensitivity list (è quello che si vede nel nostro Multiplexer). Un registro invece, o un flip flop, ha l'uscita che viene aggiornata solo con il clock oppure viene portata a '0' con il reset asincrono. E' il caso del secondo processo del nostro esempio, in cui si vede l'uscita del multiplexer che viene portata in uscita (q) solo al fronte di salita di clock e riazzerata con il reset asincrono, per cui solo questi due segnali sono nella sensitivity list.
Avrei potuto utilizzare anche l'istanza di un flip flop, per ottenere lo stesso risultato:
library IEEE;

use IEEE.std_logic_1164.all;


entity MUX is

port (
              a, b, c, d        : in  STD_LOGIC;
              ctrl              : in  STD_LOGIC_VECTOR(1 DOWNTO 0);
              a_rst             : in  STD_LOGIC;
              clk               : in  STD_LOGIC;
              q                 : out   STD_LOGIC);
end MUX ;

architecture MIXED of  MUX is

COMPONENT ff_d is
port (d      : in STD_LOGIC;
      a_rst  : in STD_LOGIC;
      clk    : in STD_LOGIC;
      q      : out STD_LOGIC);
end component;

signal q_1 : STD_LOGIC;
begin
   MUX_proc:   PROCESS( a, b, c, d, ctrl )

      CASE ctrl IS

          WHEN   "00"  =>
                q_1 <= a;
         WHEN   "01"   =>
                 q_1 <= b;
         WHEN   "10"   =>
                q_1 <= c;
         WHEN   "11"   =>

                q_1 <= d; 

         end CASE;
    end PROCESS;

FLIP_FLOP_u0: ff_d
port map (
          d => q_1,
          a_rst => a_rst,
          clk => clk,
          q => q );

end BEHAVIOURAL;
Questo è un esempio di struttura mista, in cui un flip flop è stato inserito attraverso un'istanza di un altro file/sottomodulo. Questo sottomodulo, per essere utilizzato, deve essere inserito tra i file di progetto.

Consiglio prezioso...

A questo punto mi riservo di consegarvi un prezioso consiglio: in VHDL una strategia senza dubbio vincente è l'utilizzo di un approccio TOP-DOWN: è davvero molto importante iniziare con il capire innanzitutto cosa dobbiamo fare, suddividere le varie funzionalità, pensare ogni funzione come un sottomodulo, e scendere man mano nel dettaglio, se necessario anche attraverso sottomoduli di sottomoduli, sempre preferendo file piuttosto semplici anche se numerosi, piuttosto che pochi moduli ma molto complessi.

... torniamo a noi ...

Esiste anche un livello di astrazione più basso, Gate-Level, che solo in alcune circostanze viene utilizzato. Ad esempio, se anzichè un multiplexer avessimo bisogno di una OR tra i 4 segnali,  potremmo sostituire il processo MUX_process con:

q_1 <= a OR b OR c OR d;

oppure, mantenendo la scelta di un Multiplexer:

q_1 <= a when ctrl = "00" else b when ctrl = "01" else c when ctrl="10" else d;

Difficilmente si sceglie di scendere a questo livello di astrazione, se non per alcune sezioni del codice. Non è sicuramente una strategia vincente lavorare a Gate, dato che, per sistemi complessi sarebbe davvero troppo oneroso, mentre per sistemi semplici non vale la pensa utilizzare un FPGA!!!!

...molto importante è senza dubbio...

la capacità di realizzare dei buoni testbench.

Cos'è un testbench? Beh, una volta che avete scritto il vostro codice, il quale in relazione a degli stimoli dovrà rispondere come volete voi, prima di mettere il tutto su FPGA è necessario fare una simulazione comportamentale, per verificare che a determinati input corrispondano  gli output desiderati. Per cui dovrete essere in grado di realizzare un modulo di livello superiore, in cui istanziare il vostro sistema, e che a questo invierà tutte le combinazioni di stimoli necessarie a verificarne la correttezza. Considerate che generalmente la quantità di operazioni che è capace di fare un sistema realizzato in un FPGA è davvero enorme, e non basta fare accendere dei LED per verificarne la correttezza. Capita anche molto spesso che, se si lavora su nuovi sistemi da realizzare, difficilmente si ha a disposizione la scheda prima di aver realizzato buona parte del sistema VHDL, per cui una simulazione ben fatta sicuramente è importante per accelerare i tempi e per realizzare un sistema il più possibile robusto.

C'è una scuola di pensiero, che abbraccio completamente, che ritiene fondamentale per un'azienda che chi realizza il sistema e chi realizza il testbench debbano essere due persone diverse e scorrelate (nel senso che meno si scambiano informazioni e meglio è). Immaginate il caso in cui il progettista ha compreso male una specifica, realizza il sistema in base a questa, poi magari inizia a fare un testbench in base a quello che ha capito, e magari limitato a quello che secondo lui è importante testare.... i possibili errori si moltiplicano a dismisura!!!

Una classica struttura di testbench è composta, come in figura, da un Driver, che invia gli stimoli al nostro DUT (Device Under Test), e da un Monitor che riceve le uscite di questo per valutarne l'esattezza.

Il file di testbench istanzierà i 3 componenti che si vedono in figura opportunamente connessi. Esistono dei tool che permettono di fare queste connessioni in schematico, forse è un po' più semplice, ma per fare pratica con il VHDL, consiglio di non utilizzare lo schematico finché non siamo padroni del linguaggio a tal punto che, quando si utilizza lo schematico, abbiamo ben chiaro nella nostra mente il codice VHDL che lo rappresenta.

L'importanza del driver è quella di simulare tutti gli stimoli richiesti in specifica. Se il nostro sistema ha il compito, ad esempio, di ricevere dei dati da un ADC, ad esempio provenienti da un microfono, ed eliminare le componenti di rumore, il compito di un driver è produrre una sequenza di dati con lo stesso formato fornito dagli ADC, e di ampiezza tale da emulare il comportamento del rumore (ad esempio ampiezze minori di uno specificato valore di soglia ripetuto per un valore sufficiente di campioni).

E il monitor? Ha il compito di verificare che il DUT si comporti correttamente secondo le specifiche. Generalmente un monitor non è necessario durante le prime simulazioni del sistema, dato che i simulatori consentono di vedere, attraverso forme d'onda, tutte le variazioni di ogni segnale esterno ed interno al nostro sistema. Ma per effettuare una verifica di "matching" tra le specifiche e i risultati, bisogna realizzare un monitor che, ad ogni specifica, risponda "passed" oppure "failed" in base alle uscite del sistema realizzato.

Particolari accorgimenti

Ci sono degli aspetti che vanno presi in considerazione ogni volta che si è alle prese con un sistema da realizzare in VHDL.

L'indicazione che sento di dovervi assolutamente dare è: "ricordatevi  sempre che quel codice che scrivete deve realizzare un sistema Hardware".

Una delle difficoltà iniziali, soprattutto per chi è abituato a scrivere software, è ricordare che non abbiamo a che fare con un linguaggio software. E' importante svincolarsi dalle proprie abitudini "softwariane" per calarsi in un ambiente del tutto "hardwariano".

Per cui scordiamoci di poter leggere un file situato in qualche posto del nostro PC, perchè sulla scheda il nostro Harddisk non è presente...

In compenso, altrettanto importante è quest'altra indicazione: al momento della realizzazione del testbench potete tralasciare la precedente indicazione!!!!!

Quando andrete a realizzare un testbench, vi accorgerete che produrre un'infinità di stimoli da inviare al sistema è davvero (ma davvero!!) ostico, e vi faranno molto comodo alcune soluzioni alternative, tra cui proprio la lettura di un file da PC (e anche scrittura).

Esiste in VHDL una libreria, chiamata TEXTIO, che permette di utilizzare comandi capaci di leggere e scrivere dei file di testo. E' facile pensare come a questo punto si possa semplificare un testbench automatizzando o configurando le possibilità di stimoli semplicemente creando dei file di testo opportuni.

Per indicazioni su come utilizzare questa libreria vi rimando al solito allegato, capitolo 3 della mia tesi di laurea.

Spero di avervi destato curiosità ed interesse. Purtroppo non si impara il VHDL con un articolo, ma il link al manuale e l'allegato che vi ho fornito sono senza dubbio utilissimi e certamente sufficienti a darvi l'input giusto per farvi diventare, con i giusti stimoli, degli FPGA Designer autosufficienti.

Dicevo all'inizio dell'articolo che a questo punto dovreste essere in grado di accedere e spegnere LED su un'evaluation board. Potrebbero mancare alcuni dettagli, in particolare il file per la pinout, ma con le evaluation board forniscono sempre progetti prova, che si possono sfruttare come appoggio, e con la pinout completa già realizzata, e basta usare gli stessi nomi dei pin per avere realizzata la connessione verso l'esterno.

Per cui posso dirvi senza dubbio: "D'ora in poi siete FPGA Designer".

 

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. Andres Reyes Andres Reyes 7 novembre 2013
  2. Tiziano.Pigliacelli Tiziano.Pigliacelli 7 novembre 2013
  3. Tiziano.Pigliacelli Tiziano.Pigliacelli 11 novembre 2013
  4. Giorgio B. Giorgio B. 18 novembre 2013
  5. Tiziano.Pigliacelli Tiziano.Pigliacelli 18 novembre 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