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

  • How to Use This Course
  • Reading Paths
  • Concept Map
  • Meet DCRouter
  • Glossary
  • Part 0: What Verification Is8
    • Verification, Validation and Test
    • The Cost of an Escape
    • Intent, Design and Implementation
    • You Cannot Test Everything
    • Confidence, Not Proof
    • The Verification Stack
    • Meet DCRouter
    • Drills: What Verification Is
  • Part 1: What Can Go Wrong11
  • Part 2: Specifications as Checkable Rules8
  • Part 3: Observability and Controllability7
  • Part 4: Stimulus11
  • Part 5: Checking11
  • Part 6: Coverage10
  • Part 7: Formal and Simulation10
  • Part 8: Verification Levels and Reuse8
  • Part 9: Planning and Risk9
  • Part 10: Emulation and Prototyping8
  • Part 11: Post-Silicon Validation8
  • Part 12: Bug Economics8
  • Part 13: Debug7
  • Part 14: Sign-Off7
  • Part 15: Verification in Context8
  • Part 16: Case Studies5
  • Part 17: Capstones5
  • Part 18: Interview Preparation6
Loading lesson

‹Part 0: What Verification Is
  1. Topics
  2. First Principles of Verification Strategy
  3. Part 0: What Verification Is
  4. You Cannot Test Everything

Part 0 · What Verification Is · Working (W)

You Cannot Test Everything

Why no amount of simulation can try every case, even for a small block: counting states and input sequences, with DCRouter's 811 bits of state as the example. What that forces verification to become.

On this page

    Note

    Level: Working (W) · Answers: What does it mean for a chip to work?

    Before this: Intent, Design and Implementation, Meet DCRouter

    A new engineer looks at DCRouter, a router you could read in an afternoon, and asks a fair question: it is so small, why not simulate every possible input and be certain? The arithmetic answers in one line. DCRouter holds 811 bits of state. The number of states it could be in has 245 digits. A simulator running for the age of the universe would not visit a measurable fraction of them.

    If even a small design cannot be tested exhaustively, what does testing actually achieve?

    The obvious answer, and why it breaks

    The obvious answer is "more": more tests, more seeds, more cycles, a bigger compute farm, until every case is covered. That intuition comes from software functions with a handful of inputs, where trying them all is sometimes possible. Hardware is different in two ways. It has state: what a block does this cycle depends on everything it has seen before. And it runs every cycle: each clock edge multiplies the possibilities by every input combination. Both grow exponentially, and exponential growth defeats any amount of compute.

    The idea: count before you test

    Two numbers bound what exhaustive testing would need (fact M1):

    • States. A design with k bits of state can be in up to 2^k states. Each extra bit doubles the count.

    • Input sequences. With i input bits per cycle, there are 2^(i·L) different input sequences of L cycles. Bugs often need a particular sequence, not just a particular state.

    states≤2ksequences of length L=2i⋅L

    Not every state is reachable in practice, and many states behave identically, so real designs are smaller than these bounds suggest. But the bounds are so large that even a tiny reachable fraction is out of reach.

    Build it: counting DCRouter

    The model counts DCRouter's state bits from its RTL, then asks how long it would take merely to visit every state of designs of growing size, at an illustrative simulation speed of 10,000 cycles per second and emulation speed of 1,000,000, assuming every single cycle reached a new state (which real tests never do).

    example.py
    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
    """Why exhaustive simulation is impossible: counting states and input sequences.
    
    Part 1 counts DCRouter's state bits from its RTL (FIFO storage and pointers, per-input
    packet state, per-output lock and credit state, registers, sleep control). Part 2 asks how
    long it would take just to visit every possible state of designs of growing size, at an
    illustrative simulation speed of 10,000 cycles per second and emulation speed of 1,000,000,
    even if every cycle reached a new state. Part 3 counts input sequences: DCRouter has 119
    input bits per cycle (valids, data, lasts, credit returns and the APB inputs), so the number
    of distinct 10-cycle input sequences is 2^(119*10).
    """
    import math
    
    inventory = {                         # (bits per copy, copies)
        "FIFO storage, 8 x 17 bits":      (8 * 17, 4),
        "FIFO pointers and count":        (3 + 3 + 4, 4),
        "per-input packet state":         (4 + 5 + 8 + 1 + 2 + 1 + 1, 4),
        "per-output lock, owner, rr, credits": (1 + 2 + 2 + 3, 4),
        "CTRL fields":                    (4 + 1 + 1, 1),
        "ERR_CNT and PKT_CNT":            (8 + 16, 4),
        "sleep and idle counter":         (1 + 4, 1),
    }
    state_bits = sum(b * n for b, n in inventory.values())
    input_bits = 4 + 64 + 4 + 4 + 1 + 1 + 1 + 8 + 32   # in_vld, in_data, in_last, out_crd, psel, penable, pwrite, paddr, pwdata
    SIM, EMU = 1e4, 1e6                                 # cycles per second (illustrative)
    YEAR = 3.15e7                                       # seconds
    
    print(f"DCRouter state bits: {state_bits}  (2^{state_bits} = 10^{state_bits * math.log10(2):.0f} possible states)")
    print(f"DCRouter input bits per cycle: {input_bits}")
    print("state bits:          " + " ".join(f"{b:>7d}" for b in (16, 32, 48, 64, 80, 96)))
    print("log10 of states:     " + " ".join(f"{b * math.log10(2):>7.1f}" for b in (16, 32, 48, 64, 80, 96)))
    print(f"log10 of cycles in a year: simulation {math.log10(SIM * YEAR):.1f}, emulation {math.log10(EMU * YEAR):.1f}")
    rows = []
    for name, speed in (("simulation, years:", SIM), ("emulation, years: ", EMU)):
        logs = [b * math.log10(2) - math.log10(speed * YEAR) for b in (16, 32, 48, 64, 80, 96)]
        rows.append(logs)
        print(f"{name}   " + " ".join(f"{('1e%+.0f' % l):>7s}" for l in logs))
    seq_log10 = input_bits * 10 * math.log10(2)
    print(f"distinct 10-cycle input sequences: 10^{seq_log10:.0f}")
    
    assert state_bits == 811 and input_bits == 119
    assert rows[0][1] > -2.5 and rows[1][3] > 5    # 32 bits: days in simulation; 64 bits: a million years in emulation
    print("PASS: even 64 bits of state outlast any emulator, and DCRouter has 811")

    It prints:

    Diagram
    DCRouter state bits: 811  (2^811 = 10^244 possible states)
    DCRouter input bits per cycle: 119
    state bits:               16      32      48      64      80      96
    log10 of states:         4.8     9.6    14.4    19.3    24.1    28.9
    log10 of cycles in a year: simulation 11.5, emulation 13.5
    simulation, years:      1e-7    1e-2    1e+3    1e+8   1e+13   1e+17
    emulation, years:       1e-9    1e-4    1e+1    1e+6   1e+11   1e+15
    distinct 10-cycle input sequences: 10^358
    PASS: even 64 bits of state outlast any emulator, and DCRouter has 811
    The model's numbers: the state count passes a year of simulation at about 38 bits and a year of emulation at about 45 bits; DCRouter has 811.

    How to read it: the state count rises in a straight line on this log scale, adding three digits for every ten bits. A year of simulation covers about 10^11.5 cycles, which a 38-bit design already exceeds. A 64-bit counter would take about a million years on an emulator. DCRouter, with 811 bits, is beyond any of these by more than two hundred orders of magnitude, and its input sequences are worse still: 10^358 different ten-cycle sequences.

    What this forces verification to become

    If trying everything is impossible, verification has to choose what to try, and justify the choice. Every technique in this course is a different answer to "which tiny fraction is worth running?"

    Strategy

    How it cuts the space

    What it costs or risks

    Directed tests on risky cases

    Engineers pick the cases they believe matter

    Only finds bugs someone imagined

    Random and constrained-random sampling

    Samples the space broadly and cheaply

    Rare corners stay rare (Part 4)

    Coverage

    Measures which planned situations the samples reached

    Only as good as the plan behind it (Part 6)

    Formal proof

    Reasons about every sequence at once, symbolically

    Works on blocks, not whole chips (Part 7)

    Hierarchy and abstraction

    Verifies small pieces thoroughly, then their composition

    Integration bugs live between the pieces (Part 8)

    Risk-based planning

    Spends effort where bugs are likely and costly

    Depends on judging risk well (Part 9)

    How real teams work within the limit

    Practice

    What it does with the impossibility

    Constrained-random verification (SystemVerilog, fact V1)

    Generates millions of legal, varied tests instead of hand-writing a few

    Functional coverage (fact V1)

    Replaces "did we try everything?" with "did we reach everything in the plan?"

    Formal property checking (fact V2)

    Proves properties of control blocks for every sequence the assumptions allow

    Sign-off on evidence

    Accepts a stated residual risk instead of claiming completeness (Part 14)

    What breaks

    A team (illustrative) planned verification of a 16-entry, 4-port arbiter by "running random tests until nothing fails for a week". Nothing failed for a week. The arbiter's bug needed all four ports to request in one cycle while its pointer wrapped, a state the random traffic reached perhaps once a month. A one-line count of the arbiter's state and the probability of that combination would have shown the week proved little, and pointed to either biased stimulus or a formal check of the arbiter, which found the bug in minutes.

    Why this matters

    Senior lens. Whenever someone proposes "run more", ask what fraction of the relevant space "more" adds, and whether the cases that matter are in it. The useful question is never "have we tested everything?" but "which cases have we chosen, why those, and what evidence says the rest are safe?" That question is what verification planning, coverage and sign-off answer.

    Interview

    Asked: "Why not just simulate every input?"

    Weak answer: It would take too long, so we use random tests.

    Strong answer: Because both the state space and the space of input sequences grow exponentially. A design with k state bits has up to 2^k states, and with i input bits per cycle there are 2^(i·L) sequences of length L. Even 48 bits of state is more states than a year of simulation has cycles, and a small router can have hundreds of bits. So verification is a sampling and reasoning problem: choose which cases to run with risk-based planning, sample broadly with constrained random, measure what was reached with coverage, and prove properties of small control blocks formally, then sign off on stated evidence and residual risk.

    Follow-ups: (1) If not exhaustive, how do you know when you have done enough? (2) Where does formal help with this?

    Check yourself A block has 40 bits of state. Could a year of simulation at 10,000 cycles per second visit every state?

    No. 2^40 is about 1.1 × 10^12 states, while a year at 10^4 cycles per second is about 3.2 × 10^11 cycles, and real tests revisit states constantly.

    Check yourself Why do input sequences matter as much as states?

    Many bugs need a particular order of events across cycles, such as a request arriving the cycle after a reset; the number of sequences grows with every cycle of length, far faster than the number of states.

    Check yourself Does unreachable state make exhaustive simulation feasible after all?

    Rarely: the reachable fraction is smaller than 2^k, but for any real design it is still astronomically large; reachability arguments are what formal tools exploit, not simulation.

    Key takeaways

    • States grow as 2^k and input sequences as 2^(i·L): exhaustive simulation is impossible for any real design.

    • Verification is therefore a choice of which cases to run, and the evidence that the choice was good.

    • Every technique in this course (random, coverage, formal, planning) is an answer to that choice.

    Keep going

    Next: Lesson 0.5, Confidence, Not Proof. If proof is out of reach, what exactly does verification give you?

    Related topics

    • Part 0 overview: What Verification Is

    • Formal course: Formal versus Simulation

    Previous

    9 / 160

    Next: Confidence, Not Proof

    Up next

    Up nextConfidence, Not Proof

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Verification, Validation and Test
    • The Cost of an Escape
    • The Verification Stack