SV-04

SystemVerilog
Functional Coverage

EcrioniX · SystemVerilog Series· ~16 min read· 6 Code Examples
Coverage Types — From Coarse to Fine
CODE COVERAGE Line / Branch / Toggle Auto — tool generated FUNCTIONAL COV covergroup / coverpoint cross / bins Manual — verification plan FORMAL COV Property checking SVA assume/cover CLOSURE = All three at 100%

Code Coverage vs Functional Coverage

AspectCode CoverageFunctional Coverage
Generated byTool automatically (EDA)Engineer (manual)
MeasuresWhich lines/branches ranWhich design behaviors exercised
Defined inRTL sourceVerification plan + covergroups
100% meansAll RTL paths executedAll scenarios from spec tested
Can be misleading?Yes — no assertion means no bug foundYes — wrong plan misses real scenarios

1. Covergroup and Coverpoint Basics

SystemVerilog — Basic covergroup
// Standalone covergroup — sampled at posedge clk
covergroup cg_axi_txn @(posedge clk);

  // Coverpoint: tracks all values of 'size'
  cp_size: coverpoint size {
    bins byte_tx  = {3'b000};
    bins half_tx  = {3'b001};
    bins word_tx  = {3'b010};
    bins dword_tx = {3'b011};
    illegal_bins rsvd = {[4:7]};   // values 4-7 must NEVER occur
  }

  // Coverpoint: tracks write vs read
  cp_rw: coverpoint write {
    bins rd = {0};
    bins wr = {1};
  }

  // Coverpoint with ranges
  cp_burst: coverpoint len {
    bins single  = {0};
    bins short   = {[1:15]};
    bins medium  = {[16:63]};
    bins long_b  = {[64:255]};
  }

endgroup

// Instantiate and sample
cg_axi_txn cov = new();    // auto-samples at posedge clk

// Or sample manually:
cov.sample();
$display("Coverage: %.1f%%", cov.get_coverage());

2. Inside a Class — Sampling from Monitor

SystemVerilog — Class-based covergroup
class AXICoverage;
  AXITxn txn;   // current transaction being sampled

  covergroup cg_axi;
    // Use txn.field syntax inside class covergroup
    cp_size: coverpoint txn.size {
      bins sizes[] = {[0:3]};    // auto-name: sizes[0], sizes[1], ...
    }
    cp_write: coverpoint txn.write;
    cp_len:   coverpoint txn.len {
      bins lo  = {[0:15]};
      bins hi  = {[16:255]};
    }

    // Cross: all size × write combinations must be seen
    cx_size_rw: cross cp_size, cp_write;

  endgroup

  function new();
    cg_axi = new();
  endfunction

  function void sample(AXITxn t);
    txn = t;
    cg_axi.sample();    // manually triggered
  endfunction

  function void report();
    $display("AXI Coverage: %.1f%%", cg_axi.get_coverage());
  endfunction
endclass

3. Cross Coverage

Cross coverage checks that every combination of two (or more) coverpoints was exercised. It's essential for protocols where behavior depends on multiple simultaneous conditions:

SystemVerilog — Cross coverage
covergroup cg_apb @(posedge clk);

  cp_state: coverpoint apb_state {
    bins idle   = {IDLE};
    bins setup  = {SETUP};
    bins access = {ACCESS};
  }

  cp_rw: coverpoint PWRITE {
    bins rd = {0};
    bins wr = {1};
  }

  cp_err: coverpoint PSLVERR {
    bins ok  = {0};
    bins err = {1};
  }

  // 3-way cross: every state × direction × error combination
  // 3 × 2 × 2 = 12 cross bins must all be hit
  cx_all: cross cp_state, cp_rw, cp_err;

  // Selective cross: only some combinations matter
  cx_rw_err: cross cp_rw, cp_err {
    ignore_bins no_rd_err = binsof(cp_rw.rd) && binsof(cp_err.err);
  }

endgroup

4. Wildcard Bins

SystemVerilog — Wildcard bins
covergroup cg_opcode @(posedge clk);
  cp_op: coverpoint opcode {
    // wildcard: ? matches any bit value
    wildcard bins arith  = {8'b000?????};  // any opcode starting 000
    wildcard bins logic_ = {8'b001?????};
    wildcard bins mem    = {8'b01??????};
    wildcard bins branch = {8'b1???????};
    // Anything not matched goes to default bin
    bins others         = default;
  }
endgroup

5. ignore_bins and illegal_bins

KeywordEffectUse When
ignore_binsExcluded from coverage report — not counted as covered or uncoveredDon't-care scenarios, reset states
illegal_binsCauses a coverage error if the value occursReserved encodings, protocol violations
SystemVerilog
covergroup cg_fifo @(posedge clk);
  cp_fill: coverpoint fill_level {
    bins empty  = {0};
    bins low    = {[1:7]};
    bins mid    = {[8:24]};
    bins hi     = {[25:31]};
    bins full   = {32};

    // Ignore values during reset (X propagation)
    ignore_bins x_val = {[33:63]};

    // Should NEVER go above 32 — flag as error if seen
    illegal_bins overflow = {[33:63]};
  }
endgroup

6. Complete AXI-Stream Coverage Model

SystemVerilog — Full coverage class
class AXISCoverage;
  bit tvalid, tready, tlast;
  bit [7:0] tdata;
  bit [7:0] burst_len;   // tracked externally

  covergroup cg_axis;
    // Handshake states
    cp_hs: coverpoint {tvalid, tready} {
      bins idle         = {2'b00};
      bins valid_wait   = {2'b10};
      bins xfer         = {2'b11};
      bins ready_early  = {2'b01};
    }

    // Data value ranges
    cp_data: coverpoint tdata {
      bins zero    = {8'h00};
      bins ff      = {8'hFF};
      bins mid     = {[8'h01:8'hFE]};
    }

    // Burst length buckets
    cp_burst: coverpoint burst_len {
      bins single = {1};
      bins short_ = {[2:8]};
      bins long_  = {[9:255]};
    }

    // Cross: xfer × burst — did we do long transfers?
    cx_xfer_burst: cross cp_hs, cp_burst {
      ignore_bins no_xfer = binsof(cp_hs.idle);
    }

    // TLAST hit with every burst length
    cp_last: coverpoint tlast;
    cx_last_burst: cross cp_last, cp_burst {
      ignore_bins no_last = binsof(cp_last) intersect {0};
    }

  endgroup

  function new(); cg_axis = new(); endfunction

  function void sample_hs(bit v, r, l, [7:0] d, [7:0] blen);
    tvalid=v; tready=r; tlast=l; tdata=d; burst_len=blen;
    cg_axis.sample();
  endfunction

  function void report();
    $display("AXIS Coverage = %.2f%%", cg_axis.get_coverage());
    $display("  Handshake:  %.2f%%", cg_axis.cp_hs.get_coverage());
    $display("  Burst len:  %.2f%%", cg_axis.cp_burst.get_coverage());
    $display("  Cross xfer: %.2f%%", cg_axis.cx_xfer_burst.get_coverage());
  endfunction
endclass

Coverage Closure Workflow

  1. Define coverage plan — list all behaviors from the spec that need to be tested
  2. Write covergroups — translate each behavior into coverpoints and bins
  3. Run constrained-random tests — let the simulator generate stimulus
  4. Check coverage report — identify uncovered bins
  5. Add targeted directed tests or tighten constraints — drive toward 100%
  6. Merge coverage databases — aggregate across multiple simulation runs for full closure
🔗
Next: UVM Basics (SV-05) — learn how assertions, classes, randomization, and coverage fit together inside the Universal Verification Methodology framework.