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

  • Start Here6
  • SystemVerilog Language Foundations28
  • Object-Oriented SystemVerilog for Verification30
  • Constraint Randomization — Interview-Critical Deep Dive36
  • SystemVerilog Assertions — Interview-Critical Deep Dive40
    • SVA Fundamentals
    • Sequences: Temporal Building Blocks
    • Implication and Property Operators
    • Sampled Value Functions
    • Protocol Assertion Cookbook
    • Advanced SVA: Local Variables, Multiclock & More
    • Assertion Debug & Methodology
    • SVA Interview Drills
      • Handshake Drills
      • Pulse & Stability Drills
      • Ordering & Counting Drills
      • Data & Reset Drills
      • FSM & Arbiter Drills
      • Q&A: Assertion Fundamentals
      • Q&A: Operators & Semantics
      • Q&A: Vacuity, Debug & Formal
  • Functional Coverage in SystemVerilog22
  • Testbench Architecture in SystemVerilog23
  • Advanced Language & Integration25
  • Senior & Interview Preparation21
  • Principal-Level Verification28
Loading lesson

‹SVA Interview Drills
  1. Topics
  2. SystemVerilog
  3. SystemVerilog Assertions — Interview-Critical Deep Dive
  4. SVA Interview Drills
  5. Pulse & Stability Drills

Part 4 · Assertions (SVA) · Intermediate

Pulse & Stability Drills

Drill: a one-cycle pulse, a strobe exactly 3 cycles wide, and data stable while a transfer waits.

On this page

    Why this matters

    A pulse check written as $rose(kick) |-> !kick failed on every pulse in the first run. It asked for kick to be both 1 and 0 in the same cycle.

    After this lesson you can: write one-cycle pulse, exact-width and stable-while-waiting checks that every simulator checks the same way.

    The three prompts

    Drill 1. kick is always a one-cycle pulse.

    Drill 2. strobe, once it rises, is high for exactly 3 cycles and then low.

    Drill 3. valid, ready and an 8-bit data: while valid waits for ready, data does not change.

    Write the three assertions before opening the reveal. Copy the starter into the Code Lab, replace each 1'b1 with your property (add modeling code above it if you need state), and run it on Verilator with assertions on. The grader runs legal traffic, where your assertions must stay silent, then one planted bug per drill, which yours must report. If an answer uses a repetition, or a range followed by more steps, and the grader says it missed its bug, read the tool notes on the sequences pages: Verilator 5.048 misses some failures in those forms.

    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
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    // SVA drill starter: write each property (and any modeling code), then run it.
    // SVA drills: pulses and stability. Each drill has its own signals.
    module tb_sva_pulse;
      logic clk = 0, rst_n = 0;
      always #5 clk = ~clk;
      logic kick = 0;                          // drill 1: kick is always a one-cycle pulse
      logic strobe = 0;                        // drill 2: strobe is high for exactly 3 cycles
      logic valid = 0, ready = 0;              // drill 3: data holds while valid waits for ready
      logic [7:0] data = 0;
      int f1 = 0, f2 = 0, f3 = 0;
    
      // Your answers: one property per drill, plus any modeling code you need.
      ap_drill1: assert property (@(posedge clk) disable iff (!rst_n)
        1'b1   // replace 1'b1 with your property
      ) else f1++;
      ap_drill2: assert property (@(posedge clk) disable iff (!rst_n)
        1'b1   // replace 1'b1 with your property
      ) else f2++;
      ap_drill3: assert property (@(posedge clk) disable iff (!rst_n)
        1'b1   // replace 1'b1 with your property
      ) else f3++;
    
      // The grader: legal traffic first, then one planted bug per drill.
      task automatic pulse(int width);
        @(negedge clk) kick = 1;
        repeat (width) @(negedge clk);
        kick = 0;
        repeat (2) @(negedge clk);
      endtask
      task automatic strobe_for(int width);
        @(negedge clk) strobe = 1;
        repeat (width) @(negedge clk);
        strobe = 0;
        repeat (3) @(negedge clk);
      endtask
      task automatic offer(logic [7:0] d, int wait_cycles, bit change);
        @(negedge clk) valid = 1; data = d;
        repeat (wait_cycles) begin @(negedge clk); if (change) data = data + 1; end
        ready = 1; @(negedge clk) ready = 0; valid = 0;
        repeat (2) @(negedge clk);
      endtask
      function automatic int verdict(string name, int clean, int caught);
        if (clean != 0) begin $display("%s: wrong, it fired %0d times on legal traffic (too strict)", name, clean); return 1; end
        if (caught == 0) begin $display("%s: wrong, it missed its planted bug (too loose)", name); return 1; end
        $display("%s: ok", name);
        return 0;
      endfunction
    
      initial begin
        int c1, c2, c3, wrong;
        repeat (2) @(negedge clk);
        rst_n = 1;
        repeat (3) pulse(1);
        repeat (2) strobe_for(3);
        offer(8'h10, 0, 0); offer(8'h20, 3, 0);
        c1 = f1; c2 = f2; c3 = f3;
        pulse(2);                      // planted: kick held for 2 cycles
        strobe_for(2);                 // planted: a strobe one cycle short
        offer(8'h30, 2, 1);            // planted: data changes while waiting
        wrong = verdict("drill 1, one-cycle pulse", c1, f1 - c1)
              + verdict("drill 2, strobe exactly 3 wide", c2, f2 - c2)
              + verdict("drill 3, data stable while stalled", c3, f3 - c3);
        if (wrong != 0) $fatal(1, "FAIL: %0d of 3 drills wrong", wrong);
        $display("PASS: all 3 drills right");
        $finish;
      end
    endmodule
    Predict first Before you write drill 1: what is wrong with $rose(kick) |-> !kick?

    It contradicts itself. $rose(kick) means kick is 1 in this cycle, so !kick in the same cycle can never hold and every pulse fails. The low cycle is the next one: |=>.

    Check yourself Reveal one set of answers (open only after your own run)

    One set of answers, run through the same grader:

    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
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    // SVA drills: pulses and stability. Each drill has its own signals.
    module tb_sva_pulse;
      logic clk = 0, rst_n = 0;
      always #5 clk = ~clk;
      logic kick = 0;                          // drill 1: kick is always a one-cycle pulse
      logic strobe = 0;                        // drill 2: strobe is high for exactly 3 cycles
      logic valid = 0, ready = 0;              // drill 3: data holds while valid waits for ready
      logic [7:0] data = 0;
      int f1 = 0, f2 = 0, f3 = 0;
    
      // Your answers: one property per drill, plus any modeling code you need.
      ap_drill1: assert property (@(posedge clk) disable iff (!rst_n)
        $rose(kick) |=> !kick                                         // ANSWER
      ) else f1++;
      ap_drill2: assert property (@(posedge clk) disable iff (!rst_n)
        $rose(strobe) |-> strobe ##1 strobe ##1 strobe ##1 (strobe == 0)   // ANSWER
      ) else f2++;
      ap_drill3: assert property (@(posedge clk) disable iff (!rst_n)
        (valid && !ready) |=> $stable(data)                           // ANSWER
      ) else f3++;
    
      // The grader: legal traffic first, then one planted bug per drill.
      task automatic pulse(int width);
        @(negedge clk) kick = 1;
        repeat (width) @(negedge clk);
        kick = 0;
        repeat (2) @(negedge clk);
      endtask
      task automatic strobe_for(int width);
        @(negedge clk) strobe = 1;
        repeat (width) @(negedge clk);
        strobe = 0;
        repeat (3) @(negedge clk);
      endtask
      task automatic offer(logic [7:0] d, int wait_cycles, bit change);
        @(negedge clk) valid = 1; data = d;
        repeat (wait_cycles) begin @(negedge clk); if (change) data = data + 1; end
        ready = 1; @(negedge clk) ready = 0; valid = 0;
        repeat (2) @(negedge clk);
      endtask
      function automatic int verdict(string name, int clean, int caught);
        if (clean != 0) begin $display("%s: wrong, it fired %0d times on legal traffic (too strict)", name, clean); return 1; end
        if (caught == 0) begin $display("%s: wrong, it missed its planted bug (too loose)", name); return 1; end
        $display("%s: ok", name);
        return 0;
      endfunction
    
      initial begin
        int c1, c2, c3, wrong;
        repeat (2) @(negedge clk);
        rst_n = 1;
        repeat (3) pulse(1);
        repeat (2) strobe_for(3);
        offer(8'h10, 0, 0); offer(8'h20, 3, 0);
        c1 = f1; c2 = f2; c3 = f3;
        pulse(2);                      // planted: kick held for 2 cycles
        strobe_for(2);                 // planted: a strobe one cycle short
        offer(8'h30, 2, 1);            // planted: data changes while waiting
        wrong = verdict("drill 1, one-cycle pulse", c1, f1 - c1)
              + verdict("drill 2, strobe exactly 3 wide", c2, f2 - c2)
              + verdict("drill 3, data stable while stalled", c3, f3 - c3);
        if (wrong != 0) $fatal(1, "FAIL: %0d of 3 drills wrong", wrong);
        $display("PASS: all 3 drills right");
        $finish;
      end
    endmodule
    Terminal
    drill 1, one-cycle pulse: ok
    drill 2, strobe exactly 3 wide: ok
    drill 3, data stable while stalled: ok
    PASS: all 3 drills right

    Why these answers

    A width rule needs a terminator. $rose(strobe) |-> strobe [*3] checks that strobe lasted at least 3 cycles and says nothing about the fourth; adding ##1 (strobe == 0) closes it. The reveal writes the run out as strobe ##1 strobe ##1 strobe, the form Verilator 5.048 checks reliably; strobe [*3] ##1 (strobe == 0) passed this grader too, but the repetition lessons showed cases where the compact form missed a break. And the terminator is (strobe == 0), not !strobe, because Verilator rejects ! straight after ##1.

    Stability is a level rule: every cycle that valid waits without ready, the next cycle's data must match. (valid && !ready) |=> $stable(data) renews the obligation each waiting cycle, which is exactly what the spec says.

    Common pitfall

    Writing $stable(data) in the cycle valid rises compares against the value before the offer and fires on legal traffic. Start the obligation from the waiting cycle and look one cycle ahead.

    Interview

    Likely follow-ups: allow widths 2 to 4, or let data change only when valid is low. Each is one edit to the answers above; say which line changes before writing it.

    Remember

    • The low cycle after a pulse is the next one: |=>.

    • A width rule needs a terminator.

    • Stability rules renew every waiting cycle.

    Rule of thumb: every width check names the cycle where the signal must be low again.

    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.

    The starter was run with every property left as 1'b1, and its grader reported all three drills wrong; the revealed answers passed the same grader.

    Related topics

    • Ordering & Counting Drills

    Previous

    134 / 259

    Next: Ordering & Counting Drills

    Up next

    Up nextOrdering & Counting Drills

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Data & Reset Drills
    • FSM & Arbiter Drills
    • Q&A: Assertion Fundamentals