Thursday, March 15, 2018

Using Object Members in Functional Coverage Coverbins

While implementing a functional coverage model one of the requirements was to create coverbins whose values are a function of the sampled objects members. Below is a simplified example of the initial implementation with a sampled class object and a coverpoint meeting these requirements.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class my_item;
  rand bit [7:0] data_size;
  rand bit [7:0] inside_data_size;

  constraint my_c { 
    inside_data_size <= data_size;
    inside_data_size >= 0;
  }
endclass
//-----------------------------------------//
class my_cov;
my_item itm_p;
//---------//
covergroup my_grp;
  data_size_cp:        coverpoint itm_p.data_size;
  
  inside_data_size_cp: coverpoint itm_p.inside_data_size {
    bins  zero        = {0};
    bins  lower_half  = {[1:(itm_p.data_size/2)-1]};
    bins  half        = {itm_p.data_size/2};
    bins  upper_half  = {[(itm_p.data_size/2)+1:itm_p.data_size-1]};
    bins  max         = {itm_p.data_size};
  }
endgroup
//----------//
function new();
  my_grp = new;
endfunction: new
//----------//
task do_sample();
  my_grp.sample();
endtask: do_sample
endclass
//-----------------------------------------//
module tb();
initial begin
  my_item itm_p;
  my_cov  cov_p;
  
  cov_p = new();
  itm_p = new();

  for(int i = 0; i < 10; i++) begin
    itm_p.randomize();
    cov_p.itm_p = itm_p;
    cov_p.do_sample();
  end
end
endmodule: tb

Needless to say, this coverpoint implementation would not work. If you don't see the problem here, I will point it out; When the covergroup is created, there is an attempt to access the object member "itm_p.data_size" for the coverbin "inside_data_size_cp". Since an object has not been created yet and the current object pointer is null, a null pointer access is triggered terminating the simulation. So such an implementation is obviously not the way to go however the dependency for our coverage model still exists. Lets go for a different coverbin implementation, one that will work. 
What is needed is a variable which is a function of the data size but not a member of the sampled object. This new variable can be a member is the coverage class wrapper and updated right before the covergroup sampling. 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class my_cov;

typedef enum {
  ZERO = 0,
  LOWER_HALF,
  HALF,
  UPPER_HALF,
  MAX
} e_inside_data_size;

my_item             itm_p;
e_inside_data_size  inside_data_size_e;
//---------//
covergroup my_grp;
  data_size_cp:        coverpoint itm_p.data_size;
  inside_data_size_cp: coverpoint inside_data_size_e;
endgroup
//----------//
function new();
  my_grp = new;
endfunction: new
//----------//
task do_sample();
  case(1)
    (itm_p.inside_data_size == 0):                  inside_data_size_e = ZERO;
    (itm_p.inside_data_size > 0 && 
     itm_p.inside_data_size < itm_p.data_size/2):   inside_data_size_e = LOWER_HALF;
    (itm_p.inside_data_size == itm_p.data_size/2):  inside_data_size_e = HALF;
    (itm_p.inside_data_size > itm_p.data_size/2 && 
     itm_p.inside_data_size < itm_p.data_size ):    inside_data_size_e = UPPER_HALF;
    (itm_p.inside_data_size == itm_p.data_size):    inside_data_size_e = MAX;
    default: $error("inside_data_size=%x is not within data_size of %x", itm_p.inside_data_size, itm_p.data_size);
  endcase

  my_grp.sample();
endtask: do_sample
endclass

In the last example an enum type was created defining different value ranges for our coverbin. A class member is defined in the coverage wrapper class using this enum as the type. Right before the covergroup is sampled, this member is updated as a function of the received item using the case(1) statement. So now the coverbin no longer creates a null pointer access and the required dependency for the functional coverage is fulfilled.