Sie sind auf Seite 1von 16

SystemVerilog Functional Coverage

Keywords: covergroup, coverpoint, bins, auto_bin_max, sample(), start(), stop(), iff,


ignore_bins, illegal_bins
A covergroup is similar to class object. You define it once and instantiate it one or
multiple times. A covergroup can have coverpoints, formal arguments, options and
optional triggers. It encompasses one or more data points, all of which are sampled
at the same time.
class transaction;
rand [3:0] data;
rand [2:0] port;
endclass
transaction tr;
covergroup covport;
coverpoint tr.port
endgroup
covport ck;
initial
begin
tr = new();
ck = new();
assert (tr.randomize())
ck.sample()
end
A covergroup can be defined in a class, in a program or in a module level. In all
cases, the covergroup must be explicitly instantiated to sample.
When a covergroup is defined in a class, we dont need a separate name for the
covergroup at instantiating. We can use the covergroup name to instantiate.
class transaction;
rand [3:0] data;
rand [2:0] port;
covergroup covport;
coverpoint port
endgroup
function new();
covport = new();
endfunction
endclass
transaction tr;

initial
begin
tr = new();
assert (tr.randomize())
tr.covport.sample()
end
Triggering a covergroup
There are two parts associated with functional coverage.
i.
ii.

The sampled data values.


The time when to sample these values

When new set of values are ready, the testbench triggers the covergroup to sample
the values.
A covergroup can be triggered using the sample function associated with the
covergroup from a procedural code or by using blocking expressions such as @ or
wait in the covergroup definition.
Using sample():
module test;
class transaction;
rand bit [ 3:0] data;
rand bit [ 2:0] port;
endclass
transaction tr;
covergroup covport;
coverpoint tr.port;
coverpoint tr.data;
endgroup
covport ck;
initial
begin
tr = new();
ck = new();
repeat(25)
begin
assert(tr.randomize());
ck.sample();
end
$finish();
end
endmodule

Using an event trigger:


module test;
class transaction;
rand bit [ 3:0] data;
rand bit [ 2:0] port;
endclass
transaction tr;
event trans_ready;
covergroup covport @(trans_ready);
coverpoint tr.port;
coverpoint tr.data;
endgroup
covport ck;
initial
begin
tr = new();
ck = new();
repeat(32)
begin
assert(tr.randomize());
-> trans_ready;

end
$finish();
end
endmodule

To run:
vlog -novopt +cover=bcst test.sv
vsim -c -novopt -coverage -voptargs="+cover=bcefst" test -do "coverage save
-onexit test.ucdb; run -all"
To view:
Vsim viewcov test.ucdb
So, when to use sample() and blocking expressions?
When there is no explicit signal or event that tells when to trigger or if there are
multiple instances of covergroup that trigger separately, at that time use sample()
function to trigger the covergroup.
If we want to use existing event or signal to trigger coverage, use the blocking
expression in the covergroup definition.
We can use events from SVA to trigger the covergroups.
How the coverage information gathered:

When a variable or expression is specified in a coverpoint, SV automatically creates


bins to record how many times each value has been seen. These bins are the
basic units of measurement for the functional coverage.
For a 3-bit coverpoint, there are 8 possible bins. The coverage will be number of
sampled bins/total number of bins.
For eg, in a simulation, if values 0-6 are sampled and the value 7 is not seen, then
the bin associated with 7 will not have a sample. So, the coverage will be 7/8.
SV automatically creates bins based on the number of possible values for a
coverpoint. For an N-bit coverpoint, there are 2^N bins. For an enumerated type,
the number of bins will be the number of named values.
The covergroup option, auto_bin_max specifies the number of bins to create
automatically with a default value of 64. For eg, for an 8-bit variable or expression
specified in a coverpoint, 64 bins are created each of which covers 4 values.
module test;
class transaction;
rand bit [ 7:0] data;
rand bit [ 2:0] port;
endclass
transaction tr;
covergroup covport;
coverpoint tr.data;
endgroup
covport ck;
initial
begin
tr = new();
ck = new();
repeat(128)
begin
assert(tr.randomize());
ck.sample();
end
$finish();
end
endmodule

We can set the number of bins created automatically. In this case, the domain of
values for the coverpoint will be grouped into the bins accordingly.
module test;
class transaction;
rand bit [ 3:0] data;
rand bit [ 2:0] port;
endclass
transaction tr;
covergroup covport;
coverpoint tr.data {
option.auto_bin_max = 4;
}
endgroup
covport ck;
initial
begin
tr = new();
ck = new();
repeat(16)
begin
assert(tr.randomize());
ck.sample();
end
$finish();
end
endmodule
In this example, 4 bins are created for 16 possible values of data coverpoint. So,
each bin covers 4 values of data coverpoint.

The auto_bin_max option can be set to individual coverpoints or to the covergroup


as a whole.

module test;
class transaction;
rand bit [ 3:0] data;
rand bit [ 2:0] port;
endclass
transaction tr;
covergroup covport;
coverpoint tr.data {
option.auto_bin_max = 4;
}
coverpoint tr.port {
option.auto_bin_max = 4;
}
endgroup
covport ck;
initial
begin
tr = new();
ck = new();
repeat(16)
begin
assert(tr.randomize());
ck.sample();
end
$finish();
end
endmodule

module test;
class transaction;
rand bit [ 3:0] data;
rand bit [ 2:0] port;

endclass
transaction tr;
covergroup covport;
option.auto_bin_max = 4;
coverpoint tr.data;
coverpoint tr.port;
endgroup
covport ck;
initial
begin
tr = new();
ck = new();
repeat(16)
begin
assert(tr.randomize());
ck.sample();
end
$finish();
end
endmodule

Sampling expressions:
We can sample expressions, but need to make sure the coverage report has the
expected values. We may have to adjust the width of computed expression.
For eg,
class packet;
rand bit [ 3:0] payload_len;
rand bit [ 2:0] hdr_len;
endclass

packet pkt;
covergroup covport;
len16: coverpoint pkt.payload_len+ pkt.hdr_len;
len32: coverpoint pkt.payload_len+ pkt.hdr_len+5d0;
endgroup
In this example, SV creates 16 bins automatically. Our domain of values will be 0:22.
So, we are adding 5d0 to the expression to cover bins from 16:22.
Here the issue is, len16 will not cover all the bins in the domain, and len32 has
holes for the bins 23:31. In general, the automatically created bins are okay for
values that are power of 2.
For other values, we should explicitly create bins to improve accuracy and coverage
report analysis.

To specify the bins,


covergroup covport;
len32: coverpoint (pkt.payload_len+ pkt.hdr_len+5d0)
{
bins Len[] ={ [0:22]};
}
endgroup

Naming coverpoint bins:


module test;
class packet;
rand bit [ 3:0] length;
endclass
packet pkt;
covergroup covport;
len: coverpoint pkt.length
{
bins zero = {0};
bins sml = {[1:5], 8};
bins lrge[] = {[12:$]};
bins misc = default:
}
endgroup
covport ck;
initial
begin

pkt = new();
ck = new();
repeat(200)
begin
assert(pkt.randomize());
ck.sample();
end
$finish();
end
endmodule

In this example, we are sampling a 4-bit variable. For this, there are 16 possible
bins. Here we are creating bins such a way that one bin to sample value 0, one bin
to sample values from 1 to 5 and 8. There is one bin for each value from 12 to 15.
The values which are not covered in these bins are covered by misc bins. This is
indicated by default.
When we define the bins, we are restricting the values used for coverage to those
that are interesting to us. SystemVerilog no longer automatically creates bins, and it
ignores values that do not fall into a predefined bin. More importantly, only the bins
we create are used to calculate functional coverage. We get 100% coverage only as
long as we get a hit in every specified bin.
Conditional Coverage:
We can use iff keyword to add a condition to a coverpoint. The main reason is to
disable coverage during reset process. We can use start and stop function
associated with the covergroup to enable and disable coverage.
covergroup covport;
len: coverpoint pkt.length iff(reset_l)
endcovergroup
ignore values:
With some coverpoints, we will never get 100% coverage. For eg, a 3-bit variable
used to cover 6 values from 0 to 5. If we use automatically created bins, we will
never get 100% coverage.

To overcome this,
i.
We need to create bins explicitly for storing values from 0 to 5 as,
coverpoint val
{
bins len[] = {[0:5]};
}
ii.
We can use automatically created bins and let SV to ignore values that we
are not in interested using ignore_bins as,
coverpoint val
{
ignore_bins hi[] = {[6:7]};
}
module test;
class packet;
rand bit [ 3:0] length;
endclass
packet pkt;
covergroup covport;
len: coverpoint pkt.length
{
bins interest = {[0:10]};
}
endgroup
covport ck;
initial
begin
pkt = new();
ck = new();
repeat(30)
begin
assert(pkt.randomize());
ck.sample();
end
$finish();
end
endmodule

module test;
class packet;
rand bit [ 3:0] length;
endclass
packet pkt;
covergroup covport;
len: coverpoint pkt.length
{
Ignore_bins not_interested = {[11:$]};
}
endgroup
covport ck;
initial
begin
pkt = new();
ck = new();
repeat(30)
begin
assert(pkt.randomize());
ck.sample();
end
$finish();
end
endmodule

illegal bins:
When some values not only be ignored, but cause an error if they are seen. In this
case we use illegal_bins.
module test;
class packet;
rand bit [ 3:0] length;
endclass
packet pkt;

covergroup covport;
len: coverpoint pkt.length
{
illegal_bins illegal = {[12:14]};
}
endgroup
covport ck;
initial
begin
pkt = new();
ck = new();
repeat(30)
begin
assert(pkt.randomize());
ck.sample();
end
$finish();
end
endmodule
In this example, if the length is 12,13,14, then there will be error messages.
# ** Error: (vsim-8565) Illegal state bin got covered at value='b1100. The bin
counter for the illegal bin '\/test/ck .len.illegal' is 1.
# Time: 0 ps Iteration: 0 Instance: /test
# ** Error: (vsim-8565) Illegal state bin got covered at value='b1101. The bin
counter for the illegal bin '\/test/ck .len.illegal' is 2.
# Time: 0 ps Iteration: 0 Instance: /test
If we have the packet object modified as,
class packet;
rand bit [ 3:0] length;
constrainst c_length {
0 <= length;
Length < 12;
}
endclass
There will be no errors in this case.
Cross Coverage: