Toggle coverage measures whether each bit of every signal in the design has transitioned in both directions — 0→1 and 1→0 — at least once during simulation. Unlike other code coverage metrics that track whether a line or branch was executed, toggle coverage works at the signal level and is unique in its ability to detect stuck-at signals: bits that never change state throughout the entire regression, regardless of how much other logic was exercised.

What You'll Learn

  • How toggle coverage bins work and what each one tracks
  • What toggle holes reveal about missing stimulus and dead logic
  • Which signals to prioritize and which to safely exclude
  • How to interpret toggle coverage reports and close holes efficiently

The Two Bins Per Bit

For every single-bit signal, the simulator tracks exactly two coverage bins:

  • 0→1: the signal transitioned from low to high at least once
  • 1→0: the signal transitioned from high to low at least once

Both bins must be hit for that bit to be considered fully covered. A signal that powers up at 0 and stays at 0 the entire simulation has zero bins covered. A signal that powers up at 0, goes to 1, and stays at 1 has only one bin covered (0→1). Only a signal that transitions in both directions is fully covered.


module fifo_ctrl (
    input  logic        clk,
    input  logic        rst_n,
    input  logic        wr_en,      // Write enable
    input  logic        rd_en,      // Read enable
    output logic        full,       // FIFO full flag
    output logic        empty,      // FIFO empty flag
    output logic [3:0]  count       // Current fill level
);
    // ... implementation
endmodule

For this module, the simulator generates toggle bins for every input, output, and internal signal. A partial toggle coverage report might look like this:


Signal          0->1        1->0        Coverage
-------         ----        ----        --------
wr_en           HIT         HIT         100%
rd_en           HIT         NOT HIT     50%    << rd_en was never de-asserted
full            HIT         HIT         100%
empty           NOT HIT     NOT HIT     0%     << empty was never asserted
count[3]        NOT HIT     NOT HIT     0%     << FIFO never reached 8+ entries
count[2]        HIT         HIT         100%
count[1]        HIT         HIT         100%
count[0]        HIT         HIT         100%

Three distinct problems are visible immediately. rd_en was never de-asserted after going high — the testbench never tested back-pressure or a stalled read. empty was never asserted — the FIFO was never fully drained. count[3] never toggled — the fill level never reached 8 or above, meaning the upper half of FIFO capacity was never exercised.

Quick Check

Q: A signal initialises to 1 at time zero and toggles to 0 midway through the simulation, then stays at 0. Which toggle bins are covered?

Show Answer

Only the 1→0 bin is covered. The signal started at 1 and went to 0, but never returned to 1, so the 0→1 transition was never observed. Toggle coverage for this signal is 50%.

Toggle Coverage on Multi-Bit Signals

For a bus or vector signal, the simulator generates two bins per bit. A logic [7:0] data signal produces 16 bins total — two for each of the eight bits. This is where toggle coverage can expose incomplete stimulus at the bit level that would be invisible to any other metric.


module alu (
    input  logic [7:0] operand_a,
    input  logic [7:0] operand_b,
    input  logic [2:0] opcode,
    output logic [7:0] result,
    output logic       carry_out
);

Consider a testbench that only drives small positive values (0x00–0x0F) through operand_a. The lower four bits toggle freely, but bits [7:4] are stuck at 0 throughout. Toggle coverage flags bits [7], [6], [5], and [4] of operand_a as having zero transitions — immediately revealing that the testbench never exercised the upper half of the input range. This class of bug — incomplete input space coverage — is very difficult to detect with branch or statement coverage alone.

For a signal declared as logic [N-1:0], the simulator generates 2×N toggle bins. A 32-bit bus produces 64 bins. Reviewing toggle holes on wide buses bit-by-bit is the most direct way to see which portions of the input or output data range were never driven.

Toggle Coverage at the DUT Interface

In block-level verification, the highest-value application of toggle coverage is on the DUT's primary input and output ports. Input toggle holes directly reveal where the testbench stimulus is incomplete — specific bits, modes, or data patterns that were never driven. Output toggle holes reveal logic paths that were never activated enough to produce those signal states, often pointing to missing functional scenarios deeper in the design.

What Toggle Holes Reveal

A toggle coverage hole on a signal can mean one of three things, and identifying which one determines the correct response:

1. Missing Stimulus

The most common cause. The testbench simply never drove the signal into one of its states. This is the actionable case — add or modify stimulus to hit the missing transition.


// error_inject input never driven high in any test
input logic error_inject

// Toggle report:
// error_inject   0->1: NOT HIT   1->0: NOT HIT

2. Dead or Disconnected Logic

The signal is driven by RTL logic that can never produce that transition given the rest of the design — either because the logic is structurally dead, or because a constant upstream feeds into it. This is a design bug, not a testbench gap.


// Example: a signal that should toggle based on a control input,
// but the control input is accidentally tied to a constant
assign flush_en = cfg_reg[4] & 1'b0;   // Bug: always 0, flush_en stuck low

No amount of stimulus will make flush_en go high because it is ANDed with a constant zero. The toggle hole here is pointing at an RTL bug, not a verification gap.

3. Legitimately Unreachable State

Some signal bits are architecturally constrained. For example, a 3-bit opcode field that only encodes values 0–4 will never have bit [2] go high without bit [1] also being set, meaning certain individual-bit transitions may be structurally impossible. These should be formally excluded with documented justification.

Never exclude a toggle hole without first investigating why the signal is stuck. What looks like a constrained architectural signal may be a connectivity bug or an accidental constant assignment. Toggle holes on interface signals especially warrant careful review before exclusion.

Signals to Exclude from Toggle Coverage

Not all signals benefit equally from toggle coverage analysis. Including every signal in the design produces an enormous number of bins, many of which are not useful. The standard practice is to selectively exclude categories of signals that are either impractical to toggle or produce misleading results:

Signal CategoryWhy Exclude
Memory arrays (RAM/ROM cells)Millions of bits; exhaustive toggling is impractical and adds no verification value beyond functional testing of read/write paths
Clock signalsToggle freely by definition; always 100% covered and add noise to the report
Scan-chain signalsOnly active during DFT scan mode; toggled by scan patterns, not functional tests
Clock-gating cells (ICG outputs)Toggle behavior is controlled by the clock tree, not functional stimulus
Tied-off or constant netsArchitecturally constant by design; a toggle hole here is expected

Most EDA tools support toggle exclusion via a coverage exclusion file or inline pragmas. Centralise your exclusion list in a shared file and review it during coverage closure meetings — it is easy for exclusions to quietly grow and mask real gaps over time.

Quick Check

Q: A design has a 256×8 RAM instantiated as a sub-module. Should its bit cells be included in toggle coverage? Why or why not?

Show Answer

No — they should be excluded. The RAM has 2048 bit cells, each producing two toggle bins, for a total of 4096 bins. Toggling every cell would require writing and reading every address with both 0 and 1 data patterns, which is impractical in a functional simulation. The RAM's read and write paths are better verified through statement and branch coverage of the surrounding control logic, plus targeted read/write functional tests.

Toggle Coverage vs Other Metrics

Toggle coverage is structurally different from all other code coverage metrics because it operates on signals rather than on code constructs. This gives it unique visibility into scenarios the other metrics cannot see:

ScenarioStatementBranchExpressionToggle
A line of code never executedCatchesCatches—Catches (output stuck)
A signal bit stuck at 0 or 1May missMay missMay missAlways catches
Input data range not fully drivenMissMissMissCatches (bit-level)
Accidental constant assignment in RTLMissMissPartialAlways catches
A condition never evaluated as trueCatchesCatchesCatchesIndirect

The stuck-at and constant-assignment scenarios are where toggle coverage provides unique value. A signal hardwired to a constant by an RTL bug — assign en = cfg & 1'b0; — produces no branch or statement holes (the statement was executed, both branches may have been taken elsewhere). But toggle coverage immediately flags it: the 0→1 transition of en was never observed.

Common Mistakes

Mistake #1: Reporting toggle coverage as a percentage of the total without excluding noise signals

Including clock signals, scan chains, and memory arrays in the denominator inflates the total bin count and makes the percentage number meaningless. A design showing 78% toggle coverage may actually have 99% coverage on functional logic once clocks and memories are properly excluded. Always define your exclusion scope before setting coverage targets.

Mistake #2: Ignoring the direction of a stuck signal

A signal stuck at 1 (missing the 1→0 transition) and a signal stuck at 0 (missing the 0→1 transition) imply different root causes. Stuck-at-1 on an active-low reset or enable often points to missing de-assertion tests. Stuck-at-0 on a flag or status output often points to the condition that sets it never being triggered. Reading the direction of the missing bin focuses the debug effort immediately.

Mistake #3: Treating all toggle holes as testbench gaps

Some toggle holes are RTL bugs — a signal connected to the wrong source, a constant accidentally ANDed in, or a port left unconnected. Before adding tests to close a toggle hole, confirm in the RTL that the signal can make the missing transition. If it cannot, the hole is a design defect, not a stimulus deficiency.

Summary

In this tutorial, you learned:

  • Toggle coverage tracks two bins per signal bit — 0→1 and 1→0 — and both must be hit for a bit to be considered fully covered
  • Multi-bit buses generate 2×N bins, making toggle coverage the most effective metric for detecting incomplete input data range coverage at the bit level
  • Toggle holes can indicate missing testbench stimulus, dead RTL logic, or accidental constant assignments — identifying which determines the correct fix
  • Clocks, memory arrays, scan chains, and tied-off nets should be excluded from toggle coverage to keep the report focused on meaningful functional signals
Did you find what you were looking for?

Quiz

No quiz questions available for this article.

Cron Job Starts