In both previous coverage blog posts (Part I and the Part II), we showed two
solutions for refining instance-based coverage in a reusable way. And in doing
so, we demonstrated a case where using the instance_ignore option is
more suitable than using the extension under
when solution.

Now, let us modify the requirement a little, by adding a new
item to the covergroup:

extend
packet_generator{

cover packet_generated is also{

item p_length: uint(bits:4) =
cur_packet.length;

};

};

The length of the packet depends on the value of the size
field according to the following constraints:

extend
packet{

length: uint(bits:4);

keep size == SMALL => length in [0..2];

keep size == MEDIUM => length in [3..6];

keep size == LARGE => length in [7..10];

keep size == HUGE => length in [11..15];

};

So again, for each packet_generator, some of the higher
length values might be irrelevant due to the max_packet_size constraint.

We can set the ignored values using either of the following
techniques:

Using the instance_ignore
option:

cover packet_generated is also{

item
p_length using also instance_ignore =

(((inst.max_packet_size == SMALL) and (p_length > 2)) or

((inst.max_packet_size == MEDIUM) and (p_length > 6)) or

((inst.max_packet_size == LARGE) and (p_length > 10)));

};

};

Or by extending the
covergroup under subtypes:

when SMALL'max_packet_size packet_generator{

cover
packet_generated is also{

item
p_length using also ignore = (p_length > 2);

};

};

when MEDIUM'max_packet_size packet_generator{

cover
packet_generated is also{

item
p_length using also ignore = (p_length > 6);

};

};

when BIG'max_packet_size packet_generator{

cover
packet_generated is also{

item
p_length using also ignore = (p_length > 10);

};

};

Here we recommend using the extension under when subtype
code (the second bulleted option above), since the ignore expressions that need to be evaluated with this code are much simpler than the instance_ignore
expression.

In some cases, only one of the solutions can be used:

A different setting of one
of the other coverage options (for example weight) for each instance can
only be achieved by extending the covergroup under when.

For example, if we want to have a larger weight for packet generators that can generate any size of packet,
we need to add the following code:

when HUGE'max_packet_size packet_generator{

cover
packet_generated using also weight=2;

};

On the other hand, when
collecting a covergroup under instances of a unit that is not the definition
type of the covergroup (using the per_unit_instance=<other_type> group
option), extending the under when subtype cannot be applied. In these cases,
only the use of the instance-based options is possible.

For example, suppose that instead
of defining the covergroup under the packet_generator unit, we would have
defined it under the packet struct (but still collect it per instances of
packet_generator):

extend packet{

cover
packet_generated using per_unit_instance=packet_generator is{

item
p_size: packet_size_t = cur_packet.size;

};

};

Now the covergroup can only be
extended under the packet type, but we'd like to control the ignored
values of its items according to a configuration field of packet_generator
unit. So extension under when will
not help us here.

But since instance-based options
have a reference to the collection unit type (packet_generator) instance via
the inst field, they can be used in the same manner that they are used
when the covergroup is collected per instances of its declaration unit type.