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 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.
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 |
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).
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 |
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.
Later failures are often consequences of the first; fixing the first frequently removes the rest.
Running the credit audit early: it failed, showing credits were lost before the arbitration checker complained.
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.