Part 7 · Advanced & Integration · Intermediate
Wave Dumping & Runtime Control
$dumpfile/$dumpvars scope control, FSDB conceptually, plusarg-driven dump windows, $finish vs $stop vs $fatal, and runtime verbosity.
Controlling what gets dumped
$dumpfile names the VCD output and $dumpvars(depth, scope) selects how much hierarchy to record: depth 0 means the scope and everything below it, depth 1 means only the scope's own signals. Dump scope is the single biggest lever on both simulation speed and disk usage — full-design dumps routinely double run time and produce files in the tens of gigabytes. Commercial flows use FSDB (or vendor equivalents) instead of VCD: same scoping concepts, dramatically better compression, driven by tool-specific system tasks.
initial begin
$dumpfile("waves.vcd");
// depth 0 = this scope and EVERYTHING below — expensive
$dumpvars(0, tb_top);
// Better: target the suspect block only
// $dumpvars(0, tb_top.dut.u_dma); // one subtree
// $dumpvars(1, tb_top.dut); // dut's own signals, no children
// Multiple targeted calls compose:
// $dumpvars(0, tb_top.dut.u_dma);
// $dumpvars(1, tb_top.dut.u_arb);
end
// FSDB conceptually identical (Verdi flow):
// $fsdbDumpfile("waves.fsdb");
// $fsdbDumpvars(0, tb_top.dut.u_dma);Dump windows: record only around the failure
A 10-millisecond regression run that fails at 9.2 ms does not need 9 ms of waves. $dumpoff and $dumpon gate recording at run time; drive the window edges from plusargs and the rerun of a failing seed records only the region around the failure — small file, fast run, full visibility where it matters.
// Plusarg-driven dump window
time dump_start = 0;
time dump_stop = 0; // 0 = run to the end
initial begin
if (!$test$plusargs("DUMP")) begin
// no +DUMP → no wave overhead at all
end else begin
void'($value$plusargs("DUMP_START=%d", dump_start));
void'($value$plusargs("DUMP_STOP=%d", dump_stop));
$dumpfile("waves.vcd");
$dumpvars(0, tb_top.dut);
if (dump_start > 0) begin
$dumpoff; // armed but not recording
#(dump_start) $dumpon; // open the window
end
if (dump_stop > dump_start)
#(dump_stop) $dumpoff; // close it
end
end
// First run (no waves): simv +TESTNAME=stress
// → fails at 9_200_000 ns
// Rerun with a window: simv +TESTNAME=stress +DUMP \
// +DUMP_START=9000000 +DUMP_STOP=9400000DUMP WINDOW STRATEGY
full dump ██████████████████████████████ 20 GB, 2x slower
0ms 10ms
windowed dump ░░░░░░░░░░░░░░░░░░░░░░░░██░░░ 0.4 GB, ~1.05x
▲ ▲
DUMP_START failure @9.2ms
9.0ms DUMP_STOP 9.4ms
regression default: +DUMP absent → zero wave cost
failure rerun: +DUMP +window around the failing timeEnding the run: $finish, $stop, $fatal — and verbosity
Three ways out
$finish — normal termination: ends the process, runs final blocks; the standard end of a passing or cleanly failing test.
$stop — pause, not exit: drops into the interactive debugger prompt; useful at a breakpoint moment, but it hangs batch regressions waiting for input.
$fatal(status, msg) — error termination: prints a fatal message and finishes with a status; the status argument feeds the exit code on most tools, letting scripts distinguish failure kinds.
Exit-code discipline: the regression script must see nonzero on failure — check your tool's mapping of $fatal status to process exit code, and grep logs as a backstop.
// Runtime verbosity: one knob, checked by a log helper
int verbosity = 1; // 0=errors only, 1=normal, 2=debug
initial void'($value$plusargs("VERBOSITY=%d", verbosity));
function void log_msg(int level, string msg);
if (level <= verbosity)
$display("[%0t] %s", $time, msg);
endfunction
// Timeout guard — every testbench needs one:
initial begin
#50ms;
$fatal(1, "TIMEOUT: test did not complete");
end
// End-of-test:
task end_of_test(int errors);
if (errors == 0) begin
$display("TEST PASSED");
$finish; // exit code 0
end else
$fatal(1, "TEST FAILED: %0d errors", errors); // nonzero exit
endtaskKey takeaways
Dump scope and depth are the biggest sim-speed levers — regressions run dump-free, reruns dump a window.
Drive $dumpon/$dumpoff windows from plusargs so the failing seed reruns with waves only around the failure.
$finish ends, $stop pauses for interaction (never in batch), $fatal ends with an error status for scripts.
Make verbosity a runtime plusarg — re-running at higher verbosity must not require a recompile.
Common pitfalls
$dumpvars(0, tb_top) as the regression default — gigabytes of waves and doubled run time for passing tests.
$stop in code that runs under batch regression — the job hangs at an interactive prompt until killed.
Passing test paths that never call $finish — the timeout guard fires and a green test reports red.
Trusting exit codes without verifying the tool's $fatal status mapping — scripts mark failing tests as passed.
Interview angle
Expect: $finish vs $stop vs $fatal (exit, pause, error-exit with status); how to cut wave overhead in regression (no default dump, plusarg-windowed rerun); and the flow question — describe your debug loop when a regression seed fails. The expected answer: rerun the seed with +DUMP and a window around the failure time, at higher verbosity, without recompiling.