La forma d'onda che ti serve davvero
$display stampa testo. Va bene per un controllo veloce, ma appena devi fare debug di un contatore con un problema di temporizzazione o di una macchina a stati bloccata, vuoi un'immagine: segnali disegnati come tensioni nel tempo, da scorrere e ingrandire, con un cursore da posizionare su qualsiasi transizione.
Quell'immagine è un file VCD ("value change dump"), un formato di testo che l'IEEE ha standardizzato nella specifica originale di Verilog. Ogni simulatore moderno sa scriverne uno e ogni visualizzatore di forme d'onda moderno sa leggerlo. Per produrlo bastano due righe nel testbench.
Le due righe
Dentro un blocco initial, di solito lo stesso che contiene lo stimolo, aggiungi:
$dumpfile("dump.vcd");
$dumpvars(0, test);
$dumpfiledà il nome al file di output. Puoi passare qualsiasi percorso; se non contiene una directory, il file finisce nella directory di lavoro del simulatore.$dumpvars(0, test)dice "registra tutti i segnali dello scopeteste di ogni sotto-scope, ricorsivamente, con profondità illimitata".
Questa è tutta la configurazione. Esegui la simulazione e avrai un dump.vcd da aprire in GTKWave o nella scheda Waveform dell'editor del browser.
Un esempio completo
Eseguilo. La scheda Waveform ora mostra tre segnali, clk, reset e count, disegnati lungo tutto il tempo di simulazione. Puoi posizionare un cursore in qualsiasi punto e leggere i valori dei segnali in quell'istante. Puoi trascinare per ingrandire e ispezionare un singolo ciclo di clock.
Cosa fa il primo argomento di $dumpvars
$dumpvars(depth, scope) percorre scope e ogni sotto-istanza che contiene, registrando i segnali fino a depth livelli di profondità. I valori di profondità:
0: illimitata. Vengono registrati tutti i segnali discopee di ogni sottomodulo annidato.1: solo i segnali dichiarati direttamente inscope. I sottomoduli non vengono registrati.2:scopepiù un livello di sottomoduli.N:scopepiù N-1 livelli di sottomoduli.
In pratica $dumpvars(0, test) è ciò che usa quasi ogni testbench. Catturare tutto costa poco (i VCD memorizzano solo le transizioni, non gli stati stabili) e non vuoi scoprire a metà debug che il segnale che ti serve non è stato registrato.
Se hai un progetto molto grande e il VCD diventa troppo pesante, puoi registrare in modo selettivo:
$dumpvars(0, dut.inner_module); // just the interesting sub-module
$dumpvars(0, dut.regs); // just the register file
Puoi chiamare $dumpvars più volte per accumulare più scope.
Registrare segnali specifici
$dumpvars accetta anche un elenco di segnali specifici al posto di un intero scope:
$dumpvars(0, test.clk, test.reset, dut.count);
Così vengono registrati solo quei tre segnali. È utile quando il progetto è enorme e ti interessano solo pochi segnali. Per progetti piccoli è più semplice registrare tutto.
Controllare il dump durante la simulazione
Altri due task si abbinano a $dumpvars:
$dumpoff: mette in pausa il dump. Nessun ulteriore cambiamento finisce nel VCD.$dumpon: riprende il dump.
initial begin
$dumpfile("dump.vcd");
$dumpvars(0, test);
// ... interesting region ...
#1000 $dumpoff;
// ... long boring region we don't want in the VCD ...
#5000 $dumpon;
// ... another interesting region ...
end
È così che salti la parte noiosa di un test lungo, quella in cui "gira per un milione di cicli", senza produrre un file VCD da 5 GB.
Visualizzare il risultato
I modi principali sono due:
Nell'editor del browser
L'editor di questa pagina mostra i VCD direttamente. Esegui la simulazione e passa alla scheda Waveform: i segnali compaiono con la loro gerarchia da una parte e un cursore trascinabile dall'altra. Fai clic in un punto qualsiasi di una traccia per posizionare il cursore: accanto al nome di ogni segnale compaiono delle piccole etichette con i valori in quell'istante.
In GTKWave
Se hai eseguito la simulazione in locale (iverilog -o sim test.v e poi vvp sim), apri il VCD risultante con:
gtkwave dump.vcd
GTKWave carica il file, mostra l'albero degli scope e aspetta che trascini i segnali nell'area delle forme d'onda. Fai clic con il tasto destro su un segnale a più bit per cambiarne il formato di visualizzazione (binario, esadecimale, decimale, analogico). Usa la casella di ricerca in fondo per saltare a tempi specifici o a transizioni di un segnale.
Pattern comuni
Un piccolo aiuto per i testbench
La maggior parte dei file di testbench inizia esattamente con questo blocco. Puoi tenerlo corto mettendo tutto in un solo initial:
initial begin
$dumpfile("dump.vcd");
$dumpvars(0, test);
// ... stimulus ...
$finish;
end
Dump condizionale
In un ambiente di test in cui vuoi l'output VCD solo per i test che falliscono:
initial begin
if (DUMP_VCD) begin
$dumpfile("dump.vcd");
$dumpvars(0, test);
end
// ... stimulus ...
end
DUMP_VCD sarebbe un parameter impostato dalla riga di comando o definito in base alla modalità di test. Fa risparmiare spazio su disco nelle suite di regressione.
Dump delle memorie
Le memorie (array unpacked) per default non vengono registrate da $dumpvars, perché possono essere enormi. Se le vuoi, usa esplicitamente $dumpvars(0, dut.memory), oppure $dumpmem in alcuni simulatori.
Errori comuni
File VCD vuoto. Hai dimenticato $dumpfile o $dumpvars, oppure la simulazione ha chiamato $finish prima che cambiasse qualche segnale. Fai girare almeno qualche unità di tempo dopo la configurazione.
Segnali mancanti nella forma d'onda. Lo scope che hai passato non li includeva. $dumpvars(0, dut) registra solo ciò che sta dentro dut; se il testbench pilota segnali al livello di test, quelli non compariranno. Fai sempre il dump dallo scope del testbench: $dumpvars(0, test).
File VCD enorme. Una simulazione lunga con segnali larghi che cambiano rapidamente produce moltissime righe VCD. Tre soluzioni: registra uno scope più ristretto, usa $dumpoff/$dumpon attorno alle parti noiose oppure passa a un formato più compatto come FST (supportato sia da iverilog sia da GTKWave con i flag -fst).
Cosa viene dopo
L'ultima pagina di questo capitolo, Timescale and Delays, spiega la direttiva \timescalee come#delay` corrisponde davvero al tempo reale. Dopo di che avrai completato la documentazione dall'inizio alla fine.
Domande frequenti
Cos'è un file VCD in Verilog?
VCD sta per Value Change Dump: un formato di testo che registra ogni transizione dei segnali durante la simulazione. Il simulatore scrive il valore iniziale di ogni segnale al tempo 0 e poi ogni cambiamento con il relativo timestamp. I visualizzatori di forme d'onda come GTKWave leggono il file e lo mostrano come un diagramma temporale grafico da scorrere e ingrandire.
Come si genera un file VCD in Verilog?
Aggiungi due system task dentro un blocco initial del testbench: $dumpfile("dump.vcd"); dà il nome al file di output e $dumpvars(0, top_module); registra tutti i segnali di top_module e dei livelli sottostanti. Al termine della simulazione avrai un file dump.vcd da aprire in qualsiasi visualizzatore di forme d'onda.
Cosa significa $dumpvars(0, ...) in Verilog?
$dumpvars(depth, instance) registra i segnali a partire da instance, scendendo ricorsivamente di depth livelli. $dumpvars(0, test) significa 'tutti i segnali dello scope test e di ogni sotto-scope, ricorsivamente': la profondità 0 è speciale e vuol dire illimitata. $dumpvars(1, test) registrerebbe solo i segnali direttamente in test, non quelli dei sottomoduli istanziati.
Perché il mio file VCD è vuoto in Verilog?
Le cause probabili sono tre: non hai chiamato affatto $dumpfile/$dumpvars; la simulazione ha raggiunto $finish prima che cambiasse qualche segnale (fai girare almeno qualche unità di tempo dopo la chiamata di dump); oppure lo scope passato a $dumpvars non corrisponde alla gerarchia reale. Una sequenza minima funzionante è $dumpfile("dump.vcd"); $dumpvars(0, test); #10; $finish;.