Functional coverage concepts, the covergroup construct as a user-defined type, coverage points, cross coverage, clocking and block events for sampling, formal arguments including ref, and embedding covergroups inside classes for tightly-bound property coverage.
Functional coverage is a user-defined metric that measures how much of the design specification has been exercised by simulation. Unlike code coverage (which is inferred automatically from design code), functional coverage is written explicitly to reflect the intent of the design — what scenarios, corner cases, and invariants must be tested.
Functional coverage is used as a guide: when coverage is high, the verification team can redirect simulation effort to areas not yet exercised rather than running redundant tests.
The SV functional coverage constructs enable: coverage of variables and expressions; automatic and user-defined coverage bins; bins for values, transitions, and cross products; filtering conditions; event- and sequence-triggered sampling; and procedural activation and query of coverage data.
A covergroup is a user-defined type that encapsulates an entire coverage model. The type is defined once, and any number of instances can be created via new(). It can be defined inside a module, program, interface, or class.
// Define the covergroup type covergroup cg; // ... coverage points, cross, options endgroup // Create an instance cg cg_inst = new; // Optional closing name — must match opening name covergroup my_cov; // ... endgroup : my_cov // Multiple instances of the same covergroup type cg inst_a = new; cg inst_b = new; // independent coverage tracking per instance
new(). Multiple instances track coverage independently — useful when the same coverage model applies to multiple bus channels, ports, or objects.sample() manually.ref variables.// Showing all five components covergroup g2 @(posedge clk); // ① clocking event Hue: coverpoint pixel_hue; // ② coverage point (labeled) Offset: coverpoint pixel_offset; // ② coverage point (labeled) AxC: cross color, pixel_adr; // ③ cross (2 implicit coverpoints) all: cross color, Hue, Offset; // ③ cross (1 var + 2 explicit points) option.per_instance = 1; // ⑤ coverage option endgroup
The covergroup type is defined once. Instances are created with new(). Instance options like name and comment can differ per instance; type options like weight and goal apply to all instances.
// Simple type and instance covergroup cg; ... endgroup cg cg_inst = new; // Instance options can be set after creation cg_inst.option.comment = "Bus A coverage"; cg_inst.a.option.weight = 3; // weight for coverpoint 'a' of this instance // Type options set with :: — affect all instances gc::type_option.comment = "Global coverage model"; gc::a::type_option.weight = 3;
A clocking event specifies when coverage points are sampled automatically. Without one, the covergroup must be sampled procedurally by calling .sample().
// Sample on every posedge clk covergroup cg1 @(posedge clk); coverpoint state; endgroup // Sample on any change of member m_z (event-based) covergroup cg2 @m_z; coverpoint data; endgroup // No clocking event — must call sample() manually covergroup cg3; coverpoint addr; endgroup cg3 c = new; initial begin @(posedge clk); c.sample(); // trigger sampling explicitly end
type_option.strobe = 1 to restrict sampling to the Postponed region — once per time slot regardless of multiple triggers.Instead of a clocking signal, a covergroup can trigger on the start or end of execution of a named block, task, function, or class method.
// Trigger on BEGIN of task "write_burst" covergroup cg_begin @@(begin write_burst); coverpoint burst_len; endgroup // Trigger on END of task "write_burst" covergroup cg_end @@(end write_burst); coverpoint status; endgroup // OR: fire on end of either of two functions covergroup cg_or @@(end read_bus or end write_bus); coverpoint return_code; endgroup
@@(begin task_name) — fires immediately before the task’s first statement.@@(end task_name) — fires immediately after the task’s last statement.disabled.@@(end f1 or end f2).A coverage point samples an integral variable or expression at each clocking event. It can have an optional label (becoming the point’s name) and an optional iff guard condition.
// Labeled coverage point on an enum — 3 auto bins (red, green, blue) enum { red, green, blue } color; covergroup g1 @(posedge clk); c: coverpoint color; // label 'c' creates the coverpoint name endgroup // Guard condition: sample s0 only when reset is inactive covergroup g4; coverpoint s0 iff(!reset); // coverage ignored when reset is true endgroup // Explicit bins: named ranges covering a 10-bit variable bit [9:0] v_a; covergroup cg @(posedge clk); coverpoint v_a { bins a = { [0:63], 65 }; // one bin for this value set bins b[] = { [127:150],[148:191] }; // one bin per value (65 bins) bins c[] = { 200, 201, 202 }; // three individual bins bins d = { [1000:$] }; // $ = maximum value of v_a bins others[] = default; // catch-all: one bin per uncovered value } endgroup
| Syntax | Effect |
|---|---|
| bins name = {range_list} | One bin for the entire value set |
| bins name[] = {range_list} | One bin per value in the set (array of bins) |
| bins name[N] = {range_list} | N fixed bins; values distributed uniformly |
| bins name = default | One bin per value not covered by other bins (not counted in coverage %) |
| ignore_bins name = {values} | Exclude these values from coverage entirely |
| illegal_bins name = {values} | Exclude and report runtime error if seen |
| wildcard bins name = {4’b11??} | X/Z/? treated as 0 or 1 wildcard (2-state match) |
auto_bin_max) bins, where M = bit-width. Default auto_bin_max = 64.auto[value] or auto[low:high].Cross coverage tracks the Cartesian product of two or more coverage points. Every combination of bins from the participating points becomes a cross-product bin. When a variable (not a coverpoint) is listed in a cross, SV implicitly creates a coverpoint for it.
// Simple 2-variable cross: 16×16 = 256 cross-product bins bit [3:0] a, b; covergroup cov @(posedge clk); aXb : cross a, b; // implicit coverpoints for a and b endgroup // Expression coverpoint crossed with a variable covergroup cov2 @(posedge clk); BC: coverpoint b+c; // explicit coverpoint for expression aXb: cross a, BC; // a implicitly created; BC already explicit endgroup // Explicit cross bins using select expressions covergroup cg @(posedge clk); a: coverpoint v_a { bins a1={[0:63]}; bins a2={[64:127]}; } b: coverpoint v_b { bins b1={0}; bins b2={[1:84]}; } c: cross v_a, v_b { // cross products where a does NOT intersect [100:200] → 4 products bins c1 = !binsof(a) intersect {[100:200]}; // cross products in a2 OR in b2 → 7 products bins c2 = binsof(a.a2) || binsof(b.b2); // cross products in a1 AND in b4 → 1 product bins c3 = binsof(a.a1) && binsof(b.b2); // ignore: exclude specific cross products from coverage ignore_bins foo = binsof(a) intersect {5, [1:3]}; } endgroup
binsof(cp) yields all bins of a coverpoint. binsof(cp.bin_name) selects a specific named bin. binsof(cp) intersect {range} selects only bins whose values overlap the range. The negated form !binsof(cp) intersect {range} selects bins whose values do NOT overlap. Combine with && and || for complex cross bin selection.Options control binning behaviour, goals, weights, and reporting. Instance options (option.name) are per-instance; type options (type_option.name) apply to all instances of the covergroup type.
| Instance option | Default | What it controls |
|---|---|---|
| weight | 1 | Weight of this point/cross toward overall coverage |
| goal | 90 | Target coverage percentage for this instance/point |
| name | unique | Explicit name for this instance in coverage reports |
| comment | “” | Comment stored in coverage database and reports |
| at_least | 1 | Minimum hits per bin to count as covered |
| auto_bin_max | 64 | Max automatic bins for coverpoints without explicit bins |
| cross_auto_bin_max | unbounded | Max automatic cross product bins |
| detect_overlap | 0 | Warn if bin ranges overlap within a coverpoint |
| per_instance | 0 | Track coverage individually per instance (in addition to type-level) |
| Type option | Default | What it controls |
|---|---|---|
| weight | 1 | Weight toward the simulation-wide cumulative coverage |
| goal | 90 | Target for the covergroup type overall |
| comment | “” | Comment for the covergroup type in reports |
| strobe | 0 | 1 = sample in Postponed region (one sample per time slot) |
// Options inline in the covergroup definition covergroup g1(int w, string instComment) @(posedge clk); option.per_instance = 1; option.comment = instComment; type_option.strobe = 1; // sample once per time slot a: coverpoint a_var { option.auto_bin_max = 128; // 128 bins for this point } b: coverpoint b_var { option.weight = w; // instance option set from argument type_option.weight = 5; // type option — must be a constant } endgroup
Covergroups can accept arguments, allowing generic coverage models reusable across different variables and ranges. A ref argument causes the covergroup to track the variable — sampling its current value at each clock tick. An input argument captures the value once at new() time.
// Generic covergroup with ref variable and range arguments covergroup gc(ref int ra, int low, int high) @(posedge clk); coverpoint ra { // ra sampled by reference at each clock bins good = { [low : high] }; // range from input args bins bad[] = default; } endgroup int va, vb; gc c1 = new(va, 0, 50); // c1 tracks va; good = [0:50] gc c2 = new(vb, 120, 600); // c2 tracks vb; good = [120:600] // ref vs input distinction: // ref int ra → ra is sampled at every clocking event (tracks variable) // int low → low is evaluated once when new() is called (snapshot)
Embedding a covergroup inside a class tightly binds coverage to the class properties — including local and protected members that would otherwise be inaccessible from outside. The embedded covergroup becomes part of the class’s type definition.
// Simple embedded covergroup class xyz; bit [3:0] m_x; int m_y; bit m_z; covergroup cov1 @m_z; // samples on change of m_z coverpoint m_x; coverpoint m_y; endgroup function new(); cov1 = new; endfunction // MUST instantiate in new() endclass // Multiple covergroups in one class — different sampling events class MC; logic [3:0] m_x; local logic m_z; // local — only embedded covergroup can access bit m_e; covergroup cv1 @(posedge clk); coverpoint m_x; endgroup covergroup cv2 @m_e; coverpoint m_z; endgroup // cv2 covers local m_z — impossible from outside the class endclass
new() method by assigning cg_name = new(...). If it is not, the covergroup is never created and no data is sampled.local and protected — without changing the class’s data encapsulation.class Helper; int m_ev; endclass class MyClass; Helper m_obj; int m_a; covergroup Cov @(m_obj.m_ev); // trigger on m_obj.m_ev change coverpoint m_a; endgroup function new(); m_obj = new; // MUST create m_obj before Cov! Cov = new; // Cov references m_obj.m_ev — m_obj must exist first endfunction endclass
class C1; bit [7:0] x; covergroup cv(int arg) @(posedge clk); option.at_least = arg; // each bin must be hit 'arg' times to count coverpoint x; endgroup function new(int p1); cv = new(p1); // pass in minimum hit count at construction time endfunction endclass initial begin C1 obj = new(4); // each bin must be hit at least 4 times end
| Item | Syntax | Notes |
|---|---|---|
| Define type | covergroup name; … endgroup | Type only — no sampling yet |
| Instantiate | name inst = new(args) | Sampling begins at construction |
| Clock trigger | covergroup cg @(posedge clk) | Auto-samples at every trigger |
| Block trigger | covergroup cg @@(end task_name) | Samples at start/end of named block |
| Manual sample | inst.sample() | Required when no clocking event |
| Coverage point | label: coverpoint expr; | Label becomes coverpoint name |
| Guard condition | coverpoint x iff(!reset) | Skip sample when condition false |
| Cross | label: cross cp1, cp2; | Cartesian product of all bins |
new()..sample() procedurally.default bin catches uncovered values but does not count toward coverage %.auto_bin_max) bins.local and protected.new() — or they never collect data.m_obj.m_ev) must be created before the covergroup is instantiated.type_option values must be constants; option values can be expressions evaluated at new() time.per_instance can only be set in the covergroup definition, not procedurally afterward.parameter type), localparam in generate blocks, the $ token for unbounded ranges, $isunbounded(), and parameter dependencies.