Code Coverage
Functional coverage is user-defined — a covergroup only tracks what someone explicitly wrote a coverpoint for. Code coverage is the opposite: a tool derives it automatically from the RTL's own structure, with no test-writer input required at all. Both feed the same CDV loop, but they answer genuinely different questions — code coverage asks "did the test suite exercise this line/branch/signal at all," functional coverage asks "did the test suite exercise this scenario the spec cares about."
The five structural metrics
- Statement (line) coverage — the simplest metric: did every executable statement in the RTL run at least once. Easy to understand, easy to reach a high percentage on, and the weakest signal of the five — a statement running once says nothing about whether it ran with every input combination that matters.
- Branch (decision) coverage — for every
if/case, was each branch actually taken, not just the statement inside it executed. Stronger than line coverage, since a statement can technically execute while its sibling branch (theelse, the othercasearm) never does. - Condition coverage — for a compound boolean expression like
if (a && b), branch coverage only confirms the whole expression was true at least once and false at least once. It says nothing about whetheraandbwere each independently exercised true and false. Condition coverage closes exactly that gap — a real, common source of a passing branch-coverage report hiding an unexercised sub-case. Some tools report a closely related metric under a separate name, expression coverage: rather than just confirming each operand in a compound boolean expression was independently exercised true and false (condition coverage's own bar), it evaluates the full truth-table combinations of the expression's operands as reported by the tool — a stricter check than condition coverage, though not as strict as MC/DC's requirement that a condition demonstrably change the overall decision's outcome on its own. - Toggle coverage — for every bit of every signal, did it transition both
0→1and1→0at least once during simulation:
data[3] toggles 0→1 and, later, 1→0 — both directions observed, closing toggle coverage for this bit.
A bit that never toggles at all is a strong, cheap signal that something is wrong — either the stimulus never reached that bit, or the bit is stuck (tied off, or a real design bug holding it constant).
- FSM coverage — reported as two separate numbers, both required for "full" FSM coverage: state coverage (was every state actually entered) and transition/arc coverage (was every legal directed edge between states actually taken, not just every state visited via some path). A state machine can reach 100% state coverage while several of its legal transitions — an error-recovery edge, a specific two-step sequence — are never exercised at all. EDA tools typically auto-detect the state register and extract the full state graph directly from the RTL, without needing a hand-written covergroup for it.
MCDC: a stricter version of condition coverage
Condition coverage confirms a and b were each independently exercised true and false — but it doesn't confirm that flipping a alone, holding b fixed, actually changed the decision's outcome. Modified condition/decision coverage (MC/DC) closes that gap: for every condition in a compound expression, it requires a pair of test cases where only that condition's value changes and the overall decision's result changes as a direct result — proving each condition can independently affect the outcome, not just that it was toggled somewhere alongside others. It's the strictest of these metrics, common in safety-critical flows (avionics, automotive) more than general ASIC/FPGA sign-off, precisely because it's more expensive to close than plain condition coverage.
Why 100% code coverage doesn't mean the design is correct
Every one of these five metrics answers whether code ran, never whether the result was right. A statement can execute, a branch can be taken, a bit can toggle both ways — all while computing a wrong value the entire time, if nothing is actually checking the output. That checking job belongs to the scoreboard and functional coverage, not to code coverage at all. Code coverage's real value is different and still essential: it's the fastest, cheapest way to find stimulus gaps — code that never ran, a bit that never moved — long before anyone has to ask whether what did run produced the right answer.
What's next
Code coverage is structural and automatic. The next page returns to functional coverage's own territory — not its syntax (already covered), but the judgment calls SystemVerilog's own page never addressed: what's actually worth turning into a coverpoint, and what isn't.