目录
五星上将麦克阿瑟说过:这篇文章通俗易懂,我很欣赏!
首先要理解什么是功能覆盖率?功能覆盖率的代码是不是需要我们手写?代码覆盖率已经100%了,功能覆盖率还需要再验证?等等问题,都是我们第一次接触这个概念会遇到的。
功能覆盖率是一种比例数据,指芯片中已验证通过的功能占该芯片全部功能的百分比,验证工作的目标就是尽量使功能覆盖率达到100%.功能覆盖率与verification point有一些类似,也可以认为是把verification point里的feature分别写成一个个的coverpoint/cross。与verification point不同的是功能覆盖率能有效的知道已验证的功能的百分比,verification point是人工管理,比较容易出错,而且也不能保证某一条已经完成的feature是真实有效的测试到了(因为没有数据支持)。
换句话说,每一个功能点对应的场景是多种多样的,我们需要考虑到当某个特定条件满足时的所有场景。这就是功能验证的意义。代码覆盖率就好比一张平面,只要每行的代码能够覆盖就行。功能覆盖率更像是一个立体。我们需要每一个随机的验证用例可以覆盖到空间中的每一个粒子。
通常,功能覆盖率不需要我们手写!通过EXECL中填写的关键信息,通过脚本,转化成最终我们需要的sv文件。
接下来,我将对这些细节详细的展开叙述。
功能覆盖率以covergroup为一个群体单元,一个covergroup里包含了所测模块的部分或者全部的功能点,一个block可以有一个或者多个的covergroup。
一个covergroup 可以自动trigger,也可以用户自己决定什么时候trigger.
covergroup test
(@posedge clk){
coverage specification
}
endgroup:test
test cg_inst
cg_inst = new()
倒数2行创建一个covergroup的实体,创建之后,第2行在clk的上升沿就会去收集这个covergroup的覆盖率数据。
covergroup test
coverage specification
endgroup:test
test cg_inst
cg_inst = new()
forever begin
repeat(10) (@posedge clk);
cg_inst.sample();
end
在covergroup里没有启动条件,forever 就是用户自定义的启动条件,每过10个clk就收集一次覆盖率数据。
我们在收集覆盖率数据的时候尽量不要用clk的沿作为启动条件,虽然这样收集的次数会很多,保证数据不会遗漏,使得最终的结果很完美。但是,缺点也很大!因为每个clk的收集,会极大的影响我们的仿真效率,拖垮仿真时间。通俗的理解,现在有一个32bit位宽的计数器,如果每个clk采集一次数据的话,一个验证用例你要跑几天几夜的时间。那几百个case同时跑,服务器无奈的摇摇头,五星上将麦克阿瑟无奈的摇摇头。
那么应该怎么做才合理呢?
一般我们可以把covergroup分为静态的和动态的:
covergroup里一般包含coverpoint和cross,coverpoint和cross里又包含bins
一个coverpoint一般是对某个变量的描述,如该变量的最大值/最小值,某些特定值是否能cover等。当然两个变量的比较关系也是一种特殊的coverpoint。
每一个1bit的变量,取值都会是0和1,这也就是代码中出现AUTO的原因。
//该覆盖率组命名为test_cov_cg
covergroup test_cov_cg;
option.name = "test_cov_cg";
//变量sa_en的coverpoint
cp_sa_en: coverpoint cfg.test_cfg.sa_en iff(sample_cp_sa_en) {
type_option.weight =2;
//分为两个bins(仓),分别为0和1
bins bin_0 = {0}; // AUTO
bins bin_1 = {1}; // AUTO
}
//变量test_mode的coverpoint
cp_test_mode: coverpoint cfg.test_cfg.test_mode iff(sample_cp_test_mode){
type_option.weight = 2;
//分为四个仓,分别为0/1/2/3
bins bin_0 = {0}; // AUTO
bins bin_1 = {1}; // AUTO
bins bin_2 = {2}; // AUTO
bins bin_3 = {3}; // AUTO
}
//sa_en和test_mode的cross可自定义仓,也可以ignore某些仓
cs_cp_sa_en_cp_test_mode: cross cp_sa_en, cp_test_mode{
type_option.weight =2;
bins bin_cp1_1 = binsof(cp_sa_en) intersect {1};
}
endgroup
同样的,两个不同的变量也可以组合起来使用,就是cross。可以很明确的说,这些代码不用我们自己写。后面我会详细的介绍。
bins r0 = {0,13,64}
bins r1 = {[10:$]} // 10 to MAX
bins r[] = {0,13,64} // r[0]= 0/r[1]=13/r[2]=64
bins a =(1=>2)
bins b=(1=>2=>3)
bins c=(1,5=>6,7) //1=>5 or 1=>7 or 5=>6 or 5=>7
bins d={3[*3]} // 3=>3=>3
bins e=(4=>5),([7:9],11=>12) //4=>5 or 7/8/9/11=>12
bins f[]=(4=>5),([7:9],11=>12) //自动分为很多仓
只关注最低2bit位,其余的bit位是0是1都可以接受。
wildcard bins a ={7'b?????01};
//忽略1/2/3
bins legal={[0:15]}
ignore_bins ignore ={1,2,3}
illegal_bins a ={4=>5} //出现4=>5平台会报error
功能覆盖率代码有一定的格式,本着手动写既浪费时间又容易出错的原则,所以自动产生func_cov的代码很有必要。把功能点写到Excel表格里,用一个脚本自动产生对该Excel表格的功能覆盖率代码。这便是我们后面章节重点要说的内容。通过第一张的内容,我们只需要理解功覆盖率文件中的一些语法即可,接下来就是如何用脚本生成代码的事情了。
下面这幅图只是简单的说明。
TYPE第一列:选择是coverpoint还是cross
VARIABLE第二列:选择是变量
BITS第三列:是位宽
QTY第四列:针对的是数组
NAME第五列:信号名,excel自动生成
BINS第六列:BINS,填写我们关注的场景
CP1/CP2/CP3...主要用在CROSS这种情况中
下面将介绍一些常用到的一些场景
Coverpoint BINS
类型 | 说明 | 例子 |
AUTO | 自动拆分为2的位宽个bins | cp_var_a:coverpoint var_a{ ? ? ? ? bins bin_0 = {0}; // AUTO ? ? ? ? bins bin_1 ={1}; // AUTO? ? ? ?? } |
MIN | 有MIN和MIN=xx两种 情况, MIN=xx支持10进制和16进制,如果只写MIN,那么MIN=0 | MIN = 8'ha =>? bins bin_min = {8'ha}; //MIN |
类型 | 说明 | 例子 |
MAX | 有MAX和 MAX=xx两种情况,MAX=xx支持10进制和16进制, 如果仅写MAX,那么MAX=2位宽-1 | MAX=200?? => bins bin_max = {8'hc8};? //MAX |
LOW | MIN和MAX取中间,中间偏左的为LOW(不包含MIN) | MAX=8'hAA,MIN=10,LOW? => bins bin_min = {8'ha};? //MIN bins bin_max = {8'haa}; //MAX bins bin_low = {[8'hb:8'h5a]}; //LOW |
HIGH | MIN和MAX取中间,中间偏右的为HIGH(不包含MAX) | MAX=8'hAA,MIN=10,HIGH? => bins bin_min = {8'ha};? //MIN bins bin_max = {8'haa}; //MAX bins bin_high= {[8'h5b:8'ha9]}; //HIGH |
Cross BINS:
类型 | 说明 | 例子 |
ONLY | 不关心自动cross的结果,只考虑ONLY里的仓 | |
IGNORE | 在自动cross的基础上,exclude掉部分仓 |
需要用到 Cadence IMC?
首先导入代码覆盖率文件。
?
?第二步: 打开功能覆盖率选项
结果如下图所示:
虽然我打开了代码覆盖率的total文件,但是功能覆盖率我同样也已经覆盖了,所以只需要切换一下选项即可。这里要说的是,如果你的功能覆盖率没有达到100%,可以添加一些定向的case到验证环境中。
举个例子:
下面的功能覆盖率只有75%,为什么呢?因为最小值0,没有覆盖到。
假设这个信号叫做counter_sig,8bit 位宽。它的BINS是【MIN, LOW, HIGH,MAX】
那么1~7F, 7F~FE, FF这三种情况都覆盖到了,但是当counter_sig=0 (MIN)却没有覆盖到。
存在的原因有2中:你的验证用例功能的不完善;或者是你的随机的次数太少,没有覆盖到这种情况。通常都是后者导致的,所以要是收集代码覆盖率的时候,可以让随机的次数多一些,结果会理想的很多。
脚本的介绍将会在以后的文章中提到!欢迎大家随时讨论交流!
?