A coverpoint with no bin declarations gets one bin per value, up to a cap. The cap is option.auto_bin_max, and its default is 64.
Wider value spaces are dealt evenly across that many buckets, with any remainder in the last bucket. The simulator gives no warning by default.
| What you get |
|---|---|
What you think you get | 256 bins, one per value |
What you actually get | 64 bins of 4 values: |
Consequence |
|
Wider fields |
|
Auto bins suit narrow fields. A 4-bit opcode gets 16 per-value bins, and an enum coverpoint gets one named bin per literal.
64 bins. Values 0, 1, 2 and 3 share auto[0], so len==0 is unverifiable on its own.
Explicit bins replace the carve-up with named, plan-driven buckets. 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] len);
cp_len : coverpoint len {
bins zero = {0}; // single value
bins one = {1};
bins small = {[2:8]}; // one bin for the range
bins medium = {[9:64]};
bins large = {[65:254]};
bins max_len = {255}; // boundary as its own bin
bins odd_picks = {3, 17, 129}; // list → still ONE bin
}
endgroup
// 7 goal bins. Hitting ANY value in [2:8] covers "small".
// The report reads like the verification plan.Each bin is one plan scenario. Hitting any value in [2:8] covers small, and the report reads like the plan.
Any of the three values covers it. It adds exactly one goal bin.
Appending [] turns one bin into an array with one element per value in the set. Appending [N] creates exactly N bins and distributes the values across them.
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] len);
// ONE bin — any value in 0..15 covers it
cp_a : coverpoint len { bins any_low = {[0:15]}; }
// SIXTEEN bins — every value 0..15 must be hit individually
cp_b : coverpoint len { bins each_low[] = {[0:15]}; }
// FOUR bins — 16 values distributed 4 per bin:
// each_q[0]={0..3} each_q[1]={4..7} each_q[2]={8..11} each_q[3]={12..15}
cp_c : coverpoint len { bins each_q[4] = {[0:15]}; }
endgroupDeclaration | Bins | It proves | Choose it when |
|---|---|---|---|
| 1 | The range was touched | Entering the range at all is the scenario |
| 16 | Every value was seen | Every value matters (mind the explosion) |
| 4 | Every quarter was seen | You want deliberate resolution between extremes |
When each value is not a distinct plan item. It is self-inflicted bin explosion that makes closure impossible.
A range dealt across bins b[N] divides evenly when it can. When the value count does not divide evenly, the last bin takes the remainder.
Declaration | Split |
|---|---|
| 16 values over 4 bins: q[0] = 0 to 3, q[1] = 4 to 7, q[2] = 8 to 11, q[3] = 12 to 15 |
| 10 values over 3 bins, remainder 1: t[0] = 0 to 2, t[1] = 3 to 5, t[2] = 6 to 9 (four values) |
| 64 each: h[0] = 0 to 63, ..., h[3] = 192 to 255 |
| Ranges pooled first, then dealt: m[0] = 0 to 3, m[1] = 8 to 11 |
The m[2] alignment on range boundaries is coincidental. Uneven multi-range sets pool values first, so verify uneven splits instead of relying on range boundaries.
Setting N above the value count leaves extra bins uncreated, like b[]. Most tools warn; treat the warning as a design smell.
The bench counts this lesson's bins with the bins model: the seven named length bins, then one range bin, a per-value array and a four-way split, all fed the same eight values.
any_low, each_low[] and each_q[4], six of them inside 0 to 15. What does each report?any_low 1 of 1, because any value in the range covers it. each_q[4] 4 of 4, because the six values happen to land in all four quarters. each_low[] only 6 of 16, because each value is its own bin.
// uses: covmodel
// Explicit bins, one bin versus many, and the [N] split, counted with the bins model.
module tb_bins_explicit;
cm_point cp_len = new("cp_len"), cp_a = new("cp_a"), cp_b = new("cp_b"), cp_c = new("cp_c"), cp_t = new("cp_t");
initial begin
// bins zero = {0}; one = {1}; small = {[2:8]}; medium = {[9:64]}; large = {[65:254]};
// max_len = {255}; odd_picks = {3, 17, 129};
cp_len.add("zero", 0, 0); cp_len.add("one", 1, 1); cp_len.add("small", 2, 8);
cp_len.add("medium", 9, 64); cp_len.add("large", 65, 254); cp_len.add("max_len", 255, 255);
cp_len.add_values("odd_picks", '{3, 17, 129});
cp_a.add("any_low", 0, 15); // bins any_low = {[0:15]};
cp_b.add_each("each_low", 0, 15); // bins each_low[] = {[0:15]};
cp_c.add_split("each_q", 0, 15, 4); // bins each_q[4] = {[0:15]};
cp_t.add_split("t", 0, 9, 3); // bins t[3] = {[0:9]};
// The same eight values reach every coverpoint.
begin
int vals[8] = '{0, 1, 3, 5, 9, 12, 70, 255};
foreach (vals[i]) begin
cp_len.sample(vals[i]); cp_a.sample(vals[i]); cp_b.sample(vals[i]); cp_c.sample(vals[i]);
if (vals[i] <= 9) cp_t.sample(vals[i]);
end
end
cp_len.report(); cp_a.report(); cp_c.report();
$display(" coverpoint cp_b (each_low[]): %0.2f%% (%0d of 16 bins)", cp_b.get_coverage(), cp_b.n_covered());
cp_t.report();
$display(" t[2] holds %0d values; t[0] and t[1] hold %0d each", cp_t.bin_list[2].vals.size(), cp_t.bin_list[0].vals.size());
if (cp_len.get_coverage() != 100.0 || cp_a.n_covered() != 1 || cp_b.n_covered() != 6 || cp_c.n_covered() != 4) $fatal(1, "FAIL: bin counts");
if (cp_t.bin_list[2].vals.size() != 4) $fatal(1, "FAIL: split remainder");
$display("PASS: the same samples covered 1 of 1, 6 of 16 and 4 of 4 bins, and t[2] took the remainder");
$finish;
end
endmodule coverpoint cp_len: 100.00% (7 of 7 bins)
zero 1
one 1
small 2
medium 2
large 1
max_len 1
odd_picks 1
coverpoint cp_a: 100.00% (1 of 1 bins)
any_low 6
coverpoint cp_c: 100.00% (4 of 4 bins)
each_q[0] 3
each_q[1] 1
each_q[2] 1
each_q[3] 1
coverpoint cp_b (each_low[]): 37.50% (6 of 16 bins)
coverpoint cp_t: 100.00% (3 of 3 bins)
t[0] 2
t[1] 2
t[2] 1
t[2] holds 4 values; t[0] and t[1] hold 3 each
PASS: the same samples covered 1 of 1, 6 of 16 and 4 of 4 bins, and t[2] took the remaindert[2] = {6..9}. Ten values over three bins leaves a remainder of one, and the last bin takes it.
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.
The same eight values covered 1 of 1, 6 of 16 and 4 of 4 bins in the three forms, and t[3] = {[0:9]} put four values in t[2].