1. 前言
通常说的覆盖率有两种类型:code coverage(代码覆盖率)和functional coverage(功能覆盖率)。代码覆盖率是使用EDA工具自动从设计代码里提取出来的,功能覆盖率是用户指定的,用于衡量测试设计意图和功能进展。因此,功能覆盖率有两个关键点:
- 它是用于指定的,而不是根据设计代码自动推测生成的;
- 它是基于设计需求,独立于实际设计代码和结构;
覆盖率主要由覆盖率组(covergroup)、覆盖率点(coverage point)、交叉覆盖率(cross coverage)、覆盖率选项(coverage option)和覆盖率方法(coverage method)组成的。
2. covergroup
Covergroup用于构建覆盖率模型,它将覆盖率模型和规范封装起来,内部可以包含以下组件:
- 用于coverage point同步和采样的时钟事件;
- Coverage points;
- Cross coverage;
- 可选的参数;
- Coverage options
Covergroup是用户定义的类型,可以定义在package、module、program、interface、checker或class里面。类似于class,covergroup可以在多处地方调用new()构造函数例化。如下所示,covegroup name是cg,通过new()构造函数,创建了cg的例化cg_inst。
covergroup cg; ... endgroup
cg cg_inst = new;
covergroup可以通过new(xx)构造函数传递参数进去,参数的类型只能是ef(会被处理成const ref)或input,而不能时output或inout。
可以通过@event或sample()方法来指定coverage何时采样。Covergroup可以包含一个或多个coverage points。Coverage point可以覆盖一个变量或一个表达式。Coverage point内部可以包含一组bins(仓),用于采集values或value transitions。用于采集value 集合的bin称为state bins,用于采集value transitions的bin称为transition bins。
也可以将coverage group嵌入到class定义中,这是一种常见的做法,它提供了一种简单的方式去覆盖类中的属性,可以保护类的封装性,这种方式称作embedded covergroup declaration。
3. coverage point
Coverpoint表达式(包括iff condition)的采样是发生在covergroup被采样的时候。Coverpoint会创建一个层次化范围且可选的labeled。如果有使用label,那么该label就是coverage point的名字。该名字也可以用于cross coverage 和访问coverpoint中的方法。如果没有指定label且coverpoint只和一个单一变量关联,那么该变量名可以是coverpoint的名字,其它情况,由工具实现定义,但该自动生成的名字只是用于coverpoint报告,不能被其它地方语言引用。
Coverpoint bin将一个name和count与一组value或value transition 序列联系起来,当一个bin指定的value或value transition 序列每一次满足时,相应的count加1。每一个bins的后面都可以跟着iff construct来指定该bins是否满足采样条件,如果是false,那么count肯定不会增加的。Transition bin在每一个sample中,最多只能增加1,不管同时有几个hit同一个bins。
bins允许对于给定范围列表的每一个value创建一个独立的bin,可以在bin name后面加上[]就可以了,或者如果要把给定范围列表分配到几个bin内,可以在[]里加上正整数expression。如果bins的固定个数小于values的指定个数,那么尽力采用均分,无法均分,最后一个全部兜着。如果bins的个数大于values的指定个数,那么有一些bins将会是空的。
bins允许对于范围列表创建一个单一的bin,也就是bin name的等号后面使用{}指定一组values。
对于范围列表,允许使用[ expression : $ ] or [ $ : expression ]。
如果没有指定bins的话,coverpoint bin会自动创建,创建的最大个数为auto_bin_max(coverage option)指定的。
default可以用于替代没有被显式定义的bins中指定的其它值,对于coverpoint覆盖率的计算不考虑default bin,同样的,cross coverage也不考虑default。default sequence用于替代没有被显式定义的transition bins中指定的其它transition值。defualt或者defualt sequence bin不能被显式ignored。如果一个bins被指定为ignore_bins且被指定为default或defualt sequence,那么会报错的。
Wildcard bin使得所有的X、Z或?可以被当作0或1。如下:
wildcard bins g12_15 = { 4'b11?? };
如果采样值有1100、1101、1110和1111,那么g12_15命中的次数就增加。
Wildcard bins也可以用于separate bins,例如:
wildcard bins g12_15_array[] = { 4'b11?? };
上述会创建1100、1101、1110和1111这4个bin。
Wildcard bins也可以用于transition bins,例如:
wildcard bins T0_3 = (2'b0x => 2'b1x);
每当有下面的value transitions,T0_3 bin的计数会增加,有点类似于(0,1=>2,3)方法。
00 => 10、00 => 11、01 => 10、01 => 11
3.1. Transition bins的指定方式
value1(range_list1) => value2(range_list2):表示value1的下一次sample要是value2;如果有用到range_list,那么SV会拓展range_list里的值其它值进行转换,比如:
1,5 => 6, 7
那么它的效果相当于:( 1=>6 ), ( 1=>7 ), ( 5=>6 ), ( 5=>7 )
trans_item [* repeat_range ]: 表示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 )
trans_item [-> repeat_range],或trans_item [= repeat_range]:表示trans_item出现个数,中间不管有什么其它值。比如:
3 [-> 3]
上述等于:...=>3...=>3...=>3,(...)代表任何不包含值为3的转换。在比如:
1 => 3 [ -> 3] => 5
上述等于:1...=>3...=>3...=>3 =>5
4. cross coverage
Coverage group可以指定在两个或多个coverpoints或变量之间进行cross coverage。如果指定的是变量,那么SV会隐式地帮它定义一个coverpoint,然后再参与到cross。因此cross coverage的输入本质上只有coverpoint。另外expression不能直接用于cross中,只能先将expression定义成coverpoint,然后再用cross。
Cross coverage提供了一个可选的label,该label会为cross中定义的bins创建一个层次化范围。Cross coverage也可用iff来选择是否在该次统计coverage。
对于coverpoint中定义为default、ignored或illegal的bins,在cross中不会创建bins的。Cross coverage只允许用同一个coverage group中的coverage points进行cross,引用其它group的coverpoint将会导致编译错误。
除了cross自动生成的bins之外,SV允许用户定义指定的cross coverage bins。可以使用bin select 方式来定义用户自定义的bins。用户自定义cross bins和自动生成 bins可以在同一个cross中生成的。只要没有被用户定义的cross bin截断的其它自动生成bins都会保持。如下例子:
int i,j;
covergroup ct;
coverpoint i { bins i[] = { [0:1] }; }
coverpoint j { bins j[] = { [0:1] }; }
x1: cross i,j;
x2: cross i,j {
bins i_zero = binsof(i) intersect { 0 };
}
endgroup
x1 cross的结果为:
<i[0],j[0]>
<i[1],j[0]>
<i[0],j[1]>
<i[1],j[1]>
x2 cross的结果为:
i_zero // user-specified bin for <i[0],j[0]> and <i[0],j[1]>
<i[1],j[0]> // an automatically generated bin that is retained
<i[1],j[1]> // an automatically generated bin that is retained
binsof语法产生它里面表达式的bins,该表达式可以是coverage point(显式)或单个变量(隐式生成coverpoint),或coverpoint bin。生成的结果bins可以进一步选择,通过intersect语法来选择或排除某些bins的值。Bins值的选择可以使用逗号分隔来选取多个,因此可以选择1个value、一个范围value、也可以范围值。例如:
[ $ : value ] => The set of values less than or equal to value
[ value : $ ] => The set of values greater or equal to value
bins的选择可以和其它bins的的选择进行逻辑运算(&&, ||)来进一步选择的。
5. coverage option
Coverage options可以用于控制covergroup、coverpoint和cross的行为。有两种options类型:一种用于指定covergroup instance的行为,另一种用于指定covergroup type的行为。如果对于同样option,指定多个值会报错的。
5.1 Covergroup instance options
下表为instance-specific covergroup options及其描述。这些options可以在初始化instance-specific options时指定不同的值。这些初始化option value只影响对应的instance。
Instance-specific options可以在covergroup定义的时候set进去。在covergroup定义时设置这些options的语法如下:
option.member_name = expression;
每一个covergroup、coverpoint或corss内部都自带有option这个成员变量。covergroup定义时,内部的option赋值语句是在该covergroup例化时生效的。per_instance和get_inst_coverage options只能在covergroup定义时设置。auto_bin_max和detect_overlap options只能在covergroup和coverpoint定义时生效。其它的instance-specific options可以在covergroup例化之后,通过赋值来设置的。下表总结了instance options在不同语法层次(covergroup、coverpoint或cross)的总结。所有的instance options可以在covergroup层次指定。除了weight、goal、comment和per_instance options,所有其它options在covergroup设置后,也作为该covergroup内部所有coverpoints和crosses的相应options的默认值。当然独立的coverpoints或crosses可以覆盖这些默认值。weight、goal、comment和per_instance options在covergroup层次设置时,不会影响更低层次(coverpoint和cross)相应options的默认值。
5.2 Covergroup type options
下表列出的options描述covergroup type整体的属性。它们就像是class中的static data members一样,对于所有的instances都起作用的。
上述提到的covergroup type options可以在covergroup定义时设置,语法如下:
type_option.member_name = constant_expression;
type_option是每个covergroup、coverpoint和cross内建的static 成员。不同instances不能对type_options赋不同的值。这些options只能在初始化时通过常数表达式来设置。Strobe type option只能在covergroup定义时设置,其它type options可以在仿真进行中赋值,通过::方式来的。如下:
covergroup gc @(posedge clk) ;
a : coverpoint a_var;
b : coverpoint b_var;
endgroup
...
// Set the comment for all covergroups of type "gc"
gc::type_option.comment = "Here is a comment for covergroup g1";
// Set the weight for coverpoint "a" of all covergroups of type gc
gc::a::type_option.weight = 3;
gc g1 = new;
下表列出了不同层次的type options可以是否被设置。covergroup层次的设置不影响到底下层次的设置。
6. coverage method
covergroup提供了一些coverage方法,这些方法可以在任何时刻被调用:
get_coverage()返回type coverage,它包含了所有该type例化出来的coverage累积,它是static方法,可以用::操作符和.操作符来引用。get_inst_coverage()返回指定instance的coverage,它只能对应的instance有关联,不是static方法,因此只能用.操作符。另外,covergroup里的sample()函数其实可以使用with关键字来override的。
SV提供了以下的系统方法去帮助管理覆盖率数据收集:
- $set_coverage_db_name ( filename ):设置覆盖率数据库的文件名,在仿真运行结束时将覆盖率信息保存到该数据库中。
- $load_coverage_db ( filename ):从给定的文件名加载所有coverage group类型的累积覆盖率信息。
- $get_coverage ( ):返回0~100范围内所有coverage group类型的总体覆盖率的实数。这个数字是按照前面描述的方法计算的。
7. coverage computation
关于覆盖率的计算,请看这篇文章《Systemverilog覆盖率的合并和计算方式_覆盖率merge-CSDN博客》。