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
  • 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
    • The Debug Loop
    • Reproducing Failures
    • Following the Wait
    • Bisection and Delta Debugging
    • Triage at Scale
    • Is It the Testbench?
    • Drills: Debug
  • Part 14: Sign-Off7
  • Part 15: Verification in Context8
  • Part 16: Case Studies5
  • Part 17: Capstones5
  • Part 18: Interview Preparation6
Loading lesson

‹Part 13: Debug
  1. Topics
  2. First Principles of Verification Strategy
  3. Part 13: Debug
  4. The Debug Loop

Part 13 · Debug · Working (W)

The Debug Loop

Debugging is a loop: observe the failure precisely, form a hypothesis about its cause, design the smallest experiment that would confirm or refute it, and narrow. The failure message is evidence, not a verdict. The loop, the habits that make it fast, and examples from this course where the first message pointed at the wrong thing.

On this page

    Note

    Level: Working (W) · Answers: How do we find the cause fast?

    Before this: Part 13 overview, Bug Propagation and Masking

    A DCRouter regression fails with "R6: low-priority packet from input 1 won output 3 over a waiting high-priority packet from input 3". The obvious reading is an arbitration bug, and an engineer spends an afternoon reading the arbiter. The arbiter is fine. The design had lost credits, which shifted when packets left, which made the checker's model of arbitration timing wrong (lesson 5.5's version 2). The message was accurate about what the checker saw and wrong about the cause. Debug starts by treating it as evidence.

    How do you approach a failing test?

    The obvious answer, and why it breaks

    The obvious approach reads the error message, opens the code it names and looks for something wrong. Messages report where a check noticed a problem, which is often far from where the problem began (lesson 3.3): a wrong value travels before anyone checks it, and a checker's assumptions can misattribute. Searching the named code first works when the message is right and wastes hours when it is not.

    The idea: a hypothesis loop

    Each pass observes more precisely, forms candidate causes, runs the experiment that best separates them, and narrows, until one cause explains every symptom.

    Step

    Good practice

    DCRouter example

    Observe

    First failure, exact time, the signals at the interface it names, not a summary

    The first R6 failure time; out_vld and out_crd on output 3 around it

    Hypothesise

    Several candidates, including "the checker is wrong" (lesson 13.6)

    Arbiter bug; checker timing model wrong; credits lost

    Test

    The cheapest experiment that separates candidates

    Rerun with the credit audit early: does it fail first?

    Narrow

    Keep candidates the result did not rule out

    Credit audit fails: credits are lost, the arbiter is innocent

    Confirm

    The cause explains every symptom, and a fix removes them all

    Fix the credit counter: both the audit and the R6 failures disappear

    Habits that make the loop fast

    • Start from the first failure in time, not the last or the loudest: later errors are often consequences.

    • Read the message as "a check saw this", then ask what could make that check see it.

    • Write hypotheses down; experiments that cannot distinguish them waste a run.

    • Change one thing per experiment, and keep a log.

    • Stop when one cause explains every symptom, not when one symptom goes away (lesson 12.5).

    How real teams debug

    Practice

    Purpose

    Failure messages that name the rule, the time and the values

    Observation starts precise

    Debug logs kept with the bug report

    Hypotheses and experiments reviewable and reusable

    Pairing a designer and a verifier on hard failures

    Design intent and testbench assumptions both in the room

    What breaks

    The opening story happened in building this course: the arbitration checker's second version reported credit bugs as priority violations. The rule was the checker's model, not the arbiter. Starting from "which check fired first, and what does it assume?" found it in one experiment; starting from the arbiter's code would not have found it at all.

    Why this matters

    Senior lens. Treat every failure message as evidence from a checker with assumptions. Observe precisely, list candidate causes including the testbench, run the experiment that best separates them, and stop only when one cause explains every symptom. Speed in debug comes from good experiments, not from reading code faster.

    Interview

    Asked: "How do you approach a failing test?"

    Weak answer: Read the error and look at the code it points to.

    Strong answer: As a hypothesis loop. First observe precisely: the first failure in time, the exact signals and values at the interface it names. Then list candidate causes, including the testbench and the checker's own assumptions. Pick the cheapest experiment that separates them, run it, keep what survives, and repeat until one cause explains every symptom and the fix removes them all. A message says what a check saw; on the course's router, a priority-violation message was really lost credits confusing the checker's timing model.

    Follow-ups: (1) Why start from the first failure? (2) How do you choose the next experiment?

    Check yourself Why should debug start from the first failure in time rather than the most alarming one?

    Later failures are often consequences of the first; fixing the first frequently removes the rest.

    Check yourself In the opening story, which experiment separated "arbiter bug" from "lost credits"?

    Running the credit audit early: it failed, showing credits were lost before the arbitration checker complained.

    Key takeaways

    • Debug is a loop: observe, hypothesise, test, narrow.

    • A failure message is evidence from a checker with assumptions, not a verdict.

    • Stop only when one cause explains every symptom.

    Keep going

    Next: Lesson 13.2, Reproducing Failures. Seeds, minimal cases and determinism.

    Related topics

    • Part 13 overview: Debug

    Previous

    123 / 160

    Next: Reproducing Failures

    Up next

    Up nextReproducing Failures

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Following the Wait
    • Bisection and Delta Debugging
    • Triage at Scale