← Design Verification Interviews

Interview Question · Debug

The Monitor That Waited Zero Delays

L1 JuniorL2 Mid-Levelsystemverilogschedulingmonitorsdebug

The Question

The interviewer asks

A monitor wakes on posedge clk, waits #0 to "let the design settle", then reads the DUT's output flop. The log shows every beat one cycle late. A colleague suggests a second #0. What is going on?

log
t=15 monitor: q=00   (waveform at t=15: q changes to a1)
t=25 monitor: q=a1   (waveform at t=25: q changes to b2)
t=35 monitor: q=b2   (waveform at t=35: q changes to c3)
Reveal the Model Answer

The flop is written with <=, so its new value lands in the NBA region. A #0 only moves the monitor to the Inactive region, which runs before NBA. No number of #0 delays gets past it, because NBA starts only when Active and Inactive are both empty. Instead, sample the flop through a clocking block at the next edge. There, the value written at this edge is settled.

Where a #0 Goes, and Where the Flop Update GoesThe regions of one time step, in IEEE 1800-2017 order. Arrows show where the scheduler goes next. The Reactive set is Reactive, Re-Inactive and Re-NBA.
Where a #0 goes, and where the flop update goesThe regions of one time step, in IEEE 1800-2017 order. Arrows show where the scheduler goes next. The Reactive set is Reactive, Re-Inactive and Re-NBA. region Preponed samples for #1stepand assertions region Active woken processes run;<= reads its rightside region Inactive processes resumedafter #0 region NBA pending <= updatesare written region Observed concurrentassertions evaluate region Reactive set program code andassertion actions region Postponed $strobe prints;nothing may change thenthenthen<= updateswakes readersall three emptythennothing left
Read the diagram as text
  • Preponed: samples for #1step and assertions
  • Active: woken processes run; <= reads its right side
  • Inactive: processes resumed after #0
  • NBA: pending <= updates are written
  • Observed: concurrent assertions evaluate
  • Reactive set: program code and assertion actions
  • Postponed: $strobe prints; nothing may change
  • Preponed → Active: then
  • Active → Inactive: then
  • Inactive → NBA: then
  • Active → NBA: <= updates
  • NBA → Active: wakes readers
  • NBA → Observed: all three empty
  • Observed → Reactive set: then
  • Reactive set → Postponed: nothing left

A #0 moves a process from Active to Inactive only. Inactive runs before NBA, so a #0 reader still sees the old flop value.

Self-Check

Tick each key point you covered in your answer.

What Interviewers Listen For (Junior)

A good junior answer puts #0 in the Inactive region and the flop update in NBA. It uses that reason to reject adding a second #0.

Cross-Questions

Where the interviewer goes next. Open a node to practise that follow-up.

WhyWhat IfProve ItCompare

  1. The Monitor That Waited Zero Delays
  2. WhyWhy NBA Updates Wait for the Inactive RegionL2 Mid-Level

    Why is the NBA region placed after the Inactive region instead of before it?

    Reveal the Model Answer

    Every process that wakes at the edge must read pre-edge values, even one that waits with #0. Only then do nonblocking assignments model flops correctly. If NBA updates landed before Inactive, a #0 reader would see half-updated state. Then the result of <= would depend on process order again.

    Two Pipelines Fed by the Same InputA pipeline written with <= and one written with =, fed by the same input. One column per clock period; the rising edges at 5, 15 and 25 start columns 1 to 3.
    0123clkd11223344a1 (<=)00112233a2 (<=)001122b1 (=)00112233b2 (=)00112233
    1. Cycle 0

      Before the first edge, d is 11 and both pipelines hold 00.

    2. Cycle 1

      At t=5 the <= pipeline moves 11 into a1 only, and a2 takes the old 00. The blocking pipeline copies 11 into both stages.

    3. Cycle 2

      The value 11 reaches a2 one edge later. b2 never lags b1: the blocking version behaves as one register.

    4. Cycle 3

      After t=25, a2 holds 22 and b2 holds 33, as the last $strobe line shows.

    Data moves one stage per edge only when each stage reads the value from before the edge.

    Self-Check

    Tick each key point you covered in your answer.

    Half-Truth

    "Inactive exists to let testbenches go last."

    It was a Verilog-era tool for ordering within the Active set. Using it as a "go last" lever fails as soon as a second process does the same.

    Source IEEE 1800-2017 §4.4.2.3

  3. CompareClocking Blocks vs Driving on the Falling EdgeL2 Mid-Level

    Compare a clocking block with driving stimulus on the falling edge as ways to avoid testbench races.

    Reveal the Model Answer

    Driving on the falling edge puts drives and samples in different time steps, so it is simple and race-free. But it only works for single-edge designs with a known duty cycle. A clocking block samples inputs just before the active edge (#1step, the Preponed region). It drives outputs after a set skew, so the testbench stays cycle-based on the real edge. Clocking blocks scale to agents and interfaces; falling-edge drives suit small directed benches.

    Self-Check

    Tick each key point you covered in your answer.

    Spec Misquote

    "An input skew of #1step means one nanosecond before the edge."

    1step is one unit of the time precision, not one nanosecond. The sample is taken in the Preponed region, so it reads the values from just before the edge.

    Source IEEE 1800-2017 §14.4, §4.4.2.1

  4. What IfReading a Clockvar After the Raw EdgeL2 Mid-Level

    Asked if they write a monitor with clocking blocks

    A monitor waits for @(posedge clk) and then reads cb.rdata. It sometimes reports the previous beat. What happened?

    systemverilog
    clocking cb @(posedge clk);
      default input #1step;
      input rdata;
    endclocking
    initial forever begin
      @(posedge clk);
      $display("rdata=%h", cb.rdata);
    end
    Reveal the Model Answer

    Clockvars (the sampled signals of a clocking block) are updated when the clocking event is processed, in the Observed region. A process that resumes on the raw posedge clk can read cb.rdata before that update. It then gets the previous sample. Wait on @(cb) instead, so the read happens after the clockvars change.

    Self-Check

    Tick each key point you covered in your answer.

  5. Prove ItSolve 6.7.1: The Monitor That Saw the FutureSimulator-graded

    Show it, don't just say it: this Silicon Lab problem is graded by the simulator.

    Open Problem 6.7.1

  6. What IfA Monitor That Waits for the Signal to ChangeL1 JuniorL2 Mid-Level

    Asked if they propose waiting on the signal itself

    What if the monitor waits with @(q) after the edge instead of using #0?

    Reveal the Model Answer

    It wakes on the NBA update and reads the new value, but only when the value actually changes. A beat that repeats the previous value never wakes it, so the monitor silently drops it. Sampling once per clocking event is the only scheme that sees every beat.

    Self-Check

    Tick each key point you covered in your answer.

    Missed Corner

    "@(q) fires once per clock because q is a flop."

    An event control on a variable waits for a change of value, not for a write. Writing the same value again creates no event.

    Source IEEE 1800-2017 §9.4.2

What People Get Wrong

Common wrong answers and why they fail. Run It shows the wrong belief failing on a real simulator.

Misconception

"Two or three #0 delays are enough to cross the NBA updates."

Each #0 re-enters the Inactive region of the same slot, and NBA waits until Active and Inactive are empty. The twin uses three and still reads the old value.

Run It

A flop written with <= at t=5, read after three #0 delays.

RUNVerilator · simulator service
Edit the code, then run it
Expected: after three #0: q=0 FAIL: #0 only reaches the Inactive region; the NBA update has not happened yet
See the Fix
module tb;
  logic clk = 0, q = 0;
  always @(posedge clk) q <= 1;          // edge 1 updates q
  clocking cb @(posedge clk); input q; endclocking   // default input skew #1step
  initial begin #5 clk = 1; #5 clk = 0; #5 clk = 1; end
  initial begin
    @(cb); @(cb);                        // the fix: read the value sampled at the next edge
    $display("sampled at the next edge: q=%0d", cb.q);
    if (cb.q == 1) $display("PASS: the clocking block sampled the settled value from edge 1");
  end
endmodule

Prints: sampled at the next edge: q=1 PASS: the clocking block sampled the settled value from edge 1

Half-Truth

"Use #1 instead; it always works."

It moves the read past the update in this bench. But its meaning depends on the time precision, and it breaks when real delays appear. It hides the race instead of removing it.

Source Spear & Tumbush, SystemVerilog for Verification (3rd ed.), ch. 4 p141

Delivery

Blames the DUT for a one-cycle latency bug.

The waveform shows q changing at the edge where the monitor reads. The data is right and the sample point is wrong, so the fix belongs in the monitor.

Learn It, Then Prove It