Skip to content

SystemVerilog · Module 11

Transition Coverage

Coverage of value sequences across consecutive samples. The => operator, multi-step chains, range and list endpoints, the three repetition forms ([*N], [=N], [->N]), and the sampling-granularity-vs-transition decision that separates working FSM coverage from silently-broken FSM coverage.

Module 11 · Page 11.6

What Transition Coverage Measures

Named bins (Module 11.4) measure values; transition bins measure sequences of values across consecutive sample events. A transition bin is hit when the coverpoint's value at sample N+1 matches the bin's "to" specification AND the coverpoint's value at sample N matched the bin's "from" specification. The simulator carries a one-sample memory of the coverpoint's previous value; that history is what makes the transition measurable.

The canonical use case is FSM coverage: every spec-defined state transition becomes a transition bin, and the report tells you which transitions the regression exercised. The same machinery applies anywhere temporal value sequences matter — protocol command ordering (read-then-write, write-then-read, back-to-back writes), reset-recovery sequences, and pipeline-stage hand-offs.

Syntax — The => Operator

The basic transition bin uses the => operator inside an explicit bins declaration:

SystemVerilog — basic transition bin syntax
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
covergroup cg_fsm @(posedge clk);
    cp_state: coverpoint state {
        bins idle_to_active = (IDLE   => ACTIVE);
        bins active_to_done = (ACTIVE => DONE);
        bins done_to_idle   = (DONE   => IDLE);
    }
endgroup

What this does. Three counted bins. Each one increments by one every time the simulator sees the named "from" value at one sample and the named "to" value at the immediately-following sample. The bin's name is the verification-plan row; the report reads cp_state.idle_to_active 100.0% (142 hits).

The reading rule: a transition bin is a named bin whose value space is a pair of consecutive samples, not a single value. All the named-bin discipline from Module 11.4 applies — the bin name describes the spec scenario, not the literal values; the option.comment cites the verification-plan row; per-bin option.at_least and option.weight are available.

Endpoint forms — single, range, and list

Either endpoint of the => can be a single value, a range, a list, or a mix:

SystemVerilog — endpoint variations on transition bins
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
covergroup cg_endpoints;
    cp_state: coverpoint state {
        // ── Single → single (the basic form) ────────────────────────
        bins reset_to_idle = (RESET => IDLE);
 
        // ── List → single — any of {ERR1, ERR2, ERR3} → IDLE ─────
        bins err_recovered = (ERR1, ERR2, ERR3 => IDLE);
 
        // ── Single → list — IDLE → any of {READ, WRITE, REFRESH} ─
        bins idle_dispatch = (IDLE => READ, WRITE, REFRESH);
 
        // ── List → list — Cartesian product of both sides ──────────
        // 2 sources × 3 destinations = 6 distinct transitions, ONE bin
        bins any_error_to_recovery = (ERR1, ERR2 => IDLE, RECOVER, RESET);
 
        // ── Range endpoints — using inclusive [lo:hi] ─────────────
        bins low_to_high = ([STATE_0 : STATE_7] => [STATE_8 : STATE_15]);
    }
endgroup

The semantic rule for lists and ranges. When the "from" side is a list of N values and the "to" side is a list of M values, the bin's value space is the Cartesian product — N × M distinct (from, to) pairs all map to the same single bin. The hit count is the total across every pair; the report cannot tell you which of the N × M pairs contributed. If you need per-pair visibility, write a separate transition bin per pair.

Multi-Step Sequences — Chained =>

A transition bin can chain multiple => operators to describe a sequence of three or more consecutive samples. The bin fires when all the named values appear in order across N consecutive samples (for an N-1-step chain).

SystemVerilog — multi-step transition chains
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
covergroup cg_sequences @(posedge clk);
    cp_state: coverpoint state {
        // ── Three-sample chain — the happy path ────────────────────
        bins full_cycle = (IDLE => ACTIVE => DONE => IDLE);
        // Fires when 4 consecutive samples are IDLE, ACTIVE, DONE, IDLE in order.
 
        // ── Mixed-length chains — different bins, different lengths
        bins short_recovery = (ERR => IDLE);
        bins long_recovery  = (ERR => RECOVER => RESET => IDLE);
 
        // ── Range / list inside a chain ─────────────────────────────
        // From any IDLE-class state → ACTIVE → any DONE-class state → back to IDLE-class
        bins serviced_request = (IDLE, IDLE_LP => ACTIVE => DONE, DONE_OK, DONE_ERR => IDLE);
    }
endgroup

Expected output (urg-style, partial).

Multi-step transition coverage report
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
Group  cg_sequences                           coverage   75.0%
  cp_state    full_cycle                       100.0%   ( 138 hits )
              short_recovery                   100.0%   (   8 hits )
              long_recovery                      0.0%   (   0 hits )   ← gap
              serviced_request                 100.0%   ( 244 hits )

The long_recovery bin reads zero — the random stimulus produced short-recovery sequences (ERR => IDLE) but never the longer ERR => RECOVER => RESET => IDLE shape. The next directed test is the closure path.

Repetition Operators — [* N], [= N], [-> N]

Three operators let a single transition bin describe sequences with a value that repeats N times. Picking the right one is the difference between "stayed in this state for N cycles" and "this state appeared N times eventually."

Consecutive repetition — [* N]

(A [* N]) matches N consecutive samples of value A. The bin fires once when the (N-1)th consecutive A is followed by an (N)th consecutive A. Useful for "stayed in state X for at least N cycles" scenarios.

SystemVerilog — consecutive repetition
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
covergroup cg_stuck @(posedge clk);
    cp_state: coverpoint state {
        // Held in IDLE for exactly 5 consecutive samples
        bins idle_5_cycles = (IDLE [* 5]);
 
        // Held in BUSY for any duration in [3:10] consecutive samples
        bins busy_held = (BUSY [* 3:10]);
 
        // Combined with a preceding/following transition
        bins idle_then_long_active = (IDLE => ACTIVE [* 8]);
        bins long_busy_then_idle   = (BUSY [* 3] => IDLE);
    }
endgroup
 
// idle_5_cycles fires on:    IDLE IDLE IDLE IDLE IDLE
// busy_held fires on:        BUSY BUSY BUSY  (3 in a row, lower bound met)
//                              also BUSY×4, BUSY×5, ..., BUSY×10
// Does NOT fire on:          IDLE IDLE IDLE ACTIVE IDLE IDLE
//                              (broken by the ACTIVE — restart count)

The discipline: [* N] measures duration in the sample timeline, not the clock timeline. If the sample event is @(posedge clk), [* 5] means five consecutive clock cycles. If the sample event is @(transaction_committed), [* 5] means five consecutive transactions — possibly spanning hundreds of clock cycles.

Non-consecutive repetition — [= N]

(A [= N]) matches A appearing N times, not necessarily consecutively, with any sequence of non-A samples allowed between them. Useful for "A happened N times eventually" scenarios.

SystemVerilog — non-consecutive repetition
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
covergroup cg_counts @(posedge clk);
    cp_state: coverpoint state {
        // ERR appeared 3 times before reaching IDLE — any pattern in between
        bins three_errors_then_idle = (ERR [= 3] => IDLE);
 
        // The full pattern fires on, e.g.:
        //   ERR ACTIVE BUSY ERR ACTIVE ERR IDLE      ✓ (3 ERRs, then IDLE)
        //   ERR ERR ERR IDLE                          ✓ (3 ERRs back-to-back, then IDLE)
        //   ERR ACTIVE ERR IDLE                       ✗ (only 2 ERRs before IDLE)
    }
endgroup

Use [= N] when the spec calls for "N occurrences of X" without requiring them to be contiguous — useful for fault-injection scenarios ("three injected errors recovered into a clean state").

Goto repetition — [-> N]

(A [-> N]) matches A appearing N times, with the Nth occurrence being the next sample that the chain continues from. The semantic difference from [= N] is subtle but important: [-> N] consumes the Nth A as the chain anchor, while [= N] allows arbitrary samples (including more A's) between the Nth A and the next chain element.

SystemVerilog — goto repetition
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
covergroup cg_goto @(posedge clk);
    cp_state: coverpoint state {
        // Goes to IDLE on the 3rd ACTIVE, immediately after
        bins idle_after_third_active = (ACTIVE [-> 3] => IDLE);
 
        // Fires on:
        //   ACTIVE BUSY ACTIVE ERR ACTIVE IDLE        ✓ (IDLE is next sample after 3rd ACTIVE)
        //   ACTIVE ACTIVE ACTIVE IDLE                  ✓ (3 ACTIVEs back-to-back, then IDLE)
        //   ACTIVE ACTIVE ACTIVE ACTIVE IDLE          ✗ (4th ACTIVE between 3rd ACTIVE and IDLE
        //                                                — IDLE is not the next sample after 3rd ACTIVE)
    }
endgroup

The form is rare in practice but appears in protocol-handshake scenarios: "after the third valid request, the next sample must be the grant" — the goto operator captures that exactly.

A Complete Working Example — Memory-Controller FSM Transition Coverage

The pattern below builds a complete transition-coverage model for a five-state memory-controller FSM, combining single-step, multi-step, and repetition transition bins.

SystemVerilog — memory-controller FSM transition coverage
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
typedef enum bit [2:0] {
    S_IDLE   = 3'b000,
    S_ACTIVE = 3'b001,    // bank activated
    S_READ   = 3'b010,
    S_WRITE  = 3'b011,
    S_PRECHG = 3'b100,
    S_RFR    = 3'b101,
    S_ERR    = 3'b111
} mem_state_e;
 
covergroup cg_mem_fsm @(posedge clk);
    option.comment = "vplan §6 — memory FSM transition coverage";
 
    cp_state: coverpoint state {
        // ── Mandatory single-step transitions (happy path) ─────────
        bins idle_to_active   = (S_IDLE   => S_ACTIVE);
        bins active_to_read   = (S_ACTIVE => S_READ);
        bins active_to_write  = (S_ACTIVE => S_WRITE);
        bins read_to_prechg   = (S_READ   => S_PRECHG);
        bins write_to_prechg  = (S_WRITE  => S_PRECHG);
        bins prechg_to_idle   = (S_PRECHG => S_IDLE);
 
        // ── Refresh subcycle ───────────────────────────────────────
        bins idle_to_rfr      = (S_IDLE => S_RFR);
        bins rfr_to_idle      = (S_RFR  => S_IDLE);
 
        // ── Multi-step happy-path sequences ────────────────────────
        bins read_cycle  = (S_IDLE => S_ACTIVE => S_READ  => S_PRECHG => S_IDLE);
        bins write_cycle = (S_IDLE => S_ACTIVE => S_WRITE => S_PRECHG => S_IDLE);
 
        // ── Error transitions (must be exercised) ──────────────────
        bins any_to_err  = (S_ACTIVE, S_READ, S_WRITE, S_PRECHG => S_ERR);
        bins err_to_idle = (S_ERR => S_IDLE);
 
        // ── Duration bins — controller spec says ACTIVE must
        //     be held for at least 3 cycles (tRCD constraint)
        bins active_held_min = (S_ACTIVE [* 3]);
 
        // ── Stress scenario — controller saw 5 refreshes,
        //     reaching IDLE between each (non-consecutive)
        bins five_refreshes  = (S_RFR [= 5] => S_IDLE);
 
        // ── Illegal transitions — must NEVER happen ────────────────
        illegal_bins idle_to_read  = (S_IDLE => S_READ);    // skipped activate
        illegal_bins read_to_write = (S_READ => S_WRITE);   // no precharge between
 
        option.comment = "vplan §6.1–§6.7";
    }
endgroup

What this code does. Declares a covergroup sampled at every clock edge with a single coverpoint on the FSM state. Six single-step transitions cover the spec-mandatory legal moves; two more cover the refresh subcycle. Two five-step chains cover the happy-path full cycles for read and write. A list-source transition (any_to_err) collapses the four "→ ERR" transitions into one bin. A duration bin (active_held_min) verifies the controller honours the tRCD minimum hold. A non-consecutive repetition bin documents a stress scenario. Two illegal transitions enforce the spec's "must never happen" contract — idle_to_read (no activate before read) and read_to_write (no precharge between read and write) — surfacing any spec violation immediately.

How to simulate it. Instantiate the covergroup in a monitor or interface scope where state is visible. Drive the controller through realistic workloads (read traffic, write traffic, refresh interactions, error injection) for at least 10,000 clock cycles. Dump coverage with the simulator's reporter.

Expected output (urg-style, partial).

cg_mem_fsm coverage report
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
Group  cg_mem_fsm                              coverage   88.9%
  cp_state    idle_to_active                    100.0%   ( 412 hits )
              active_to_read                    100.0%   ( 198 hits )
              active_to_write                   100.0%   ( 214 hits )
              read_to_prechg                    100.0%   ( 198 hits )
              write_to_prechg                   100.0%   ( 214 hits )
              prechg_to_idle                    100.0%   ( 412 hits )
              idle_to_rfr                       100.0%   (  87 hits )
              rfr_to_idle                       100.0%   (  87 hits )
              read_cycle                        100.0%   ( 198 hits )
              write_cycle                       100.0%   ( 214 hits )
              any_to_err                        100.0%   (  12 hits )
              err_to_idle                       100.0%   (  12 hits )
              active_held_min                   100.0%   ( 408 hits )
              five_refreshes                      0.0%   (   0 hits )   ← gap
              idle_to_read                  ILLEGAL    (   0 hits )   ← good
              read_to_write                 ILLEGAL    (   0 hits )   ← good

What to read out of this. Thirteen of fourteen counted bins are at 100% — the regression exercises the legal transition graph thoroughly. The five_refreshes non-consecutive bin is a real gap: no test ran long enough to accumulate five S_RFR samples reaching S_IDLE. The two illegal transitions read ILLEGAL — 0 hits, which is the right outcome — the controller never produced the spec-forbidden moves. Paired with an SVA assertion for sub-cycle catching (per Module 11.5), the illegal transitions form the temporal-contract evidence the audit trail needs.

Common Pitfalls — Where Transition Coverage Silently Lies

Pitfall 1 — Sampling granularity mismatch

SystemVerilog — covergroup samples on transactions, transition spans clocks
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
covergroup cg @(posedge clk iff vif.tready);   // ← samples only when tready high
    cp_state: coverpoint state {
        bins reset_to_idle = (RESET => IDLE);
    }
endgroup
 
// The RTL:    RESET RESET RESET (tready=0) (tready=0) IDLE IDLE
// Samples:    RESET RESET RESET                       IDLE IDLE
// Result: the simulator sees a consecutive RESET → IDLE in its sample sequence.
//          The bin fires. Looks like success.
// Reality: there were two stall cycles between RESET and IDLE — the design
//          was in some other state. The transition bin records the *sample-event*
//          adjacency, not the *RTL* adjacency.

Fix: if the transition bin is meant to describe RTL adjacency, sample at every clock edge (@(posedge clk)), not at filtered events. If the bin is meant to describe sample-event adjacency (the transaction-level equivalent), name it accordingly in the bin identifier and the option.comment.

Pitfall 2 — Lists collapse audit visibility

SystemVerilog — list endpoint hides which transition actually fired
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
bins any_error = (ERR1, ERR2, ERR3 => IDLE);
// Bin fires 30 times → 30 error → IDLE transitions occurred.
// But: was it 30× ERR1→IDLE? 10× ERR1, 10× ERR2, 10× ERR3? Unknown.
// If the verification plan distinguishes the error sources, the bin is wrong.

Fix: if the plan rows are per-error-source, write per-source transition bins. If the plan row is genuinely "any error recovers," the list form is correct — and the option.comment should cite the plan row to make the choice auditable.

Pitfall 3 — Repetition operators on the wrong operator

SystemVerilog — [*N] vs [=N] confusion
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Intent: "S_BUSY appeared 5 times during one workload (not necessarily contiguous)"
bins busy_5_total = (S_BUSY [* 5]);   // ← BUG: requires 5 *consecutive* BUSY samples
 
// The correct form for "5 occurrences, any positions":
bins busy_5_total_fixed = (S_BUSY [= 5]);

Fix: the repetition-operator choice is part of the verification-plan rendering. [* N] is "duration"; [= N] is "count"; [-> N] is "anchor." Reading the bin and the spec row together should make the operator choice obvious — if not, the bin needs a comment.

Pitfall 4 — Transitions on a covergroup with no event

SystemVerilog — manual-sample covergroup, no temporal history
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
covergroup cg;                              // ← no @event; manual sample()
    cp_state: coverpoint state {
        bins t = (IDLE => ACTIVE);          // transition bin
    }
endgroup
 
// In the testbench:
state = IDLE;   cg.sample();
state = ACTIVE; cg.sample();
// Transition bin DOES fire here — the simulator's "previous sample" is IDLE
// at the moment of the second sample().
 
state = ACTIVE; cg.sample();
state = IDLE;   cg.sample();
state = ACTIVE; cg.sample();
// Each consecutive sample() in this group might or might not fire the bin
// depending on the previous sample()'s value. The model is well-defined
// but easy to misuse — manual sampling needs careful sequencing of values
// and sample() calls, or the transition counts drift from the RTL.

Fix: transition bins compose best with event-triggered covergroups (@(posedge clk) or a named event). Manual sampling works but is fragile; if you use it, the sampling discipline must be documented and code-reviewed alongside the bin definitions.

Debug Lab — "The Transition Bin Doesn't Fire, but $display Says the Transition Happened"

A debugging session every team encounters once.

Buggy code
SystemVerilog — sampling event filters out the transition
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
covergroup cg_handshake @(posedge clk iff vif.tvalid);   // ← filtered sample
    cp_state: coverpoint state {
        bins reset_to_idle = (RESET => IDLE);
    }
endgroup
 
initial begin
    // RTL drives:
    //   cycle 1:  state = RESET,  tvalid = 1     → sample fires; cp=RESET
    //   cycle 2:  state = RESET,  tvalid = 0     → no sample
    //   cycle 3:  state = IDLE,   tvalid = 0     → no sample
    //   cycle 4:  state = ACTIVE, tvalid = 0     → no sample
    //   cycle 5:  state = ACTIVE, tvalid = 1     → sample fires; cp=ACTIVE
    //
    // Sample sequence the covergroup sees: RESET, ACTIVE  (IDLE skipped)
    // → reset_to_idle bin does NOT fire (no IDLE in the sample sequence)
end
Symptom

A $display placed in the FSM clocked block clearly shows state moves RESET → IDLE during cycle 3. The verification engineer believes the transition is happening and that the bin should fire. The coverage report says reset_to_idle 0.0% (0 hits). Hours of debugging the covergroup definition follow — the bin definition is audited against the spec, the state names are confirmed, the => syntax is checked. The bin definition is correct. The covergroup looks correct. The transition is not counted.

Root cause

The covergroup's sampling event is @(posedge clk iff vif.tvalid) — it fires only on clock edges where tvalid is high. During the RESET → IDLE → ACTIVE sequence above, tvalid was low for cycles 2, 3, and 4, so the simulator only sampled cycles 1 and 5 — giving it the sample sequence [RESET, ACTIVE]. The IDLE state existed in the RTL but was never sampled, so the simulator's "previous sample" memory transitioned directly from RESET to ACTIVE. The reset_to_idle bin's definition was correct; the sampling event filtered out the values it needed to see.

This is the structural mismatch behind most transition-coverage debugging sessions: the transition bin describes RTL-cycle adjacency, but the sampling event measures filtered-event adjacency. The two timelines disagree, the bin reads zero, and no diagnostic tool surfaces the gap because both halves are individually correct.

Fix

Two valid fixes, depending on the verification-plan intent.

Fix A — if the transition bin describes RTL cycle adjacency: sample at every clock edge, drop the iff filter.

SystemVerilog — Fix A: sample every clock edge
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
covergroup cg_handshake @(posedge clk);
    cp_state: coverpoint state {
        bins reset_to_idle = (RESET => IDLE);
    }
endgroup

Fix B — if the transition bin describes transaction-event adjacency: rename the bin to reflect the sample-event timeline and document the granularity in option.comment.

SystemVerilog — Fix B: name the bin per the sample-event timeline
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
covergroup cg_handshake @(posedge clk iff vif.tvalid);
    cp_state: coverpoint state {
        // Bin fires when consecutive *valid* transactions show
        // a RESET-state transaction immediately followed by an
        // IDLE-state transaction. Sub-handshake cycles are ignored
        // by design — see vplan §X.Y.
        bins valid_xn_reset_to_idle = (RESET => IDLE);
        option.comment = "transition counted across valid handshakes only "
                          + "(vplan §X.Y) — sub-handshake state is out of scope";
    }
endgroup

The discipline rule that prevents recurrence: the sampling event is part of every transition bin's contract. Code review verifies the sampling event matches what the bin's name and comment claim it measures. Lint rules cannot catch this class — it is a semantic-vs-syntactic mismatch — but a same-PR audit of (event, bin_name, comment) triples catches it consistently.

Industry Context — Where Transition Coverage Is Mandatory

  • FSM-driven RTL. Memory controllers (DDR4 / LPDDR5 command FSMs), PCIe LTSSM, USB device-state machines, Ethernet auto-negotiation — every one is transition-coverage-mandatory at sign-off. The tape-out gate at major IP vendors includes "100% on mandatory transition bins" as an explicit row, separate from total coverage percentage.
  • Reset-recovery scenarios. Spec-defined recovery sequences (warm reset → init → calibration → ready) are textbook transition-chain bins. The chain form ((WARM_RST => INIT => CAL => READY)) directly mirrors the spec section.
  • Protocol handshake ordering. AXI's "AWADDR before WLAST" rule, AHB's "ACTIVE before WAIT" rule, APB's "SETUP → ACCESS" two-cycle handshake — all are transition-coverage rows on the appropriate state coverpoint.
  • Power-state management. SoC PMU FSMs (RUN → IDLE → SLEEP → WAKEUP → RUN) verify their full cycle and every exit path via transition bins; coverage holes here are deferred-tape-out events.
  • Error-recovery coverage. Spec-defined recovery paths (ERR_DETECTED => CLEAR_REQ => CLEAR_ACK => READY) are usually three- or four-step chains; the gap analysis identifies which specific recovery paths the regression has missed.

The reason transition coverage is mandatory in these contexts is structural: code coverage and individual-value functional coverage cannot distinguish "the state was reached" from "the state was reached as part of the spec-defined sequence." The reset-recovery FSM that reaches RUN via a back-door write looks identical to the FSM that reaches RUN via the spec's defined path — until you measure the transitions.

Interview Q&A — Ten Questions You Will Be Asked

It declares a transition bin — the bin fires when the coverpoint's value at the previous sample equals the operator's left-hand value and the value at the current sample equals the right-hand value. The simulator carries a one-sample memory of the coverpoint's previous value; that history is what makes the transition measurable.

Coding Guidelines — Seven Rules for Transition-Coverage Discipline

  1. Match the sampling event to the timeline the transition describes. RTL-cycle adjacency → unfiltered @(posedge clk). Transaction-event adjacency → @(posedge clk iff valid) with the bin name and option.comment documenting the granularity. Mismatched timelines are the single most common source of "the bin doesn't fire" debugging sessions.
  2. Every transition bin's name describes the spec scenario, not the literal values. reset_to_idle is the right shape; state_0_to_state_1 is the wrong shape. The good names trace to verification-plan rows; the bad names go stale when the enum changes.
  3. Use list endpoints (A, B => C) only when the plan row genuinely doesn't distinguish the sources. When the plan rows are per-source, write per-source bins. Lists collapse audit visibility — once one bin, you cannot split it later from the report alone.
  4. Pick the repetition operator that matches the spec language. "For N cycles" → [* N]. "N times total" → [= N]. "On the Nth occurrence" → [-> N]. The right operator makes the bin self-documenting; the wrong operator silently miscounts.
  5. Cite the verification-plan row in option.comment for every transition bin. The chain form (A => B => C) is easy to author and hard to audit — the comment becomes the audit anchor that links bin to spec row.
  6. Pair illegal-transition bins with SVA assertions for sub-cycle catching. Transition bins fire at sample time; SVA can fire at sub-cycle granularity. For a "must never happen" temporal contract, use both — illegal transition for the audit-trail row, SVA for the sub-cycle catch.
  7. Verify chain bins by simulating the chain explicitly. Before trusting (A => B => C => D) 100% hits, run a directed test that drives the exact chain and confirm the bin's hit count incremented by exactly one per execution. Chain bins are easy to write incorrectly (extra spaces, wrong arrows, mis-named constants); the directed-test sanity check is the cheapest way to detect the error.

Summary

Transition bins extend named-bin discipline to value sequences. The => operator is the basic form; chained => describes multi-step sequences; the three repetition operators ([* N], [= N], [-> N]) describe value repetition with different temporal semantics. The single most common failure mode is sampling-granularity mismatch — the bin definition is correct but the sampling event filters out the values the chain needs to see. Match the sample event to the transition's intended timeline, name bins for spec scenarios, prefer per-source bins over collapsed lists when the plan rows distinguish, cite the plan row in option.comment, and pair illegal transitions with SVA assertions for sub-cycle catching. Module 11.7 builds on this with cross coverage — measuring feature combinations, the natural extension of measuring feature sequences.