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

  • SystemVerilog Language Foundations34
  • Object-Oriented SystemVerilog for Verification33
  • Constraint Randomization — Interview-Critical Deep Dive56
  • SystemVerilog Assertions — Interview-Critical Deep Dive54
    • SVA Fundamentals
    • Sequences: Temporal Building Blocks
    • Implication & Property Operators
    • Sampled Value Functions
      • $rose, $fell, $stable, $changed
      • $past: Looking Backward
      • $countones, $onehot, $onehot0, $isunknown
      • Sampled-Value Edge Cases
      • Sampled Functions with Clock & Gating Arguments
      • Building Data-Integrity Checks
    • Protocol Assertion Cookbook
    • Advanced SVA: Local Variables, Multiclock & More
    • Assertion Debug & Methodology
    • Interview SVA Patterns — Write-the-Assertion Drills
    • SVA Interview Q&A — Deep Answers
  • Functional Coverage in SystemVerilog28
  • Testbench Architecture in SystemVerilog32
  • Advanced Language & Integration30
  • Senior & Interview Preparation29
Loading lesson

‹Sampled Value Functions
  1. Topics
  2. SystemVerilog
  3. SystemVerilog Assertions — Interview-Critical Deep Dive
  4. Sampled Value Functions
  5. $rose, $fell, $stable, $changed

Part 4 · Assertions (SVA) · Intermediate

$rose, $fell, $stable, $changed

Edge detection on sampled values vs @posedge events, the LSB rule, the X-transition table, and level vs edge antecedents.

On this page

    Edges between samples, not events on wires

    Procedural code detects an edge as an event — @(posedge req) fires the instant req transitions, at any point in time. $rose(req) is something entirely different: it compares the value of req sampled at the current clock tick against the value sampled at the previous clock tick, and returns true when that pair is (not-1, 1). No clock tick, no edge — a pulse that rises and falls between two clock edges is invisible to $rose because neither snapshot ever captured it high.

    The four functions split into two families. $rose and $fell are edge detectors on the least significant bit of their argument. $stable and $changed are full-vector comparators: $stable(v) is true when every bit of v matches the previous sample, and $changed(v) is its exact negation.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // All four functions, sampled at posedge clk by the property clock
    property p_grant_follows_req;
      @(posedge clk) disable iff (!rst_n)
        $rose(req) |-> ##[1:3] $rose(gnt);
    endproperty
    assert property (p_grant_follows_req);
    
    // $stable on a full vector: config must not move while the core is busy
    assert property (@(posedge clk) disable iff (!rst_n)
      busy |-> $stable(cfg_reg));
    
    // $changed: every data movement must be flagged by a valid pulse
    assert property (@(posedge clk) disable iff (!rst_n)
      $changed(data_bus) |-> valid);

    Cycle-by-cycle waveforms

    Replay these by hand — interviewers love asking you to mark exactly which tick each function returns true. Remember the value row shows the sampled value at each tick (Preponed snapshot), and each function compares tick N against tick N−1.

    Diagram
    $rose / $fell on a single-bit signal
    
      tick         :   1    2    3    4    5    6    7    8
      clk          :   ┌┐   ┌┐   ┌┐   ┌┐   ┌┐   ┌┐   ┌┐   ┌┐
      req (sampled):   0    0    1    1    1    0    0    1
                                 ^              ^         ^
      $rose(req)   :   -    0    1    0    0    0    0    1
      $fell(req)   :   -    0    0    0    0    1    0    0
      $stable(req) :   -    1    0    1    1    0    1    0
      $changed(req):   -    0    1    0    0    1    0    1
    
      tick 3: previous sample 0, current 1  → $rose=1
      tick 4: previous sample 1, current 1  → $rose=0  (still high ≠ rising)
      tick 6: previous sample 1, current 0  → $fell=1
      tick 1: no previous sample exists → previous value treated as X,
              so $stable is false and $rose(req) with req=0 is false
    Diagram
    Glitch invisibility: pulse between ticks is never seen
    
      tick         :    1         2         3
      clk          :    ┌──┐      ┌──┐      ┌──┐
      req (actual) : ___________┌──┐_________________
                                └──┘  ← rises AND falls between ticks 2 and 3
      req (sampled):    0         0         0
      $rose(req)   :    -         0         0   ← never fires
    
      @(posedge req) in procedural code WOULD trigger here.
      $rose(req) under @(posedge clk) cannot — no snapshot saw req=1.

    The LSB rule and the X-transition table

    Pass a multi-bit expression to $rose and it silently watches only bit 0. $rose(data_bus) is true when data_bus[0] went to 1 — almost never what you meant. This compiles cleanly on every simulator, which is exactly why it is a classic code-review and interview trap. For vectors, say what you mean: $changed(data_bus), or $rose(|data_bus) if you want “bus became non-zero”.

    The 4-state definition matters too: $rose is true when the LSB changes to 1 from any non-1 value — including from X or Z. Right out of reset, a signal whose snapshot history is X→1 reports a rise. That can fire assertions during bring-up before the design is meaningfully initialized, which is one reason disable iff (!rst_n) belongs on nearly every property.

    Diagram
    X-TRANSITION TABLE (LSB of the argument)
    
      previous → current   $rose   $fell   $stable  $changed
      ───────────────────────────────────────────────────────
          0    →   1         1       0        0        1
          1    →   0         0       1        0        1
          x    →   1         1       0        0        1   ← x→1 counts as rose
          x    →   0         0       1        0        1   ← x→0 counts as fell
          z    →   1         1       0        0        1
          0    →   x         0       0        0        1   ← to-X: neither edge,
          1    →   x         0       0        0        1     but $changed fires
          x    →   x         0       0        1        0   ← X to X is "stable"
          1    →   1         0       0        1        0
          0    →   0         0       0        1        0
    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    // WRONG: watches only data_bus[0]
    assert property (@(posedge clk) $rose(data_bus) |-> valid);
    
    // RIGHT: any movement on the vector
    assert property (@(posedge clk) $changed(data_bus) |-> valid);
    
    // RIGHT: bus transitioned from all-zero to non-zero
    assert property (@(posedge clk) $rose(|data_bus) |-> valid);

    Level vs edge antecedents

    Choosing req |-> ... versus $rose(req) |-> ... changes how many evaluation threads you spawn. A level antecedent matches every cycle the level holds — if req stays high for 5 cycles you get 5 overlapping attempts, 5 potential failures for one stuck request, and noisy logs. An edge antecedent matches once per event, which is usually the intent for “when a request arrives, then...” style rules. Use the level form only when the rule genuinely applies continuously, such as “while busy, config is stable”.

    Diagram
    Level vs edge antecedent: attempts spawned
    
      tick          :   1    2    3    4    5    6    7
      req (sampled) :   0    1    1    1    0    0    0
    
      req |-> ##2 gnt        attempts start at ticks 2,3,4  (three threads)
      $rose(req) |-> ##2 gnt attempt starts at tick 2 only  (one thread)
    
      If gnt arrives exactly once at tick 4:
        edge form  → tick-2 attempt checks gnt at tick 4 → PASS, done
        level form → tick-3 attempt checks gnt at tick 5 → FAIL
                     tick-4 attempt checks gnt at tick 6 → FAIL
                     two spurious failures from one transaction

    Interview angle

    The two most common probes here: “What is the difference between @(posedge sig) and $rose(sig)?” — answer with the sampling model: one is an asynchronous event, the other a comparison of two clock-tick snapshots, so sub-cycle pulses are invisible to $rose. And “what does $rose of a bus mean?” — the LSB rule. Strong candidates also volunteer the X table (x→1 is a rise) and explain when they would deliberately choose a level antecedent over an edge one. If asked to write “grant within 3 cycles of request” on a whiteboard, start from $rose(req) |-> ##[1:3] gnt and say why you picked the edge form.

    Key takeaways

    • $rose/$fell compare consecutive sampled values of the LSB — they are not event controls.

    • $stable/$changed compare the entire vector; use them (or a reduction) for multi-bit signals.

    • x→1 counts as $rose and x→0 as $fell — gate bring-up with disable iff.

    • Edge antecedents spawn one attempt per event; level antecedents spawn one per cycle held.

    • Pulses that live entirely between clock ticks are invisible to all sampled value functions.

    Common pitfalls

    • $rose(data_bus) on a vector — silently checks bit 0 only; compiles without warning.

    • Using a level antecedent for a one-shot rule — N overlapping attempts and duplicate failures.

    • Expecting $rose to catch a glitch the waveform viewer shows between edges — it cannot.

    • Forgetting that tick 1 has no previous sample — $stable is false and X-history can fake an edge.

    • Writing $rose(req) when req can legally start high before reset release — the rise is never seen.

    Previous

    142 / 296

    Next: $past: Looking Backward

    Up next

    Up next$past: Looking Backward

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • $countones, $onehot, $onehot0, $isunknown
    • Sampled-Value Edge Cases
    • Sampled Functions with Clock & Gating Arguments