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
      • Cross Basics
      • binsof & intersect
      • Pruning Crosses: ignore_bins & illegal_bins
      • Managing Cross Explosion
      • Cross Coverage Patterns
    • Coverage Options & Methods
    • Coverage Closure & Sign-Off
  • Testbench Architecture in SystemVerilog23
  • Advanced Language & Integration25
  • Senior & Interview Preparation21
  • Principal-Level Verification28
Loading lesson

‹Cross Coverage
  1. Topics
  2. SystemVerilog
  3. Functional Coverage in SystemVerilog
  4. Cross Coverage
  5. Cross Basics

Part 5 · Functional Coverage · Intermediate

Cross Basics

Product-of-bins semantics, auto cross bins, three-point crosses, and when a cross carries intent.

On this page

    Why this matters

    Opcode and length coverpoints both read 100%, and a divide on a single beat had never run. Every divide in the regression had been a long burst.

    After this lesson you can: predict the size of a cross, read its cells as pairs of source bins, and decide whether a combination deserves a cross.

    What a cross generates

    A cross names two or more coverpoints and generates one cross bin for every combination of the source bins. It crosses bins, not raw values: a length field bucketed into 3 named bins contributes 3 things, not 256.

    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.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // not-run: Verilator 5.048 ignores covergroups (COVERIGN) and Icarus 13 has none; the bins model counts it
    covergroup op_cg @(posedge clk iff valid);
      cp_op : coverpoint opcode {
        bins add  = {OP_ADD};
        bins sub  = {OP_SUB};
        bins mul  = {OP_MUL};
        bins div  = {OP_DIV};
      }
      cp_len : coverpoint burst_len {
        bins single = {1};
        bins short_b = {[2:4]};
        bins long_b  = {[5:16]};
      }
      // Full product: 4 op bins x 3 len bins = 12 cross bins
      x_op_len : cross cp_op, cp_len;
    endgroup

    cp_len.single

    cp_len.short_b

    cp_len.long_b

    cp_op.add

    <add,single>

    <add,short_b>

    <add,long_b>

    cp_op.sub

    <sub,single>

    <sub,short_b>

    <sub,long_b>

    cp_op.mul

    <mul,single>

    <mul,short_b>

    <mul,long_b>

    cp_op.div

    <div,single>

    <div,short_b>

    <div,long_b>

    12 cross bins, each needing at_least hits to close. One sample fills exactly one cell: the pair of its current op bin and its current length bin.

    Auto bins are named from their source bin pair, and reports show entries like <add,single>. Some tools use a hierarchical form such as x_op_len.add_x_single instead; the exact auto-bin name is tool-dependent, not defined by the standard.

    Each sample increments exactly one cell of the auto product. That one-cell rule holds for auto bins only: named selections can overlap so that one sample hits several bins, and a sample ignored everywhere counts toward no goal bin.

    Crossing three coverpoints

    A cross takes any number of coverpoints, and the product grows multiplicatively. Three points with 4, 3, and 2 bins yield 4 × 3 × 2 = 24 cross bins.

    The listing below is not run in this course's checks, for the same reason.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // not-run: Verilator 5.048 ignores covergroups (COVERIGN) and Icarus 13 has none; the bins model counts it
    covergroup bus_cg @(posedge clk iff txn_done);
      cp_dir   : coverpoint is_write  { bins rd = {0}; bins wr = {1}; }
      cp_size  : coverpoint xfer_size { bins b1 = {1}; bins b2 = {2}; bins b4 = {4}; }
      cp_resp  : coverpoint resp      { bins okay = {0}; bins slverr = {1}; }
    
      // 2 x 3 x 2 = 12 cross bins — every dir/size/resp combination
      x_all : cross cp_dir, cp_size, cp_resp;
    endgroup

    Cross form

    Product control

    Verdict

    cross cp_a, cp_b

    Named coverpoints with shaped bins; the product size is known

    Preferred

    cross addr, len

    Implicit coverpoints with auto bins over raw widths

    Almost always wrong

    Coverpoint with option.weight = 0

    Still samples for the cross but skips the parent percentage

    Use for cross-only helpers

    Cross bins respect the source coverpoints' ignore_bins. A value ignored at the coverpoint never appears in any cross cell.

    When a cross carries intent

    A cross earns its closure cost only when the combination changes DUT behavior. Ask whether the design has logic that looks at both fields together; if not, the cross measures noise.

    Combination

    Shared logic?

    Verdict

    Write direction × burst length

    Burst buffering exists on the write path only

    Good cross

    Opcode × operand-is-zero

    Divide-by-zero is a real corner

    Good cross

    Packet ID × payload byte 3

    No logic correlates the two fields

    Noise

    Two fields constrained to be equal

    Off-diagonal cells are unreachable by construction

    Noise

    Interview

    “Why do we need cross coverage when both coverpoints are at 100%?” is a standard screen. The answer: 100% on each point proves each value occurred in some sample, but not in the same sample. Every add may have been a single beat and every div a long burst — <div,single> can be empty while both points read 100%. Follow-up interviewers like: “how big is the cross of 4 × 3 bins?” — say twelve, then immediately discuss whether all twelve matter.

    Check yourself Every div was a long burst and every single-beat transfer was an add, with both coverpoints at 100%. Why is <div,single> empty?

    The values never shared a sample. Per-point hits say nothing about combinations, so the combination cell stayed empty while both points read 100%.

    Check yourself What goes wrong crossing a raw 32-bit address against a length field?

    The tool builds implicit coverpoints with auto bins over raw values. The product counts unshaped values instead of a handful of shaped bins.

    Testbench

    The bench builds the lesson's 4 × 3 cross with the bins model and feeds it a regression in which every div is a long burst and every single beat is an add.

    Predict first Eight samples: add 1, add 3, sub 3, sub 6, mul 2, mul 7, div 6, div 9. What do the two coverpoints and the cross read?

    Both coverpoints read 100%: every op and every length bin was seen. The cross reads 7 of 12, 58.33%. <div,single> and four other cells are holes, because those values never shared a sample.

    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
    // uses: covmodel
    // The 4 x 3 op-by-length cross: both coverpoints close while the cross does not.
    module tb_cross_basics;
      cm_point cp_op = new("cp_op"), cp_len = new("cp_len");
      cm_cross x_op_len;
      initial begin
        cp_op.add("add", 0, 0); cp_op.add("sub", 1, 1); cp_op.add("mul", 2, 2); cp_op.add("div", 3, 3);
        cp_len.add("single", 1, 1); cp_len.add("short_b", 2, 4); cp_len.add("long_b", 5, 16);
        x_op_len = new("x_op_len", cp_op, cp_len);                  // cross cp_op, cp_len;
        $display("  cross bins: %0d", x_op_len.n_bins());
        // A regression where every div is a long burst and every single beat is an add.
        begin
          int ops[8]  = '{0, 0, 1, 1, 2, 2, 3, 3};
          int lens[8] = '{1, 3, 3, 6, 2, 7, 6, 9};
          foreach (ops[i]) begin cp_op.sample(ops[i]); cp_len.sample(lens[i]); x_op_len.sample(); end
        end
        cp_op.report(); cp_len.report(); x_op_len.report();
        if (x_op_len.n_bins() != 12 || cp_op.get_coverage() != 100.0 || cp_len.get_coverage() != 100.0 || x_op_len.n_covered() != 7)
          $fatal(1, "FAIL: cross math");
        $display("PASS: both coverpoints read 100%% and the cross reads 7 of 12; <div,single> was never sampled together");
        $finish;
      end
    endmodule
    Terminal
      cross bins: 12
      coverpoint cp_op: 100.00% (4 of 4 bins)
        add            2
        sub            2
        mul            2
        div            2
      coverpoint cp_len: 100.00% (3 of 3 bins)
        single         1
        short_b        3
        long_b         4
      cross x_op_len: 58.33% (7 of 12 bins)
        hole: <add, long_b>
        hole: <sub, single>
        hole: <mul, single>
        hole: <div, single>
        hole: <div, short_b>
    PASS: both coverpoints read 100% and the cross reads 7 of 12; <div,single> was never sampled together

    Common pitfall

    Crossing raw wide variables builds implicit auto-bin coverpoints and explodes the product. Crossing every pair of coverpoints “to be safe” spends closure effort with zero added intent. And the cross samples when the covergroup samples: both fields always come from the same event.

    Remember

    • A cross crosses bins, not values: 4 × 3 bins give 12 cells.

    • One sample fills one cell of the auto product.

    • Per-point 100% says nothing about combinations.

    Rule of thumb: cross only fields the design looks at together.

    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.

    Both coverpoints read 100% while the cross read 7 of 12, with <div,single> among the holes.

    Related topics

    • binsof & intersect

    • Sampling strategies

    Previous

    149 / 259

    Next: binsof & intersect

    Up next

    Up nextbinsof & intersect

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Pruning Crosses: ignore_bins & illegal_bins
    • Managing Cross Explosion
    • Cross Coverage Patterns