Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • Start Here4
  • UVM Foundations14
  • UVM Phases & Simulation Lifecycle26
  • Factory & Configuration15
  • Transaction-Level Modeling (TLM)13
  • UVM Sequences & Stimulus21
  • UVM Agents & Protocol VIP21
  • Environment & Test Classes11
  • Checking & Coverage in UVM21
  • UVM Register Abstraction Layer (RAL)22
  • Advanced UVM in Practice13
  • Debug & Regression10
    • Debug Toolkit and Playbooks
    • Regression and Sign-off
      • Seeds and Exact Replay
      • Regression Triage by Signature
      • Regression Infrastructure and CI
      • Waveforms at Scale
      • Metrics and Sign-off
  • Coding Practice47
  • Verification in Industry Practice10
  • Senior Prep: Architecture, Leadership and Interviews32
Loading lesson

‹Regression and Sign-off
  1. Topics
  2. UVM Verification
  3. Debug & Regression
  4. Regression and Sign-off
  5. Waveforms at Scale

Part 11 · Debug & Regression · Intermediate

Waveforms at Scale

Dump nothing in regression; replay and dump the failing block from just before the first error. Scoping, windows, formats and sizes, with real runs.

On this page

    A verification lead turns on full waveform dumping for the nightly "so the waves are there when we need them". The next morning the shared disk is full, half the regression died writing files, and the runs that finished took three times longer than usual. The one failure anyone looked at needed 2 microseconds of six signals. How do you get exactly the waves a failure needs, and nothing else?

    The idea: dump on the rerun, not in the regression

    A waveform dump records the value of every selected signal at every change, so you can see what the design did over time. It is the most useful debug artifact and the most expensive one: dump size grows with the number of signals times the number of changes, and writing it slows the simulation. The rule at scale is simple. Regression runs dump nothing. When triage picks a run to debug, you replay it from its bundle (the same seed reproduces it exactly) and dump only that rerun, only the part of the design you need, and only the time window around the failure.

    A security camera system works like this. Nobody stores high-resolution footage of every corridor forever. Cameras keep low-cost logs, and when an incident is reported, someone pulls the footage for one corridor around the time of the incident. The log tells you where and when to look; the footage shows what happened.

    The picture

    Flowchart: regression run with no dump, triage finds time T and block X, replay with the same bundle, scope to block X, window from T minus a margin, small waveform, debug.
    The regression pays nothing for waves. The rerun pays for exactly the scope and time window that triage pointed at.

    What to dump, and when

    Situation

    Dump

    Why

    Nightly and weekly regression

    Nothing

    Size and run time multiply by thousands of runs

    Rerun of a failing run

    The failing block's ports and internals, from shortly before the first error

    Triage gives the time and the component

    Hang (timeout or watchdog fatal)

    The interfaces of the stuck agent, over the last part of the run

    The hang is visible at the end, not the start

    Bring-up of a new bench

    Everything, short tests only

    You do not yet know where to look

    Gate-level or power-aware run

    A small, chosen list

    Netlists have millions of nets; full dumps are impractical

    Build it: scoped, windowed dumping on the DMA bench

    The standard system tasks

    IEEE 1800 defines the VCD tasks: $dumpfile("name") opens the file, $dumpvars(levels, scope) selects signals (levels = 0 means everything below the scope, 1 means that module only), and $dumpoff / $dumpon pause and resume recording. Each vendor has its own compressed format with its own tasks or commands: FSDB for Synopsys Verdi ($fsdbDumpfile, $fsdbDumpvars), WLF for Questa, SHM for Xcelium, and the older VPD for VCS. The ideas (scope, depth, time window) are the same in all of them.

    The scratch top below is the bench's own top module with one addition: a plusarg that turns dumping on, starting at a given time. Without the plusarg, nothing is dumped, so the same executable serves the regression and the debug rerun.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // snippet: added to a copy of the bench's top module (scratch file)
      // +DUMP_FROM=<ps>: start dumping the DUT at that time (0 = from the start).
      // Without the plusarg nothing is dumped, so regression runs pay nothing.
      longint dump_from;
      initial
        if ($value$plusargs("DUMP_FROM=%d", dump_from)) begin
          #(dump_from * 1ps);
          $dumpfile("dump.vcd");
          $dumpvars(0, top.dut);
        end

    Triage pointed at dma_rand_test seed 16 on the mismatch build, first error at 345,000 ps. The rerun starts dumping 100 ns earlier.

    Watch it run (scratch runs, Verilator 5.048 with --trace)

    Diagram
    $ ./Vtop +UVM_TESTNAME=dma_rand_test +verilator+seed+16
      (no dump file)
    $ ./Vtop +UVM_TESTNAME=dma_rand_test +verilator+seed+16 +DUMP_FROM=0
      dump.vcd: 26360 bytes, 334 timestamps (5000 .. 1665000 ps), 140 signals
    $ ./Vtop +UVM_TESTNAME=dma_rand_test +verilator+seed+16 +DUMP_FROM=245000
      dump.vcd: 23372 bytes, 285 timestamps (250000 .. 1665000 ps), 140 signals
      UVM_ERROR dma_tb.sv(396) @ 345000: uvm_test_top.env.sb [SB_MISMATCH] expected 4735a210, got b8ca5def
    
      same bench built with a trace config that keeps only top.dut:
    $ ./Vtop ... +DUMP_FROM=0        dump.vcd: 18519 bytes, 111 signals
    $ ./Vtop ... +DUMP_FROM=245000   dump.vcd: 16602 bytes, 111 signals

    Three things to read in those numbers, and one surprise:

    • The window works. Starting at 245 ns drops everything before it, and the replayed run hits the same mismatch at 345,000 ps, so the waves show the exact failure triage found.

    • The DMA is tiny, so the savings are small: 140 signals over 1.7 microseconds is about 26 KB of VCD. Scale the same arithmetic to a subsystem with 500,000 signals and a 10-millisecond test, and a full VCD dump is in the range of tens to hundreds of gigabytes. Compressed formats (FSDB, WLF, SHM) are typically several times to an order of magnitude smaller than VCD, which helps but does not change the rule.

    • The surprise: this Verilator build ignored the scope argument and `$dumpoff`. $dumpvars(0, top.dut) still recorded all 140 signals of the design, and a $dumpoff / $dumpon pair in a separate scratch test did not pause recording. A delayed $dumpvars call did start the dump late, which is why the window above is built that way. On Verilator, scope is chosen at build time instead: --trace-depth, or a configuration file with tracing_off -scope "top" and tracing_on -scope "top.dut", which produced the 111-signal dumps (the remainder are package-level variables). Commercial simulators honour the scope and $dumpoff; check yours with a two-line test before you rely on either.

    Tip

    To end a window early on a tool that ignores $dumpoff, end the rerun: the debug rerun's job is the waveform, and its verdict was already decided by the regression run. A plusarg such as +DUMP_TO=<ps> that calls $finish keeps the file small for a long test.

    Dumping on the first error

    Some teams make the rerun automatic: when triage marks a run for debug, the farm reruns it with +DUMP_FROM set to the first-error time minus a margin. A related trick turns dumping on at the first error from inside the bench: a report catcher (see report catchers) that, on the first UVM_ERROR, calls $dumpvars and lets the run continue for a while. That records what happens after the error, which is what you need for a hang or a cascade, but not what led up to it; for a mismatch, the replay with a window that starts before the error is the better tool.

    What breaks: the dump that changed the bug

    A team found that a failing run passed when they reran it with waves on. It was not flaky: the bundle was identical except for one plusarg that enabled dumping, and enabling it changed the order in which two processes ran at the same simulation time. The bench had a race (a monitor sampled a signal in the same time step a driver changed it, without a clocking block), and the dump's extra work shifted the scheduling. Two lessons follow. A waveform switch is part of the bundle, so record it. And a failure that disappears when you observe it points at a race: look for signals read and written in the same time step, which is the problem the bench's clocking-block rule (war story 1) exists to prevent.

    Interview

    "How do you handle waveforms in a large regression?"

    A weak answer: "We dump everything in FSDB so we always have the waves."

    A strong answer: "Regression runs dump nothing. Every run records its seed and command, so any failure replays exactly. When triage picks a run, I rerun it with dumping scoped to the failing block and windowed from shortly before the first error; for a hang, the last part of the run on the stuck interface. The same executable does both, controlled by a plusarg. Full dumps are for bring-up on short tests only."

    Follow-ups: What if the failure disappears with dumping on? (a race; record the switch, look for same-time-step reads and writes). How do you get waves for a run that takes 10 hours to reach the bug? (checkpoint/restore where the tool supports it, or a window that starts late).

    Check yourself A test fails at 8.2 ms of a 9 ms simulation in the stream interface. What rerun command do you build, and what do you not dump?

    Replay the exact bundle with dumping scoped to the stream interface and the block behind it, starting a little before 8.2 ms (say 8.1 ms), and end the rerun shortly after the error. Do not dump the rest of the SoC, and do not dump the first 8 ms.

    Check yourself Your simulator writes VCD 10 times larger than its native format. Should you switch the regression to the native format and keep dumping everything?

    No. A 10 times smaller full dump of thousands of runs is still too large and still slows every run. Use the native format for the reruns you debug, and dump nothing in the regression.

    Next: the bugs are being found and fixed. Metrics and Sign-off is how you show the project is converging.

    Related topics

    • Up: Regression and Sign-off

    • Hang Playbook

    • Transaction recording

    Previous

    201 / 280

    Next: Metrics and Sign-off

    Up next

    Up nextMetrics and Sign-off

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Seeds and Exact Replay
    • Regression Triage by Signature
    • Regression Infrastructure and CI