Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • Start Here6
  • SystemVerilog Language Foundations28
  • Object-Oriented SystemVerilog for Verification30
  • Constraint Randomization — Interview-Critical Deep Dive36
  • SystemVerilog Assertions — Interview-Critical Deep Dive40
  • Functional Coverage in SystemVerilog22
    • Covergroups & Coverpoints
    • Bins: Explicit, Auto, Illegal & Ignore
    • Cross Coverage
    • Coverage Options & Methods
    • Coverage Closure & Sign-Off
      • From Spec to Coverage Plan
      • Hole Analysis and Triage
      • Closing Techniques
      • Exclusions and Waivers
      • Sign-Off Metrics and Review
  • Testbench Architecture in SystemVerilog23
  • Advanced Language & Integration25
  • Senior & Interview Preparation21
  • Principal-Level Verification28
Loading lesson

‹Coverage Closure & Sign-Off
  1. Topics
  2. SystemVerilog
  3. Functional Coverage in SystemVerilog
  4. Coverage Closure & Sign-Off
  5. Exclusions and Waivers

Part 5 · Functional Coverage · Intermediate

Exclusions and Waivers

Exclude only the unreachable, document every waiver, and never bulk-exclude at deadline.

On this page

    Why this matters

    Coverage went from 93% to 100% in one Friday commit of exclusions. Months later a silicon bug traced to a cell in that commit: it was reachable all along.

    After this lesson you can: decide what may be excluded, write a waiver record that survives a year, and spot a bulk exclusion in review.

    What may legitimately be excluded

    An exclusion removes a bin, cell, or hierarchy from the closure goal. It is the correct tool exactly when the scenario cannot or need not occur, and a falsification of the metric in every other case.

    The legitimacy test is simple: would hitting this bin teach anything the plan wants to know? If yes, it stays.

    • Structurally unreachable: tied-off inputs, hardware configs absent from this product, dead modes confirmed by the designer.

    • Spec-forbidden combinations that are separately checked: the illegal_bins or assertion supplies the evidence, and the cross cell leaves the goal.

    • Out-of-scope hierarchy: vendor IP verified by its supplier, behavioral models, test harness internals.

    • Deferred features: explicitly not in this release, with the plan row marked deferred and revived next release.

    • Auto-product residue: cross cells the tool generated that no plan row ever demanded. Better to prune these in the model with ignore_bins.

    The listing below is not run in this course's checks: the open simulators do not count covergroups, so the lesson's bench counts it with the bins model.

    mode_cov_if.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    // not-run: Verilator 5.048 ignores covergroups (COVERIGN) and Icarus 13 has none; the bins model counts it
    interface mode_cov_if(input logic clk);
      logic       single_ch;   // 1 in the single-channel SKU
      logic [3:0] op;          // 0-7 single-op, 8-15 dual-op
    
      covergroup mode_cg @(posedge clk);
        cp_cfg : coverpoint single_ch {
          bins single_ch = {1};
          bins dual_ch   = {0};
        }
        cp_op : coverpoint op {
          bins single_op = {[0:7]};
          bins dual_op   = {[8:15]};
        }
        x_mode : cross cp_cfg, cp_op {
          // EXCL-014: dual-channel ops are impossible in the single-channel SKU.
          // Approved: verification lead plus designer. Spec s2.1 table 2-1.
          ignore_bins single_sku = binsof(cp_cfg.single_ch) &&
                                   binsof(cp_op.dual_op);
        }
      endgroup
    endinterface

    Waiver documentation

    A waiver is the audit record behind an exclusion. The rule of thumb: a waiver must let a stranger, a year later, decide whether the exclusion is still valid, without finding the people involved.

    Field

    Example

    id

    EXCL-014: stable, referenced from code

    target

    mode_cg::x_mode <single_ch, dual_op>: the exact bins or cells

    reason

    The single-channel SKU has no dual-op datapath

    evidence

    Spec s2.1 table 2-1; designer confirmation (link)

    class

    Structurally unreachable

    approved

    Verification lead and designer, 2026-04-02

    expires

    Re-review at the next SKU addition or major spec revision

    Who approved, why, and a link to the spec are the non-negotiable three. An exclusion nobody can defend a year later is a hole wearing a costume.

    • Version-control the exclusion file with the testbench. It is part of the coverage model, and its diff history is audit evidence.

    • One exclusion per entry, each with its waiver ID. No wildcard patterns that silently swallow future bins.

    • Re-validate on RTL or spec change. Yesterday's unreachable becomes reachable when a tie-off is removed.

    • Track the exclusion count as a metric. A rising curve near a deadline is itself a review finding.

    • Prefer ignore_bins in the model over tool-side exclusion files where possible. Code review sees the former by default.

    The deadline bulk-exclusion failure mode

    Every verification organization has the story. Friday before sign-off, coverage is at 93%, and a bulk exclusion of miscellaneous unreachable crosses lands the report at 100%.

    Months later a silicon bug traces to a cell inside that bulk exclusion. It was reachable all along, just never analyzed.

    Honest closure

    Bulk exclusion at deadline

    The last 7%

    Triaged: 4% steered and closed, 2% directed and closed, 1% waived, each documented

    Excluded as a block: no per-cell analysis, no designer confirmation, one commit of 400 cells

    Result

    Every zero-hit cell has a name, an owner and a reason

    An unknown number of reachable, untested scenarios ship

    Later

    The silicon-bug post-mortem finds the exclusion commit

    Interview

    “What is the difference between ignore_bins and illegal_bins?” Both leave the coverage goal: a hit on ignore_bins is silently discarded, while a hit on illegal_bins is a runtime error. File-a-bug means illegal, shrug means ignore, and both need a documented reason since both change the denominator.

    Common pitfall

    Wildcard exclusion patterns that silently swallow future bins. One exclusion per entry, each with its waiver ID, so newly added bins stay visible.

    Check yourself A block comes from a vendor who verifies it. Exclude or cover?

    Exclude as out-of-scope hierarchy, with a waiver naming the supplier evidence. Do not spend closure effort on logic owned elsewhere.

    Check yourself Coverage jumps from 93% to 100% in one commit of exclusions. What should the review do?

    Walk every added entry item by item. A deadline spike in exclusions is a finding, and bulk entries hide reachable scenarios.

    Testbench

    The bench builds the x_mode cross twice with the bins model: once with the documented EXCL-014 exclusion only, and once with a deadline commit that excludes every cell still at zero. The regression never runs a dual-op on the dual-channel SKU; months later, a test does.

    Predict first Before the late test, what do the two crosses read? And after it?

    Before: 2 of 3 with EXCL-014, naming <dual_ch, dual_op> as the hole; 2 of 2, 100%, with the bulk exclusion. After: the honest cross closes at 3 of 3, while the bulk cross still reads 100% and silently discards the hit, because the reachable cell was excluded.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    // uses: covmodel
    // One documented exclusion against a deadline bulk exclusion, on the same regression.
    module tb_waivers;
      cm_point cp_cfg = new("cp_cfg"), cp_op = new("cp_op");
      cm_cross x_honest, x_bulk;
      function void observe(int single_ch, int op);
        cp_cfg.sample(single_ch); cp_op.sample(op); x_honest.sample(); x_bulk.sample();
      endfunction
      initial begin
        cp_cfg.add("single_ch", 1, 1); cp_cfg.add("dual_ch", 0, 0);
        cp_op.add("single_op", 0, 7);  cp_op.add("dual_op", 8, 15);
        x_honest = new("x_mode (EXCL-014 only)", cp_cfg, cp_op);
        x_bulk   = new("x_mode (bulk exclusion)", cp_cfg, cp_op);
        // EXCL-014: dual-channel ops are impossible in the single-channel SKU. Spec s2.1 table 2-1.
        x_honest.ignore(x_honest.sel("single_ch", "dual_op"));
        // The regression before the deadline: no test ever ran a dual-op on the dual-channel SKU.
        for (int op = 0; op < 8; op++) begin observe(1, op); observe(0, op); end
        // Friday: "exclude every cell still at zero", in one commit.
        foreach (cp_cfg.bin_list[i]) foreach (cp_op.bin_list[j])
          if (x_bulk.hits[x_bulk.idx(i, j)] == 0) x_bulk.ignore(x_bulk.sel(cp_cfg.bin_list[i].name, cp_op.bin_list[j].name));
        x_honest.report(); x_bulk.report();
        // Months later a test finally runs a dual-op on the dual-channel SKU, the reachable cell.
        observe(0, 12);
        $display("after a dual-op on the dual-channel SKU:");
        x_honest.report(); x_bulk.report();
        if (x_honest.n_bins() != 3 || x_honest.get_coverage() != 100.0 || x_bulk.n_bins() != 2 || x_bulk.hits[x_bulk.idx(1, 1)] != 0)
          $fatal(1, "FAIL: waiver math");
        $display("PASS: the documented exclusion named the reachable hole; the bulk exclusion read 100%% and swallowed it");
        $finish;
      end
    endmodule
    Terminal
      cross x_mode (EXCL-014 only): 66.67% (2 of 3 bins)
        hole: <dual_ch, dual_op>
      cross x_mode (bulk exclusion): 100.00% (2 of 2 bins)
    after a dual-op on the dual-channel SKU:
      cross x_mode (EXCL-014 only): 100.00% (3 of 3 bins)
      cross x_mode (bulk exclusion): 100.00% (2 of 2 bins)
    PASS: the documented exclusion named the reachable hole; the bulk exclusion read 100% and swallowed it

    Remember

    • Exclude only what cannot or need not happen.

    • Who approved, why, and the spec link: every waiver.

    • A spike in exclusions near a deadline is a finding.

    Rule of thumb: one exclusion per entry, each with its waiver ID.

    How this was checked

    Counted with the course's bins model (rich/coverage/cov_model.sv, listed on the Coverage hub) on Verilator 5.048 (--binary --timing) on 2026-10-18; every bench printed the PASS line shown. Verilator 5.048 parses covergroups with a COVERIGN warning and ignores their bins, and Icarus 13 has none, so each covergroup listing is marked not run and its bench counts the same bins with the model.

    With EXCL-014 alone the cross named the reachable hole; the bulk exclusion read 100% and silently discarded the later hit.

    Related topics

    • Coverage bins

    Previous

    161 / 259

    Next: Sign-Off Metrics and Review

    Up next

    Up nextSign-Off Metrics and Review

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • From Spec to Coverage Plan
    • Hole Analysis and Triage