Types of Coverage Metrics

In short: There are two families of coverage metrics. Code coverage is measured automatically by the simulator and tells you how much of the RTL was exercised (statement, block, branch, condition or expression, toggle, and FSM). Functional coverage is written by you and tells you whether the features from the test plan were actually tested. You need both: code coverage finds untested code, functional coverage finds untested behaviour.

Coverage is how a team measures progress in constrained-random verification. It answers the honest question “are we done yet?” This page walks through every common metric under functional coverage and code coverage, with a small example for each so the difference is clear.

A simple way to picture it

Imagine testing a new car. Code coverage is like checking that every part on the assembly list was touched at least once during the test drive: did the brakes engage, did each gear shift, did the wipers move. Functional coverage is like checking that you actually drove the real scenarios from the plan: highway merging, parallel parking, an emergency stop in the rain. You could touch every part (high code coverage) and still never test parallel parking (low functional coverage), which is exactly why both matter.

The two families of coverage

AspectCode coverageFunctional coverage
Who defines itThe simulator, automaticallyYou, from the test plan
What it measuresHow much RTL was exercisedWhether features and scenarios were tested
Depends on design code?Yes, derived from the RTLNo, derived from the specification
AnswersIs any code untested?Is any behaviour untested?
EffortLow, just enable itHigher, you write covergroups

Code coverage and its types

Code coverage is extracted by the simulator when you enable it. It has several sub-types, each looking at the RTL from a different angle. Consider this small block for the examples that follow.

always @(posedge clk) begin      // Line 1 (a block)
  if (A > B)                      // Line 2 (a branch)
    Result = A - B;              // Line 3
  else
    Result = A + B;             // Line 4
end

Statement / line coverage

Measures how many lines ran during simulation. It is the headline number most teams target at 100 percent for closure. In the block above there are four executable lines to cover.

Block coverage

A block is a group of statements between begin and end, or an if, else, case, or loop body. Block coverage checks whether each group ran. The block above has the always body, the if branch, and the else branch.

Branch / decision coverage

Looks at decisions such as if-else, case, and the ternary operator, and checks that both the true and false outcomes happened. The block above has one decision (A > B), so both its true and false sides must be seen.

Condition and expression coverage

Condition coverage counts how often each Boolean sub-expression was true and false. Expression coverage looks at the right-hand side of an assignment and treats it like a truth table, checking that the meaningful rows were seen. For an expression of three inputs, there is a full table of cases to cover.

// Expression coverage builds a truth table over A, B, C
Result = (A && B) || C;

Toggle coverage

Measures whether each signal and port switched both 0 to 1 and 1 to 0 during the run. It is handy for spotting stuck or unused signals that never change value.

FSM coverage

For a state machine, FSM coverage checks that every state was visited and every legal transition between states was taken. Missing a transition often points to a scenario your tests never triggered.

Functional coverage

Functional coverage is a user-defined metric that measures how much of the specification, as captured by features in the test plan, was actually exercised. It is not inferred from the RTL; you write it from the spec. It checks that interesting scenarios, corner cases, and invariants were observed and tested. In SystemVerilog you write it with covergroups and with cover properties. To tune how a covergroup reports, see functional coverage options.

// A tiny functional coverage example
covergroup cg_req @(posedge clk);
  cp_type: coverpoint req_type;   // were all request types seen?
endgroup

When to use which

  • Enable code coverage always; it is nearly free and flags dead or untested RTL.
  • Write functional coverage for every feature in the test plan; it is the only metric that knows your intent.
  • Use FSM and toggle coverage to catch unreached states and stuck signals early.
  • Treat 100 percent code coverage with low functional coverage as a warning, not success: behaviour is still untested.

Common mistakes to avoid

  • Chasing only code coverage and assuming the design is verified; it says nothing about intended behaviour.
  • Never excluding legitimately unreachable code, so the number can never reach the goal.
  • Writing functional coverage with no link back to the test plan, so gaps go unnoticed.
  • Gathering coverage from failing tests, which pollutes the numbers; collect only from passing runs.

Expected output, in plain words

When you enable coverage, the simulator produces a report: code coverage shows a percentage per type (line, branch, toggle, FSM, and so on), and functional coverage shows how many bins in each covergroup were hit versus the goal. Note: this describes typical tool behaviour from the IEEE 1800 model, not a captured run, and report formats vary by simulator. Confirm on your own tool.

To go deeper, see functional coverage options, the writing functional coverage guidelines, and the general questions on coverage. For more revision, browse the functional coverage and SystemVerilog categories and the interview questions.

Frequently asked questions

What are the two main types of coverage metrics?

The two families are code coverage and functional coverage. Code coverage is measured automatically by the simulator and shows how much RTL was exercised. Functional coverage is written by you and shows whether the features from the test plan were tested.

What is the difference between code and functional coverage?

Code coverage is derived from the RTL and tells you if any code is untested. Functional coverage is derived from the specification and tells you if any intended behaviour is untested. Code coverage is automatic, functional coverage is user-defined.

What are the types of code coverage?

The common types are statement or line coverage, block coverage, branch or decision coverage, condition and expression coverage, toggle coverage, and FSM coverage. Each looks at the RTL from a different angle.

What does toggle coverage measure?

Toggle coverage measures whether each signal and port switched both from 0 to 1 and from 1 to 0 during simulation. It helps identify stuck or unused signals that never change value.

What does FSM coverage check?

FSM coverage checks that every state of a state machine was visited and every legal transition between states was taken during simulation. A missing transition usually points to an untested scenario.

Why do I need functional coverage if code coverage is high?

High code coverage only means the RTL ran; it says nothing about whether the intended features were tested. Functional coverage, written from the test plan, is the only metric that confirms the design behaviour was actually exercised.

Similar Posts