Part 5 · Functional Coverage · Intermediate
Functional Coverage in SystemVerilog
Covergroups, coverpoints, bins, crosses, options, and the closure workflow — measuring what your testbench actually exercised.
What this section covers
Simulation tells you whether the tests you ran passed . Functional coverage tells you whether the tests you ran mattered — whether the scenarios your verification plan demands actually occurred. SystemVerilog builds this measurement into the language with covergroup, coverpoint, bins, and cross constructs.
Functional coverage is not code coverage. Code coverage (lines, toggles, branches) is extracted automatically by the simulator from the RTL — it measures which structure executed. Functional coverage is written by you from the spec — it measures which scenarios happened. 100% code coverage with 0% functional coverage means every line ran but no interesting scenario was ever tried. Sign-off needs both.
Topic map
┌─────────────────────────────────────────────────────────────────────┐
│ FUNCTIONAL COVERAGE — topic map │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 1. COVERGROUP BASICS │
│ anatomy │ sampling │ expressions │ embedded vs standalone │ │
│ first model │ code vs functional │
│ │
│ 2. BINS │
│ auto vs explicit │ range/array/default │ transitions │ │
│ illegal/ignore │ wildcard/with │ bin design strategy │
│ │
│ 3. CROSS COVERAGE │
│ cross semantics │ binsof filtering │ cross explosion control │
│ │
│ 4. OPTIONS & METHODS │
│ per_instance │ weight/goal │ at_least │ sample()/get_coverage() │
│ │
│ 5. COVERAGE CLOSURE │
│ plan traceability │ merge across seeds │ holes → new tests │
│ │
└─────────────────────────────────────────────────────────────────────┘Topics in this section
Covergroup Basics — anatomy, sampling strategies, coverpoint expressions, embedded vs standalone covergroups, your first coverage model, and code vs functional coverage.
Bins — auto vs explicit bins, ranges and arrays, transition bins, illegal_bins and ignore_bins, wildcard and with filtering, and intent-driven bin design.
Cross Coverage — combining coverpoints, binsof selection, and managing cross-product explosion.
Options & Methods — option.per_instance, weights, goals, at_least, and the runtime query API.
Coverage Closure — connecting bins to the verification plan, merging regression databases, and turning holes into tests.
The coverage data path
Coverage is a measurement pipeline that runs alongside checking. Stimulus drives the DUT, a monitor (or clocking event) samples the relevant fields, the covergroup buckets each sampled value into bins, and the simulator writes hit counts to a coverage database. Regression merges those databases, and the merged report — not any single run — is what closure is judged against.
COVERAGE DATA PATH
stimulus (random / directed)
│
▼
┌──────────┐ pins ┌──────────────────┐
│ DUT │ ────────────► │ sampled fields │
└──────────┘ │ (monitor txn or │
│ @(posedge clk)) │
└──────────────────┘
│ cg.sample(...) or clocked event
▼
┌──────────────────┐
│ covergroup bins │
│ cp_op: ADD ✓ │
│ cp_op: SUB ✗ │
│ x_op_len: ... │
└──────────────────┘
│ per-seed database (UCDB/VDB)
▼
seed1.ucdb ─┐ ┌──────────────────┐
seed2.ucdb ─┼── merge ────► │ merged database │
seedN.ucdb ─┘ (union) └──────────────────┘
│
▼
┌──────────────────┐
│ closure report │
│ holes → new tests│
└──────────────────┘Why this is a language feature, not a methodology add-on
Covergroups are pure SystemVerilog — they work in modules, interfaces, and classes with no library required.
The simulator maintains hit counts and the database natively; you declare intent, the tool measures.
Methodologies like UVM only decide WHERE the covergroup lives and WHEN sample() is called — the semantics here are the foundation.
Bins are the contract between your verification plan and the simulator: each bin is a scenario the plan says must happen.
Key takeaways
Functional coverage measures scenarios from the spec; code coverage measures structure from the RTL — sign-off needs both.
The covergroup/coverpoint/bins constructs are core SystemVerilog, independent of any methodology.
Closure is judged on the merged regression database, never on a single seed's percentage.
Every bin should trace to a verification-plan item — coverage without a plan is just numbers.
Common pitfalls
Treating 100% code coverage as 'verification done' — it proves no scenario intent at all.
Writing covergroups after the testbench is finished — coverage should be planned with the stimulus, not bolted on.
Chasing a single-run coverage percentage — different seeds hit different bins; only the merge matters.
Auto-bins on wide fields — thousands of meaningless buckets that can never close.