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 Here4
  • UVM Foundations14
  • UVM Phases & Simulation Lifecycle26
  • Factory & Configuration15
  • Transaction-Level Modeling (TLM)13
  • UVM Sequences & Stimulus21
  • UVM Agents & Protocol VIP21
  • Environment & Test Classes11
  • Checking & Coverage in UVM21
    • Scoreboard Architecture: Expected vs Actual
    • Reference Models: Predictors, DPI-C and Built-in Comparators
    • Coverage & Closure
      • Designing a Coverage Model from the Spec
      • Coverage Components and Sampling
      • Bins, Illegal Bins and Ignore Bins
      • Crosses and Plan Traceability
      • Coverage Options That Change the Numbers
      • SVA cover property vs Covergroups
      • Regression Merge and the Closure Loop
      • Closing Coverage: The Holes Random Never Hits
      • Reporting and Verbosity Control
      • Code Coverage and How It Closes with Functional Coverage
  • UVM Register Abstraction Layer (RAL)22
  • Advanced UVM in Practice13
  • Debug & Regression10
  • Coding Practice47
  • Verification in Industry Practice10
  • Senior Prep: Architecture, Leadership and Interviews32
Loading lesson

‹Coverage & Closure
  1. Topics
  2. UVM Verification
  3. Checking & Coverage in UVM
  4. Coverage & Closure
  5. Bins, Illegal Bins and Ignore Bins

Part 8 · Checking & Coverage · Intermediate

Bins, Illegal Bins and Ignore Bins

Explicit, illegal, ignore, wildcard and transition bins on the DMA's covergroups, and the illegal bin that turned out to be legal.

On this page

    An earlier version of the course bench had a line in status_cg that looks like a safety net: illegal_bins both = {2'b11}; // the DMA never reports both. If DONE and ERR are ever read together, a commercial simulator raises a run-time error. A reviewer nods: an impossible state, guarded.

    Then a test leaves an ERR uncleared and starts another job, and STATUS reads 0x6. The DUT is behaving exactly as its spec says. So who was wrong, and what does illegal_bins actually claim? This lesson is about the vocabulary of a covergroup, and about the responsibility each word carries.

    The idea: bins are the plan's vocabulary

    Think of a sorting office. Each bin is a labelled pigeonhole; a sampled value lands in every pigeonhole whose label matches it, and a pigeonhole with at least one letter counts as covered. An ignore bin is a sign saying "not our department": matching values are thrown away and the pigeonhole does not exist for the score. An illegal bin is an alarm: a value that must never be posted has arrived, and the simulator reports an error. A default bin is the floor pile, which nobody counts.

    Without explicit bins, the tool creates automatic bins: one per value for small types, or values grouped into at most auto_bin_max (64 by default) buckets for wide ones. A 1-bit coverpoint gets two automatic bins, auto[0] and auto[1]. Explicit bins are how you make the buckets match plan rows.

    The picture: what happens to one sampled value

    Decision flowchart for a sampled value: illegal bins first (error), then ignore bins (dropped), then regular bins (hit), otherwise not counted.
    Precedence for one sample: an illegal bin wins over every other bin, an ignore bin removes the value from every regular bin, and only then do regular bins count.

    The order matters. A value listed in both an illegal bin and a regular bin is illegal. A value listed in both an ignore bin and a regular bin is ignored. Neither illegal nor ignore bins appear in the coverage denominator.

    Build it: the bins of dma_coverage

    Step 1: explicit bins named after plan items

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // snippet: from dma_coverage in the course DMA bench
    covergroup job_cg with function sample(bit [15:0] len, bit irq); option.per_instance = 1;
      cp_len: coverpoint len {
        bins zero    = {0};
        bins one     = {1};
        bins few     = {[2:4]};
        bins many    = {[5:15]};
        bins max_pkt = {16};
        bins over    = {[17:$]};
      }
      cp_irq: coverpoint irq;
      len_x_irq: cross cp_len, cp_irq;
    endgroup
    • The boundaries come from the spec, not from round numbers. Zero is the special case where DONE is set at GO; one is a single-beat job; 16 is the largest job the random constraint creates; 17 and up are legal (LEN is 16 bits) but never random.

    • `[17:$]`: $ in a range means the largest value of the coverpoint's type, here 65535.

    • The names avoid keywords. The bench first named bins small and large, which are SystemVerilog keywords (charge strengths), and it failed to compile. So do matches and program.

    • `cp_irq` has no bins list, so its 1-bit value gets auto[0] and auto[1].

    Step 2: illegal and ignore bins in status_cg

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // snippet: from dma_coverage in the course DMA bench
    covergroup status_cg with function sample(bit done, bit err); option.per_instance = 1;
      cp_outcome: coverpoint {err, done} {
        bins         done_only = {2'b01};
        bins         err_only  = {2'b10};
        bins         both      = {2'b11};   // legal: ERR survives GO unless cleared
        ignore_bins  idle      = {2'b00};   // a read before the job ends says nothing
      }
    endgroup

    The coverpoint is the concatenation {err, done}, so ERR is the high bit: 2'b01 is DONE alone, 2'b10 is ERR alone. The four kinds of bin behave like this:

    Kind

    In the denominator?

    When a value matches

    Use it for

    bins

    Yes

    Hit count + 1

    Plan items

    ignore_bins

    No

    Dropped silently

    Legal values the plan excludes on purpose, such as an idle STATUS read

    illegal_bins

    No

    Simulator run-time error

    Values the spec forbids

    default

    No, and it cannot be crossed

    Dropped from the score

    Rarely: it hides values instead of measuring them

    The illegal-bin error comes from the simulator's coverage engine, not from UVM. It does not pass through the report server, so a run can end with UVM_ERROR : 0 printed and an illegal-bin error further up the log. A regression must catch simulator errors (log scan or exit status), and the real check for a forbidden state belongs in an assertion or the scoreboard. Treat an illegal bin as a second tripwire, never as the only one.

    Step 3: clear_cg, bins for combinations

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    // snippet: from dma_coverage in the course DMA bench
    covergroup clear_cg with function sample(bit [1:0] w1c); option.per_instance = 1;
      cp_clear: coverpoint w1c {
        bins clear_done = {2'b01};
        bins clear_err  = {2'b10};
        bins clear_both = {2'b11};
      }
    endgroup

    clear_both can be hit only when DONE and ERR were both set before the write. Keep that in mind for the war story below.

    Step 4: wildcard bins

    A wildcard bin treats ? (and x or z) in its values as "either". The keyword is what turns those characters into don't-cares. A view of the full 3-bit STATUS read might look like this (not in the bench):

    design.sv
    1
    2
    3
    4
    5
    // snippet: a wildcard view of STATUS {ERR, DONE, BUSY}
    cp_status: coverpoint rdata[2:0] {
      wildcard bins busy      = {3'b??1};   // BUSY, whatever DONE and ERR say
      wildcard bins ended_err = {3'b1?0};   // ERR set, not busy
    }

    Step 5: transition bins need a sample every cycle

    A transition bin such as (2'b10 => 2'b11) matches when two consecutive samples of the same coverpoint have those values. status_cg is sampled only on STATUS reads that show an outcome, so consecutive samples are whole jobs apart: a transition bin there would mean "a DONE read, then an ERR read some jobs later", not a DUT state change. A real transition needs a sample on every clock, which means a covergroup in the interface (this one is not in the bench):

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // snippet: inside axis_if, sampled on every clock out of reset
    covergroup hs_cg @(posedge clk iff rst_n);
      cp_hs: coverpoint {tvalid, tready} {
        bins idle       = {2'b00, 2'b01};
        bins stall      = {2'b10};
        bins xfer       = {2'b11};
        bins stall_xfer = (2'b10 => 2'b11);             // a stall, then the transfer
        bins long_stall = (2'b10 [*3:16] => 2'b11);     // 3 to 16 stalled clocks first
        bins b2b        = (2'b11 => 2'b11);             // back-to-back transfers
      }
    endgroup
    hs_cg hs = new();

    On the input side of the current bench, b2b would stay empty for the same reason gap=0 does: the driver never holds TVALID across two beats.

    Watch it run: STATUS = 0x6

    A scratch test (not part of the course bench) runs a job with LEN = 8 and a 3-word packet, so the DMA ends it early with ERR, and deliberately does not clear ERR. It then starts a 4-word job with IRQ_EN off and polls STATUS until DONE. Scratch run, Verilator:

    Diagram
    +UVM_TESTNAME=dma_both_bits_test   (scratch run)
    UVM_INFO closure_tb.sv(81) @ 315000: uvm_test_top [BOTH] job 1 ended early: STATUS=00000004, ERR not cleared
    UVM_INFO closure_tb.sv(88) @ 685000: uvm_test_top [BOTH] job 2 done: STATUS=00000006
    UVM_INFO dma_tb.sv(411) @ 825000: uvm_test_top.env.sb [SB] 7 words matched, 0 mismatched
    UVM_ERROR :    0
    UVM_FATAL :    0
    • STATUS=00000004 after job 1: ERR alone, as the early TLAST demands.

    • STATUS=00000006 after job 2: DONE and ERR. GO clears DONE but never ERR, exactly as the spec says.

    • 7 words matched: the data path was right throughout. With the earlier illegal_bins both, a commercial simulator turned this final read into a coverage error.

    What breaks: the illegal bin that was legal

    The comment says "the DMA never reports both". What is true is that the bench's tests never let it: run_job writes 0x6 after every job, so ERR is always cleared before the next GO. The illegal bin encoded a habit of the testbench as a property of the DUT. The first test that skipped the clear, which is precisely the spec's "ERR survives GO" row, would fail the regression for a design that did nothing wrong, and the natural reaction, deleting the line, would leave that spec row with no coverage at all.

    The fix is a decision, not an edit. Find the spec sentence that forbids the value. If there is one, keep the illegal bin and add the matching assertion. If there is not (as here), make it a regular bin tied to its plan row, bins done_and_err = {2'b11}; // ERR survives GO, and write the test that hits it. The course bench made exactly this change: status_cg now reads bins both = {2'b11}; // legal: ERR survives GO unless cleared.

    Common pitfall

    The opposite mistake is quieter. An ignore_bins on a value the plan requires removes it from the denominator, and the percentage goes up while the hole disappears from the report. Review every ignore bin as if it were a waiver, because that is what it is.

    Interview

    "What is the difference between illegal_bins and ignore_bins?"

    A weak answer: "Illegal is for errors and ignore is for don't-care values." It says nothing about counting, precedence or who reports what.

    A strong answer: "Neither is in the coverage denominator. An ignore bin silently drops matching values, even if a regular bin also lists them. An illegal bin wins over every other bin and makes the simulator report a run-time error when it is sampled. That error is outside the UVM report server, so the regression must catch it separately, and because it only fires when sampling happens, the real check belongs in an assertion. An illegal bin is a claim about the spec, so I want the spec sentence next to it. On our DMA bench, an illegal bin for DONE and ERR together turned out to be legal: ERR survives GO."

    Expect the follow-ups: What happens to a value that matches no bin? (with explicit bins it is simply not counted) and Why not add a default bin to catch the rest? (it is excluded from coverage, cannot be crossed, and never shows as a hole, so it hides values).

    Check yourself If status_cg had no ignore_bins idle line, would its coverage percentage change?

    No. With explicit bins, a value that matches no bin is simply not counted, so 2'b00 would fall through either way. The ignore bin documents a decision (idle reads are deliberately out of scope) and keeps that decision if someone later adds a catch-all bin. On an automatically binned coverpoint, ignore bins do change the bins that are created.

    Check yourself Someone adds bins done_then_err = (2'b01 => 2'b10); to cp_outcome. What would a hit actually mean?

    That one outcome read showed DONE and the next outcome read showed ERR. status_cg is sampled only on reads that show an outcome, so the two samples belong to different jobs. It says nothing about the DUT's state machine. Transition bins need a coverpoint sampled every clock.

    Check yourself Why did the bench rename its LEN bins from small and large to few and many?

    small and large are SystemVerilog keywords (charge strengths for trireg nets), so using them as bin names is a compile error. matches and program are keywords too.

    Next: single coverpoints say which values occurred. Crosses and Plan Traceability asks which combinations occurred, and how every plan row finds its bins.

    Related topics

    • Up: Coverage & Closure

    • SystemVerilog: illegal and ignore bins

    • SystemVerilog: transition bins

    • The DMA spec: ERR survives GO

    Previous

    139 / 280

    Next: Crosses and Plan Traceability

    Up next

    Up nextCrosses and Plan Traceability

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Designing a Coverage Model from the Spec
    • Coverage Options That Change the Numbers
    • SVA cover property vs Covergroups