A technical knowledge portal by eVision Systems GmbH

EDA Praxis / Practical knowledge

Code coverage: What a high number shows and leaves open

Use coverage to identify missing tests without equating executed code with functional correctness.

Code coverage tells you which parts of a description were reached during simulation. On its own, it does not tell you whether those parts did the right thing. A test can execute every statement and still miss an incorrect data value if no suitable check exists. Coverage is therefore especially useful as a guide to investigation: it draws attention to gaps and supports discussion of which requirements have not yet been verified convincingly.

Different metrics answer different questions

Statement coverage measures executed statements; branch coverage examines decisions and their branches. Other metrics investigate conditions, signal transitions or state transitions, for example. Aldec describes these different views for its coverage tools and the mergeable ACDB database for Riviera-PRO. Check the actual available scope and required instrumentation for the configuration in use. Aldec: Code coverage and ACDB.

A number without its metric is difficult to interpret. Ninety percent of statements executed does not mean ninety percent of requirements checked. Two tools may also present or configure similarly named metrics differently. A comparison therefore needs the same measurement definition, design revision and exclusions. Otherwise, a percentage creates an impression of precision without a reliable basis.

A small counter example

A counter with reset and enable has at least three basic behaviours: resetting, counting and holding. A test that simply counts continuously after reset can reach many statements. It does not automatically check whether the counter holds when enable is inactive, or whether reset after prolonged operation has the same effect as reset at startup. Overflow is yet another requirement.

-- Eigenes, bewusst verkürztes RTL-Beispiel:
if rising_edge(clk) then
  if rst = '1' then
    count <= (others => '0');
  elsif enable = '1' then
    count <= count + 1;
  end if;
end if;

The absence of an assignment in the hold case is intentional here. A report of executed assignments does not explain that intent. A functional check must compare the previous value across several clock edges. Similarly, the addition may execute without ever reaching the maximum value. A practical rule follows: every relevant coverage gap should prompt a question about the specification, and every closed point needs a meaningful observation.

A counter needs more than executed linesAn example verification plan, not measured coverage or a record of tests already passed.
Four verification goals for the counter example
RequirementTargeted stimulusRequired observation
ResetAssert reset at start-up and during operation.The output reaches the specified reset value at the required time.
CountAssert Enable over several relevant clock edges.Within the counting range, the next value equals the previous value plus one.
HoldDeassert Enable over several clock edges.The output remains unchanged; the absence of an assignment alone does not prove this.
Boundary / overflowReach the specified boundary and continue counting.Behaviour at the boundary matches the specification.

On narrow screens, the table can be scrolled horizontally.

Depending on the metric, code coverage shows executed code elements and reached branches or states. The functional checker evaluates the observed result against the expectation. Both pieces of information must be considered together.

Combine code and functional coverage

Code coverage is derived from the implementation. Functional coverage instead describes situations of particular interest, such as packet lengths, operating modes or combinations of state and event. Such a measurement point may represent the test plan more directly, but also needs review. If the coverage model shares the design’s incorrect assumption, both can produce reassuring yet incomplete results together.

Start with a manageable table: requirement, stimulus, checker, observation and coverage goal. For a FIFO, examples might include writing when empty, reading when full, and simultaneous reading and writing. The permitted behaviour must come from the specification. This table prevents a large number of random transactions from being confused with clear, targeted verification coverage.

Investigate gaps systematically

An unreached location may indicate missing stimuli, a blocking precondition, an intentionally disabled configuration or genuinely unreachable code. Examine these possibilities in a consistent order. Identify the relevant test first, then check inputs and preconditions. Only when the architecture explains why the code is unreachable should a justified exclusion be considered. Excluding code merely to raise the percentage is not a verification measure.

For parameterised modules, make clear which configuration a report describes. A branch can be unreachable in one instance and essential in another. This information must survive the merging of several runs. Keep the configuration, seed and design revision with the report. Existing exclusions also deserve another look after a change.

Make results useful for decisions

A review should see more than the overall percentage. Useful information includes remaining gaps by risk, justified exclusions, failed tests and changes since the last approved revision. If large amounts of trivial logic dominate the total, a small safety-relevant controller can disappear within it. Examine meaningful functional areas separately and connect the assessment to requirements.

Set measurement goals before a milestone. Different modules may need different criteria: a simple register interface and a complex protocol state machine present different risks. A universal requirement for one hundred percent can encourage ineffective tests or unjustified exclusions. An appropriate target always includes a technical rationale and a policy for remaining gaps.

The next useful step

First add coverage to a small test suite that already checks its own results. Investigate one concrete gap and add a test that both reaches the situation and checks its outcome. Then run a deliberately faulty design revision to assess the checker’s effectiveness. This connects the metric to actual defect detection rather than treating it as a decorative progress indicator.

The OSVVM application note introduces structured checks. The Riviera-PRO page explains the product context for tool selection. This article contains neither our own vendor-tool runtime measurements nor a claimed coverage demonstration for a real design.

Sources and date

Research checked on 19 October 2026. Aldec: Code coverage and ACDB, Aldec Riviera-PRO.

Would you like to apply this approach to your project?

Review your development workflow with us

EDA PRAXIS / NEWSLETTER

Fresh perspectives.
Straight to your inbox.

Practical knowledge about HDL, simulation and verification. New articles, application notes and insights into useful tools.