You are on page 1of 4

Coverage coding: simple tips and gotchas

Bhushan Safi
Functional coverage has been most widely accepted way by which we track the completeness of any CRV
driven testbench. But does achieving 100% functional coverage means, that the DUV is bug free? Certainly
not , but it boosts up the confidence of the verification engineer and management.
Based on my experience of defining functional covergroups for different projects, I realized that coverage
constructs and options in the SystemVerilog language have their own nuances that one needs to keep an eye
out for. These have to be understood so that they can be used optimally to achieve the appropriate usage
results in the correct alignment with the intent desired. Let me talk about some of these finer aspects so that
you can use the constructs more productively.
Usage of ignore_bins
ignore_bins construct is meant to exclude a collection of bins from coverage. While using this particular
construct, you might end up with multiple shapes issues (By shapes I mean Guard_OFF and
Guard_ON, which appears in the report whenever ignore_bins is used). Lets look at a simple usage of
ignore_bins is as shown in figure 1.
covergroup sample_variable_a @(sample_event);
a: coverpoint variable_a {
type_option.comment = Coverage of variable A;
option.weight = 1;
bins value_1 = {1};
bins value_0 = {0};
ignore_bins ignore_value_1_when_cfg_1
= {1} iff (cfg.disable = 1);
}

Figure 1 - ignore_bins with "iff" condition


Looking at the code above, we would assume that since we have set cfg.disable = 1 the bin with value 1
would be ignored from the generated coverage report. Here we use the iff condition to try to match our
intent of not creating a bin for the variable under the said condition. However in simulations, where the
sample_event is not triggered, we see that we end up having an instance of our covergroup which still
expects both the bins to be hit. (See the generated report in figure 1). Why does this happen? If you dig deep
into the semantics, you will understand that the iff condition will come into action only when the event
sample_event is triggered. So if we are writing ignore_bins for a covergroup which may/may not be
sampled on each run then we need to look out for an alternative. And indeed there is a way to address this
requirement and that is through the usage of the multi-mastered intelligent ternary operator. Look at the code
below to see how the ternary operator is used to model the same intent.

covergroup sample_variable_a @(sample_event);


a: coverpoint variable_a {
type_option.comment = Coverage of variable A;
option.weight = 1;
bins value_1 = {1};
bins value_0 = {0};
ignore_bins ignore_value_1_when_cfg_1
= {(cfg.disable == 1) ? 1 : 2b11};
}

Figure 2 - ignore_bins with "ternary operator"


Now the report is as per your expectations!!!
Using the above mentioned coding style we make sure that the bin which is not desired in specific conditions
is ignored irrespective of the condition of covergroup is being sampled or not. Also, we use the value
2b11 to make sure that we dont end up in ignoring a valid value for the variable concerned.
Using "detect_overlap"
The coverage option called "detect_overlap" helps in issuing a warning if there is an overlap between the
range list (or transition list) of two bins of a coverpoint.
Whenever we have plenty of ranges to be covered, and there is a possibility of overlap, it is important to use
this option. Why is it important and how can you be impacted if you dont use it? You might actually end up
with incorrect and unwanted coverage numbers!

CHECK_A : coverpoint check_4_a {


type_option.comment = "Check value of A ";
bins min = {0};
bins mid_low = {[1:25]};
bins mid_high = {[25:49]};
bins max = {50};
}

PROBLE
M!!!

SOLUTIO
N
CHECK_A : coverpoint check_4_a {
type_option.comment = "Check value of A ";
option.detect_overlap = 1;
bins min = {0};
bins mid_low = {[1:25]};
bins mid_high = {[25:49]};
bins max = {50};
}

Figure 3 - Example of "detect overlap"


Lets look at an example. In the above scenario, if a value of 25 is generated, the coverage scores reported
would be 50% when the desired outcome would ideally have been 25%. This is because the value 25

contributes to two bins out of four bins when that was probably not wanted. The usage of detect_overlap
would have warned you about this and you could have fixed the bins to make sure that such a scenario
doesnt occur.
Coverage coding for crosses and assigning weight
What does the LRM say about the weight attribute? "If set at the covergroup syntactic level, it specifies the
weight of this covergroup instance for computing the overall instance coverage of the simulation. If set at the
coverpoint (or cross) syntactic level, it specifies the weight of a coverpoint (or cross) for computing the
instance coverage of the enclosing covergroup.
What kinds of surprises can a combination of cross and option.weight throw up?
The SystemVerilog LRM shows a very simple way of writing a cross. Lets look at the code alongside.
The expectation here is that for a single
simulation (expecting one of the bins to be
CHECK_A: coverpoint check_4_a {
hit), we will end up with 25 % coverage as
type_option.comment = "Check value of A ";
we have specified the weight of the
option.weight = 0;
individual coverpoints to zero. However,
bins a_one = {1};
what essentially happens is the following, 2
bins a_zero = {0};
internal coverpoints for check_4_a and
}
check_4_b are generated which are used to
CHECK_B : coverpoint check_4_b {
compute the coverage score of the crossed
type_option.comment = "Check value of B ";
coverpoint here. So you'll end up with having
option.weight = 0;
total 4 coverpoints, 2 having option.weight
bins b_one = {1};
specified to 0 (i.e. CHECK_A and
bins b_zero = {0};
CHECK_B) and 2 coverpoints with
}
option.weight as 1 (i.e. check_4_a and
CHECK_CROSS : cross check_4_a, check_4_b {
check_4_b). Thus for a single simulation, you
type_option.comment = "Check value of their cross ";
will not get the 25% coverage desired.
}
Now with this report we see the following
issues:
1. We see 4 coverpoints while
expectation is only 2 coverpoints
2. The weights of the individual
coverpoints is set to be expected to
zero as option.weight is set to 0
3. The overall coverage numbers are
undesired.
In order to avoid above disastrous results
we need to take care of following aspects:
1. Use the type_option.weight = 0,
instead of option.weight = 0.
2. Use the coverpoint labels instead
of coverpoint names to specify the
cross.

CHECK_A: coverpoint check_4_a {


type_option.comment = "Check value of A ";
type_option.weight = 0;
bins a_one = {1};
bins a_zero = {0};
}
CHECK_B : coverpoint check_4_b {
type_option.comment = "Check value of B ";
type_option.weight = 0;
bins b_one = {1};
bins b_zero = {0};
}
CHECK_CROSS : cross CHECK_A, CHECK_B {
type_option.comment = "Check value of their cross ";
}
Hope my findings would be useful for you and you would use these options/ attributes appropriately to get
the best value out of them (without losing any sleep or debug cycles to figure out why they didnt behave as
you deemed them to)

You might also like