Specifiche strutturali e schemi logici in VHDL


Introduzione

Per fissare le idee consideriamo un esempio semplice semplice. Prendiamo ad esempio la rete logica in figura:

Questa rete realizza un demultiplexer che e' un componente logico che funziona cosi: quando l' ingresso di controllo c0 e' a 0 i bit di ingresso i0 i1 vengono riportati sulle uscite u00 e u01. Quando l' ingresso di controllo e' invece a 1 gli ingressi risultano collegati invece a u10 e u11. Questa data a parole e' la specifica comportamentale del componente da realizzare mentre lo schema nel disegno rappresenta la descrizione strutturale del componente. Impareremo ora a tradurre questa descrizione strutturale in un ''programma'' VHDL. Nella seconda parte vedremo invece come tradurre in VHDL la descrizione comportamentale del componente.


Terminologia: Modelli, Entita', Librerie

In VHDL piu' che di programmi si deve parlare di modelli. Un modello VHDL e' sostanzialmente un documento dove si dice come funziona un certo sistema. Nella terminologia VHDL per indicare un sistema si usa il termine entita'. Lo schema della figura rappresenta dunque un modello della entita' demultiplexer. Un modello (o una descrizione) strutturale in VHDL risulta poi costituito da una serie di altre entita' interconnesse tra di loro. Nell' esempio le entita' sono cinque e sono: le quattro porte AND A,B,C,D e la porta NOT E. La descrizione di queste cinque entita' sara poi contenuta in un file separato o libreria. In VHDL si chiamano librerie le collezioni di una o piu' entita'. Piu' precisamente una libreria VHDL puo' contenere insieme ad una o piu' entita' anche dei package. Con il termine package in VHDL si indicano delle collezioni di procedure e funzioni. Tuttavia, per ora, tralasceremo i package, li vedremo in seguito e quindi, ricapitolando, possiamo dire che:

Tanto per fissare le idee il file sgates.vhd fornisce un esempio di libreria contenente 4 entita': and2, or2, xor2, not1.


Interfaccia di una entita' e Segnali

Scrivere un codice VHDL per descrivere una entita' vuol semplicemente dire descrivere il suo comportamento dando un modello del funzionamento dell' entita. Come e' ovvio aspettarsi le entita' VHDL comunicano tra di loro mediante dei canali di comunicazione che trasportano ogni tipo di informazione. Tali canali prendono, nella terminologia VHDL, il nome di segnali.

Ogni entita' avra' dei segnali in ingresso e dei segnali in uscita. La prima parte della descrizione di una entita' sara' dunque la descrizione della sua interfaccia. In VHDL l' interfaccia di una entita' si descrive dicendo quale e' il nome dei segnali in ingresso e quale il nome dei segnali in uscita. Per il demultiplexer della figura tale dichiarazione avra' la forma:

entity dmpx is
 port(i0,i1,c0:in bit;u00,u01,u10,u11:out bit); 
end dmpx;

Che dichiara che l' entita' dmpx ha come ingressi i bit i0,i1,c0 e come uscite u00, u01,u10,u11 (si noti che la parola chiave ''in'' puo' anche essere omessa).


Architetture Data-Flow

Dopo aver definito l' interfaccia di una entita' bisogna anche dire come funziona effettivamente l' entita' o, seguendo la terminologia VHDL, bisogna definire l' architettura dell' entita'. Questo si puo' fare seguendo due approcci uno strutturale e l' altra comportamentale. Seguendo l' approccio strutturale descriveremo l' entita' dando semplicemente lo schema dei collegamenti che ci permette di realizzare l' entita' connettendo entita' piu' semplici gia' definite. Ovviamente altre alternative sono possibili. Per questa ragione VHDL prevede che una entita' possa avere piu' architetture.

A livello di massima semplificazione, per delle reti esclusivamente combinatorie possiamo definire l' entita' dando l'espressione delle funzioni di che definiscono le relazioni tra ingresso e uscita. Il modello VHDL prodotto con questo tipo di approccio prende il nome di modello data flow. Per il demultiplexer in figura le relazioni che ne definiscono il comportamento sono:

nc0<=not c0; u00<= nc0 and i0; u01<= nc0 and i1; u10<= c0 and i0; u11<= c0 and i1;

L' architettura data flow di questo demultiplexer e' data quindi dal frammento VHDL:

architecture dmpx_df of dmpx is 
 signal nc0:bit; begin
 nc0<=not c0;u00<=nc0 and i0;u01<= nc0 and i1;u10<=c0 and i0;u11<=c0 and i1; end 
dmpx_df;

La nostra architettura e' pronta per essere simulata, sarebbe tuttavia vedere ancora per un attimo il significato delle cose scritte in questa architettura. Notiamo subito che la sintassi della dichiarazione di architettura e' la seguente:

architecture_body ::=
        architecture identifier of entity_name is
          architecture_declarative_part begin
          architecture_statement_part end [
          architecture_simple_name ] <;>

dove architecture_declarative_part e' una lista di dichiarazioni di segnali e architecture_statement_part e' una lista di assegnazioni di segnali. Vediamo dunque di seguito una trattazione dettagliata dei segnali


Segnali: tipo ed assegnazione

Vediamo alcune generalita' sui programmi sull' effetto della loro esecuzione e su come nei programmi le strutture di memoria necessarie per contenere i dati vengano rappresentate dalle cosiddette variabili.

Dichiarazione di un segnale

Il progettista che descrive un circuito in un linguaggio ad alto livello come il VHDL non pensa alla scheda come ad una serie di piste ma, per sua comodita', puo' permettersi di pensare ai collegamenti elettrici come ad una collezione di segnali, ciascuno con il suo tipo. La presenza di un segnale viene segnalata nella dichiarazione dell' interfaccia, se il segnale attraversa i confiini dell' entita' che stiamo considerando, oppure inserendo una dichiarazione di segnale nella architettura con una riga del tipo

 signal nc0:bit; 

dove nc0 e' il nome del segnale e bit e' il suo tipo. Da li' in poi potremo usare nc0 per propagare un bit, attraverso delle assegnazioni che sovrascriveranno il valore precedentemente presente sul segnale. Ovviamente portemo anche leggere il valore della segnale ed usarlo nell' architettura in vari modi:

Tipo di un segnale

Il tipo di un segnale indica sostanzialmente i valori che possono essere propagati attraverso quel segnale e le operazioni che si possono compiere con (il valore presente su) quella linea. In VHDL sono presenti (tra l' altro e non solo) i seguenti tipi. bit integer real. Vedremo tra un attimo come definire segnali costituiti da piu' linee.

Istruzione di assegnazione

E' l' istruzione con cui possiamo operare sul segnlae scrivendovi dei valori. I valori scritti nei segnali devono essere quelli previsiti dal tipo del segnale. Vediamo come si scrive una assegnazione e cosa significa eseguire una assegnazione. In VHDL l' assegnazione ad un segnale si indica con <= Sono assegnazioni ad esempio;

 nc0<='0'; nc0 <= not c0 ;

Quando viene eseguita l' assegnazione s<=e prima viene valutata l' espressione e ed il risultato della valutazione viene sovrascritto nel segnale s. Ad es. nc0<=not c0; mette in nc0 l' opposto del valore presente su c0. Affinche' questa operazione abbia senso bisogna che in c0 ci sia gia' un valore. Per questa ragione VHDL prevede che i segnali possano essere inizializzati, prima di essere usati. Questo puo' essere fatto all' atto della dichiarazione del segnale. Consideriamo ad esempio il framento VHDL:

 signal a,b,c:bit:='0';

Questa dichiarazione oltre a creare tre segnali a,b,c specifica per essi il valore iniziale '0'. Siamo quindi pronti ad esaminare la sintassi (quasi) completa di una dichiarazione di segnale che e' la seguente:

 signal_declaration::= signal identifier_list: subtype_indication [:= expression];

Se la dichiarazione compare nell' interfaccia di una entita' come abbiamo visto bisogna omettere la parola chiave signal.


Esercizio:

Scrivere una entita' VHDL che modelli un semisommatore (Half-adder). Il componente ha due ingressi a,b e due uscite s,r con s=a+b mod 2 (s da il primo bit della somma) e r=(a+b)/2 (r da' il riporto). [soluzione e .ENV]


Esercizio:

Scrivere una entita' VHDL che modelli un sommatore (Full-adder). Il componente ha due ingressi a,b,carry e due uscite s,r con s=a+b+carry mod 2 (s da il primo bit della somma) e r=(a+b+carry)/2 (r da' il riporto). [soluzione e .ENV]


Istruzioni di assegnazione con ritardi di propagazione

Ci troveremo spesso e volentieri a dover esprimere qualcosa del tipo: il segnale c e' ottenuto facendo l' and logico tra a e b e le variazioni si propagano a c con un ritardo di 10ns. In VHDL questa assegnazione a c si scrive:

 c <= a and b after 10ns;

A essere rigorosi la corretta scrittura in VHDL sarebbe :

 c <= transport a and b after 10ns;

mentre la scrittura senza transport implica anche che: sul segnale c non vi possono essere oscillazioni di durata inferiore a 10ns anche se queste sono presenti su a o b. La seconda forma e' tuttavia raramente usata nella letteratura VHDL, vediamo perche'. Consideriamo il problema di modellare un demultiplexer che debba essere inserito su una scheda che lavora a 200Mhz e richiediamo quindi un componente che lavori correttamente fino a 500Mhz. Questo avra' la capacita' di lavorare con segnali in ingresso che sono delle onde quadre con frequenza massima di 500Mhz e quindi con una transizione ogni 1ns. Se le transizioni si succedono piu' velocemente l' uscita del dispositivo non e' piu' corretta. Questo comportamento si ottiene scrivendo l' architettura nel modo seguente (ricordiamo che un' entita' puo' avere piu' architetture):

architecture dmpx_df_500Mhz of dmpx is 
 signal nc0:bit; begin
 nc0<=not c0 after 1ns;
 u00<=nc0 and i0 after 1ns;
 u01<= nc0 and i1 after 1ns;
 u10<=c0 and i0 after 1ns;
 u11<=c0 and i1 after 1ns;
end dmpx_df_500Mhz;

se avessimo invece usato le assegnazioni con transport avremmo ottenuto un dispositivo (irreale) che funzionava anche oltre i 500Mhz producendo pero' le sue uscite presumibilmente troppo in ritardo rispetto alla componentistica presente sulla scheda. I dispositivi reali, se usati oltre il loro massimo rating in frequenza, non funzionano proprio piu' nel senso che producono in uscita una tensione che non e' piu' sicuramente interpretabile dai dispositivi a valle, ne come un '1' logico ne come uno '0' logico e quindi il modello corretto del loro funzionamento e' fornito da una assegnazione senza transport che non fa passare impulsi di durata inferiore ad 1ns.

Osserviamo infine che le espressioni da scrivere dopo ''after'' indicanti tempi sono espressioni di un tipo fisico predefinito in VHDL chiamato TIME. I prefissi delle unita' di tempo riconosciute dal VHDL sono le seguenti:

type TIME is range implentation_defined -- dipende dal tipo di compilatore
           units
                fs;                             -- femtosecond
                ps      =  1000 fs;             -- picosecond
                ns      =  1000 ps;             -- nanosecond
                us      =  1000 ns;             -- microsecond
                ms      =  1000 us;             -- millisecond
                sec     =  1000 ms;             -- second
                min     =  60 sec;                      -- minute
                hr      =  60 min;                      -- hour
          end units;

Visto questo tipo di definizione sara' perfettamente lecito scrivere in VHDL espressioni del tipo 1hr o 60min o 3600sec che indicano tutte la stessa cosa.


Appunti a cura di morando@disi.uinge.it