SV--coverage
1:fcov(assert和功能)、ccov(行、分支、条件、fsm)、pcov
covergroup、coverpoint、cross
bins、ignore_bins、illegal_bins、binsof
default、default_sequence、$、item
6.2 详细
1:pcov:plan cov
验证计划目标覆盖率、代码覆盖率和功能覆盖率。
制定验证计划中的功能点的时候, 需要考虑如下三个问题。
哪些功能点需要检查?
这个功能点的哪些数据需要检查?
如何对这些数据进行采样?
一般情况下, 以下几类是参考的对象: 功能要求、 接口要求、 系统规范、 协议规范等。
2:code cov:分支:条件分支
条件、表达式:表达式的各种逻辑组合。
3:covergroup可以在module、program、class、interface、package等里定义。
覆盖组可以定义参数,在其例化时需传递实参,实参在 new 的过程中采样;时钟事件定义了功能覆盖组的采样条件,若不定义时钟采样条件,则需要通过调用内置的采样方法sample。
在类中可以不使用例化, 但仍需在类的构造函数中调用 new 对覆盖组进行分配初始化
4:coverpoint
lable是可选的覆盖点的名称,用户可指定具体的名字以便通过层次化引用来访问该覆盖点; 若不指定,则由仿真器自动分配。该覆盖点在采样事件激发或者内置sample被调用时采样统计。 iff结构可以指定采样条件,若指定条件不成立时,则不作覆盖率统计。
如果没有显示定义,自动创建分组柜的最大数目将由 auto_bin_max这个内置参数决定,默认64.。不管是显示定义还是自动生成,若分组柜中各种情况的总数除以分组柜的个数,其商就是每个组的平均个数,余数部分会归入最后一个分组柜中,如下例所示:
Bins fixed[3] = {1:10};
5:cross
Ignore_bins可以定义忽略的交叉覆盖点,该类交叉覆盖点出现的时候不列入统计的范围,计数器不做自加; illegal_bins可以定义非法的交叉覆盖点,一旦出现该类交叉覆盖点,系统会报告出错。
6:内置参数
功能覆盖率的两个重要部分是采样的数据和数据被采样的时刻。数据被采样的时刻可以是1)使用wait或@来阻塞赋值,2)使用sample的方法。采样的数据则需要在代
码中加入覆盖组(Covergroup)和仓(Bin),覆盖组可以定义在类中,程序块,模块中。使用覆盖组之前必须先进行实例化。所以一般在类中使用覆盖组时,将
覆盖组的实例化加在类的构造函数new()中。Covergroup和Coverpoint的命名应当尽可能的明确,这样方便检查覆盖率文件。
class Driver_cbs_coverage extends Driver_cbs; event trans_ready; //@event来触发采样
covergroup CovPort; covergroup CovPort @(trans_ready)
....... coverpoint ifc.cb.port;
endgroup endgroup
virtual task post_tx(Transaction tr);
CovPort.sample(); //显示通过callback来回调sample函数,完成采样
endtask
SV支持自动仓的创建,但是更多地适用于2的幂次方,因为这样才有可能100%命中,最大的自动创建仓的数目是64。auto_bin_max限制自动创建仓的个数,SV这
时,会将值域平分在各个仓。
covergroup CovPort; covergroup CovPort;
coverpoint tr.port options.auto_bin_max = 2; //对整个covergroup有效
{options.auto_bin_max=2;} //只对此coverpoint有效 coverpoint tr.port;
endgroup endgroup
用户自定义创建仓(bin),将coverpoint和仓分别明确的命名。
covergroup Covkind;
kind:coverpoint tr.kind{ //用kind为coverpoint命名
bins zero={0}; //自定义一个名为zero的仓,值为0
bins lo={[1:3],5}; //自定义一个名为lo的仓,值为[1:3]或5
bins hi[]={[8:$]}; //自定义$-8个仓,8个值得范围在[8:$]
bins misc=default; //定义一个default的仓,所示所有的剩下的不关心的值
}
endgroup
为覆盖点增加条件控制采样时间段,关键字iff 。
covergroup CoverPort;
coverpoint port_value iff(!bus_if.reset);
endgroup
为枚举类型创建仓(bin),所有枚举类型之外的值都会被忽略,SV默认每个枚举的值一个仓。
typedef enum{INIT, DECODE, IDLE}fsmstate_e;
fsmstate_e pstate, nstate;
covergroup cg_fsm;
coverpoint pstate;
engroup
忽略某个coverpoint的某些值,覆盖率不在检查该值,关键字ignore_bins。 illegal_bins不仅忽略某个coverpoint的值,还会报错。
bit [2:0]low_ports_0_5; bit [2:0]low_ports_0_5;
covergroup CoverPort; covergroup CoverPort;
coverpoint low_ports_0_5{ coverpoint low_ports_0_5{
options.auto_bin_max=4; options.auto_bin_max=4;
ignore_bins hi={[6,7]}; illegal_bins hi={[6,7]};
} }
endgroup endgroup
使用cross关键字创建交叉覆盖率。 //使用串联值的方式来替换交叉覆盖
covergroup Covport; covergroup CrossBinnames;
port:coverpoint tr.port a:coverpoint tr.a{bins a0={0}; bins a1={1};}
{bins port[] = {[0:$]};} b:coverpoint tr.b{bins b0={0}; bins b1={1};}
kind:coverpoint tr.kind ab:cross a,b {bins a0b0=binsof(a.a0)&&binsof(b.b0);
{bins zero={0}; bins a1b0=binsof(a.a1)&&binsof(b.b0);
bins lo={[1:3],5}; //注释同上,只创建一个仓 bins b1=binsof(b.b1);}
bins hi[]={[8:$]}; ab:coverpoint{tr.a, tr.b} //用串联值得方式来替换
bins misc=default;} {bins a0b0={2'b00};bins a1b0={2'b10};}
cross kind,port{ endgroup
ignore_bins hi=binsof(port) intersect{7}; //去除port这个coverpoint的仓7
ignore_bins md=binsof(port) intersect{0} &&
binsof(kind) intersect{[9:11]};
ignore_bins lo=binsof(kind.lo);} //去除kind这个coverpoint的lo仓
endgroup
对于单个的covergroup,它的覆盖率是由简单覆盖点和交叉覆盖点两部分组成的,可以通过关键字option.weight来控制整体的覆盖率倾向。
covergroup CovPort;
Kind:coverpoint tr.kind {bins zero={0}; option.weight=5;}
port:coverpoint tr.port {bins port={0}; option.weight=0;} //计算该covergroup的覆盖率时,忽略该coverpoint
cross kind,port {option.weight = 10;}
endgroup
当需要编写的覆盖组之间十分接近时,可以写出一个通用的覆盖组,然后通过new函数或ref的形式来传递参数。
bit[2:0]port; bit[2:0]port_a,port_b;
covergroup CoverPort (int mid); covergroup CoverPort (ref bit[2:0]port, input int mid); //定义ref形式
coverpoint port{bins lo={[0:mid-1]}; coverpoint port{bins lo={[0:mid-1]};
bins hi={mid:$};}; bins hi={mid:$};};
endgroup endgroup
CoverPort cp; //定义新的covergroup CoverPort cpa, cpb; //定义新的covergroup
initial cp=new(5); //例化covergroup并传递参数 initial begin cpa=new(port_a,4); //例化covergroup并传递参数
............. cpa=new(port_b,4);
设置某个covergroup的inst_name,set_inst_name();
使用VCS等仿真工具可以追溯到每个实例的覆盖率,但此时covergroup中应该添加声明。
covergroup CoverLength(string comment);
coverpoint tr.length;
option.per_instance=1; //指定需要单个实例的覆盖率
option.comment=$psprintf("%m");
/或者指定自己的注释
option.comment = comment;
endgroup
CoverLength cp_lo = new("Low port numbers");
option.at_least,在无法有效的建立bin时,通过该设置保证bin被击中N次后,就算是覆盖完全。
还有两个重要的命令:option.cross_num_print_missing = N; // 让仿真工具给出所有的仓,柏阔那些没有被命中的仓(默认不会报出)
option.goal=N; // 设置覆盖组或覆盖点的目标 如90等
在长仿真过程中:
$get_coverage:Covergroup::get_coverage()/cgInst:Covergroup()得到某个覆盖组或者inst的coverage
$get_inst_coverage:得到特定inst的覆盖率。