DV Methodology

Chapter 1 of 15

Coverage in One Page: Functional vs. Code Coverage

Draw the line between functional coverage (what you declare you care about) and code coverage (what a tool automatically measures from the RTL) -- a common interview question and the anchor for this whole module -- before any covergroup syntax at all.

uvm and uvm-advanced both checked correctness: did an observed transaction match what was expected. Neither ever measured thoroughness — whether the scenarios that ran were actually the ones worth running, or how many of them there even were to run. SV assertions (ch15) named the word covergroup in passing and stopped there; SV capstone-testbench (ch16) closed its stimulus→drive→check loop without a coverage step at all, on purpose, promising this track would pick it up. This is that pickup — and it starts with a distinction worth getting exactly right, since it's one of the most common interview questions in this field.

Two things sharing one name

"Coverage" refers to two genuinely different measurements, and confusing them is the single most common way this topic goes wrong in an interview answer:

Functional CoverageCode Coverage
What it measuresWhether the scenarios you declared you care about occurredWhether lines/branches/bits/states of the RTL itself were exercised
Who writes itA verification engineer, in SystemVerilog (covergroup)Nobody — a tool instruments the RTL automatically
What it's derived fromYour understanding of the spec and what's worth testingThe DUT's source code, mechanically
What 100% meansEvery scenario you thought to declare happened at least onceEvery line/branch/bit/state the tool found got exercised at least once
The classic trapYou never declared the scenario that mattered — 100% of what you measured says nothing about what you didn'tA line can execute with the wrong value and still count as "covered" — code coverage says nothing about correctness

Neither one checks correctness — that's still assertions' and scoreboards' job (uvm-advanced chapters 2, 5). Both answer "was this tested," from two independent angles: one asks whether your intent was exercised, the other asks whether the code was exercised — and a design can score well on one while scoring badly on the other. A test that hammers one register address a thousand times gets excellent code coverage on that address's logic and zero functional coverage on every other register; a beautifully designed set of functional coverage bins that never actually runs the DUT (a broken testbench, say) gets 0% on both.

A first look at each — full syntax is chapter 2's job

Functional coverage is declared directly in SystemVerilog:

covergroup axi_addr_cg;
  cp_addr: coverpoint txn.addr;
endgroup

This says "I care about which values txn.addr takes" — nothing about how to bucket those values (that's bins, chapter 2), nothing about combinations across multiple fields (that's cross, also chapter 2). Just enough here to recognize the shape: a covergroup containing one or more coverpoints, instantiated like any other class-adjacent construct, sampling automatically or on demand.

Code coverage has no SystemVerilog syntax to show at all — there's nothing to write. A tool instruments the compiled RTL and, after a run, reports something shaped roughly like this:

Line Coverage:     87.3%  (401/459 lines)
Branch Coverage:   72.1%  (52/72 branches)
Toggle Coverage:   65.0%  (130/200 bits)
FSM Coverage:      50.0%  (2/4 states, 3/6 transitions)

Four different metrics, each asking a different question about the same source code — chapters 3-5 take each one in turn, concretely, against axil_regfile's own RTL.

This module's DUT: axil_regfile, again

Every chapter in this module reuses axil_regfile (uvm-advanced chapter 1) rather than mux2 — deliberately. mux2 is one always_comb line: there's no branch worth discussing and no state machine at all. axil_regfile has real case-statement branches (its response-code decoding) and a real small state machine (the write channel's aw_have/w_have latching) — exactly the material line/branch/toggle/FSM coverage need to be concrete rather than abstract. If the RTL and the driver/monitor code in the next few chapters look unfamiliar, uvm-advanced chapters 1-2 are the place to go refresh them; nothing about the DUT itself changes here.

A verification-feasibility note, stated once

Checked directly, the same way earlier limitations in this project were checked rather than assumed: Icarus Verilog does not implement covergroup at all — the simplest possible covergroup/coverpoint fails to even parse. Code coverage collection has no Icarus equivalent either, in principle — it's exclusively a commercial-tool feature. That means every example in this module needs the same simulator switch uvm-advanced already established: on EDA Playground, pick a commercial-grade simulator such as Aldec Riviera-PRO (free, no license of your own required) instead of Icarus. Later chapters in this module will reference this note briefly rather than repeat it.

Summary

  • Functional coverage is authored — a verification engineer declares which scenarios matter in SystemVerilog (covergroup), and the tool tallies whether they happened.
  • Code coverage is automatic — a tool instruments the RTL itself and reports which lines/branches/bits/states executed, with no SystemVerilog written for it to exist.
  • 100% of either one is a well-known trap: 100% functional coverage only proves what someone thought to declare; 100% line coverage says nothing about whether the logic that ran was actually correct.
  • This module reuses axil_regfile (uvm-advanced ch1) throughout, since it has real branches and real state that mux2 never had.
  • Icarus Verilog can't run any example in this module — every chapter needs a commercial-grade simulator on EDA Playground instead.

What's the fundamental difference between functional coverage and code coverage?

A DUT reaches 100% line coverage. What does that actually guarantee?

Which SystemVerilog keyword declares a functional coverage model? (lowercase)