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

AboutRoadmapCareersInternshipsFAQContactPrivacyTerms
Skip to lesson

Course contents

  • Start Here5
  • SystemVerilog Language Foundations28
  • Object-Oriented SystemVerilog for Verification30
  • Constraint Randomization — Interview-Critical Deep Dive39
  • SystemVerilog Assertions — Interview-Critical Deep Dive41
    • SVA Fundamentals
    • Sequences: Temporal Building Blocks
    • Implication and Property Operators
    • Sampled Value Functions
      • $rose, $fell, $stable, $changed
      • $past: Looking Backward
      • $countones, $onehot, $onehot0, $isunknown
      • Building Data-Integrity Checks
    • Protocol Assertion Cookbook
    • Advanced SVA: Local Variables, Multiclock & More
    • Assertion Debug & Methodology
    • SVA Interview Drills
  • Functional Coverage in SystemVerilog25
  • Testbench Architecture in SystemVerilog24
  • Advanced Language & Integration26
  • Senior & Interview Preparation23
  • Principal-Level Verification34
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
On this page

    Part 4 of 9, lesson 15 of 41Part 4 of 9/Assertions (SVA)/Lesson 15 of 41Intermediate

    $rose, $fell, $stable, $changed

    Edges between clock-tick snapshots: rose, fell, stable, changed, the LSB rule, and glitch blindness.

    A check on a 16-bit status bus used $rose(status) to catch any new flag. It only ever saw bit 0, and a stuck bit 7 went unnoticed for a release.

    After this lesson you can: use $rose, $fell, $stable and $changed correctly on bits and vectors, and choose an edge or a level antecedent.

    Two snapshots decide every edge

    Procedural code detects an edge as an event. @(posedge req) fires the instant req transitions, at any point in time.

    $rose(req) is a comparison of two snapshots. It is true when the current sample of bit 0 is 1 and the previous sample was not 1.

    $fell is the mirror image on falling values. $stable(v) compares the whole vector against its previous sample, and $changed(v) is its exact negation.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    // snippet
    assert property (@(posedge clk) disable iff (!rst_n)
      $rose(req) |-> ##[1:3] $rose(gnt));
    assert property (@(posedge clk) disable iff (!rst_n)
      busy |-> $stable(cfg_reg));
    assert property (@(posedge clk) disable iff (!rst_n)
      $changed(data_bus) |-> valid);

    The rose lane pulses only on the slot where req newly reads 1. The fell lane pulses only where it newly reads 0.

    • Slot 0: req 0 with no earlier sample, so rose 0 and fell 0.

    • Slot 1: req still 0, so both lanes stay 0.

    • Slot 2: req 1 after 0, so rose 1.

    • Slot 3: req still 1, so rose 0: high is not rising.

    • Slot 4: req still 1, so rose 0.

    • Slot 5: req 0 after 1, so fell 1.

    • Slot 6: req still 0, so fell 0.

    • Slot 7: req 1 after 0, so rose 1.

    Bit zero and the unknown table

    A multi-bit argument to $rose silently watches only bit 0. $rose(data_bus) is true when data_bus[0] went to 1, which is almost never the intent.

    For vectors, say what is meant. $changed(data_bus) catches any movement, and $rose(|data_bus) means the bus became non-zero.

    Previous to current

    $rose

    $fell

    $stable

    $changed

    0 to 1

    1

    0

    0

    1

    1 to 0

    0

    1

    0

    1

    X to 1

    1

    0

    0

    1

    X to 0

    0

    1

    0

    1

    Z to 1

    1

    0

    0

    1

    0 to X

    0

    0

    0

    1

    1 to X

    0

    0

    0

    1

    X to X

    0

    0

    1

    0

    1 to 1

    0

    0

    1

    0

    0 to 0

    0

    0

    1

    0

    Four-state values follow the same rule. A snapshot pair ending in 1 with a non-1 predecessor counts as a rise, including X to 1.

    At the first tick, the previous value is the default sampled value: the declaration initializer, or the type default when there is none (X for uninitialized logic, 0 for bit). $stable and $rose there compare against that default, so gate start-up with disable iff or a warm-up qualifier.

    design.sv
    // bad-example
    assert property (@(posedge clk) $rose(data_bus) |-> valid);
    design.sv
    // snippet
    assert property (@(posedge clk) $changed(data_bus) |-> valid);
    assert property (@(posedge clk) $rose(|data_bus) |-> valid);

    Passing a bus to $rose compiles cleanly on every simulator and checks bit 0 only. Reviewers flag it, and interviews use it as a trap.

    Check yourself A 32-bit data_bus goes from 0x04 to 0x00. Does $rose(data_bus) fire?

    No. Bit 0 was 0 in both samples. $changed(data_bus) fires, and $fell(|data_bus) reports the bus returning to zero.

    One attempt or one per cycle

    A level antecedent matches every cycle the level holds. If req stays high for 5 cycles, req |-> ... spawns 5 overlapping attempts.

    An edge antecedent matches once per event. $rose(req) |-> ... spawns one attempt, which is the intent for most request rules.

    Stimulus

    Level antecedent

    Edge antecedent

    req high for ticks 2, 3, 4; gnt once at tick 4

    Attempts at 2, 3, 4; two of them fail

    One attempt at tick 2; it passes

    Rule holds while busy is high

    Correct: the obligation renews each cycle

    Wrong: only the rising cycle is checked

    Pulses that live entirely between clock ticks are invisible to every sampled value function. Neither snapshot captures them, so no edge is reported.

    That blindness is correct for synchronous rules: a glitch no flop captures is harmless. Asynchronous needs, such as glitch detection, need event-based checks instead.

    Likely question: “What is the difference between @(posedge sig) and $rose(sig)?”

    • Event control reacts at the instant of transition, even between clocks.

    • Sampled edge compares two clock-tick snapshots, so sub-cycle pulses never appear.

    • Answer with the glitch case, then volunteer the LSB rule.

    Check yourself One request pulse stays high for 3 cycles and its single grant arrives 2 cycles after the rise. Which antecedent form passes cleanly?

    The edge form $rose(req) |-> ... with one attempt. The level form opens two extra attempts that expire without their own grant.

    Testbench

    The bench counts real $rose, $fell and $changed covers over the 8-beat trace from the diagram, then moves a bus one bit at a time, then holds a request for three ticks under a level and an edge antecedent.

    Predict first The bus goes 00, 02, 03, 00. How often does $rose(bus) fire? And $changed(bus)?

    $rose once: it looks at bit 0 only, which rises on 02 to 03. $changed three times: every step changed some bit.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    module tb_edge_funcs;
      logic clk = 0;
      always #5 clk = ~clk;
      logic sig = 0, req = 0, gnt = 0;
      logic [7:0] bus = 8'h00;
      int rises = 0, falls = 0, changes = 0, bus_rises = 0, bus_changes = 0, level_fails = 0, edge_fails = 0;
    
      cp_rose:    cover property (@(posedge clk) $rose(sig))    rises++;
      cp_fell:    cover property (@(posedge clk) $fell(sig))    falls++;
      cp_changed: cover property (@(posedge clk) $changed(sig)) changes++;
      // On a vector, $rose looks at bit 0 only; $changed looks at every bit.
      cp_bus_rose:    cover property (@(posedge clk) $rose(bus))    bus_rises++;
      cp_bus_changed: cover property (@(posedge clk) $changed(bus)) bus_changes++;
      // One request held for 3 ticks, one grant: level versus edge antecedent.
      ap_level: assert property (@(posedge clk) req |-> ##2 gnt)        else level_fails++;
      ap_edge:  assert property (@(posedge clk) $rose(req) |-> ##2 gnt) else edge_fails++;
    
      initial begin
        // sig over 8 beats: high on beats 2, 3, 4 and 7, as in the diagram.
        for (int t = 0; t < 8; t++) begin
          sig = (t == 2 || t == 3 || t == 4 || t == 7);
          @(negedge clk);
        end
        sig = 0;
        repeat (2) @(negedge clk);
        $display("sig: %0d rises, %0d falls, %0d changes", rises, falls, changes);
        bus = 8'h02; @(negedge clk);                     // only bit 1 moves
        bus = 8'h03; @(negedge clk);                     // bit 0 rises
        bus = 8'h00; @(negedge clk);
        repeat (2) @(negedge clk);
        $display("bus 00 -> 02 -> 03 -> 00: $rose(bus) %0d, $changed(bus) %0d", bus_rises, bus_changes);
        req = 1; repeat (2) @(negedge clk);              // req held for 3 ticks ...
        gnt = 1; @(negedge clk);                          // ... with the grant on the third
        req = 0; gnt = 0;
        repeat (4) @(negedge clk);
        $display("req held 3 ticks, gnt on the 3rd: level antecedent %0d failures, edge antecedent %0d", level_fails, edge_fails);
        if (rises != 2 || falls != 2 || changes != 4 || bus_rises != 1 || bus_changes != 3 || level_fails != 2 || edge_fails != 0)
          $fatal(1, "FAIL: %0d %0d %0d %0d %0d %0d %0d", rises, falls, changes, bus_rises, bus_changes, level_fails, edge_fails);
        $display("PASS: edges counted between snapshots, $rose(bus) saw bit 0 only, and the level antecedent failed twice where the edge passed");
        $finish;
      end
    endmodule
    Terminal
    sig: 2 rises, 2 falls, 4 changes
    bus 00 -> 02 -> 03 -> 00: $rose(bus) 1, $changed(bus) 3
    req held 3 ticks, gnt on the 3rd: level antecedent 2 failures, edge antecedent 0
    PASS: edges counted between snapshots, $rose(bus) saw bit 0 only, and the level antecedent failed twice where the edge passed
    • Edges compare two clock-tick snapshots; pulses between ticks are invisible.

    • $rose and $fell on a vector look at bit 0 only.

    • Edge antecedents start one attempt per event; levels one per cycle.

    Rule of thumb: anchor request rules on $rose, and use $changed for vectors.

    How this was checked

    Run with Verilator 5.048 (--binary --timing --assert, plus --coverage when a listing has a cover property) on 2026-10-18; every bench printed the PASS line shown. Verilator stops at the first $error or failing assertion without an action block, so the benches count failures in the action block. Icarus 13 has no concurrent assertions.

    Related topics

    • Past and gated history

    • One-snapshot classifiers

    Previous

    117 / 275

    Next: $past: Looking Backward

    Up next

    Up next$past: Looking Backward

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error

    See also

    • $countones, $onehot, $onehot0, $isunknown
    • Building Data-Integrity Checks
    clkreqrosefell
    Rise, hold, fall, and rise again on a sampled signal