Part 5 · Functional Coverage · Intermediate

Managing Cross Explosion

Bin-count multiplication math, coarser source bins, targeted named cross bins, splitting covergroups, and with-filtered crosses.

The multiplication problem

Cross bin counts multiply, and the numbers get away from you fast. Three coverpoints that each look reasonable in isolation can produce a cross no regression will ever close — and every empty cell costs triage time at sign-off.

diagram
EXPLOSION MATH

  cp_addr_region : 16 bins   (address map regions)
  cp_burst_len   : 16 bins   (1..16, one bin each)
  cp_qos         :  8 bins   (QoS levels)

  cross cp_addr_region, cp_burst_len, cp_qos
      = 16 × 16 × 8 = 2048 cross bins

  Regression reality check:
    ~50k transactions/seed × 100 seeds = 5M samples
    5M samples / 2048 cells ≈ 2441 avg hits/cell — looks fine, BUT
    samples are NOT uniform: random stimulus clusters, corner cells
    may see one sample per million. Last 5% of cells dominate the
    entire closure schedule.

  Same intent, restructured:
    region(4 coarse) × len(3) × qos(2 groups) = 24 cells
    + 6 named precision bins for plan-critical exact combos
    = 30 bins. Closeable in days, reviewable in minutes.

The fix is never 'run more seeds'. It is restructuring the cross so the goal contains only cells the plan actually demands.


Strategy 1 & 2 — coarsen sources, name only targets

systemverilog
// STRATEGY 1: coarser source bins — shrink the factors
cp_len : coverpoint burst_len {
  bins single = {1};
  bins short_b = {[2:4]};
  bins long_b  = {[5:15]};
  bins max_b   = {16};        // 16 bins -> 4 bins
}

// STRATEGY 2: keep sources fine, but replace the auto product
// with only the named bins the plan demands.
x_len_qos : cross cp_len, cp_qos {
  bins max_hiqos  = binsof(cp_len.max_b) && binsof(cp_qos) intersect {[6:7]};
  bins single_any = binsof(cp_len.single);
  // everything else: explicitly not a goal
  ignore_bins rest = !binsof(cp_len.max_b) && !binsof(cp_len.single);
}

Strategy 3 — split covergroups by concern

One covergroup crossing everything against everything is a smell. Split by verification concern: a performance covergroup crosses QoS with length; an address-map covergroup crosses region with direction. Each cross stays two-dimensional and reviewable, and option.weight on each group keeps the rollup percentage meaningful.

systemverilog
covergroup perf_cg @(posedge clk iff txn_done);
  cp_qos : coverpoint qos      { bins lo = {[0:3]}; bins hi = {[4:7]}; }
  cp_len : coverpoint burst_len{ bins s = {1}; bins m = {[2:8]}; bins l = {[9:16]}; }
  x_perf : cross cp_qos, cp_len;            // 6 cells
endgroup

covergroup addrmap_cg @(posedge clk iff txn_done);
  cp_reg : coverpoint region   { bins r[4] = {[0:15]}; }   // 4 coarse bins
  cp_dir : coverpoint is_write { bins rd = {0}; bins wr = {1}; }
  x_map  : cross cp_reg, cp_dir;            // 8 cells
endgroup
// 6 + 8 = 14 goal cells instead of one 2048-cell monster.

What reviewers flag

Cross-review checklist

  • Any cross over ~50 cells without a written justification line in the plan.

  • Crosses of 3+ coverpoints where no design logic examines all three fields together.

  • Auto product accepted wholesale — no named bins, no pruning — on any non-trivial cross.

  • A coverpoint with per-value bins (bins b[] = ...) feeding a cross — the factor explodes silently.

  • Goal cells that have been at zero hits across three consecutive regressions — either unreachable (prune) or unplanned-for (write the test).

Interview angle: "You inherit a covergroup with a 16×16×8 cross at 61% after a 500-seed regression. What now?" The expected shape: quantify (2048 cells, ~800 empty), classify empties by reachability, coarsen or split so the goal matches intent, keep a handful of named precision bins for the spec-critical exact combinations, re-baseline, and present the before/after goal math to the review. Mentioning that you would NOT just 'add seeds' is most of the answer.

Key takeaways

  • Cross size is the product of source bin counts — control the factors before the product.

  • Replace the auto product with named target bins plus an ignore_bins catch-all when only specific combos matter.

  • Split monolithic covergroups by verification concern — several small crosses beat one giant one.

  • Closure effort lives in the emptiest cells — a goal of 30 intentional cells beats 2048 accidental ones.

Common pitfalls

  • bins x[] per-value array bins feeding a cross — the multiplication happens out of sight.

  • Answering explosion with more regression seeds — random stimulus clusters; rare cells stay rare.

  • Coarsening bins so far the cross stops distinguishing the corner the plan cares about — keep named precision bins.

  • Splitting covergroups but leaving all weights at default — the rollup percentage no longer reflects priorities.