Die Waveform, die du wirklich willst
$display druckt Text. Das ist okay für einen schnellen Sanity-Check, aber in dem Moment, in dem du einen Counter mit Timing-Problem oder einen Automaten debuggst, der hängt, willst du ein Bild: Signale als Spannungen über Zeit gezeichnet, scrollbar, zoombar, mit einem Cursor, den du auf jeden Übergang setzen kannst.
Dieses Bild ist eine VCD-Datei - "value change dump", ein Textformat, das die IEEE in der ursprünglichen Verilog-Spec standardisiert hat. Jeder moderne Simulator kann eine schreiben; jeder moderne Waveform-Viewer eine lesen. Die Kosten, eine zu produzieren: zwei Zeilen in deiner Testbench.
Die zwei Zeilen
In einem initial-Block - meist demselben, der auch deinen Stimulus hält - ergänze:
$dumpfile("dump.vcd");
$dumpvars(0, test);
$dumpfilebenennt die Ausgabedatei. Übergib einen beliebigen Pfad; ohne Verzeichnis landet sie im Arbeitsverzeichnis des Simulators.$dumpvars(0, test)sagt "zeichne jedes Signal imtest-Scope und jedem Sub-Scope auf, rekursiv, mit unbegrenzter Tiefe".
Das ist das ganze Setup. Lass die Simulation laufen, und du hast eine dump.vcd, die du in GTKWave oder im Waveform-Tab des Browser-Editors öffnen kannst.
Ein vollständiges Beispiel
Lass es laufen. Der Waveform-Tab zeigt jetzt drei Signale - clk, reset, count - über die volle Simulationszeit gezeichnet. Du kannst den Cursor an einer beliebigen Stelle absetzen und die Signalwerte zu dieser Zeit ablesen. Du kannst per Drag zoomen, um einen einzelnen Taktzyklus zu inspizieren.
Was das erste Argument von $dumpvars tut
$dumpvars(depth, scope) läuft scope und jede darin enthaltene Sub-Instanz durch und zeichnet Signale bis zu depth Ebenen tief auf. Die Tiefenwerte:
0- unbegrenzt. Jedes Signal inscopeund jedem verschachtelten Submodul wird aufgezeichnet.1- nur Signale, die direkt inscopedeklariert sind. Submodule werden nicht aufgezeichnet.2-scopeplus eine Ebene Submodule.N-scopeplus N-1 Ebenen Submodule.
In der Praxis nutzt fast jede Testbench $dumpvars(0, test). Alles zu erfassen ist günstig (VCDs speichern nur Übergänge, keine stabilen Zustände), und du willst nicht mitten beim Debug feststellen, dass das Signal, das du brauchst, nicht gedumpt wurde.
Hast du ein wirklich großes Design und ist die VCD zu groß, kannst du selektiv dumpen:
$dumpvars(0, dut.inner_module); // nur das interessante Submodul
$dumpvars(0, dut.regs); // nur das Register-File
Du kannst $dumpvars mehrfach aufrufen, um Scopes zu akkumulieren.
Bestimmte Signale dumpen
$dumpvars kann statt eines ganzen Scopes auch eine Liste bestimmter Signale annehmen:
$dumpvars(0, test.clk, test.reset, dut.count);
Das zeichnet nur diese drei Signale auf. Nützlich, wenn das Design riesig ist und du dich nur für eine Handvoll Signale interessierst. Für kleine Designs ist Alles-Dumpen einfacher.
Dump mid-Simulation steuern
Zwei weitere Tasks ergänzen $dumpvars:
$dumpoff- Dumping pausieren. Keine weiteren Änderungen wandern in die VCD.$dumpon- Dumping fortsetzen.
initial begin
$dumpfile("dump.vcd");
$dumpvars(0, test);
// ... interessante Region ...
#1000 $dumpoff;
// ... lange langweilige Region, die nicht in die VCD soll ...
#5000 $dumpon;
// ... wieder interessante Region ...
end
So überspringst du den langweiligen "läuft eine Million Zyklen"-Teil eines langen Tests, ohne eine 5-GB-VCD zu produzieren.
Das Ergebnis ansehen
Zwei Hauptwege:
Im Browser-Editor
Der Editor auf dieser Seite rendert VCDs inline. Lass die Simulation laufen; wechsel zum Waveform-Tab; die Signale erscheinen mit ihrer Hierarchie links und einem draggable Cursor rechts. Klicke irgendwo auf eine Spur, um den Cursor zu platzieren; er zeigt die Signalwerte zu dieser Zeit als kleine Pills neben jedem Signalnamen.
In GTKWave
Hast du die Simulation lokal laufen lassen (iverilog -o sim test.v und dann vvp sim), öffne die entstandene VCD mit:
gtkwave dump.vcd
GTKWave lädt die Datei, zeigt links den Scope-Baum und wartet, dass du Signale in den Wellenform-Bereich rechts ziehst. Rechtsklick auf ein Mehrbit-Signal, um das Anzeigeformat zu ändern (binär, hex, dezimal, analog). Nutze das Suchfeld unten, um zu bestimmten Zeiten oder Signalübergängen zu springen.
Übliche Muster
Ein winziger Testbench-Helfer
Die meisten Testbench-Dateien starten mit genau diesem Block. Du kannst ihn kurz halten, indem du alles in ein initial packst:
initial begin
$dumpfile("dump.vcd");
$dumpvars(0, test);
// ... Stimulus ...
$finish;
end
Bedingtes Dumping
In einer Testumgebung, in der du VCD-Ausgabe nur für fehlgeschlagene Tests willst:
initial begin
if (DUMP_VCD) begin
$dumpfile("dump.vcd");
$dumpvars(0, test);
end
// ... Stimulus ...
end
DUMP_VCD wäre ein parameter, den du von der Kommandozeile aus setzt oder je nach Testmodus definierst. Spart Plattenplatz in Regressions-Suites.
Memory-Dumps
Memories (unpacked Arrays) werden von $dumpvars standardmäßig nicht gedumpt - sie können enorm sein. Nutze $dumpvars(0, dut.memory) explizit, wenn du sie willst, oder $dumpmem in manchen Simulatoren.
Häufige Fehler
Leere VCD-Datei. Du hast $dumpfile oder $dumpvars vergessen, oder die Simulation hat $finish aufgerufen, bevor sich irgendein Signal geändert hat. Lass mindestens ein paar Zeiteinheiten nach dem Setup laufen.
Signale fehlen in der Waveform. Der übergebene Scope enthielt sie nicht. $dumpvars(0, dut) zeichnet nur das auf, was in dut ist; treibt deine Testbench Signale auf der test-Ebene, tauchen die nicht auf. Dumpe immer vom Testbench-Scope aus: $dumpvars(0, test).
VCD-Datei ist riesig. Eine lange Simulation mit sich schnell ändernden, breiten Signalen produziert viele VCD-Zeilen. Drei Fixes: einen engeren Scope dumpen, $dumpoff/$dumpon um die langweiligen Teile setzen oder auf ein kompakteres Format wie FST umsteigen (das iverilog und GTKWave beide mit -fst-Flags unterstützen).
Wie es weitergeht
Das letzte Doc dieses Kapitels - Timescale und Delays - erklärt die `timescale-Direktive und wie #delay tatsächlich auf Wanduhrzeit abbildet. Danach hast du die Docs durchgearbeitet.
Häufig gestellte Fragen
Was ist eine VCD-Datei in Verilog?
VCD steht für Value Change Dump - ein Textformat, das jeden Signalübergang während der Simulation aufzeichnet. Der Simulator schreibt den Anfangswert jedes Signals zur Zeit 0, dann jede Änderung mit Zeitstempel. Waveform-Viewer wie GTKWave lesen die Datei und rendern sie als grafisches Timing-Diagramm, durch das du scrollen und zoomen kannst.
Wie erzeuge ich eine VCD-Datei in Verilog?
Füge zwei System-Tasks in einen initial-Block deiner Testbench ein: $dumpfile("dump.vcd"); benennt die Ausgabedatei, und $dumpvars(0, top_module); zeichnet jedes Signal in top_module und darunter auf. Nach Ende der Simulation hast du eine dump.vcd-Datei, die du in jedem Waveform-Viewer öffnen kannst.
Was bedeutet $dumpvars(0, ...) in Verilog?
$dumpvars(depth, instance) zeichnet Signale ab instance auf und steigt depth Ebenen tief hinab. $dumpvars(0, test) heißt 'alle Signale im test-Scope und jedem Sub-Scope, rekursiv' - Tiefe 0 ist speziell und bedeutet unbegrenzt. $dumpvars(1, test) würde nur Signale direkt in test aufzeichnen, nicht in instanziierten Submodulen.
Warum ist meine VCD-Datei in Verilog leer?
Drei wahrscheinliche Ursachen: Du hast $dumpfile/$dumpvars gar nicht aufgerufen; die Simulation hat $finish erreicht, bevor sich Signale änderten (lass nach dem Dump-Aufruf mindestens ein paar Zeiteinheiten laufen); oder der Scope, den du $dumpvars übergeben hast, passt nicht zur tatsächlichen Hierarchie. Eine minimale Arbeitsfolge ist $dumpfile("dump.vcd"); $dumpvars(0, test); #10; $finish;.