vcs 覆盖率收集1——类型、covergroup、数据采样-爱代码爱编程
文章目录
前言
2023.3.15
2023.3.20
一、覆盖率知识
1、覆盖率类型
(1)代码覆盖率
衡量RTL代码是否被充分运行的指标,100%是验证工作完备的必要性,一般设置为95%
。
语句覆盖率
(statement coverage):指的是程序的每一行代码是否被执行过。条件覆盖率
(condition coverage) :指的是每个条件中的逻辑操作数被覆盖的情况。决策覆盖率
(branch coverage) :指的是在if, case, _while,repeat, forever,for和loop语句中各个分支执行的情况。事件覆盖率
(event coverage):该覆盖率用来记录某一个事件被触发的次数。跳转覆盖率
(toggle coverage):用来记录某个设计边界信号数据位的0/1跳转情况,例如从0到1,或者从1到0的跳转。状态机覆盖率
(finite stage machine coverage) :仿真器的覆盖率功能可以识别出设计中的状态机部分,记录各种状态被进X的次数,以友状态之间的跳转情况。
(2)功能覆盖率
(2-1)覆盖率分析
- 覆盖率稳步增长:添加种子或者加长测试
- 增速放缓:添加额外的约束
- 增长停止:创建新的测试
- 覆盖率达到100%还有设计漏洞:某些功能点没有进行测试
(2-2)功能覆盖率策略
收集信息而非数据
:数量太大的话,应当拆分成多个小范围+边界。着眼于状态而不是某个数据只测量需要的内容
:收集覆盖率的时候开销是很大的验证的完备性
:同时驱动高的代码覆盖率和高的功能覆盖率
代码覆盖率低功能覆盖率高:没有执行所有的代码,验证计划也不完整
代码覆盖率高功能覆盖率低:可以执行所有代码,没有所有功能点都测试到了
(3)断言覆盖率
断言描述本身也支持覆盖率收集,一般可以通过仿真或者硬件加速的方式来收集,也可以通过形式验证的工具来收集。
定义:用于一次性地或在一段时间对一个或者多个设计信号在逻辑或者时序上的声明性代码,也可以用其他task/function来进行断言,是等价的
关心某个信号值或者状态是否改变,断言覆盖率需要自己设置,覆盖率会被收集到一个覆盖率数据库中。
- 在常见的仿真中,仿真器会记录断言的先决条件是否被触发,以及判断语句成功或者失败。
- 根据选择的验证方法不同,我们可以将断言覆盖率分为:
基于动态仿真或者硬件加速的断言覆盖率
基于形式验证的静态断言覆盖率
2、覆盖组/covergroup
- 需要例化才能采样数据,一次定义就可以多次实例化
- 衡量这些变量在某些特定时间采样到的值,定义采样哪些变量、数值,定义采样事件。
- 可在
class
、interface
、module
里面定义 - 一个类可以有多个
covergroup
,都是独立的,可以自行使能或者禁止(之前的有constraint、randomize可以使能) sample()
:手动采样,显示采样
wait/@
:借助已有的事件阻塞触发
//采样方式一 : sample()
covergroup Covport;
coverpoint port; //没有定义数值,意思就是采样所有的值
endgroup
Covport cg1 = new(); //例化
cg1.sample(); //手动采样
//采样方式二 : 事件触发,最好不用这种方式
event trans_ready; //定义事件
covergroup Covport@(trans_ready); //也可以用wait
coverpoint port;
endgroup
3、数据采样
(1)bins/仓
bin/仓
:衡量功能覆盖率的基本单位,记录每个数值被捕捉到的次数
可以手动或者SV自动定义bin域
:可能数值的个数。- 每一个
coverpoint
组合成covergroup的覆盖率,所有的covergroup
组成整体的覆盖率。 覆盖率 = 采样值的数目 / bin的数目
例如:一个3bit变量的域是7:0,正常情况下会自动分配8个bin。如果仿真过程中有7个值被采样到,那么最终的coverpoint的覆盖率就是7/8- 采样变量范围太大时,系统会默认分配
64bin
,再将数值平均分配到64个。
auto_bin_max
:指定自动创建bin的最大数目, - 定义在 covergroup 的option设置会影响整个covergroup ,即当前covergroup下的所有coverpoint都被设置了。coverpoint里面的设置会覆盖covergroup的设置。
covergroup Covport;
option.auto_bin_max = 8;//covergroup中的option
coverpoint tr.port{
//这个option会覆盖covergroup的设置
option.auto_bin_max = 2;//coverpoint中的option
}
endgroup
//-----------------------------------------------
covergroup Covkind;
coverpoint tr.kind{
bins zero = {0}; //1个仓代表kind=0
bins lo = {[1:3], 5}; //1个仓表示1:3和5
bins hi[] = {[8:$]}; //8个独立的仓代表8:15
bins misc = default; //1个仓表示剩余的所有值
}
endgroup
(2)条件覆盖率
关键词iff
:需要满足条件才会采样,附加条件
start/stop
函数:单独使能或者关闭
covergroup Covport;
coverpoint port iff{!vif.rstn} {bins t1 = default;} //复位期间不采样
endgroup
Covport cb = new();
cb.stop();
if(vif.rstn = 1'b1)begin
cb.start();
end
(3)翻转覆盖率
covergroup Covport;
coverpoint port{
bins t1 = (0 => 1),(0 => 2) , (0 => 3) ;//满足其中任何一个,就会记录一次
}
endgroup
(4)wildcard覆盖率
X/Z/:会被当成0或者1
wildcard bins even = {3'b??0};//偶数
wildcard bins odd = {3'b??1};//奇数
(5)ignore_bins
有些coverpoint可能始终无法得到全部的域值,可以用 ignore_bins
来排除不计算功能的域,最终这些值不会计入coverpoint的覆盖率
bit [2:0] low_ports;
covergroup Covport;
coverpoint low_ports{
ignore_bins hi = {[6,7]}; //排除6和7
}
endgroup
(6)illegal_bins
不想要某些值,出现这些数值就会报错
coverpoint port{
illegal_bins hi = {[6,7]};//出现6~7就停止仿真,报错
}
(7)交叉覆盖率
某一时刻多个变量之间值的组合,cross出来的数据量一般比较大,可以手动忽略一些,更好的方法是自己声明感兴趣的cross bin。
binsof
:指定覆盖点 coverpoint
intersect
:指定数值集
//第一种:这种写法是去忽略某些值
class Transaction;
rand bit [3:0] kind;
rand bit [2:0] port;
endclass
transaction tr;
covergroup Covkind;
port: coverpoint tr.port{
bins port[] = {[0:$]}; //port是3bit,所以是8个bin
}
kind: coverpoint tr.kind{
bins zero = {0}; //1个仓代表kind=0
bins lo = {[1:3], 5}; //1个仓表示1:3和5
bins hi[] = {[8:$]}; //8个独立的仓代表8:15
bins misc = default; //1个仓表示剩余的所有值
} //这里总共11个bins,看bins的数量是看前面是数组还是变量
cross kind, port{
ignore_bins hi = binsof(port) intersect {7}; //忽略port为7时的11个kind bin
ignore_bins md = binsof(port) intersect {0} && binsof(kind) intersect {[9:11]}; //忽略port为0时,kind里面的hi[]
ignore_bins lo= binsof(kind.lo); //忽略kind.lo,也就是当kind=1,2,3,5时忽略
}
endgroup
//第二种:首先不去收集覆盖率,设置为0;然后去采样特定的cross交叉覆盖率
//哪个写起来更方便就可以使用哪种
class Transaction;
rand bit a, b;
endclass
Transaction tr;
covergroup CovTrans;
a: coverpoint tr.a{
bins a0 = {0};
bins a1 = {1};
option.weight = 0; //不计算覆盖率
}
b: coverpoint tr.b{
bins b0 = {0};
bins b1 = {1};
option.weight = 0; //不计算覆盖率
}
ab: cross a, b{
bins a0b0 = binsof(a.a0) && binsof(b.b0);
bins a1b0 = binsof(a.a1) && binsof(b.b0);
bins b1 = binsof(b.b1);
}
endgroup
4、覆盖选项
option
:covergroup和coverpoint都可以有option
option.per_instance = 1
:单独列出每个covergroup实例的覆盖率option.goal = xxx
:覆盖率目标,一般设置为100%option.comment
:如果有多个covergroup实例,可以通过参数来对每一个实例传入单独的注释。这些注释最终会显示在覆盖率数据的总结报告中option.weight = 0
:设置覆盖率权重,定义在coverpoint中,表示不关心这个coverpoint的覆盖率at_least
:默认情况下,数值采样次数1次就可以计入有效的bin,可以通过修改at_least来修改每个bin的数值最少采样的次数,如果低于at_least数值,则不会被计入bin
covergroup CoverLegth;
coverpoint tr.length;
option.per_instance = 1; //设置覆盖选项,单独列出每一个的覆盖率
endgroup
//----------------------------------
covergroup CoverLegth(int hi,lo, string comment);//传入comment
option.comment = comment; //设置注释
option.per_instance = 1;
coverpoint port{
bins range {[lo:hi]};
}
endgroup
...
Coverlength cp_lo = new(0,3,"Low port numbers");
Coverlength cp_lo = new(2,3,"Hign port numbers");
5、covergroup函数
sample()
:采样
get_coverage()
:加权后的覆盖率,返回0-100的real数值
get_inst_coverage()
:当前实例的覆盖率,返回0-100的real数值
set_inst_name(string)
:设置coverpoint的名称,体现在数据报告上
start()/stop()
:使能或者关闭覆盖率的收集
$get_coverage()
:系统函数,获得总体的覆盖率