功能验证的目标在于确定设计有关的功能描述是否被全部实现了。
这一检查中可能会存在一些不期望的情况:(要尽量发现)
我们无法通过代码覆盖率得知要求的功能是否被实现了,而需要显性地通过功能覆盖率与设计功能描述做映射,继而量化功能验证的进程。
所以功能覆盖率极其重要,用来量化验证的指标。
覆盖组可以在以下中定义(覆盖组与类相似,在一次定义以后便可以多次进行例化)
在类中的覆盖组也可以采集类的成员变量。
覆盖组应该定义在适当的抽象层次上。
一个类/接口中,中往往可以定义多个覆盖组 。多个覆盖组可以在测试过程中,根据需要将它们使能或者禁止。
覆盖组含有
覆盖组为了采样变量,必须先定义采样事件。只要采样事件被触发后,覆盖组监测的变量才会在该时刻被采样。(对任何事务的采样都必须等到数据被待测设计接收到以后。)
覆盖组可以采集任何可见的变量:
定义覆盖组:
covergroup
. . .
endgroup
示例:
enum { red,green,blue ] color;
bit [3:0] pixel_adr,pixel_offset,pixel_hue;
covergroup g2 @(posedge clk);
Hue: coverpoint pixel_hue;
Offset: coverpoint pixel_offset;
AxC: cross color,pixel_adr; // cross 2 variables
all: cross color,Hue,Offset; // cross 1 VARs and 2 CPs
endgroup
g2 cg_inst = new () ;
//covergroup. . .endgroup 来定义覆盖组
//内部可以定义多个coverpoint
//如果不在covergroup声明时指定采样事件,
//那么默认该覆盖组只能依赖于其另外一个手动采样函数sample()
//即在外部通过覆盖组提供sample(),在采样事件发生时,做手动采样
嵌入式覆盖组声明
在类中声明的covergroup的方式被称为嵌入式覆盖组声明,
我们更多地将covergroup定义在类中,从而可以去覆盖类的成员变量。
由此,它不但可以通过虚接口去采样硬件信号,也可以去覆盖类的成员变量
示例:
声明一个覆盖组类型cov1和它的实例c1。
c1的采样事件,即xyz的成员变量m_z。只有它发生变化时,就会采样其余两个变量m_x和m_y。
class xyz;
bit [3:0] m_x;
int m_y;
bit m_z;
covergroup cov1 @m_z; // embedded covergroup
coverpoint m_x;
coverpoint m_y;
endgroup
function new() ;
cov1 c1 = new () ;
endfunction
endclass
一个covergroup可以包含一个或者多个coverpoint,一个coverpoint可以用来采样数据值或者数据的变化。
一个coverpoint可以对应多个数据采样的仓(cover bin(仓))。
仓可以用来表示对被采用数据感兴趣的值,或者值的变化。
这些仓可以显性指定,也可以隐性指定。
coverpoint对数据的采样发生在covergroup采样的时候。
在定义coverpoint时可以不给名字或者给名字,我们建议给不同的coverpoint以不同的名字
这些有名字的coverpoint可以用来做更进一步的处理,例如在交叉覆盖率中使用某个coverpoint或者cover bin
可以通过iff在一些情况下禁止coverpoint的采集
covergroup g4;
coverpoint s0 iff(!reset);//对于s0的采样,必须要在复位信号释放以后,才允许
endgroup
//覆盖组cg具有三个ref类型的参数x y c
//内部定义了若干个覆盖点。一个匿名的覆盖点和三个有名字的覆盖点。一个交叉覆盖点
covergroup cg ( ref int x , ref int y, input int c);
coverpoint x;//创建CP x
b: coverpoint y; //创建CP b
cx : coverpoint x;//创建CP cx
d: coverpoint y[31:24];//创建CP d
cross x, y ;//创建交叉覆盖率 crossCP xXy
endgroup
关键词bins
可以用来将每个感兴趣的数值均对一个独立的bin,或者将所有值对应到一个共同的bin
iff语句(可以用在bin的定义)
表示条件为false,那么在采集该bin的时候,该bin的采样数目不会增长
示例:
bit [9:0] v_a;
//覆盖组c会在时钟上升沿对覆盖点v_a做采样
//在采样数据中,只对列举在仓中的数值感兴趣
covergroup cg @(posedge clk);
coverpoint v_a {
bins a = { [0:63],65 };//va变量只要在采样时刻=0-63或者65任意一值。该仓就被采用一次
bins b[] = { [127:150],[148:191] };//数组中 [127:150],[148:191]都将被独立采样,放置到独立的仓中
bins c[] = { 200,201,202 } ;
bins d = { [1000:$] };
bins others[] = default;//除了之前列举的所有数据之外,都将被归类为others这样一个覆盖仓数组
}
endgroup
除了可以采样某一个时刻的变量值,还可以记录覆盖数值的变化
示例:
从一个值变为另一个值或者,在连续的事件当中,该变量一直保持为某一个数值
value1 => value2
value1 => value3 => value4 => value5
range_list1 =>range_list2
1,5 =>6,7
trans_item [*repeat_range ]
3[*5]
表示3=>3=>3=>3=>3
3[* 3:5]
表示(3=>3=>3 ). (3=>3=>3=>3 )或(3=>3=>3=>3=>3 )
如果coverpoint没有指定任何覆盖仓bin,那么SV将会为其自动生成bin,但是覆盖仓的数量不会超过自动的默认覆盖仓最大数值。
自动生成bin遵循的原则是:
ignore_bins用来将其排除在有效统计的bin集合之外
covergroup cg23;
coverpoint a {
ignore_bins ignore_vals = {7,8} ;
ignore_bins ignore_trans = (1=>3=>5) ;
}
endgroup
illegal_bins用来指出采样到的数值为非法制
如果illegal_bins被采样到,那么仿真将报错
covergroup cg3;
coverpoint b {
illegal_bins bad_vals = {1.2.3} ;
illegal_bins bad_trans = (4=>5=>6);
}
endgroup
covergroup可以在两个或者更多的coverpoint或者变量之间定义数值的组会覆盖情况(即交叉覆盖率(cross coverage) )。
示例: 1
在对a和b产生交叉覆盖率之前,系统会先为它们隐性产生对应的coverpoint和bin,每个coverpoint都有16个自动产生的bin。
两个coverpoint交叉以后将生成256个交叉的bin。
bit [3:0] a. b;
covergroup cov @(posedge clk);
aXb : cross a, b;
endgroup
示例: 2
下面的覆盖点A有10个bin,b_var对应的覆盖点将有16个bin,因此CC将会有10x16=160个bin。
bit [31 :0] a_var ;
bit [3:0] b_var ;
covergroup cov3 @(posedge clk);
A: coverpoint a_var { bins yy[] = { [0:9] }; }
cc: cross b_var, A;
endgroup
被声明为default/ignore/illegal的bin将不会参与交叉覆盖率的运算。
交叉覆盖率只允许在同一个covergroup中定义的覆盖点参与运算。