The previous lesson planted the bugs and gave the complete bench. This lesson reads the results: for each bug, the first checker to fire, the cycle, and whether any other checker would have caught it. It ends with the sign-off review for the whole capstone.
Each bug was run by editing the default parameter. The cycle is the monitor's cycle count from the start of simulation.
BUG | First checker | Cycle | First message | Also fired |
|---|---|---|---|---|
1 ID swap | scoreboard and a_no_orphan | 142 | UNEXPECTED response for ID 2 with nothing outstanding | Mismatches on ID 0 after it |
2 strobe drop | scoreboard (expected data from the memory model) | 41 | MISMATCH ID 6 expected 650c7b25 got 651f7b25 | Only the scoreboard |
3 lost after reset | watchdog | 1024 | ID 1 waited 200 cycles (issued at 824) | driver at 1238, drain at 4644 |
4 starvation | a_fair | 5 | port 0 accepted twice while port 1 waited | Only a_fair |
5 duplicate | scoreboard, then a_no_orphan | 41, 42 | MISMATCH on ID 6, then UNEXPECTED on ID 6 | - |
6 order within ID | scoreboard | 31 | MISMATCH ID 7 (two values swapped) | Only the scoreboard |
Three things in the table are worth a reviewer's attention.
Bug 1 needed a nearly full table. The ID mux bug is in entry 7, and the table hands out the lowest free entry, so entry 7 is allocated only when entries 0 to 6 are busy (7 or more reads outstanding). CV1's 8+ bin is not the evidence: in the passing run entry 7 was allocated 30 times, 20 of them by reads that found 7 outstanding (the 4-7 bin) and 10 by reads that found 8, while only 10 of the 58 reads in the 8+ bin took entry 7. The white-box row CV1b counts entry 7 directly; a test with 0 there could not have found this bug.
Bug 3 was found 204 cycles after the reset, by the watchdog, not by a data compare. Liveness checks matter: without the watchdog and the bounded drain, a lost response is a silent timeout.
Bugs 2, 4 and 6 have exactly one checker each. Removing that one checker lets the bug through. The plan should say so, and those checkers deserve the most review.
Mutation of the bench, not the design, shows what each piece is worth. Two runs from the closure lesson make the point: with the mid-traffic reset removed, BUG = 3 fires no checker; coverage rows CV8 and CV9 report holes and the bench's "reset did not happen" check fails. With the fairness assertions removed, BUG = 4 fires nothing and only CV7 (port 1 wins) reports a hole. The bench still fails in both cases because unmet coverage goals and the test's own sanity checks fail it. That is the reason to make coverage goals part of the pass criterion rather than a report someone reads later.
A sign-off review asks for evidence, not assurances. For this capstone:
Question | Evidence here |
|---|---|
Is every rule owned by a checker? | Checker table in Checking: R1-R6 each have at least one owner |
Do the checkers work? | Checker unit test (7 cases) and six planted bugs, each caught, with cycle numbers |
Did the stimulus reach the risky states? | Every coverage row at goal in the full run on 31 seeds; CV1 8+, CV1b, CV2, CV3, CV8 and CV9 are the high-risk rows |
Are the holes understood? | CV1 depth 0 was structural; the directed phase D closes it on every seed; the per-test vs regression meaning is recorded per row |
Can the bench hang or pass vacuously? | Bounded drivers, bounded drain, a global timeout, activity gates (CV2, CV3), and a check that the reset happened |
Are tool limits recorded? | Covergroups mirrored; cover properties need --coverage-user; local-variable assertion not run on Verilator 5.048; clocking-block drives (a Verilator 5.048 workaround, and good style) |
Is it reproducible? | Fixed seed 11 by default; +seed and +items for other runs; all results in this topic regenerated from the code shown |
What this capstone does not prove is also part of sign-off: no formal proof of the ordering rule, no coverage of an ID reused while a same-ID response is stalled (no row defines it), CV10 and CV11 not enforced on Verilator (they exist only as cover properties), and one design configuration. A principal engineer lists these as known gaps with an owner, rather than leaving them for someone to discover.
A tighter watchdog limit, or the ticket assertion with a smaller MAX_LAT, would report it closer to the first stuck read. The cost is false failures when back-pressure legally delays a response, so the limit must stay above the worst legal latency (up to 69 cycles measured here).
The ticket assertion from the Checking lesson on a simulator that supports local variables, or an auxiliary-code assertion that records, per ID, the accept order of each read's sequence number and checks that responses retire them in order. Either would catch the swap without the scoreboard.