How to Ignore Cross Coverage Bins Using Expressions in SystemVerilog

Lately, I’ve been playing with the coverage features of SystemVerilog. One thing I wanted to do was to filter out some bins from the auto-generated list of cross bins. I searched the Internet for a solution, but only found similar questions with no clear answers. Therefore, I started to work on this problem and came up with two solutions, which I will share with you.

To better illustrate the problem, let’s assume that we want to generate two variables – one always less than or equal to the other, and collect the valid coverage for the generated value.

rand bit[3:0] x, y;

constraint c {
  x <= y;
}

We will use SystemVerilog coverage constructs like covergroup, coverpoint and cross to confirm that we’ve generated all legal values.

auto_generated_bins_of_a_cross_coverage

Because we are interested only in values x <= y, we’ll need to have some kind of filtering on the cross coverage bins. As you can notice in the picture above, we must filter 120 bins out of the total of 256 bins. It would be a tedious work to try to exclude them bin by bin. So, here are my solutions:

Using ‘with’

The simplest way to filter unwanted bins is ‘with’ inside an ignore_bins construct:

covergroup cover_me;
  x_cp : coverpoint x;
  y_cp : coverpoint y;

  x_y_cross: cross x_cp, y_cp {
    ignore_bins ignore_x_values_higher_than_y = x_y_cross with (x_cp > y_cp);
  }
endgroup

Using CrossQueueType

The second solution is to use CrossQueueType. CrossQueueType is the type of a cross coverage bin. Starting with the SystemVerilog standard 2012 (IEEE1800-2012), you can define a function that returns a queue of type CrossQueueType and use it to define the ignored cross coverage bins.

Pay attention, the function returns the ignored bins, not the valid ones!

covergroup cover_me;
  x_cp : coverpoint x;
  y_cp : coverpoint y;

  x_y_cross : cross x_cp, y_cp {
    function CrossQueueType createIgnoreBins();
      // Iterate over all bins
      for (int xx=0; xx<=15; xx++) begin
        for (int yy=0; yy<=15; yy++) begin
          if (xx > yy)
            // Ignore this bin
            createIgnoreBins.push_back('{xx,yy});
          else
            // This is a valid bin
            continue;
        end
      end
    endfunction

    ignore_bins ignore_x_values_higher_than_y = createIgnoreBins();
  }
endgroup

Unfortunately, not all simulators support the above constructs. I prepared two complete code examples – test_with.sv and test_CrossQueueType.sv, which are ready to be compiled and run. You may want to download them to see what works for you.

There may be other solutions as SystemVerilog is quite complex. In case you have knowledge of other solutions please share them.

Comments

13 Responses

  1. More generically, you can punch out any pattern you’d like by following the pattern here. Not better, just different. This way does make you manually enter all of the X-Y coordinates, but if your pattern is random, then this works.

    covergroup cg1 ;
     cA: coverpoint myenumA  {
       bins a_bin[] = {[A1:A3]};
     } 
     cB: coverpoint myenumB {
      bins b_bin [] = {[B1:B3]};
     } 
     cC: coverpoint myenumC {
      bins c_bin[] = {[C1:C3]};
     } 
    // Remember - the spec says that when a bin is named it's taken *out* of
    // the autobin list.  So the
    aXb: cross cA, cB, cC { 
       // Keep triple combinations = {A1+B2+C3} and {A1+B1+C1}
       bins A1B2C3 = binsof (cA) intersect {A1}  &&
                  binsof (cB) intersect {B2}  &&
                  binsof (cC) intersect {C3} ; 
       bins A1B1C1 = binsof (cA) intersect {A1}  &&
                  binsof (cB) intersect {B1}  &&
                  binsof (cC) intersect {C1} ; 
       // should ignore everything that's not above ^^
       ignore_bins IGNORE_A_B =
                ( !binsof (cA) intersect {A1}  ||
                  !binsof (cB) intersect {B2}   ||
                  !binsof (cC) intersect {C3}     ) 
                &&
                ( !binsof (cA) intersect {A1}   ||
                  !binsof (cB) intersect {B1}   ||
                  !binsof (cC) intersect {C1}     )
               ; 
    } 
    endgroup
    
    1. Hi, Todd.

      Thank you for sharing your oppinion.
      Yes, that’s the “classical” style aproach. But as you’ve noticed, it’s not scalable when bins number is large. It is error prone and difficult to read.

      In my oppinion you may use any convenient solution (‘with clause’, ‘CrossQueueType’ or ‘binsof() +intersect’) when there are less than 8 bins but when there are more bins involved you need to pick the easiest solution.

      Regards,
      Aurelian

  2. Hi, Aurelian,

    I have met exactly the same problem with you.I searched the whole internet and your post is the ONLY solution.

    Your first method passed the vcs, and the second failed both vcs and irun.

    Since our team choose irun as our main simulator, so i have no choice but ToddM’s traditional way.

    Anyway, thanks for your share, maybe i will use it next time.

  3. The ignore_bins…with construct will be supported in irun in version 14.2 which should be available before the end of Jan.

    Tim

  4. Hi Aurelian Ionel Munteanu,

    I was searching exactly for this kind of solution, which is not present in System Verilog LRM. It works well with QuestaSim. Don’t know why it is not mentioned in LRM though. Or did I miss it?

    Thanks !!

    Murali

    1. Hi, Murali.

      The ‘with’ operator and the ‘CrossQueueType’ are mentioned in the SystemVerilog standard 2012 (IEEE1800-2012), in chapters 19.5.1.1 and 19.6.1.3 respectively.

      The solution itself, as mentioned in my article, is not found in the LRM, but it might be a good idea to have it mentioned in future versions of the LRM. A real project need and the lack of LRM suggestions on ignoring cross coverage bins, made me come up with those solutions.

      Anyway, i’m glad it helped you.

      Best regards,
      Aurelian

  5. Can we do ignore the bins in cross coverage with different cover groups?? Please let me know….??

    1. Hi, Nishchitha.

      I don’t think I understand your question. The ignoring of bins is done within one cover group.

    1. Hello, Stefan!

      Very good question.

      ‘{xx,yy} will match also an interval.
      An xx value of 1 will be able to match also an interval containing value 1 (e.g. [0:2])

      This is best illustrated in the example bellow, where the only bins left for the x_y_cross are:
      Bins of x_y_cross:
      {a,13}, {a,14}, {a,15}, {b,15}

      All the other bins are ignored because the x interval (bins a or b) contains a value higher than the y value, which implies that it will be ignored according to the condition xx > yy.
      Ignored bins for x_y_cross:
      {a,0}, {a,1}, …, {a,12}
      {b,0}, {b,1}, …, {b,14}

      class my_s;
           rand bit[3:0] x, y;
      
           covergroup cover_me;
                x_cp : coverpoint x {
                    bins a = {[0:13]};
                    bins b = {[14:15]};
                }
                y_cp : coverpoint y;
      
                x_y_cross : cross x_cp, y_cp {
                     function CrossQueueType createIgnoreBins();
                          // Iterate over all bins
                          for (int xx=0; xx<=15; xx++) begin
                               for (int yy=0; yy<=15; yy++) begin
                                    if (xx > yy)
                                         // Ignore this bin
                                         createIgnoreBins.push_back('{xx,yy});
                                    else
                                         // This is a valid bin
                                         continue;
                               end
                          end
                     endfunction
      
                     ignore_bins ignore_x_values_higher_than_y = createIgnoreBins();
                }
           endgroup
      
           function new();
                cover_me = new();
           endfunction
      endclass
      
      module top;
           my_s obj;
           initial begin
                obj = new;
                for (int i=0; i<100; i++) begin
                     assert(obj.randomize());
                     obj.cover_me.sample();
                end
           end
      endmodule
      

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?