In hardware verification, there are typically two types of coverage: code coverage and functional coverage. Code coverage is automatically extracted from the design code by EDA tools, while functional coverage is user-specified to measure the progress of testing the design intent and functionality. Therefore, functional coverage has two key aspects:
- It is specified by the user, not automatically inferred from the design code.
- It is based on the design requirements and is independent of the actual design code and structure.
Functional coverage is primarily composed of covergroups, coverage points (coverpoints), cross coverage, coverage options, and coverage methods.
1. Covergroup
A covergroup is used to build a coverage model, encapsulating the model and its specifications. It can contain the following components:
- A clocking event for synchronizing and sampling coverpoints.
- Coverpoints.
- Cross coverage.
- Optional parameters.
- Coverage options.
A covergroup is a user-defined type and can be defined within a package, module, program, interface, checker, or class. Similar to a class, a covergroup can be instantiated multiple times using the new()
constructor. As shown below, covergroup name is "cg". An instance of cg, named cg_inst, was created through the new() constructor.
covergroup cg;
...
endgroup
cg cg_inst = new;
Parameters can be passed to a covergroup via the new()
constructor. The parameter types can only be ref (treated as const ref) or input, but not
output or inout.
The timing for coverage sampling can be specified using an@event
or the sample()
method. A covergroup can contain one or more coverpoints. A coverpoint can cover a variable or an expression. Within a coverpoint, a set of bins can be defined to collect values or value transitions. Bins that collect a set of values are called state bins, while those that collect value transitions are called transition bins.
A common practice is to embed a covergroup definition within a class. This is known as an embedded covergroup declaration, which provides a simple way to cover class properties while preserving encapsulation.
2. Coverage Point
The sampling of a coverpoint expression (including an iff
condition) occurs when the covergroup is sampled. A coverpoint creates a hierarchical scope and can have an optional label. If a label is used, it becomes the name of the coverpoint. This name can be used in cross coverage and for accessing the coverpoint's methods. If no label is specified and the coverpoint is associated with a single variable, the variable's name can be used as the coverpoint name. In other cases, the name is implementation-defined by the tool. Such automatically generated names are only for reporting and cannot be referenced elsewhere in the code.
A coverpoint bin associates a name and a count with a set of values or a sequence of value transitions. The corresponding count is incremented each time the specified value or transition sequence is matched. Each bin can be followed by an iff
construct to specify a sampling condition; if the condition is false, the count will not be incremented. For transition bins, the count can increase by at most 1 per sample, regardless of how many times the same bin is hit.
You can create a separate bin for each value in a given range list by appending []
to the bin name. To distribute the values in a range list into a specific number of bins, you can specify a positive integer expression within the brackets []
. If the fixed number of bins is less than the number of specified values, the tool attempts to distribute them evenly, with the last bin containing any remainder. If the number of bins is greater than the number of values, some bins will be empty.
A single bin can be created for a list of values by enclosing the values in {}
after the assignment operator.
For range lists, you can use the notations [ expression : $ ]
or [ $ : expression ]
.
If no bins are explicitly specified, they are created automatically. The maximum number of auto-created bins is determined by the auto_bin_max ( coverage option) .
The default
keyword can be used to cover all other values not specified in the explicit bins. The default bin is not considered in the calculation of coverpoint coverage or cross coverage. Similarly, default sequence
covers all other transitions not specified in explicit transition bins. A default
or default sequence bin
cannot be explicitly ignored. An error will occur if a bin is specified as both an ignore_bins
and a default
or default sequence
.
A wildcard
bin allows X, Z, or ? to be treated as 0 or 1. For example:
wildcard bins g12_15 = { 4'b11?? };
If the sampled values are 1100, 1101, 1110, and 1111, the count for g12_15
will be incremented for each match.
Wildcard bins can also be used to create separate bins:
wildcard bins g12_15_array[] = { 4'b11?? };
The above code creates four separate bins: 1100, 1101, 1110, and 1111.
Wildcard bins can also be used for transition bins:
wildcard bins T0_3 = (2'b0x => 2'b1x);
The count for the T0_3
bin increases whenever any of the following value transitions occur, which is similar to the (0,1=>2,3)
syntax:
00 => 10, 00 => 11, 01 => 10, 01 => 11
Specifying Transition Bins
The syntax for specifying transitions is as follows:
value1(range_list1) => value2(range_list2)
: This specifies that the sample following value1
must be value2
. If range lists are used, SystemVerilog expands the transition to cover all combinations. For example:
1,5 => 6, 7
This is equivalent to:
( 1=>6 ), ( 1=>7 ), ( 5=>6 ), ( 5=>7 )
trans_item[* repeat_range]
: This indicates that trans_item
must be repeated repeat_range
times consecutively. For example:
3 [* 5]
This is equivalent to:
3=>3=>3=>3=>3
You can also specify a range for the repetitions:
3 [* 3:5]
This is equivalent to:
( 3=>3=>3 ), ( 3=>3=>3=>3 ), ( 3=>3=>3=>3=>3 )
trans_item[-> repeat_range]
or trans_item[= repeat_range]
: This indicates the number of times trans_item
appears, regardless of any other values in between. For example:
3 [-> 3]
This is equivalent to:
...=>3...=>3...=>3
, where ...
represents any sequence of transitions not containing the value 3. Another example:
1 => 3 [ -> 3] => 5
This is equivalent to:
1...=>3...=>3...=>3 =>5
3. Cross Coverage
A covergroup can specify cross coverage between two or more coverpoints or variables. If a variable is specified, SystemVerilog implicitly defines a coverpoint for it before including it in the cross. Therefore, the inputs to cross coverage are essentially coverpoints. Expressions cannot be used directly in a cross; they must first be defined as coverpoints.
Cross coverage provides an optional label, which creates a hierarchical scope for the bins defined within the cross. An iff
condition can also be used to enable or disable the cross coverage calculation for a given sample.
Bins defined as default
, ignored
, or illegal
in a coverpoint are not included in the cross. Cross coverage only allows crossing between coverpoints within the same covergroup; referencing a coverpoint from another group will result in a compilation error.
In addition to automatically generated bins, SystemVerilog allows users to define specific cross coverage bins using a bin selection expression. User-defined cross bins and auto-generated bins can coexist in the same cross. Any auto-generated bins not superseded by user-defined cross bins will be retained. For example:
int i,j;
covergroup ct;
coverpoint i { bins i[] = { [0:1] }; }
coverpoint j { bins j[] = { [0:1] }; }
x1: cross i,j;
x2: cross i,j {
bins i_zero = binsof(i) intersect {0};
}
endgroup
The results for the x1
cross are:
<i[0],j[0]>
<i[1],j[0]>
<i[0],j[1]>
<i[1],j[1]>
The results for the x2
cross are:
i_zero // user-specified bin for <i[0],j[0]> and <i[0],j[1]>
<i[1],j[0]> // an automatically generated bin that is retained
<i[1],j[1]> // an automatically generated bin that is retained
The binsof
construct produces the bins of its expression, which can be an explicit coverpoint, a variable (for which a coverpoint is implicitly generated), or a coverpoint bin. The resulting bins can be further refined using the intersect
syntax to select or exclude certain values. Multiple values can be selected using a comma-separated list, including single values, ranges of values, or open-ended ranges. For example:
[ $ : value ] => The set of values less than or equal to value
[ value : $ ] => The set of values greater than or equal to value
Bin selections can also be combined using logical operators (&&
,||
) for more complex filtering.
4. Coverage Options
Coverage options control the behavior of covergroups, coverpoints, and crosses. There are two types of options: those that specify the behavior of a covergroup instance and those that specify the behavior of a covergroup type. Specifying multiple values for the same option will cause an error.
Covergroup Instance Options
Instance-specific options can be set with different values at initialization for each instance. These initial values only affect their corresponding instance.
Instance-specific options can be set within the covergroup definition using the following syntax:
option.member_name = expression;
Every covergroup, coverpoint, and cross has a built-in member named option
. Assignment statements to this member within a covergroup definition take effect when the covergroup is instantiated. The per_instance
and get_inst_coverage
options can only be set within the covergroup definition. The auto_bin_max
and detect_overlap
options are effective only when set in a covergroup or coverpoint definition. Other instance-specific options can be set by assignment after the covergroup has been instantiated.
All instance options can be specified at the covergroup level. Except for weight
, goal
, comment
, and per_instance
, all other options set at the covergroup level also serve as the default values for the corresponding options in all coverpoints and crosses within that covergroup. Individual coverpoints or crosses can override these defaults. When set at the covergroup level, the weight
, goal
, comment
, and per_instance
options do not affect the default values of the corresponding options at lower levels (coverpoint and cross).
Covergroup Type Options
Type options describe properties of the covergroup type as a whole. They behave like static data members in a class and apply to all instances.
Covergroup type options can be set within the covergroup definition using the following syntax:
type_option.member_name = constant_expression;
type_option
is a built-in static member of every covergroup, coverpoint, and cross. Different instances cannot have different values for type options. These options can only be set at initialization using a constant expression. The strobe
type option can only be set in the covergroup definition. Other type options can be assigned during simulation using the scope resolution operator (::
). For example:
covergroup gc @(posedge clk);
a : coverpoint a_var;
b : coverpoint b_var;
endgroup
...
// Set the comment for all covergroups of type "gc"
gc::type_option.comment = "Here is a comment for covergroup g1";
// Set the weight for coverpoint "a" of all covergroups of type gc
gc::a::type_option.weight = 3;
gc g1 = new;
Settings at the covergroup level do not affect the settings at lower levels.
5. Coverage Methods
Covergroups provide several methods that can be called at any time:
get_coverage()
returns the type coverage, which is the cumulative coverage of all instances of that type. It is a static method and can be called using the ::
or .
operator. get_inst_coverage()
returns the coverage for a specific instance. It is associated with a particular instance, is not a static method, and can only be called using the .
operator. Additionally, the sample()
function in a covergroup can be overridden using the with
keyword.
SystemVerilog provides the following system tasks and functions to help manage coverage data collection:
-
$set_coverage_db_name ( filename )
: Sets the filename for the coverage database where coverage information will be saved at the end of the simulation. -
$load_coverage_db ( filename )
: Loads cumulative coverage information for all covergroup types from the given file. -
$get_coverage()
: Returns a real number between 0 and 100 representing the overall coverage for all covergroup types, calculated as previously described.