Wishbone · Module 26
Coverage
Functional failures zero, coverage holes eleven — and the bin that mattered was the one access the regression never issued. Hitting a bin is not the same as being sensitive to its bug.
Every layer so far reports clean. The checkers are exercised, the monitor matches the pins, the scoreboard has nothing to say.
Now ask what the regression never tried.
1. Coverage Is Evidence About Space, Not Proof Of Correctness
// ── WHAT COVERAGE IS, AND IS NOT ────────────────────────────────────────
// Coverage is EVIDENCE ABOUT EXPLORED SPACE. It is not proof of
// correctness. A design with 100% coverage and a broken scoreboard is
// broken; a design with 60% coverage and a clean scoreboard has simply
// not been asked enough questions yet.2. Three Different Things Called Coverage
// CODE COVERAGE which lines/branches/toggles executed. A tool
// measurement of the RTL, not of intent.
// ASSERTION COVERAGE which properties ACTIVATED - wb_vplan_checker's
// act_* outputs are exactly this.
// FUNCTIONAL COVERAGE which SITUATIONS the stimulus created. THIS file.They are not substitutes. Chapter 26.2's activation audit is assertion coverage, and it answered a question neither of the others can: whether a property that reported clean had ever been asked anything.
3. Counters, Not covergroup — And Why That Is Honest
// ── WHY COUNTERS AND NOT covergroup ─────────────────────────────────────
// This module is an explicit bin model in ordinary SystemVerilog rather
// than a `covergroup`, because the simulator available here does not
// implement SystemVerilog functional coverage. The CONCEPT is unchanged
// - bins, hits, crosses, holes, exclusions - and the numbers are real
// because the counters really run. A commercial tool would express the
// same model in `covergroup` syntax and compute the same holes.The concept is not diminished by the syntax. What would be dishonest is publishing a coverage percentage produced by a tool that does not compute one.
4. The Bin Model
Five dimensions, each chosen because it changes the design's behaviour:
// op READ / WRITE - different datapaths
// term ACK / ERR / RTY - different response paths
// wait ZERO / SHORT(1-3) / LONG(4+) - different commit timing
// target REG / MEM / UNMAPPED - different decode outcomes
// sel FULL / PARTIAL - different lane handling5. Crosses Are Chosen, Not Generated
// ── CROSSES ARE CHOSEN, NOT GENERATED ───────────────────────────────────
// The full cross is 2 x 3 x 3 x 3 x 2 = 108 bins, most of them
// meaningless (a partial-lane read of an unmapped address with a long
// wait). 100% OF MEANINGLESS BINS IS MEANINGLESS. Four crosses are
// modelled because each names a situation a real bug hides in:
//
// op x wait - commit-timing bugs hide behind zero wait states
// target x term - does every target produce every response it should?
// write x sel - byte-lane handling is only exercised by partial writesEach cross has a named bug behind it. op × wait exists because every commit-timing defect in Modules 23–25 was invisible at zero wait states. write × sel exists because Chapter 26.4's lane defect is reachable only by a partial write.
"More crosses always means better coverage" is false. A cross you cannot name a bug for is a bin you will later exclude, after spending stimulus effort reaching it.
6. A Green Regression With Eleven Holes
Five operations — full-word reads and writes to both targets, plus one unmapped access. Every layer clean:
SPEC failures 0 scoreboard mismatches 0 monitor unknown 0And then the bins:
bin hits status
wait LONG 0 HOLE
sel PARTIAL 0 HOLE
READ x wait LONG 0 HOLE
WRITE x wait ZERO 0 HOLE
WRITE x wait LONG 0 HOLE
WRITE x ERR 0 HOLE
REG x ERR 0 HOLE
MEM x ERR 0 HOLE
WRITE x sel PARTIAL 0 HOLE
WRITE x PARTIAL x waited 0 HOLE
bins defined 26 hit 15 holes 11 -> FUNCTIONAL FAILURES 0. COVERAGE HOLES 11.
A regression that passes everything it ran is not
the same as a regression that ran everything.And one of those holes is not a statistic — it is a shipped bug:
The hole that matters most here is
"WRITE x sel PARTIAL": SIM H showed that a slave
ignoring [SEL_I()] is caught ONLY by a partial
write. This regression never issued one, so that
bug would have shipped with a green report.7. Closing It
Six targeted operations added — two partial writes with wait states, a read-only write, and memory traffic reaching an armed retry:
bin before after closed
wait LONG 0 0 still open
sel PARTIAL 0 2 YES
READ x wait LONG 0 0 still open
WRITE x wait ZERO 0 1 YES
WRITE x wait LONG 0 0 still open
WRITE x ERR 0 1 YES
REG x ERR 0 1 YES
MEM x ERR 0 0 still open
WRITE x sel PARTIAL 0 2 YES
WRITE x PARTIAL x waited 0 2 YES
bins defined 26 hit 22 holes 4
functional failures 0 scoreboard mismatches 08. The Remaining Holes Are Justified, Not Chased
THE REMAINING HOLES ARE JUSTIFIED, NOT CHASED:
MEM x ERR the memory endpoint has no error
condition in this system. EXCLUDED
by construction, not unreached.
READ x ERR / reachable, and reaching them adds
wait LONG no new behaviour beyond the bins
already hit. Left open DELIBERATELY. 100% OF A BIN MODEL THAT EXCLUDES THE INTERESTING
CASES IS WORTH LESS THAN 80% OF AN HONEST ONE. The
number is not the deliverable; the JUSTIFICATION FOR
EACH REMAINING HOLE is.| bin | status | why |
|---|---|---|
MEM x ERR | excluded | the memory endpoint has no error condition — unreachable by construction |
wait LONG, READ x wait LONG, WRITE x wait LONG | open, deliberately | reachable; the SHORT bins already exercise the same commit-timing paths |
An excluded bin and an unreached bin are different claims, and a coverage report that does not distinguish them is a percentage pretending to be an argument.
9. Hitting A Bin Is Not Being Sensitive To Its Bug
This is the sharpest result in the chapter, and it came out of this module's own development. The integrated test hit WRITE × sel PARTIAL — and both lane defects still escaped:
// ignored, so the lane defects would hit the coverage bin and stay
// register produces the same result whether [SEL_I()] is honoured or
// ignored, so the lane defects would hit the coverage bin and stay
// invisible. HITTING A BIN IS NOT THE SAME AS BEING SENSITIVE TO
// THE BUG THE BIN WAS CHOSEN FOR.Seeding the register with non-zero lanes first changed the detection count from 6 of 8 to 8 of 8, with the coverage number unchanged in both runs.
Coverage measures whether the stimulus reached a situation. It does not measure whether the stimulus could have told the difference. A bin model is a necessary condition for good verification and never a sufficient one.
10. Coverage Samples The Monitor, Not The Stimulus
// sampled from the MONITOR's transaction stream - coverage observes
// what actually happened, not what the stimulus intendedThat choice has a consequence worth knowing: a broken monitor corrupts the coverage report too. DUPLICATE_MONITOR inflates the partial-write bin from 1 to 3 in the discrimination matrix — the situation occurred once and was counted three times.
Sampling the stimulus instead would decouple them, and would then report coverage for accesses the design may never have seen. Neither is free, and the environment states which it chose.
11. Reading A Coverage Report Without Lying To Yourself
Four questions turn a percentage into an argument, and a report that cannot answer them is a number without a claim behind it:
1. What is the denominator? 22 of 26 bins is meaningless without the bin model. A model of 26 chosen bins and a model of 108 generated ones produce very different percentages from identical stimulus — and the 108-bin model scores worse while testing exactly the same behaviour.
2. Which holes are excluded and why? MEM × ERR is unreachable by construction here. That is a statement about the design, and it should be written down next to the bin rather than quietly subtracted from the denominator.
3. Which test hit each bin? A bin hit only by one test is a bin that disappears when that test is removed. The closure table in §7 names which operations closed which holes for exactly this reason.
4. Would the stimulus have noticed the bug? §9's answer. This is the question coverage cannot answer at all, and the one most often assumed away.
12. Coverage Against The Other Layers
Coverage is the only layer in this module that never reports a failure — and that is a property, not a weakness:
| layer | reports | on the correct design |
|---|---|---|
| checker | failures and activations | 0 failures, non-zero activations |
| monitor | census versus raw pins | exact match |
| scoreboard | mismatches | 0 |
| coverage | bins hit and holes | holes are expected |
A coverage report with no holes on the first run is a warning, not a result. Either the bin model is too coarse to distinguish anything, or the regression was written after the bins were chosen to fit it.
The healthy sequence is the one in this chapter: write the bins from the design's behaviour, run the regression you already had, find holes, then decide for each one whether to close it or justify it.
13. What This Chapter Did Not Build
- No
covergroupsyntax. Unavailable here; the bin model is explicit instead, and says so. - No code coverage. A tool measurement of the RTL, not of intent.
- No constrained-random stimulus. Targeted and deterministic on purpose — every number in this module reproduces exactly, and §37's determinism gate checks it.
- No coverage database or merging. One run, one model; regression merging is infrastructure, not concept.
Next: Chapter 26.6 — UVM Concepts takes the five components this module built and shows where each one lives in UVM — without pretending six pages make anyone a UVM expert.
Continue learning
Related tutorials
- Related topic
CPU to Peripheral Communication
A CPU reaches hardware outside itself by reading and writing addressed locations, and a peripheral is hardware it cannot execute. Everything a driver does has to be expressed as a read or a write of a location the peripheral answers for — and once more than a couple of peripherals exist, wiring each one to the core separately stops scaling. That is the problem an on-chip bus is the answer to.
- Related topic
Memory-Mapped IO
Memory-mapped I/O does not turn a peripheral into memory. It gives the peripheral's registers addresses in the processor's address space, so an ordinary load or store selects them. The address then does two jobs — name the target, name the register inside it — and the map that assigns them is a contract between software and RTL.
- Related topic
Need for Standardized Interconnects
An address map answers where a register lives. It says nothing about which wires carry the request, when they are valid, how the target reports completion, or what happens on an error. Three peripherals with three private interfaces produce three adapters, three verification efforts and three ways to be wrong — which is the argument for standardising the interface rather than the map.
- Related topic
The Open Hardware Movement
Source availability and reusability are different properties. A published core tells you what it does; it does not tell you what it requires, and requirements are what integration runs on. What reusable open IP needs beyond the RTL — licensing, documentation, an interface contract, verification, maintenance — and where open hardware is honestly weaker than its advocates claim.
Standards & specifications
- Governing standard
- Wishbone SoC Interconnection Architecture (OpenCores)(opens OpenCores in a new tab)
Defines the Wishbone signal set, the bus cycles built from it and the interface rules a portable IP core must follow. It deliberately leaves interconnect topology, address map and arbitration policy to the integrator, so those are system decisions rather than requirements of the specification.
This page also covers RTL structure, verification approach and debugging technique. Those are engineering practice built on the standard, not requirements the standard itself imposes.
Where this fits
Part of the Wishbone curriculum.
