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. Integration and Interface Bugs

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

Integration and Interface Bugs

Two blocks can each pass their own verification and still fail together, because each was tested against its own idea of the other. Why integration bugs escape block-level testing, where they hide, and how protocol checkers and subsystem tests catch them.

On this page

    Note

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

    Before this: Concurrency and Races, The Verification Stack

    A DMA engine (illustrative) was verified with a testbench model of memory that always answered within ten cycles. The memory controller was verified with a testbench model of a requester that never issued more than four reads at once. Both blocks passed everything. Connected, the DMA issued eight reads, the controller's response queue overflowed, and data went missing. Neither block was wrong by its own testbench. Each testbench was wrong about the other block.

    Why do blocks that pass their own verification fail together?

    The obvious answer, and why it breaks

    The obvious belief is that verified blocks compose: if A meets its specification and B meets its specification, A connected to B works. That holds only if the testbench's model of each neighbour behaves exactly as the real neighbour will. Testbench models are simplified, and they encode the verification engineer's assumptions about the neighbour. Every assumption that differs from the real neighbour is an integration bug waiting at the boundary.

    The idea: each block is tested against a stand-in

    Each block passed against a stand-in that was gentler than the real neighbour; the bug only exists when the two real blocks meet.

    Where integration bugs hide

    Example

    Limits each side assumes of the other

    Outstanding requests, burst lengths, response latency

    Behaviour the specification leaves open

    Whether back-pressure can last forever; ordering between channels

    Connectivity

    Signals swapped, tied off, or connected to the wrong instance

    Shared resources

    Address maps, interrupts, clocks and resets shared by several blocks

    Protocol corners

    A legal but unusual sequence one side never produces in its own tests

    How integration bugs are caught

    • Protocol checkers at every interface: assertions for the interface's rules, bound at both block and SoC level, so a neighbour that breaks a rule is caught at the boundary.

    • Testbench models as aggressive as the specification allows: maximum outstanding, worst latency, back-pressure at any time, not the polite behaviour of one real neighbour.

    • Subsystem tests with the real neighbours before full SoC integration (lesson 0.6).

    • Interface specifications with explicit limits, so assumptions are written down and checkable on both sides.

    How real teams handle the boundary

    Practice

    Purpose

    Verification IP for standard interfaces

    An independent model that exercises everything the standard allows

    Bound protocol checkers reused at every level

    The same rules checked wherever the interface appears

    Connectivity checks at SoC level

    Find miswired and tied-off signals directly

    Integration test plans per interface

    Each boundary gets tests with both real neighbours

    What breaks

    DCRouter's registers show a small version of the same class. Three Bug Zoo bugs live where the register block meets the rest of the design: input 2's error counter also counting good packets (BUG_14), one output's packet counter that cannot be cleared (BUG_16), and a clear that reaches all four error counters (BUG_19). Traffic tests never notice, because traffic does not read registers; only tests that combine traffic with register checks see the disagreement.

    Why this matters

    Senior lens. For each interface, list the assumptions each side's testbench makes about the other and compare them with the specification's limits. Every gap where a testbench is gentler than the specification allows is an untested region, and every gap the specification does not define is an integration bug waiting for two teams to discover it.

    Interview

    Asked: "Why do integration bugs escape block-level verification?"

    Weak answer: Because block tests are too small.

    Strong answer: Because each block is verified against a model of its neighbours, and the model encodes the verifier's assumptions: how many requests are outstanding, how long responses take, whether back-pressure can last. If the real neighbour behaves differently, even legally, the combination fails although each block passed. I catch them by making block-level models as aggressive as the spec allows, binding protocol checkers at every interface and reusing them up the hierarchy, writing explicit limits into interface specs, and running subsystem tests with the real neighbours before SoC integration.

    Follow-ups: (1) What makes a good stand-in model? (2) What do connectivity checks find?

    Check yourself A block's testbench never applies back-pressure for more than four cycles because the current neighbour never does. Is that a problem?

    Yes, if the specification allows longer back-pressure: a future or different neighbour may do it, and that behaviour was never tested.

    Check yourself Why bind the same protocol checker at block and SoC level?

    So the interface's rules are enforced wherever it appears; a real neighbour that breaks them is caught at the boundary, not three blocks later.

    Key takeaways

    • Blocks are verified against stand-ins for their neighbours; differences in assumptions become integration bugs.

    • Make stand-ins as aggressive as the specification allows and write limits down.

    • Bind protocol checkers at every interface and test with real neighbours before SoC level.

    Keep going

    Next: Lesson 1.6, Configuration and Mode Bugs. Parameters, registers and modes multiply the space.

    Related topics

    • Part 1 overview: What Can Go Wrong

    • VIP and compliance course: Protocol Checkers

    Previous

    18 / 160

    Next: Configuration and Mode Bugs

    Up next

    Up nextConfiguration and Mode Bugs

    Sign in to save progress

    Practice this lessonReport an error

    See also

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