How to Implement Flexible Coverage Definitions (Part 1)

In the first part of this 3-post series (part 2, part 3), I would like to show a compact way of defining flexible coverage in SystemVerilog that adapts to a variable parameter.

Let’s consider the case where you need to cover the size of a burst, which can range between 1..max, with max being configurable within 1..N. The bins are defined as 1, 2..max-1 and max.

The first implementation that comes to mind is the following:

covergroup size_cg(int max) with function sample(int size);
  option.per_instance = 1;
  type_option.merge_instances = 1;

  burst_size: coverpoint size {
    bins one_item      = { 1 };
    bins several_items = { [2:max-1] };
    bins max_items     = { max };
    illegal_bins illegal_val = default;
  }
endgroup

Even though it captures our intention, this covergroup definition is faulty. If max = 2, the several_items bin will be [2:1], which overlaps with the other two bins. When max = 1, the max_items bin will be { 1 }, which overlaps with the one_item bin. The several_items bin will be [2:0]. Not only does it overlap with the one_item and max_items bins, but it also accepts the illegal values 0 and 2, which is clearly a problem.

Solution Using the with clause

To solve this issue, the with clause will be used for the several_items and max_items bins.

covergroup size_cg(int max) with function sample(int size);
  option.per_instance = 1;
  type_option.merge_instances = 1;

  burst_size: coverpoint size {
    bins one_item      = { 1 };
    bins several_items = { [2:max-1] } with (max >= 3);
    bins max_items     = { max }       with (max >= 2);
    illegal_bins illegal_val = default;
  }
endgroup

As a consequence, the max_items bins will be created only if max >= 2, while the several_items bins will be created only if max >= 3.

The Test Module

If you want to play with the presented solution, you can use the test module below:

class cg_wrapper;
  covergroup size_cg(int max) with function sample(int size);
    option.per_instance = 1;
    type_option.merge_instances = 1;

    burst_size: coverpoint size {
      bins one_item      = { 1 };
      bins several_items = { [2:max-1] } with (max >= 3);
      bins max_items     = { max }       with (max >= 2);
      illegal_bins illegal_val = default;
    }
  endgroup

  function new(int max_size);
    size_cg = new(max_size);
    size_cg.set_inst_name($sformatf("size_cg_max_size_%0d", max_size));
  endfunction
endclass

module test;
  initial begin
    cg_wrapper cgs[5];

    foreach (cgs[max_size]) begin
      cgs[max_size] = new(max_size + 1);

      for (int size = 1; size <= max_size + 1; size++)
        cgs[max_size].size_cg.sample(size);
    end
  end
endmodule

That’s all!

Comments

4 Responses

  1. What solution would you recommend if “max_size” is not a static value i.e. max_size is configured during run time, for example max_size=some_register_value_after_reset?

    1. Hi Rashid,

      A possible implementation would be:

      covergroup cg with function sample(int val, int max_size);
        option.per_instance = 1;
      
        val_cp: coverpoint 1 {
          bins one    = { 1 } iff (                 val == 1);
          bins middle = { 1 } iff (max_size >= 3 && val inside { [2:max_size-1] });
          bins max    = { 1 } iff (max_size >= 2 && val == max_size);
        }
      endgroup
      ...
      cg.sample(some_value, some_register_value_after_reset);

      As you only really need to know that a bin has been sampled or not, the sampled value (in this case 1) doesn’t matter as long as the sampling condition is correctly specified.
      However, you’ll need to be careful and update the code to avoid coverage holes if max_size won’t be larger that 1 or 2 in the regression.

      Horia

  2. The solution presented in the article might trigger overflow warnings in some simulators, even though the bins that cause the warnings are excluded anyway when their with expressions evaluate to 0.

    Other simulators will complain that the candidate value item is not used in the with expression. Section 19.5.1.1 in IEEE Std 1800-2017 leaves room for interpretation: it mandates using the name item for the candidate value, but it is not clear whether its usage in the expression is also required. On the other hand, the array locator methods defined in section 7.12 (find(), find_index() etc.), for which the with clause is mandatory, do not generate any warnings if the iterator argument (named item or otherwise) is not used in the expression.

    Here is an alternative way to implement the coverpoint, avoiding the warnings mentioned above:

    burst_size: coverpoint size {
    bins \1 = burst_size with (MAX >= 1 && item == 1 );
    bins \2 = burst_size with (MAX >= 2 && item == 2 );
    bins \3..MAX-3 = burst_size with (MAX >= 6 && item >= 3 && item = 5 && item == MAX-2);
    bins \MAX-1 = burst_size with (MAX >= 4 && item == MAX-1);
    bins \MAX = burst_size with (MAX >= 3 && item == MAX );
    illegal_bins illegal_val = default;
    }

  3. what’ is the different between the iff and with clause in bins. They are likely the same. From LRM:
    “The expression within the iff construct at the end of a bin definition provides a per-bin guard condition. If
    the expression is false at a sampling point, the count for the bin is not incremented.”
    with clause:
    “The with clause specifies that only those values in the covergroup_range_list that satisfy the given
    expression (i.e., for which the expression evaluates to true, as described in 12.4) are included in the bin”

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Subscribe to our newsletter

Do you want to be up to date with our latest articles?