| Both sides previous revisionPrevious revisionNext revision | Previous revision |
| es_vhdl_simu_01 [2018/01/22 23:09] – admin | es_vhdl_simu_01 [2021/03/05 08:57] (current) – admin |
|---|
| Inserire la porta "a" nella sensitivity list del process significa che il process trrà costantemente sotto controllo "a". Se il process si accorge che a un certo istante $t_T$ il segnale cambia valore (in VHDL si dice che il segnale/porta subisce una "transition" o transizione), allora devono essere svolte le azioni che sono | Inserire la porta "a" nella sensitivity list del process significa che il process trrà costantemente sotto controllo "a". Se il process si accorge che a un certo istante $t_T$ il segnale cambia valore (in VHDL si dice che il segnale/porta subisce una "transition" o transizione), allora devono essere svolte le azioni che sono |
| descritte nel corpo del process, con il valore di "a" e di qualunque altro segnale o porta del sistema che mantengono il valore assunto a $t_T^+$. Capire bene il senso dell'ultima proposizione è di fondamentale importanza per la comprensione del modo in cui in VHDL si descrivono i circuiti. In sistanza, tutte le volte che un qualunque process del sistema si accorge che uno degli elementi della sua sensitivity list ha subito una transizione, è come se si interrompesse immediatamente lo scorrere del tempo. Con il tempo "fermo" (sistema immobile) l'algoritmo che costituisce il corpo del process è come se si svolgesse in una dimensione parallela. L'unico fine di un process è predisporre, sulla base della situzione attuale (quella del sistema con il tempo "congelato", avvenimenti che avranno luogo quando il tempo riprenderà a scorrere. Una volta che questi avvenimenti sono stati "predisposti", il tempo del sistema ricomincia a scorrere, e sono proprio gli avvenimenti predisposti dai porcess del sistema che, intervenendo a modificare il valore dei segnali, possono portare a una nuova attivazione di un process, al congelamento del tempo nel sistema e alla predisposizione di nuovi avvenimenti. Gli avvenimenti di cui parliamo si chiamono "eventi" in VHDL. | descritte nel corpo del process, con il valore di "a" e di qualunque altro segnale o porta del sistema che mantengono il valore assunto a $t_T^+$. Capire bene il senso dell'ultima proposizione è di fondamentale importanza per la comprensione del modo in cui in VHDL si descrivono i circuiti. In sistanza, tutte le volte che un qualunque process del sistema si accorge che uno degli elementi della sua sensitivity list ha subito una transizione, è come se si interrompesse immediatamente lo scorrere del tempo. Con il tempo "fermo" (sistema immobile) l'algoritmo che costituisce il corpo del process è come se si svolgesse in una dimensione parallela. L'unico fine di un process è predisporre, sulla base della situzione attuale (quella del sistema con il tempo "congelato", avvenimenti che avranno luogo quando il tempo riprenderà a scorrere. Una volta che questi avvenimenti sono stati "predisposti", il tempo del sistema ricomincia a scorrere, e sono proprio gli avvenimenti predisposti dai porcess del sistema che, intervenendo a modificare il valore dei segnali, possono portare a una nuova attivazione di un process, al congelamento del tempo nel sistema e alla predisposizione di nuovi avvenimenti. Gli avvenimenti di cui parliamo si chiamono "eventi" in VHDL. |
| Quando di simula il comportamento di un sistema VHDL è come se esistesse una divinità capace di fermare e far ripartire il corso del tempo. Questa divinità è "onnisciente" nel senso che è a conoscenza di tutti gli "eventi" predisposti da tutti i processi. Egli raccoglie tutti gli eventi in una lista ordinata (se un evento $E_1$ deve avvenire al tempo $t_1$ e un evento $E_2$ deve avvenire al tempo $t_2" e $t_2>t_1$ allore $E_1$ precede $E_2$ nella lista degli eventi). Ogni volta che un processo predispone un nuovo evento, la lista viene aggiornata, così Egli sa sempre, a priori, qual'è il prossimo evento che dovrà verificarsi e si prepara a fermare il tempo e ad attivare tutti i processi che sono sensibili al segnale o alla porta che subisce l'evento. | Quando di simula il comportamento di un sistema VHDL è come se esistesse una divinità capace di fermare e far ripartire il corso del tempo. Questa divinità è "onnisciente" nel senso che è a conoscenza di tutti gli "eventi" predisposti da tutti i processi. Egli raccoglie tutti gli eventi in una lista ordinata (se un evento $E_1$ deve avvenire al tempo $t_1$ e un evento $E_2$ deve avvenire al tempo $t_2$ e $t_2>t_1$, allora $E_1$ precede $E_2$ nella lista degli eventi). Ogni volta che un processo predispone un nuovo evento, la lista viene aggiornata, così Egli sa sempre, a priori, qual'è il prossimo evento che dovrà verificarsi e si prepara a fermare il tempo e ad attivare tutti i processi che sono sensibili al segnale o alla porta che subisce l'evento. |
| | |
| Nel caso nel nostro esempio, se "a" cambia da '1' a '0', il corpo del process predisporrà l'evento descritto dalla riga : | Nel caso nel nostro esempio, se "a" cambia da '1' a '0', il corpo del process predisporrà l'evento descritto dalla riga : |
| begin | begin |
| y<='1' after 100 ns, '0' after 200 ns, '1' after 300 ns; | y<='1' after 100 ns, '0' after 200 ns, '1' after 300 ns; |
| | wait; --this means no other event will be generated by this process. |
| end process; | end process; |
| |
| ghdl -a inverter.vhdl | ghdl -a inverter.vhdl |
| </code> | </code> |
| | Se il comando ha successo non viene restituito alcun errore. Inoltre, tutte le entità definite nel file analizzato entrano automaticamente a far parte della libreria predefinita "work" che è automaticamente accessibile da tutti i file vhdl presenti nella directory. Nota bene: se un file vhdl fa uso di altre entità (è il caso dell'entità testbench), le entità da utilizzare devono far già parte della libreria work. |
| | Pertanto, dopo aver analizzato il file inverter.vhdl, procediamo con il file sig_gen.vhdl e solo dopo con il file testbench.vhdl: |
| | <code> |
| | ghdl -a sig_gen.vhdl |
| | ghdl -a testbench.vhdl |
| | </code> |
| | A questo punto siamo pronti a "corstruire" la struttura di simulazione. QUesto si ottiene con il comando |
| | * ghdl -a <topentity> |
| | dove <topentity> è l'entità il cui comportamento vogliamo studiare e che comprende, eventualmente altre entità. |
| | Eseguiremo dunque: |
| | <code> |
| | ghdl -e testbench |
| | </code> |
| | A questo punto possimao far partire la simulazione vera e propria, specificando anche un file nel quale conservare i risultati della simulazione e specificando anche il tempo (tempo simulato) per il quale vovliamo protrarre l'analisi. Supponiamo di voler analizzare il nostro sistema per una durata massima di 500 ns e che vogliamo conservare il risultato in un file in formato vcd (leggibile dal programma di analisi grafica gtkwave) di nome out.vcd |
| | Scriveremo allora: |
| | <code> |
| | ghdl -r testbench --vcd=out.vcd --stop-time=500ns |
| | </code> |
| | Si noti che il simulatore si interrompe automaticamente se la lista degli eventi viene easurita prima del tempo massimo specificato. |
| | |
| | Una volta completata la simulazione possiamo utilizzare gtkwave per visulizzare i risultati: |
| | <code> |
| | gtkwave out.vcd |
| | </code> |
| | Dopo aver selezionato i segnali da visulizzare ("filo" e "uscita", nel nostro caso) e aver opportunamente regolato la scala dei tempi per la visualizzazione otteniamo quanto mostrato in figura. |
| | L'interpretazione di quanto accade dovrebbe essere completamente comprensibile sulla base di quanto esposto fino ad ora. Se non lo fosse (valori inziziali, prime transizioni ecc. ecc.), si invita a rileggere questa pagina dall'inizio. |
| | {{:snapshot1.png?600|}} |
| | |
| | Come ultimo esempio in questa introduzione, costruiamo ora un sistema composto da una catena di inverter. In questo esmpio useremo l'entità "inverter" con l'architettura "veloce". |
| | |
| | Il file vhdl seguente (catena.vhdl) descrive una catena di 10 inverter sollecitati dal generatore sig_gen prima definito. |
| | |
| | |
| | <code VHDL> |
| | |
| | entity testcatena is |
| | end entity testcatena; |
| | |
| | architecture struct of testcatena is |
| | signal gen_to_in_1:bit; |
| | signal out_1_to_in_2:bit; |
| | signal out_2_to_in_3:bit; |
| | signal out_3_to_in_4:bit; |
| | signal out_4_to_in_5:bit; |
| | signal out_5_to_in_6:bit; |
| | signal out_6_to_in_7:bit; |
| | signal out_7_to_in_8:bit; |
| | signal out_8_to_in_9:bit; |
| | signal out_9_to_in_10:bit; |
| | signal out_10:bit; |
| | begin |
| | |
| | gen :entity work.sig_gen(behav) |
| | port map (y=>gen_to_in_1); |
| | inv_01:entity work.inverter(veloce) |
| | port map (a=>gen_to_in_1, y=>out_1_to_in_2); |
| | inv_02:entity work.inverter(veloce) |
| | port map (a=>out_1_to_in_2, y=>out_2_to_in_3); |
| | inv_03:entity work.inverter(veloce) |
| | port map (a=>out_2_to_in_3, y=>out_3_to_in_4); |
| | inv_04:entity work.inverter(veloce) |
| | port map (a=>out_3_to_in_4, y=>out_4_to_in_5); |
| | inv_05:entity work.inverter(veloce) |
| | port map (a=>out_4_to_in_5, y=>out_5_to_in_6); |
| | inv_06:entity work.inverter(veloce) |
| | port map (a=>out_5_to_in_6, y=>out_6_to_in_7); |
| | inv_07:entity work.inverter(veloce) |
| | port map (a=>out_6_to_in_7, y=>out_7_to_in_8); |
| | inv_08:entity work.inverter(veloce) |
| | port map (a=>out_7_to_in_8, y=>out_8_to_in_9); |
| | inv_09:entity work.inverter(veloce) |
| | port map (a=>out_8_to_in_9, y=>out_9_to_in_10); |
| | inv_10:entity work.inverter(veloce) |
| | port map (a=>out_9_to_in_10, y=>out_10); |
| | |
| | end architecture struct; |
| | |
| | </code> |
| | |
| | Procedendo come in precedenza per eseguire la simulazione della nuova entità, si ottiene il risultato nella figura seguente (sono stati visulizzati il segnale di ingresseo e i segnali di uscita ogni 2 inverter). |
| | |
| | Si invita il lettore a interrogarsi sui trasitori iniziali che si possono osservere nei segnali in uscita alle porte più lontane dal segnale di ingresso. |
| |
| | {{:catena.png?600|}} |