← Design Verification Interviews

Interview Question · Concept

Stable, Changed and Past in a Hold Rule

L0 FresherL1 Juniorsvasampled value functionshandshake

The Question

The interviewer asks

You need to check that data does not change while a valid offer waits for ready. Which sampled value function do you use, and how exactly do you write the rule?

Reveal the Model Answer

$stable(data) compares the sampled value at this edge with the sample at the previous edge. The rule is valid && !ready |=> $stable(data): if the offer is stalled at this edge, the data must be unchanged at the next one. The tempting valid |-> $stable(data) fails on every new beat, because data legally changes at the edge where valid rises.

Two legal beats, the second one stalled
01234edge12345validreadydata1122data changed as valid rose: valid |-> $stable failsstall at 3, data held at 4: hold rule passes

New data arrives with valid; only a stalled offer must hold.

Self-Check

Tick each key point you covered in your answer.

What Interviewers Listen For (Fresher)

A good fresher answer picks $stable and says it compares with the previous edge. It starts the rule from a stalled offer with |=>.

Cross-Questions

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

What IfProve ItBreak ItCompareScale It

  1. Stable, Changed and Past in a Hold Rule
  2. ComparePast N Cycles Back vs StableL1 Junior

    Compare $past(data, 3) with $stable(data). When do you need the depth argument?

    Reveal the Model Answer

    $stable only looks one edge back. $past(data, 3) returns the sample from three edges ago. You need it when a fixed-latency output must equal an older input, as in valid_out |-> dout == $past(din, 3). For variable latency, $past cannot know the depth; capture the value in a local variable instead.

    $stable(data)$past(data, 3)
    Looks backOne edgeThree edges
    ReturnsTrue or false: unchanged?The old value itself
    Typical useHold rules during a stallOutput equals an input from 3 cycles ago

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "$past(din, 3) is the value three time units ago."

    The depth counts ticks of the assertion's clock, not time units.

    Source IEEE 1800-2017 §16.9.3

  3. What IfA Gated PastL2 Mid-Level

    What if the pipeline only advances when en is high? What does $past(din, 1, en) return?

    Reveal the Model Answer

    The third argument gates the clock. $past(din, 1, en) returns din from the most recent earlier tick where en was true, skipping stalled ticks. That matches a pipeline register with an enable. Verilator 5.052 rejects the gating argument at compile time, so on that engine keep a shadow register updated under en instead.

    $past(din, 1, en) skips the ticks where en is low
    01234edge12345endinabcdegated past-adlast enabled tick before 4 was 1: returns a

    Only ticks with en high advance the gated history.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "The gating argument makes $past return x when en is low."

    It does not mask the result; it decides which earlier ticks count as history.

    Source IEEE 1800-2017 §16.9.3

  4. Break ItA Hold Rule That Never StartedL1 JuniorL2 Mid-Level

    The hold rule passed across the whole regression. Why might that prove nothing?

    Reveal the Model Answer

    Its antecedent needs a stalled offer. If every test drives ready high, no attempt ever reaches the consequent, and the zero-failure report is vacuous. Count or cover valid && !ready and make a stalling sink part of the agent.

    Self-Check

    Tick each key point you covered in your answer.

    Half-Truth

    "Vacuous passes only come from typos."

    Here the property is correct; the stimulus never creates the situation it checks.

  5. Scale ItHold Rules Across Every Channel of an IPL3 Senior

    Your IP has twelve valid/ready channels of different widths. How do you deploy the hold rule without twelve hand-written copies?

    Reveal the Model Answer

    Write one checker module with the payload width as a parameter. It holds the hold, stable and reset rules, plus a counter of stalled cycles. Bind one instance to each channel. Make "every channel saw at least N stalls" a regression check, so a channel that never stalls is reported, not silently passed.

    Self-Check

    Tick each key point you covered in your answer.

    What Interviewers Listen For (Senior)

    A good senior answer makes the stall count part of the sign-off criteria. It binds one checker per channel instead of editing the RTL.

    Wrong Altitude

    Copies the property into each channel's RTL with renamed signals.

    Twelve copies drift. One bound checker changes in one place and reports per channel.

  6. Prove ItSolve 6.6.6: Hold the OfferSimulator-graded

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

    Open Problem 6.6.6

What People Get Wrong

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

Misconception

"valid |-> $stable(data) checks that data holds while valid is high."

$stable compares with the previous edge, so the first edge of every new beat, where data legally changed, fails. The twin's legal traffic fails twice.

Run It

Two legal beats, the second one stalled for a cycle, checked with valid |-> $stable(data).

RUNVerilator · simulator service
Edit the code, then run it
Expected: t=15 a_hold failed t=35 a_hold failed FAIL: $stable compares with the previous edge, so every new beat fails as it arrives
See the Fix
module tb;
  logic clk = 0, valid = 0, ready = 0;
  logic [7:0] data = 0;
  int fails = 0;
  always #5 clk = ~clk;
  // The fix: only a stalled offer must hold, checked at the next edge.
  a_hold: assert property (@(posedge clk) valid && !ready |=> $stable(data))
    else begin fails++; $display("t=%0t a_hold failed", $time); end
  initial begin
    // two legal beats: data changes as valid rises and holds through a stall
    @(negedge clk) begin valid = 1; data = 8'h11; end
    @(negedge clk) ready = 1;
    @(negedge clk) begin valid = 1; ready = 0; data = 8'h22; end
    @(negedge clk);
    @(negedge clk) ready = 1;
    @(negedge clk) begin valid = 0; ready = 0; end
    repeat (2) @(negedge clk);
    if (fails == 0) $display("PASS: legal traffic, no failures");
    $finish;
  end
endmodule

Prints: PASS: legal traffic, no failures

Half-Truth

"$stable(data) means data did not change at any time during the cycle."

It compares two samples, one per edge. A glitch between edges that returns to the old value is invisible to it.

Source IEEE 1800-2017 §16.9.3

Buzzword Without Mechanism

Writes data == $past(data) and calls it different from $stable(data).

For a value with no unknown bits they give the same verdict; $stable is the readable spelling. The real choice is the antecedent, not the function.

Learn It, Then Prove It