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 Here6
  • SystemVerilog Language Foundations28
  • Object-Oriented SystemVerilog for Verification30
  • Constraint Randomization — Interview-Critical Deep Dive36
  • SystemVerilog Assertions — Interview-Critical Deep Dive40
  • Functional Coverage in SystemVerilog22
  • Testbench Architecture in SystemVerilog23
  • Advanced Language & Integration25
  • Senior & Interview Preparation21
    • Senior Debug Playbook
      • Failure Triage Method
      • Waveform Debug Strategy
      • Debugging the Testbench
      • Hunting X's and Races
    • Reviewing Verification Code
    • Verification Strategy: Spec to Sign-Off
    • SystemVerilog Interview Q&A Bank
    • Capstone: Verify a Parameterized FIFO
  • Principal-Level Verification28
Loading lesson

‹Senior Debug Playbook
  1. Topics
  2. SystemVerilog
  3. Senior & Interview Preparation
  4. Senior Debug Playbook
  5. Waveform Debug Strategy

Part 8 · Senior & Interview Prep · Intermediate

Waveform Debug Strategy

Backward tracing, first-divergence markers, sampler pitfalls, and a monitor sampling case.

On this page

    Trace backward from the symptom

    Start at the first-error time and walk backward through the cone of logic. At each stage, ask which input was already wrong.

    Diagram
    BACKWARD TRACE — symptom to origin
    
      symptom @ 12,450 ns: dut.rdata = 0x00 (expected 0xA4)
           │
           ▼ what drives rdata?
      mem_rd_data was 0x00 ◄── already wrong? YES → keep going back
           │
           ▼ what drives mem_rd_data?
      mem array @ addr 0x1F4 holds 0x00 ◄── wrong? YES → when was it written?
           │
           ▼ search last write to 0x1F4
      @ 9,120 ns: wr_en=1, wr_addr=0x1F4, wr_data=0xA4  ◄── write was CORRECT
           │
           ▼ so the write was lost — look between 9,120 and 12,450
      @ 9,121 ns: mem_clr pulse  ◄── ORIGIN: clear fired mid-traffic
           │
           ▼ what asserted mem_clr? ... and so on, into the bug's home stage

    Two viewer tools speed this up: driver and load tracing, and jumping to previous edges instead of scrolling. Repeat until a stage has correct inputs but a wrong output.

    Mark the first-divergence cycle

    The first-divergence cycle is the earliest point where DUT state differs from expectation. Everything before it is provably fine, which kills whole families of wrong theories.

    • Diff a passing seed against the failing one, aligned on a common event, and bisect to the first differing cycle.

    • Diff the reference model per transaction, then open waves only around the first disagreeing transaction.

    • Drop an immediate assertion on the suspect invariant and re-run the minimized case; its first failure time is the marker.

    Group signals by interface and name markers such as first_err and divergence. A saved session resumes tomorrow where it stopped.

    The wave can disagree with the sampler

    Concurrent assertions sample in the Preponed region: the settled value just before the clock edge. The viewer draws the post-edge value at that timestamp instead.

    An assertion can therefore fire on a cycle where the wave looks correct. Judge assertion failures against the previous-slot sampled values, or use the simulator assertion view.

    Watch d and q. The display and the sampler disagree exactly when d moves at the edge.

    • Slot 0: d 0, q 0. Settled before the experiment.

    • Slot 1: d reads 1 (changed at this very edge) but q is still 0. The wave shows 1 where the flop saw 0.

    • Slot 2: d reads 0 (changed at this edge) while q is 1. Display and sample disagree again.

    • Slot 3: both settled at 0. The naive rule holds only when nothing moves at the edge.

    pre_dut.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    module pre_dut (
      input logic clk,
      input logic d,
      output logic q
    );
      logic q_r = 0;
      always_ff @(posedge clk) q_r <= d;
      assign q = q_r;
    endmodule
    

    The bench models the sampler explicitly: it records the settled value before the edge, moves d just after the edge so the outcome is identical on every engine, and checks the flop against the recorded value. A change exactly at the edge would leave the order to the scheduler.

    Two more artifacts deserve the same suspicion. Same-timestamp events have a delta order the viewer may flatten, so expand delta time around clock gating. An undumped signal shows no data at all, so confirm the dump scope before trusting a flat line.

    Common pitfall

    Trusting the displayed value at a clock edge when judging an assertion failure. Check the sampled value first.

    Check yourself An assertion fires at a cycle where the wave shows the signal correct. What do you check first?

    The sampled value from the slot before the edge. The display shows the post-edge value, which the assertion never saw.

    Worked case: the monitor that blamed the RTL

    A bus environment reported sporadic mismatches after an RTL drop. The narrative said RTL, so the playbook said check the pins first.

    Diagram
    TIMELINE — Case 1 (monitor sampling-edge fault)
    
      T+0:00  Regression: 7/400 seeds fail, all "SB data mismatch".
      T+0:10  Triage: first error only; single-field mismatch, and act
              of txn N equals exp of txn N-1 in 3 of 3 cases. SHIFTED.
      T+0:25  Minimize: 6-txn directed repro fails identically. Gold.
      T+0:40  Verdict test at the pins: wave shows DUT rdata CORRECT
              at the protocol sample point. DUT acquitted → TB fault.
      T+1:05  Backward trace in the MONITOR: it samples rdata a fixed
              N cycles after valid; new RTL legally responds with 0 wait
              states (spec allows 0-wait responses). The fixed count lands
              on the wrong beat → captures the PREVIOUS beat's data.
      T+1:20  Fix: monitor samples per spec (valid && ready), not on a
              fixed wait count. Add a 0-wait-state directed test.

    The tell was visible in ten minutes: actual data matched the previous expected data. Time-shifted data means a sampling-position fault.

    Generalized lesson: monitors must encode the protocol timing range, not the timing the current RTL exhibits. The fix added a zero-wait directed test.

    Interview

    Likely question: “Tell me about a fault that was not where it first appeared.” Use this case: shifted data, pins acquit the DUT, monitor sampled on a fixed wait count.

    Related topics

    • Debugging the Testbench

    Previous

    212 / 259

    Next: Debugging the Testbench

    Up next

    Up nextDebugging the Testbench

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Hunting X's and Races
    clkdq
    A flop captures the pre-edge value while the display shows the post-edge change