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
  • Part 1: What Can Go Wrong11
    • A Taxonomy of Bugs
    • Specification Bugs
    • Corner Cases and Boundaries
    • Concurrency and Races
    • Integration and Interface Bugs
    • Configuration and Mode Bugs
    • Performance Bugs
    • Reset, Clock and Power Bugs
    • Where Bugs Hide
    • Classifying the Bug Zoo
    • Drills: What Can Go Wrong
  • 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 1: What Can Go Wrong
  1. Topics
  2. First Principles of Verification Strategy
  3. Part 1: What Can Go Wrong
  4. Configuration and Mode Bugs

Part 1 · What Can Go Wrong · Senior (S)

Configuration and Mode Bugs

Parameters, registers and operating modes multiply the space a design must work in, and many bugs appear only in one combination. Why the default configuration hides them, how many configurations to test, and how pairwise selection covers every pair of settings with a fraction of the builds.

On this page

    Note

    Level: Senior (S) · Answers: What can go wrong?

    Before this: Integration and Interface Bugs

    A configurable interconnect IP (illustrative) ships to its fifth customer, the first to use two ports with 32-byte data. Every regression had run the default configuration: four ports, 16 bytes. In the customer's configuration, a width conversion in the arbiter truncates every other burst. The bug had been in the RTL since the first release, in a combination nobody had built.

    How do configurations and modes hide bugs, and how many of them must be verified?

    The obvious answer, and why it breaks

    The obvious approach verifies the default configuration thoroughly, on the reasoning that the logic is the same in every configuration. It is not: parameters change widths, generate different logic, change which branches are reachable and which limits are hit. Registers and modes do the same at run time. A bug in a branch that only one combination reaches is invisible in every other, and the default is only one point in the space.

    The idea: the space multiplies

    configurations=k∏​vk​DCRouter’s CTRL: 24⋅2⋅2=64
    • Build-time parameters: each value can generate different logic; each combination is effectively a different design.

    • Run-time registers and modes: DCRouter's CTRL alone has 64 settings (4 port enables, priority on or off, low power on or off), before any traffic.

    • Interactions matter more than single values: a bug often needs two settings together (two ports and wide data; priority off and a heavy load).

    Build it: covering pairs, not products

    If most configuration bugs need at most two settings together, you do not need every combination; you need every pair of values to appear in some build. The model compares all 256 builds of a four-parameter IP with 16 builds chosen from orthogonal Latin squares (fact M5), and with 16 random builds.

    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
    """Configuration bugs: covering every pair of settings without testing every combination.
    
    An IP block with four parameters, each with four legal values (illustrative: FIFO depth,
    data width, number of ports, arbitration mode). Testing every combination needs 4^4 = 256
    builds. A configuration bug that needs two specific values together (say depth 2 with
    4 ports) is found by any set of builds that contains that pair.
    Two mutually orthogonal Latin squares of order 4 give 16 builds in which every pair of
    values of every two parameters appears at least once. The model builds them, checks the
    pair coverage, and compares with 16 builds chosen at random.
    """
    import itertools, random
    
    V = 4
    # Latin squares over GF(4) elements {0,1,2,3}: L1(r,c) = r + c, L2(r,c) = r + 2c (field arithmetic)
    EXP = [1, 2, 3, 1, 2, 3]                  # powers of the GF(4) generator: 1, a, a+1
    LOG = {1: 0, 2: 1, 3: 2}
    def gmul(a, b):
        return 0 if a == 0 or b == 0 else EXP[LOG[a] + LOG[b]]
    builds = [(r, c, r ^ c, r ^ gmul(2, c)) for r in range(V) for c in range(V)]   # addition in GF(4) is XOR
    
    def pair_coverage(rows):
        have = set()
        for row in rows:
            for (i, a), (j, b) in itertools.combinations(enumerate(row), 2):
                have.add((i, j, a, b))
        total = len(list(itertools.combinations(range(4), 2))) * V * V
        return len(have), total
    
    full = list(itertools.product(range(V), repeat=4))
    c16, total = pair_coverage(builds)
    rng = random.Random(4)
    rand_cov = sorted(pair_coverage(rng.sample(full, 16))[0] for _ in range(200))
    print(f"every combination: {len(full)} builds")
    print(f"orthogonal array: {len(builds)} builds cover {c16} of {total} value pairs")
    print(f"16 random builds: cover {rand_cov[len(rand_cov) // 2]} of {total} pairs (median of 200 tries), worst {rand_cov[0]}")
    assert c16 == total == 96 and rand_cov[-1] < total
    print("PASS: 16 well-chosen builds cover all 96 value pairs that 256 builds would; 16 random builds never do")

    It prints:

    Diagram
    every combination: 256 builds
    orthogonal array: 16 builds cover 96 of 96 value pairs
    16 random builds: cover 63 of 96 pairs (median of 200 tries), worst 48
    PASS: 16 well-chosen builds cover all 96 value pairs that 256 builds would; 16 random builds never do

    How to read it: 16 well-chosen builds contain all 96 pairs of values that the full 256 would, so any bug triggered by two settings together appears in one of them. Sixteen random builds typically cover only 63 pairs and never all 96. NIST studies of real failures found most were triggered by one or two interacting parameters and all by six or fewer (fact M5), which is why pairwise (and higher-strength) selection is effective.

    The design space

    Strategy

    Builds

    Finds

    Misses

    Default only

    1

    Bugs present everywhere

    Every configuration-specific bug

    Every combination

    Product of all values

    Everything (for that axis)

    Affordable only for tiny spaces

    Pairwise (covering arrays)

    Roughly the square of the largest value count

    Any bug needing two settings

    Bugs needing three or more together

    Higher strength (3-way)

    More builds

    Bugs needing three settings

    Rarer higher interactions

    Random configurations per run

    Many, cheap

    A growing sample

    No guarantee on any pair

    Customer configurations

    As shipped

    What real users hit

    Whatever the next customer chooses

    How real teams verify configurable designs

    Practice

    Purpose

    Randomised register setup at the start of each test

    Run-time modes vary across the regression

    Configuration coverage (values and crosses)

    Shows which settings and pairs were actually tested

    Pairwise build lists for parameters

    Covers all two-way interactions at modest cost

    Every shipped configuration in the regression

    Customers' builds are never untested

    What breaks

    DCRouter has four configuration bugs. Two concern the priority setting: one ignores priority when it is enabled (BUG_6), the other applies it when it is disabled (BUG_7). A test that never writes CTRL runs only the reset configuration, with priority enabled, so it can find BUG_6 but never BUG_7, which exists only in the configuration nobody set. Another lets a disabled port accept data (BUG_23): invisible unless a test disables a port.

    Why this matters

    Senior lens. Treat the configuration space as part of the input space, with its own coverage model. Ask which settings and pairs the regression has exercised, not whether the default works. For parameterised IP, every combination a customer will build must be in the regression, and the rest should be covered at least pairwise.

    Interview

    Asked: "How would you verify a highly configurable IP?"

    Weak answer: Verify the default configuration really well.

    Strong answer: Treat configuration as part of the input space. Parameters generate different logic and registers select different behaviour, and many bugs need two settings together, so the default alone misses them. I'd randomise run-time configuration in every test, build a coverage model of settings and their crosses, choose build-time parameter sets with a covering array so every pair of values appears in some build, add three-way coverage where interactions are risky, and always include every configuration a customer actually ships.

    Follow-ups: (1) How many builds would you need for four four-valued parameters? (2) Why are random builds not enough?

    Check yourself A test suite never writes DCRouter's CTRL register. Which configurations does it test?

    Only the reset configuration: all ports enabled, priority on, low power on; the other 63 settings are untested.

    Check yourself Five parameters with three values each: how many builds for every combination, and what is the minimum to cover all pairs?

    3^5 = 243 for every combination. Any two parameters have 3 × 3 = 9 value pairs, so at least 9 builds are needed; the smallest set that covers all pairs for five parameters has 11 builds.

    Key takeaways

    • Parameters, registers and modes multiply the space; the default configuration is one point in it.

    • Most configuration bugs need one or two settings together, so cover every pair, not every combination.

    • Randomise run-time setup, measure configuration coverage, and test every shipped configuration.

    Keep going

    Next: Lesson 1.7, Performance Bugs. Correct results, delivered too slowly or unfairly.

    Related topics

    • Part 1 overview: What Can Go Wrong

    Previous

    19 / 160

    Next: Performance Bugs

    Up next

    Up nextPerformance Bugs

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • A Taxonomy of Bugs
    • Specification Bugs
    • Corner Cases and Boundaries