ignore_bins and illegal_bins both remove values from the coverage goal. A sample in an ignore_bin is silently discarded, while the same value in an illegal_bins raises a runtime error the moment it is sampled.
Ignore says out of scope. Illegal says this must never happen, and failure must be loud. A value claimed by both an ordinary bin and an illegal_bins is illegal.
Ordinary bin |
|
| |
|---|---|---|---|
Hit count | Increments | Discarded | Run-time error |
In the goal math | Yes | Removed from numerator and denominator | Removed from the goal; the run may stop |
Meaning | A scenario | Out of scope | Must never occur |
On a hit | Progress | Nothing | The test fails |
A coverpoint iff guard runs first. Skipped samples hit nothing, and they do not fire illegal_bins.
Error. Illegal takes precedence, and the value never counts as covered.
ignore_bins shrink the denominator, which makes remaining coverage easier to close. That is correct for out-of-scope values and the abuse vector reviewers watch for.
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.
// not-run: Verilator 5.048 ignores covergroups (COVERIGN) and Icarus 13 has none; the bins model counts it
covergroup cg with function sample(bit [2:0] mode);
cp_mode : coverpoint mode {
bins m[] = {[0:7]}; // start: 8 goal bins
ignore_bins rsv = {6}; // reserved encoding, out of scope
illegal_bins bad = {7}; // spec says: must never occur
}
endgroupThe bench counts exactly this coverpoint with the bins model: values 0, 1, 2 and 4, then a 6, then a 7.
4 of 6, 66.67%: ignore_bins and illegal_bins remove 6 and 7 from the goal, so the denominator is 6, not 8. The 6 is discarded silently. The 7 is reported at once, and the percentage does not move.
// uses: covmodel
// ignore_bins, illegal_bins, wildcard bins and a with filter, counted with the bins model.
module tb_bins_excl;
cm_point cp_mode = new("cp_mode"), cp_parity = new("cp_parity"), cp_align = new("cp_align");
initial begin
int m[$];
// bins m[] = {[0:7]}; ignore_bins rsv = {6}; illegal_bins bad = {7};
cp_mode.add("rsv", 6, 6, CM_IGNORE);
cp_mode.add("bad", 7, 7, CM_ILLEGAL);
for (int v = 0; v <= 5; v++) cp_mode.add($sformatf("m[%0d]", v), v, v); // m[6] and m[7] removed
// wildcard bins even = {8'b???????0}; odd = {8'b???????1};
cp_parity.add_wild("even", 8'b0000_0000, 8'b0000_0001);
cp_parity.add_wild("odd", 8'b0000_0001, 8'b0000_0001);
// bins cacheline_aligned = {[0:255]} with (item % 64 == 0); the filter runs once, over the set
for (int item = 0; item <= 255; item++) if (item % 64 == 0) m.push_back(item);
cp_align.add_values("cacheline_aligned", m);
begin
int modes[4] = '{0, 1, 2, 4};
foreach (modes[i]) cp_mode.sample(modes[i]);
end
$display("modes 0, 1, 2 and 4: %0.2f%%", cp_mode.get_coverage());
cp_mode.sample(6); // reserved: silently discarded
cp_mode.sample(7); // must never happen: reported at once
cp_mode.report();
begin
int addrs[3] = '{8'h10, 8'h3F, 8'h80};
foreach (addrs[i]) begin cp_parity.sample(addrs[i]); cp_align.sample(addrs[i]); end
end
cp_parity.report(); cp_align.report();
$display(" the with filter kept %0d values: 0, 64, 128 and 192", cp_align.bin_list[0].vals.size());
if (cp_mode.n_bins() != 6 || cp_mode.n_covered() != 4 || cp_mode.illegal_hits != 1 || cp_align.bin_list[0].hits != 1) $fatal(1, "FAIL: exclusion math");
$display("PASS: coverage is 4 of 6, not 4 of 8; the reserved value vanished and the illegal one was reported");
$finish;
end
endmodulemodes 0, 1, 2 and 4: 66.67%
[cov] cp_mode: illegal bin bad hit by 7
coverpoint cp_mode: 66.67% (4 of 6 bins) below goal 100
rsv 1 (ignore)
bad 1 (illegal)
m[0] 1
m[1] 1
m[2] 1
m[3] 0 <- hole
m[4] 1
m[5] 0 <- hole
coverpoint cp_parity: 100.00% (2 of 2 bins)
even 2
odd 1
coverpoint cp_align: 100.00% (1 of 1 bins)
cacheline_aligned 1
the with filter kept 4 values: 0, 64, 128 and 192
PASS: coverage is 4 of 6, not 4 of 8; the reserved value vanished and the illegal one was reportedm[] = {[0:7]} bins above, with ignore_bins {6}, illegal_bins {7} and four bins hit. What is the coverage, and what does a later sample of the illegal value change?66.7%, four of six. Each exclusion empties a single-value bin, and an exclusion removes a bin only when it empties it. The illegal sample raises a runtime error and changes no math.
Exclusions need a reason on the line. 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.
// not-run: Verilator 5.048 ignores covergroups (COVERIGN) and Icarus 13 has none; the bins model counts it
covergroup cg with function sample(bit [3:0] burst, bit [2:0] size,
bit [7:0] id);
cp_burst : coverpoint burst {
bins fixed = {0};
bins incr = {1};
bins wrap = {2};
ignore_bins reserved = {[3:15]}; // spec: encodings 3-15 reserved
}
cp_size : coverpoint size {
bins b[] = {[0:7]};
// this DUT's bus is 64-bit: sizes above 3 unreachable by config
ignore_bins over_width = {[4:7]};
}
cp_id : coverpoint id {
bins used[4] = {[0:127]};
ignore_bins out_of_pool = {[128:255]}; // ID pool limited by env cfg
}
endgroupReserved spec encodings take ignore_bins with a comment citing the spec section.
Configuration-unreachable values take ignore_bins per build configuration.
Must-never-occur violations take an assertion first, with illegal_bins as documented backup.
Every ignore_bins needs a justifying comment. Uncommented ignores read as coverage-goal gaming.
The assertion. It watches every cycle, while an illegal_bins fires only if the covergroup samples at the guilty moment.
Prefixing a bin with wildcard makes x, z and ? act as don't-care bit positions. One pattern then matches a whole value family in a single bin.
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.
// not-run: Verilator 5.048 ignores covergroups (COVERIGN) and Icarus 13 has none; the bins model counts it
covergroup cg with function sample(bit [7:0] addr, bit [3:0] tag);
cp_parity : coverpoint addr {
wildcard bins even = {8'b???????0}; // LSB 0 → 128 values, ONE bin
wildcard bins odd = {8'b???????1};
}
cp_region : coverpoint addr {
wildcard bins io_page = {8'b1111_????}; // 0xF0-0xFF
}
cp_tag : coverpoint tag {
wildcard bins grp_a[] = {4'b00??}; // [] → 4 bins: 0,1,2,3
}
endgroupWithout the wildcard keyword those bits are literal X and Z matches. Sampled 2-state data never equals them, so the bin silently never hits.
bins with (expression) keeps the set values where the item predicate holds. The filter runs at elaboration over the candidate set, so it must be a constant function of item alone.
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.
// not-run: Verilator 5.048 ignores covergroups (COVERIGN) and Icarus 13 has none; the bins model counts it
covergroup cg with function sample(bit [7:0] addr, bit [7:0] len);
cp_align : coverpoint addr {
bins cacheline_aligned = {[0:255]} with (item % 64 == 0);
// → {0, 64, 128, 192} in one bin
bins word_aligned[] = {[0:31]} with (item % 4 == 0);
// → 8 separate bins: 0,4,8,...,28
}
cp_len : coverpoint len {
bins powers_of_two[] = {[1:128]} with ((item & (item - 1)) == 0);
// → 1,2,4,8,16,32,64,128
bins primes[] = {[2:31]} with (is_prime(item)); // constant function
}
endgroup
function automatic bit is_prime(int unsigned n);
if (n < 2) return 0;
for (int unsigned d = 2; d * d <= n; d++)
if (n % d == 0) return 0;
return 1;
endfunctionThe subset is defined by | Use |
|---|---|
Fixed bit positions |
|
Arithmetic on the value |
|
Hand-picked plan values |
|
A run-time condition, not a property of the value |
|
with and wildcard select which values belong to a bin, a static per-value question. iff decides whether the sample counts at all, a dynamic per-sample question. 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.
// not-run: Verilator 5.048 ignores covergroups (COVERIGN) and Icarus 13 has none; the bins model counts it
covergroup cg with function sample(bit [7:0] addr, bit is_dma,
bit rst_n);
// DMA traffic only, reset excluded; bins select aligned subsets
cp_dma_align : coverpoint addr iff (rst_n && is_dma) {
bins burst_aligned = {[0:255]} with (item % 16 == 0);
wildcard bins hi_page = {8'b11??_????};
ignore_bins low_rsv = {[0:15]}; // reserved region, any source
}
endgroupIt cannot compile as intended. with sees only item; the ready condition belongs in iff.
A permanently unhittable bin. Most tools warn; treat the warning as an error and fix the range or predicate.
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.
Modes 0, 1, 2 and 4 read 4 of 6, not 4 of 8; the reserved 6 vanished and the illegal 7 was reported at once.