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. $countones, $onehot, $onehot0, $isunknown

Part 4 · Assertions (SVA) · Intermediate

$countones, $onehot, $onehot0, $isunknown

Bit-counting and classification of a sampled vector, X handling, one-hot FSM and grant checks, and X-free payload assertions.

On this page

    Classifying a single sampled vector

    Unlike $rose or $past, these four functions look at one snapshot — no history involved. $countones(v) returns the number of bits that are exactly 1. $onehot(v) is true when exactly one bit is 1; $onehot0(v) relaxes that to at most one bit (zero or one) — the right check for grant vectors that may be idle. $isunknown(v) is true when any bit is X or Z.

    X handling is the part interviews probe: $countones counts only solid 1s — X and Z bits contribute zero. Consequently $onehot(4'b1x00) is true (one solid 1; the X is not counted), which can mask a corrupted one-hot register. A robust one-hot check therefore pairs $onehot with !$isunknown.

    Diagram
    X HANDLING REFERENCE
    
      vector v      $countones  $onehot  $onehot0  $isunknown
      ─────────────────────────────────────────────────────────
      4'b0000           0          0        1          0
      4'b0100           1          1        1          0
      4'b0110           2          0        0          0
      4'b1x00           1          1*       1*         1   * X masked!
      4'b0x00           0          0        1*         1
      4'bxxxx           0          0        1*         1
      4'bz010           1          1*       1*         1
    
      Rule: X/Z bits are simply NOT counted as ones.
      $onehot/$onehot0 can return true on corrupted vectors —
      always AND with !$isunknown when X-safety matters.

    One-hot FSM state check

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // One-hot encoded FSM: exactly one state bit set, always X-free
    typedef enum logic [3:0] {
      S_IDLE = 4'b0001, S_FETCH = 4'b0010,
      S_EXEC = 4'b0100, S_WB    = 4'b1000
    } state_e;
    state_e state;
    
    // Exactly one bit, and no X/Z anywhere in the register
    assert property (@(posedge clk) disable iff (!rst_n)
      $onehot(state) && !$isunknown(state));
    Diagram
    tick           :   1      2      3      4      5
      state (sampled):  0001   0010   0110   0x00   1000
      $onehot        :   1      1      0      0      1
      $isunknown     :   0      0      0      1      0
      assertion      :  PASS   PASS   FAIL   FAIL   PASS
                                       ^      ^
                         two bits set ─┘      └─ X corruption caught only
                                                 because of !$isunknown;
                                                 $onehot0(0x00) alone = true

    Why this beats a default-case check in RTL: the assertion fires the very cycle the register is corrupted (by an SEU model, an X from an uninitialized path, or a decode bug), with a message pointing at the exact signal — instead of the FSM silently sitting in a dead state until a downstream timeout.


    Arbiter mutual exclusion and X-free payloads

    The grant vector of an arbiter is the canonical $onehot0 customer: zero grants is legal (no requester), two grants is a catastrophic bus conflict. A second classic is conservation: grants only go to requesters. The third is the X check on payloads — X on a data bus is only a bug when someone is consuming the data, so qualify it with valid. An unqualified !$isunknown(data) fires constantly on idle buses that legitimately float.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // 1. Never two grants in the same cycle (idle allowed)
    assert property (@(posedge clk) disable iff (!rst_n)
      $onehot0(gnt) && !$isunknown(gnt));
    
    // 2. Conservation: every grant bit had a matching request
    assert property (@(posedge clk) disable iff (!rst_n)
      (gnt & ~req) == '0);
    
    // 3. Payload X check — qualified by the implication
    assert property (@(posedge clk) disable iff (!rst_n)
      valid |-> !$isunknown(data) && !$isunknown(strb));
    
    // 4. Exactly-one-grant only when someone requests
    assert property (@(posedge clk) disable iff (!rst_n)
      (|req) |-> $onehot(gnt) or ##1 $onehot(gnt));
    Diagram
    Arbiter mutual exclusion, 3 requesters
    
      tick           :   1     2     3     4     5     6
      req  (sampled) :  000   011   011   100   000   010
      gnt  (sampled) :  000   010   001   110   000   010
      $onehot0(gnt)  :   1     1     1     0     1     1
      gnt & ~req     :  000   000   000   010   000   000
      check 1        :  PASS  PASS  PASS  FAIL  PASS  PASS
      check 2        :  PASS  PASS  PASS  FAIL  PASS  PASS
                                           ^
                tick 4: two grants AND a grant (bit1) without request —
                both assertions fire the same cycle, naming the rule broken

    Combining with implication

    These functions return plain booleans, so they slot directly into implications as antecedent qualifiers or consequent checks. The pattern “property holds only while enabled” is just enable |-> $onehot(sel). Resist the temptation to bury the qualification inside a boolean (!enable || $onehot(sel)) — it evaluates identically here, but the implication form documents intent, shows up as a vacuous pass when disabled (visible in coverage), and extends naturally when the consequent later grows sequence operators.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // Mode-qualified one-hot: lane select must be one-hot only in
    // striped mode; in mirror mode all-lanes (all ones) is also legal.
    assert property (@(posedge clk) disable iff (!rst_n)
      (mode == STRIPED) |-> $onehot(lane_sel));
    
    assert property (@(posedge clk) disable iff (!rst_n)
      (mode == MIRROR) |-> ($onehot(lane_sel) || lane_sel == '1));
    
    // Population-count bound: at most 4 outstanding tags
    assert property (@(posedge clk) disable iff (!rst_n)
      $countones(tag_in_flight) <= 4);

    Interview angle

    The high-frequency question is $onehot vs $onehot0: exactly-one versus at-most-one, with the arbiter grant vector as the example where idle must be legal. The differentiator question is X handling — most candidates do not know that $onehot(4'b1x00) is true, and explaining why you pair it with !$isunknown signals real-world scar tissue. Expect “write an assertion that the data bus is never X” as a trap: the correct answer qualifies with valid |-> and you should say why the unqualified version drowns you in failures on idle cycles.

    Key takeaways

    • $countones counts solid 1s only; X and Z bits contribute nothing.

    • $onehot = exactly one bit; $onehot0 = at most one — grants use $onehot0, one-hot FSM state uses $onehot.

    • X can hide inside a passing $onehot — pair with !$isunknown for X-safe checks.

    • Qualify $isunknown payload checks with valid — X on an idle bus is not a bug.

    • These are single-snapshot classifiers; combine with implication to scope when they must hold.

    Common pitfalls

    • Trusting $onehot alone on a state register — 4'b1x00 passes while the FSM is corrupted.

    • Asserting !$isunknown(data) unconditionally — fires every idle cycle on a floating bus.

    • Using $onehot on a grant vector that is legally idle — zero grants fails; you wanted $onehot0.

    • Forgetting conservation (gnt & ~req == 0) — one-hot grants to a non-requester still pass mutual exclusion.

    • Re-implementing $countones with a hand-rolled loop in a checker — slower and X-handling diverges.

    Previous

    144 / 296

    Next: Sampled-Value Edge Cases

    Up next

    Up nextSampled-Value Edge Cases

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • $rose, $fell, $stable, $changed
    • Sampled Functions with Clock & Gating Arguments
    • Building Data-Integrity Checks