DCRouter has been verified across eleven steps: a smoke test, a reference model, directed and random tests, assertions, checkers, coverage, formal proofs and a plan. This lesson prepares its tape-out review package: close what the plan left open, lay out all the evidence, and decide.
Is DCRouter ready to sign off, and what does the evidence say?
The obvious answer is yes: one testbench catches all 24 planted bugs. Lesson 9.8 showed why that is not enough: three planned features had no evidence or only partial evidence. Sign-off follows the plan, so those come first, and closing them turns out to matter.
A final bench checks the three: with low power disabled the router never sleeps (F25); each output's throughput is measured with maximum-length packets and no contention (F26); and a reset in the middle of traffic is followed by checks of reset values, counters, credits and clean traffic (F28).
// uses: dcrouter
// DCRouter step 11: closing the plan's open features before sign-off (lesson 9.8).
// F25 low power disabled: with lp_en clear, 60 idle cycles never put the router to sleep.
// F26 throughput: each input streams 6 maximum-length packets to its own output; the
// testbench measures flits per cycle on every output.
// F28 reset in the middle of traffic: reset while all four outputs are busy, then check
// reset values, empty counters, 4 credits per output and clean traffic.
module tb;
`include "dcr_env.svh"
int slept = 0, first [4], last [4], flits [4];
bit measuring = 0;
always @(posedge clk) if (!rst && sleeping) slept++;
for (genvar o = 0; o < 4; o++) begin : g_tp
always @(posedge clk) if (measuring && out_vld[o]) begin
if (flits[o] == 0) first[o] = $time / 10;
last[o] = $time / 10;
flits[o]++;
end
end
task automatic audit_credits();
int n0;
for (int o = 0; o < 4; o++) begin
drain_pct[o] = 0;
n0 = got_flits[o];
queue_pkt(0, o, 0, 15);
repeat (60) @(posedge clk);
if (got_flits[o] - n0 != 4) fail($sformatf("%0d flits left output %0d into a stalled sink after reset, expected 4", got_flits[o] - n0, o));
drain_pct[o] = 100;
wait_drain();
end
endtask
real tp [4];
initial begin
reset_dut();
// F25: low power disabled
apb_wr(8'h00, 32'h1F);
queue_pkt(0, 1, 0, 3);
wait_drain();
slept = 0;
repeat (60) @(posedge clk);
if (slept != 0) fail($sformatf("asleep for %0d cycles with lp_en clear", slept));
apb_wr(8'h00, 32'h3F);
// F26: throughput, no contention (input i to output i)
flits = '{0, 0, 0, 0};
measuring = 1;
for (int n = 0; n < 6; n++) for (int i = 0; i < 4; i++) queue_pkt(i, i, 0, 15);
wait_drain();
measuring = 0;
for (int o = 0; o < 4; o++) tp[o] = real'(flits[o]) / real'(last[o] - first[o] + 1);
// F28: reset in the middle of traffic; sources and sinks are reset with the router
for (int i = 0; i < 4; i++) for (int n = 0; n < 3; n++) queue_pkt(i, (i + 1) % 4, 0, 15);
repeat (30) @(posedge clk);
rst <= 1;
in_vld <= 0;
for (int i = 0; i < 4; i++) begin
fq[i].delete();
for (int o = 0; o < 4; o++) exp_q[i][o].delete();
in_pkt[i] = 0; occ[i] = 0; got_pkts[i] = 0; bad_pkts[i] = 0;
end
repeat (3) @(posedge clk);
rst <= 0;
check_reg(8'h00, 32'h3F, "CTRL after a reset mid-traffic");
for (int k = 0; k < 4; k++) begin
check_reg(8'h10 + 8'(4 * k), 0, $sformatf("ERR_CNT%0d after reset", k));
check_reg(8'h20 + 8'(4 * k), 0, $sformatf("PKT_CNT%0d after reset", k));
end
audit_credits();
for (int i = 0; i < 4; i++) queue_pkt(i, (i + 2) % 4, 0, 4);
wait_drain();
finish($sformatf("F25 never slept with lp_en clear; F26 throughput %.3f %.3f %.3f %.3f flits/cycle; F28 clean after reset mid-traffic", tp[0], tp[1], tp[2], tp[3]));
end
endmoduleIt passes on the clean design:
PASS: F25 never slept with lp_en clear; F26 throughput 0.953 0.953 0.953 0.953 flits/cycle; F28 clean after reset mid-trafficTwo of the three close cleanly. F26 does not match the plan: 0.953 flits per cycle, not 1. With 17-flit packets back to back there is one idle cycle per packet, because a new grant follows the previous tail by a cycle. The behaviour is consistent and functionally correct, so this is a decision, not a test failure: lesson 14.3 resolves it as a specification correction, confirmed affordable by the architects, and a silicon validation item. Run against the Bug Zoo, the bench also catches BUG_1, BUG_2, BUG_3, BUG_8, BUG_10, BUG_17, mainly through its checks after the mid-traffic reset.
Criterion (lesson 14.2) | Status | Evidence |
|---|---|---|
Every feature F1–F28 has evidence | Met (F26 with a waiver) | Lessons 4.1–7.9 and the gap bench above |
Coverage closed or decided | Met | 74 of 78 bins over 12 seeds; lp_en 0 closed by F25; three saturation bins waived (lesson 14.3) |
Key formal properties proved | Met | FIFO, arbiter and credit properties for every depth (lesson 7.9) |
Planted bugs caught | Met | 24 of 24 by the covered hunt (lesson 6.9) |
No open critical bug without a decision | Met | No open bugs in the course's design |
Bug discovery trend | Not applicable | A course design has planted bugs, not a discovery history; a real project would show its curve (lesson 12.2) |
Reviews complete | For the course: this part | A real project would record named reviewers |
Bug | Directed | Error inj. | Back-pressure | Random hunt | Checked hunt | Covered hunt | Formal proof | Gap bench | Times caught |
|---|---|---|---|---|---|---|---|---|---|
BUG_1 | · | caught | caught | caught | caught | caught | caught | caught | 7 |
BUG_2 | caught | caught | caught | caught | caught | caught | caught | caught | 8 |
BUG_3 | caught | caught | caught | caught | caught | caught | · | caught | 7 |
BUG_4 | caught | caught | · | caught | caught | caught | · | · | 5 |
BUG_5 | · | · | · | · | caught | caught | caught | · | 3 |
BUG_6 | · | · | · | · | caught | caught | caught | · | 3 |
BUG_7 | · | · | · | · | caught | caught | caught | · | 3 |
BUG_8 | caught | caught | caught | caught | caught | caught | · | caught | 7 |
BUG_9 | caught | · | caught | caught | caught | caught | caught | · | 6 |
BUG_10 | caught | · | caught | caught | caught | caught | caught | caught | 7 |
BUG_11 | caught | · | caught | caught | caught | caught | · | · | 5 |
BUG_12 | caught | caught | caught | caught | caught | caught | · | · | 6 |
BUG_13 | · | caught | · | caught | caught | caught | · | · | 4 |
BUG_14 | · | caught | · | caught | caught | caught | · | · | 4 |
BUG_15 | · | caught | · | · | · | caught | · | · | 2 |
BUG_16 | · | · | · | · | · | caught | · | · | 1 |
BUG_17 | caught | caught | caught | · | · | caught | · | caught | 5 |
BUG_18 | caught | caught | · | · | · | caught | · | · | 3 |
BUG_19 | · | caught | · | · | · | caught | · | · | 2 |
BUG_20 | · | · | caught | caught | caught | caught | · | · | 4 |
BUG_21 | · | · | · | caught | caught | caught | · | · | 3 |
BUG_22 | · | · | caught | caught | caught | caught | caught | · | 5 |
BUG_23 | · | · | · | · | · | caught | · | · | 1 |
BUG_24 | · | caught | caught | caught | caught | caught | caught | · | 6 |
How to read it: every bug is caught by at least one method, and most by several. Only BUG_16, BUG_23 are caught by a single testbench, which makes them the most fragile entries: a regression change that weakened that one bench would let them escape. Columns show what each technique contributes; rows show how much independent evidence each rule has. This is the measured version of the course's central claim: no single technique is enough, and the combination is what gives confidence.
Waivers: ERR_CNT0, 1, 3 saturation bins; throughput specification corrected to one idle cycle between packets (lesson 14.3).
Assumptions: sinks return credits only for held flits; sources hold data while stalled; R1–R13 are the right specification.
Formal scope: proofs cover FIFO, arbiter and credits; framing, CRC, counters and sleep rest on simulation evidence.
Out of scope: SoC integration, power domains switched off, electrical margins (Parts 8 and 11).
Item | Decision |
|---|---|
Outcome | Go with conditions |
Condition 1 | Architecture confirms the bandwidth budget with one idle cycle between packets; specification updated |
Condition 2 | Add the three ERR_CNT saturation loops to the nightly regression (cheap), or keep the waiver signed |
Silicon validation first | Throughput under real traffic; counter saturation; sleep and wake with real DMA traffic |
Specify first: rules R1–R13 made every check and bin traceable (Part 2).
Each technique has a pool: directed, random, error injection, timing, checkers, coverage and formal each caught bugs the others missed.
Checks must be validated: every checker built here was wrong at least once until run on the clean design and planted bugs.
The plan finds what bugs cannot: two untested features and a plan-versus-design difference appeared only when evidence was laid against the plan.
Sign-off is a decision, stated with its residual risk.
The measured throughput differed from the plan but the behaviour was consistent and functionally correct; whether it is acceptable is a system decision, resolved by correcting the specification after the bandwidth budget was confirmed.
Its detection depends on a single piece of evidence; any regression change that weakens that bench would let it escape unnoticed.
Closing the plan's last open features found a real plan-versus-design difference.
The complete matrix shows every planted bug caught, most by several independent methods.
DCRouter's sign-off: go with conditions, waivers and residual risk stated, silicon priorities named.