Tudor Timi
Tudor Timi

Reputation: 7573

Parameterizable cross length

I've got a protocol that supports bursts, where each transaction is composed of N individual transfers. Each transfer has a unique index from 0 to N-1. I would like to cover that all transfer orders have been seen (i.e. 0 1 2 3, 1 2 3 0, 0 2 3 1, etc.). The value of N is variable (though in my case I only care about 4 and 8 for now).

The naive approach would be to cover each index individually and cross them, but this would mean I would need multiple covergroups, one per each value of N.

For N = 4:

covergroup some_cg;
  coverpoint idxs[0];
  coverpoint idxs[1];
  coverpoint idxs[2];
  coverpoint idxs[3];

  cross idxs[0], idxs[1], idxs[2], idxs[3] {
    ignore_bins non_unique_idxs[] = some_func_that_computes_bins_for_4_idxs();
  }
endgroup

For N = 8:

covergroup some_cg;
  coverpoint idx[0];
  coverpoint idx[1];
  coverpoint idx[2];
  coverpoint idx[3];
  coverpoint idx[4];
  coverpoint idx[5];
  coverpoint idx[6];
  coverpoint idx[7];

  cross idx[0], idx[1], idx[2], idx[3], idx[4], idx[5], idx[6], idx[7] {
    ignore_bins non_unique_idxs[] = some_func_that_computes_bins_for_8_idxs();
  }
endgroup

The two functions that generate the ignore bins each have to return different types (queue of struct with 4/8 fields), even though conceptually the operation for computing all illegal combinations is similar, regardless of the value of N. This could probably be solved with some clever use of the streaming operator, to stream the contents of the structs into arrays of N elements. The issue of redundancy in the covergroup definitions remains though. The only way I can think of solving this is by generating the code.

Another idea would be to pack all indexes into a packed array of the appropriate size and cover that:

covergroup some_other_cg;
  coverpoint packed_idxs {
    ignore_bins non_unique_idxs[] = some_func_that_computes_bins_for_N_idxs();
  }
endgroup

// Probably won't compile, but it would also be possible to use the streaming op
// Idea is to pack into integral type
foreach (idxs[i])
  packed_idxs[i * idx_len +: len] = idxs[i];

It's a pain to debug coverage holes, as it's difficult to figure what transfer order a certain packed value belongs to, especially if the values are shown in decimal radix. I believe the way values are displayed varies from tool to tool and it's not possible to control this. I also don't see any possibility to give names to individual bins using strings.

I would welcome any input that would improve upon any of the two suggestions. The goal is to have one coverage wrapper class with a parameter for the number of transfers and to be able to instantiate that and get the coverage:

class transfer_orders_coverage #(int unsigned NUM_TRANSFERS);
  // ...
endclass

Upvotes: 2

Views: 205

Answers (2)

Karan Shah
Karan Shah

Reputation: 1992

I guess, the following solution may work in this case.

covergroup some_cg (int num);
  4n_cp : coverpoint ({idxs[0], idxs[1], idxs[2], idxs[3]}) iff (num == 4)
  {
    option.weight = (num == 4) ? 1 : 0; // Weight might change depending on other coverpoints
    ignore_bins non_unique_index[] = <Your Function>;
  }

  8n_cp : coverpoint ({idxs[0], idxs[1], idxs[2], idxs[3], idxs[4], idxs[5], idxs[6], idxs[7]}) iff (num == 8)
  {
    option.weight = (num == 8) ? 1 : 0; // Weight might change depending on other coverpoints
    ignore_bins non_unique_index[] = <Your Function>;
  }
endgroup

// Where you instantiate covergroups 
some_cg c1 = new(4);

Let me know, how the above idea works.

Upvotes: 0

sharvil111
sharvil111

Reputation: 4381

Adding as and 'Answer' since it was too long for comment. Pardon me if I am not clear.

Can you add some logic before sampling CG and use some input argument that denotes array position of idxs? For the crosses, you can maintain a packed array of size N and make individual bits 1 when a particular pattern is detected. At the end of sim, you can sample the coverage for that pattern in some different CG.

Basically the idea is to offload logic inside the covergroups and add logic surrounding sample function. Here is a rough idea about what I was thinking.

class transfer_orders_coverage #(int unsigned N = 4);
  int idxs[N];
  bit [(N -1) : 0] pattern; // Make indexes HIGH according to sampled pattern
  // ...
  covergroup cross_cg;
    mycp_cross: coverpoint pattern{
      ignore_bins myignbn = {some_generic_function_for_N(pattern)};
    }
  endgroup

  covergroup indiv_cg with function sample (int index);
      mycp_indiv: coverpoint idxs[index]{
                    // some bins to be covered in ith position of idxs
                  }
  endgroup

  function new();
    cross_cg = new;
    indiv_cg = new;
  endfunction

  function bit [(N -1) : 0] some_generic_function_for_N(bit [(N -1) : 0] pattern);
    // check which bits in "pattern" are to be covered and which are to be ignored 
    //return some_modified_pattern;
  endfunction

  function void start();
    // Any logic for sampling ith position
    foreach(idxs[i]) begin
      indiv_cg.sample(i);
      pattern[i] = 1'b1;
    end
    cross_cg.sample();

  endfunction

endclass

module top();
  transfer_orders_coverage #(4) tr;
  initial begin
    tr = new;
    tr.start();
  end
endmodule

Let me know if it seems feasible or not.

Upvotes: 1

Related Questions