← Design Verification Interviews

Interview Question · Code Writing

A Cross That Can Never Close

L1 JuniorL2 Mid-Levelfunctional coveragecross coverage

The Question

The interviewer asks

Cross the command (READ, WRITE) with burst-length bins one, short and long. A READ is never longer than 4 beats. Write the cross so it can reach 100%.

Reveal the Model Answer

The plain cross has six cells, and READ with a long burst can never happen, so it stays below 100%. Exclude that cell: ignore_bins rd_long = binsof(c) intersect {READ} && binsof(l.long_);. Here binsof(c) intersect {READ} picks the READ bins of c, and binsof(l.long_) picks one bin of l. The && keeps only cells that match both. Put the spec reference next to the line.

Six Cells, One of Them ImpossibleArrows show how the two coverpoints build the cross, and what the exclusion removes.
Six Cells, One of Them ImpossibleArrows show how the two coverpoints build the cross, and what the exclusion removes. component Coverpoint c READ, WRITE component Coverpoint l one, short, long_ component cross c, l 2 x 3 = 6 cells component ignore_binsrd_long READ with long_ component 5 cells to close All of them reachable,so 100% is possible component A matching check An assertion thatREAD is at most 4beats 2 bins3 binsremoves 1 cellguarded by
Read the diagram as text
  • Coverpoint c: READ, WRITE
  • Coverpoint l: one, short, long_
  • cross c, l: 2 x 3 = 6 cells
  • ignore_bins rd_long: READ with long_
  • 5 cells to close: All of them reachable, so 100% is possible
  • A matching check: An assertion that READ is at most 4 beats
  • Coverpoint c → cross c, l: 2 bins
  • Coverpoint l → cross c, l: 3 bins
  • ignore_bins rd_long → cross c, l: removes 1 cell
  • cross c, l → 5 cells to close
  • ignore_bins rd_long → A matching check: guarded by

The exclusion keeps the number honest. The assertion catches the day the impossible cell happens.

oneshortlong_
READreachablereachableimpossible: ignored
WRITEreachablereachablereachable

The cross as a grid. Only the READ and long_ cell is excluded.

Self-Check

Tick each key point you covered in your answer.

What Interviewers Listen For (Junior)

A good junior answer counts the six cells and names the one that can never happen. It then writes the ignore_bins line with binsof and intersect.

Cross-Questions

Where the interviewer goes next. Open a node to practise that follow-up.

WhyWhat IfProve ItBreak ItCompare

  1. A Cross That Can Never Close
  2. WhyWhat Binsof and Intersect SelectL1 Junior

    Explain what binsof(c) intersect {READ} selects. Why not just name the bin?

    Reveal the Model Answer

    binsof(c) means all the bins of coverpoint c. Adding intersect {READ} keeps only the bins whose values include READ. For an enum with automatic bins, you never wrote the bin names. Selecting by value is simpler, and it survives a bin rename. When you did name a bin, as with l.long_, binsof(l.long_) picks it directly.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "intersect means the value must equal every listed value."

    It keeps bins that share at least one value with the list. intersect {[5:8]} keeps any bin overlapping that range.

    Source IEEE 1800-2017 §19.6.1

  3. CompareA Cross vs Two Guarded CoverpointsL1 JuniorL2 Mid-Level

    Compare the cross with exclusions against two coverpoints guarded by the command. What does this version print?

    systemverilog
    module tb;
      typedef enum bit {READ, WRITE} cmd_t;
      cmd_t cmd;
      bit [3:0] len;
      covergroup cg;
        rd_len: coverpoint len iff (cmd == READ)  { bins one = {1}; bins short_ = {[2:4]}; }
        wr_len: coverpoint len iff (cmd == WRITE) { bins one = {1}; bins short_ = {[2:4]}; bins long_ = {[5:8]}; }
      endgroup
      cg cov = new();
      initial begin
        for (int i = 1; i <= 4; i++) begin cmd = READ;  len = 4'(i); cov.sample(); end
        for (int i = 1; i <= 4; i++) begin cmd = WRITE; len = 4'(i); cov.sample(); end
        $display("covergroup=%0.2f (reads complete, writes missing long)", cov.get_coverage());
      end
    endmodule
    
    Reveal the Model Answer

    It prints 83.33. The read coverpoint has only the legal read lengths, so it closes at 100%. The write coverpoint is missing long_, so it reads 66.67%, and the group averages the two. Splitting needs no exclusions, and each coverpoint reads clearly. A cross is better when many fields combine, because guarded coverpoints multiply quickly.

    RUNVerilator (coverage build) · simulator service
    Edit the code, then run it
    Expected: covergroup=83.33 (reads complete, writes missing long)

    Self-Check

    Tick each key point you covered in your answer.

    Half-Truth

    "Guarded coverpoints and a cross always give the same number."

    The covergroup averages its items, so one hole weighs differently in each model. Here a missing write bin costs 16.67 points. Compare items, not totals.

    Source IEEE 1800-2017 §19.11

  4. What IfWhen the Impossible Cell HappensL2 Mid-Level

    What if the design one day accepts a long READ? Who notices?

    Reveal the Model Answer

    Nobody, if the only trace of the rule is the ignore_bins. The ignored cell takes the hit silently, and coverage stays at 100%. Every exclusion needs a matching check, such as an assertion on the interface or a scoreboard error. The exclusion keeps the number honest, and the check catches the bug.

    Self-Check

    Tick each key point you covered in your answer.

    Buzzword Without Mechanism

    "The exclusion documents the rule, so the rule is verified."

    Documenting is not checking. A coverage exclusion tells the tool not to count; it never compares behaviour against the spec.

    Source Mehta, SystemVerilog Assertions and Functional Coverage (3rd ed.), §26.19 guidelines (PDF p477)

  5. Break ItOne Wrong Operator in an Ignore ExpressionL2 Mid-Level

    How could the exclusion itself hide holes? Suppose someone writes || instead of &&.

    Reveal the Model Answer

    With ||, the expression selects every READ cell and every long cell, so it removes four of the six cells. Only WRITE one and WRITE short remain, and short writes alone close the cross. Review exclusions by listing the cells they remove, not by reading the expression.

    CellRemoved with &&Removed with ||
    READ, onenoyes
    READ, shortnoyes
    READ, long_yesyes
    WRITE, onenono
    WRITE, shortnono
    WRITE, long_noyes

    Listing the removed cells shows the mistake at once: || removes four cells instead of one.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "|| and && give the same result here, since only one cell is impossible."

    || takes the union of the two selections. The twin closes the cross with two short WRITEs.

    Run It

    The exclusion written with ||, and a regression of short WRITEs.

    RUNVerilator (coverage build) · simulator service
    Edit the code, then run it
    Expected: cross alone=100.00 after short WRITEs only FAIL: with || the ignore removed every READ cell and every long cell, so short WRITEs close the cross
    See the Fix
    module tb;
      typedef enum bit {READ, WRITE} cmd_t;
      cmd_t cmd;
      bit [3:0] len;
      covergroup cg;
        c: coverpoint cmd;
        l: coverpoint len { bins one = {1}; bins short_ = {[2:4]}; bins long_ = {[5:8]}; }
        x: cross c, l {
          ignore_bins rd_long = binsof(c) intersect {READ} && binsof(l.long_);   // the fix: both conditions
        }
      endgroup
      covergroup cross_only;   // the same cross alone, to read its own number
        c: coverpoint cmd { option.weight = 0; }
        l: coverpoint len { bins one = {1}; bins short_ = {[2:4]}; bins long_ = {[5:8]}; option.weight = 0; }
        x: cross c, l { ignore_bins rd_long = binsof(c) intersect {READ} && binsof(l.long_); }
      endgroup
      cg cov = new();
      cross_only xo = new();
      initial begin
        // The regression only ever sent short WRITEs.
        cmd = WRITE; len = 1; cov.sample(); xo.sample();
        cmd = WRITE; len = 3; cov.sample(); xo.sample();
        $display("cross alone=%0.2f after short WRITEs only", xo.get_coverage());
        if (xo.get_coverage() == 100.0) $display("FAIL: with || the ignore removed every READ cell and every long cell, so short WRITEs close the cross");
        else $display("PASS: with && only READ/long is removed, and the READ and long cells stay as holes");
      end
    endmodule
    

    Prints: cross alone=40.00 after short WRITEs only PASS: with && only READ/long is removed, and the READ and long cells stay as holes

  6. Prove ItSolve 7.5.9: The Cross That Can Never CloseSimulator-graded

    Show it, don't just say it: this Silicon Lab problem is graded by the simulator.

    Open Problem 7.5.9

What People Get Wrong

Common wrong answers and why they fail. Run It shows the wrong belief failing on a real simulator.

Misconception

"Legal stimulus will close the cross if we run long enough."

A cell the spec forbids never gets a hit. The twin sends every legal case and the covergroup stops at 94.44%.

Run It

Every legal command and length, crossed without an exclusion.

RUNVerilator (coverage build) · simulator service
Edit the code, then run it
Expected: covergroup=94.44 after every legal case FAIL: the cross still counts the impossible READ/long cell, so it can never reach 100%
See the Fix
module tb;
  typedef enum bit {READ, WRITE} cmd_t;
  cmd_t cmd;
  bit [3:0] len;
  covergroup cg;
    c: coverpoint cmd;
    l: coverpoint len { bins one = {1}; bins short_ = {[2:4]}; bins long_ = {[5:8]}; }
    x: cross c, l {
      // The fix: the spec says a READ is never longer than 4 beats.
      ignore_bins rd_long = binsof(c) intersect {READ} && binsof(l.long_);
    }
  endgroup
  cg cov = new();
  initial begin
    // Every legal case: READ of 1 to 4 beats, WRITE of 1 to 8 beats.
    for (int i = 1; i <= 4; i++) begin cmd = READ;  len = 4'(i); cov.sample(); end
    for (int i = 1; i <= 8; i++) begin cmd = WRITE; len = 4'(i); cov.sample(); end
    $display("covergroup=%0.2f after every legal case", cov.get_coverage());
    if (cov.get_coverage() < 100.0) $display("FAIL: the cross still counts the impossible READ/long cell, so it can never reach 100%%");
    else $display("PASS: with the impossible cell excluded, legal traffic closes the cross");
  end
endmodule

Prints: covergroup=100.00 after every legal case PASS: with the impossible cell excluded, legal traffic closes the cross

Missed Corner

"Exclude whichever cells are still empty near the end."

An empty cell may be impossible, or it may be the untested case that hides a bug. Exclude only what the spec forbids.

Source Mehta, SystemVerilog Assertions and Functional Coverage (3rd ed.), §26.20 (PDF p481)

Half-Truth

"Use illegal_bins for the cell; it is the same as ignoring it."

An illegal cross bin raises an error when hit, and only when the covergroup samples. Use it only if coverage always runs; otherwise ignore it and check the rule elsewhere.

Source IEEE 1800-2017 §19.6.3

Learn It, Then Prove It