← Design Verification Interviews

Interview Question · Code Reading

Rose on a Two-Bit State

L0 FresherL1 Juniorsvasampled value functions

The Question

The interviewer asks

This counter is meant to count moves from IDLE (2'b01) to BUSY (2'b10). The design makes one such move. What does moves read?

systemverilog
logic [1:0] state;              // IDLE = 2'b01, BUSY = 2'b10
// "Count every move from IDLE to BUSY"
a_busy: assert property (@(posedge clk) !$rose(state)) else moves++;
Reveal the Model Answer

It reads 0. $rose and $fell look only at the least significant bit of their argument, and bit 0 fell from 1 to 0 in this move. To detect a change of a multi-bit value, compare the old and new values with $past. Use $changed when any change will do.

IDLE to BUSY, Seen Through Bit 0
012edge (ns)51525state2'b012'b10state[0]$rose(state)explicit IDLE to BUSY checkthe move: bit 0 falls, so $rose stays 0

One column per rising edge. The explicit check, $past(state) == IDLE && state == BUSY, sees the move at 15 ns.

Self-Check

Tick each key point you covered in your answer.

What Interviewers Listen For (Fresher)

A good fresher answer knows $rose means "went from not 1 to 1". It then asks which bit of the vector that applies to.

Cross-Questions

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

What IfProve ItBreak ItCompare

  1. Rose on a Two-Bit State
  2. CompareRose, Changed and an Explicit Past ComparisonL1 Junior

    Compare $rose(sig), $changed(sig) and $past(sig) != sig.

    Reveal the Model Answer

    $rose reports bit 0 rising, which fits single-bit strobes. $changed is true when any bit differs from the previous sample. $past(sig) != sig is the same idea written out. But != gives x for an unknown bit, and an if or an assertion treats x as false. Prefer the system functions for readability and the explicit form when you need a specific old and new value.

    ExpressionTrue whenWatch out
    $rose(sig)Bit 0 went from not-1 to 1Ignores every other bit
    $changed(sig)Any bit differs from the previous sampleSays nothing about which change
    $past(sig) != sigThe same idea, written outGives x for an unknown bit, which acts as false

    Self-Check

    Tick each key point you covered in your answer.

    Spec Misquote

    "$changed is just !$stable but newer, so it is not standard."

    $changed is a standard sampled value function, defined as the negation of $stable.

    Source IEEE 1800-2017 §16.9.3

  3. What IfChecking One Exact State TransitionL1 JuniorL2 Mid-Level

    What if you must detect exactly the move from IDLE to BUSY on a 2-bit state?

    Reveal the Model Answer

    Neither $rose nor $changed says which transition happened. Write it out: $past(state) == IDLE && state == BUSY. Guard the first tick, because $past has no real history there. Use === if unknown values must count as a mismatch.

    Self-Check

    Tick each key point you covered in your answer.

    Half-Truth

    "$rose(state == BUSY) catches IDLE to BUSY."

    It fires on entry to BUSY from any state. Another path into BUSY passes as well.

  4. What IfSampled Value Functions at the First EdgeL2 Mid-Level

    What if req is already 1 at the very first clock edge? Does $rose(req) fire there?

    Reveal the Model Answer

    There is no earlier sample. So the past value is the value in the variable's declaration, not one set later in an initial block. If req was declared 0, or left unknown, a 1 at the first edge counts as a rise. A check that must not fire at time zero should be disabled by reset, which also covers the first edges after power-up.

    Self-Check

    Tick each key point you covered in your answer.

    Missed Corner

    "Sampled value functions are undefined before the second edge, so nothing fires."

    Before the first tick, the history holds the declaration value. A variable declared 0 and driven to 1 before the first edge shows a rise there.

    Source Mehta, SystemVerilog Assertions and Functional Coverage (3rd ed.), §7.7 (PDF p120)

  5. Break ItLevel or Edge in the AntecedentL1 JuniorL2 Mid-Level

    A request is held high until it is served. Why does req |-> ##[1:3] ack fail on a design that answers every request in two cycles, and how does $rose fix it?

    Reveal the Model Answer

    A level antecedent starts a new attempt at every edge where req is high. The attempts started late in a long request have windows that end after the single ack. $rose(req) starts exactly one attempt per request. Use a level only when every cycle of the level really owes its own response.

    Self-Check

    Tick each key point you covered in your answer.

    Half-Truth

    "$rose in the antecedent is just style."

    It changes the number of attempts. With a held request the level form makes one obligation per cycle, which the design never promised.

    Source IEEE 1800-2017 §16.12.7

  6. Prove ItSolve 6.6.8: Answer in TimeSimulator-graded

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

    Open Problem 6.6.8

What People Get Wrong

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

Misconception

"$rose(state) is true whenever the bus value goes up."

Only bit 0 is examined. The twin moves 01 to 10, bit 0 falls, and no rise is seen; the explicit $past comparison counts the move.

Run It

A two-bit state moves from 01 to 10 once. $rose(state) counts the moves.

RUNVerilator · simulator service
Edit the code, then run it
Expected: moves counted: 0 FAIL: $rose looks only at bit 0, which fell from 1 to 0
See the Fix
module tb;
  logic clk = 0;
  logic [1:0] state = 2'b01;            // IDLE = 01, BUSY = 10
  int moves = 0;
  always #5 clk = ~clk;
  // The fix: compare the previous and current values explicitly.
  a_busy: assert property (@(posedge clk) !($past(state) == 2'b01 && state == 2'b10)) else moves++;
  initial begin
    @(negedge clk) state = 2'b10;       // IDLE -> BUSY
    repeat (2) @(negedge clk);
    $display("moves counted: %0d", moves);
    if (moves == 1) $display("PASS: the explicit check saw the move");
    $finish;
  end
endmodule

Prints: moves counted: 1 PASS: the explicit check saw the move

Spec Misquote

"A change from x to 1 is not a rise, because x is not 0."

The standard defines a rise as bit 0 changing to 1 from any other value. So x to 1 and z to 1 both count. Books often simplify this to 0 to 1.

Source IEEE 1800-2017 §16.9.3

Tool as Truth

"Verilator never reports an x-to-1 rise, so it does not count."

Verilator is two-state and cannot hold an x at all, so it cannot show this case either way. The rule comes from the standard.

Source ASIC Point engine notes (Verilator 5.052 SVA probes), row "x/z values"

Learn It, Then Prove It