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
      • Debugging Assertion Failures
      • When Passing Is the Bug: Vacuity & Coverage
      • Assertion Performance & Noise Control
      • Where Assertions Live
      • The Assertion Review Checklist
    • SVA Interview Drills
  • Functional Coverage in SystemVerilog22
  • Testbench Architecture in SystemVerilog23
  • Advanced Language & Integration25
  • Senior & Interview Preparation21
  • Principal-Level Verification28
Loading lesson

‹Assertion Debug & Methodology
  1. Topics
  2. SystemVerilog
  3. SystemVerilog Assertions — Interview-Critical Deep Dive
  4. Assertion Debug & Methodology
  5. The Assertion Review Checklist

Part 4 · Assertions (SVA) · Intermediate

The Assertion Review Checklist

Review every assertion against six checks, then practice on a flawed module.

On this page

    Why this matters

    A review approved seven assertions with a seven-word comment. Three were vacuous, one had reset polarity reversed, and one could never fail in simulation.

    After this lesson you can: review an assertion file against six checks and repair what fails.

    The six-point checklist

    Everything in this topic compresses into six questions for every assertion in review. Memorize the list, then internalize it on the flawed module below.

    1. COVER PAIRING: does every implication have a cover on its antecedent, and the success shape for critical rules? Zero cover hits is a sign-off blocker.

    2. ANTECEDENT PRECISION: does the attempt start once per transaction, on an edge qualifier, not every cycle of a level?

    3. RESET GATING: is disable iff the correct polarity on the actual reset, including mid-flight attempts as reset asserts?

    4. X-AWARENESS: are X checks explicit? Range and inside checks catch X only by accident (X counts as false in an assertion) and catch nothing on two-state engines; write !$isunknown.

    5. LABEL AND MESSAGE: is the label unique and greppable, with $sampled values and time in the action block?

    6. BOUNDED LIVENESS: is every eventually bounded with a spec-derived window for simulation?

    For each assert property, check in order: a paired cover exists; the antecedent fires once per transaction; disable iff uses the right reset and polarity; X on inputs is detected; the label is unique and the message prints sampled values; liveness is bounded. Any no leads to a fix; all yes leads to approval.
    Applying the six-point checklist to one assertion.

    The exercise: review this module

    This checker hides seven problems. It is not run in this course's checks because Verilator 5.048 does not support s_eventually. Find the seven before reading the key.

    bus_checks.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    // not-run: Verilator 5.048 does not support s_eventually; also a review exercise
    module bus_checks (
      input logic clk, rst_n,
      input logic req, gnt, valid,
      input logic [31:0] data
    );
      // R1: every request eventually granted
      a1: assert property (@(posedge clk)
            req |-> s_eventually gnt);
    
      // R2: data stable while valid high and not granted
      a2: assert property (@(posedge clk) disable iff (rst_n)
            valid && !gnt |=> $stable(data));
    
      // R3: grant only follows a request
      a3: assert property (@(posedge clk) disable iff (!rst_n)
            gnt |-> $past(req))
            else $error("orphan grant: req=%b gnt=%b", req, gnt);
    
      // R4: valid never unknown after reset
      a4: assert property (@(posedge clk) disable iff (!rst_n)
            valid |-> data inside {[0:32'hFFFF_FFFF]});
    endmodule

    Common pitfall

    Reviewing assertions by eyeballing the property text only misses half the checklist. Covers, vacuity data, labels, and reset polarity all live outside the property, and the inverted disable iff above is the most planted bug in senior interviews.

    Answer key and repaired module

    Seven problems: three in a1 (unbounded liveness, a level antecedent and a missing reset gate), inverted reset polarity in a2, raw-signal printing in a3 with labels a1 to a4 that nobody can grep, an obscure range check in a4 that states no X intent, and zero covers across the module.

    The repaired module bounds the grant window, hardens the antecedents, fixes the polarity, checks $isunknown explicitly, and prints sampled values. Its seen mask is harness-only. The testbench confirms that three injected faults fire (timeout, moved data, orphan grant), that the mid-flight reset and the held request stay silent, and that the unknown-data injection holds without firing on two-state checks.

    Check yourself Why is valid |-> data inside {[0:32'hFFFF_FFFF]} a bad check?

    For known values the range is always true. An unknown value makes the comparison X, which an assertion treats as a failure, so it catches X only by accident and never on two-state tools. State the intent: valid |-> !$isunknown(data).

    bus_checks_fixed.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
    module bus_checks_fixed (
      input logic clk, rst_n,
      input logic req, gnt, valid,
      input logic [31:0] data,
      output logic [3:0] seen    // harness-only: bit i latches when check i fires
    );
      localparam int MAX_GNT = 8;               // from the spec
      initial seen = 4'b0;
    
      a1_gnt_bounded: assert property (@(posedge clk) disable iff (!rst_n)
        $rose(req) |-> ##[1:8] gnt)   // literal 8 == MAX_GNT; Verilator needs a numeric range
        else begin
          seen[0] <= 1'b1;
          $display("caught grant timeout at %0t", $time);
        end
    
      a2_data_stable: assert property (@(posedge clk) disable iff (!rst_n)
        valid && !gnt |=> $stable(data))
        else begin
          seen[1] <= 1'b1;
          $display("caught moved data at %0t: %h -> %h (sampled)", $time, $past(data), $sampled(data));
        end
    
      a3_no_orphan: assert property (@(posedge clk) disable iff (!rst_n)
        gnt && $past(rst_n) |-> $past(req))
        else begin
          seen[2] <= 1'b1;
          $display("caught orphan grant at %0t: sampled req=%b gnt=%b", $time, $sampled(req), $sampled(gnt));
        end
    
      a4_data_known: assert property (@(posedge clk) disable iff (!rst_n)
        valid |-> !$isunknown(data))
        else begin
          seen[3] <= 1'b1;
          $display("caught unknown data at %0t while valid", $time);
        end
    endmodule
    
    Terminal
    caught grant timeout at 235000
    caught moved data at 465000: 00000000 -> 00000001 (sampled)
    caught moved data at 475000: 00000001 -> 00000002 (sampled)
    caught moved data at 485000: 00000002 -> 00000003 (sampled)
    caught moved data at 495000: 00000003 -> 00000004 (sampled)
    caught moved data at 515000: 00000004 -> 00000000 (sampled)
    caught orphan grant at 535000: sampled req=0 gnt=1
    PASS: three faults fired as reviewed, reset and held-request cases stayed silent, X held on two-state, covers hit

    Running the review at scale

    Make the checklist a code-review template: six checkbox lines in the pull-request description for any file adding assert property. Automate the mechanical points with lint.

    Lint for assert-without-cover, missing disable iff, s_eventually outside formal-only files, and unlabeled assertions. Pull per-assertion vacuity statistics into the regression dashboard, and re-review after design changes, not just at creation.

    Interview

    Senior interviews hand over a flawed module like the exercise and ask what is wrong. Work the checklist out loud in order, trace disable iff polarity character by character, and close with which problems a green regression would have hidden: the inverted polarity and the missing covers.

    Check yourself A renamed qualifier turns a precise antecedent vacuous overnight. What catches it?

    The antecedent cover count dropping to zero at the next regression, provided covers ship with asserts and sign-off reviews them. Re-review after design changes exists for exactly this rot.

    Remember

    • Cover pair, antecedent, reset, X, label and message, bounded liveness.

    • A check that cannot fail has not been reviewed.

    • Record cover hits at the next regression.

    Rule of thumb: approve an assertion only after all six checks pass.

    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

    • Where Assertions Live

    Previous

    132 / 259

    Next: SVA Interview Drills

    Up next

    Up nextSVA Interview Drills

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Debugging Assertion Failures
    • When Passing Is the Bug: Vacuity & Coverage
    • Assertion Performance & Noise Control