【项目实战】功能覆盖率的收集1
功能覆盖率的收集
目录
五星上将麦克阿瑟说过:这篇文章通俗易懂,我很欣赏!
1. 背景知识
1.1 概念
首先要理解什么是功能覆盖率?功能覆盖率的代码是不是需要我们手写?代码覆盖率已经100%了,功能覆盖率还需要再验证?等等问题,都是我们第一次接触这个概念会遇到的。
功能覆盖率是一种比例数据,指芯片中已验证通过的功能占该芯片全部功能的百分比,验证工作的目标就是尽量使功能覆盖率达到100%.功能覆盖率与verification point有一些类似,也可以认为是把verification point里的feature分别写成一个个的coverpoint/cross。与verification point不同的是功能覆盖率能有效的知道已验证的功能的百分比,verification point是人工管理,比较容易出错,而且也不能保证某一条已经完成的feature是真实有效的测试到了(因为没有数据支持)。
换句话说,每一个功能点对应的场景是多种多样的,我们需要考虑到当某个特定条件满足时的所有场景。这就是功能验证的意义。代码覆盖率就好比一张平面,只要每行的代码能够覆盖就行。功能覆盖率更像是一个立体。我们需要每一个随机的验证用例可以覆盖到空间中的每一个粒子。
通常,功能覆盖率不需要我们手写!通过EXECL中填写的关键信息,通过脚本,转化成最终我们需要的sv文件。
接下来,我将对这些细节详细的展开叙述。
1.2 启动
功能覆盖率以covergroup为一个群体单元,一个covergroup里包含了所测模块的部分或者全部的功能点,一个block可以有一个或者多个的covergroup。
一个covergroup 可以自动trigger,也可以用户自己决定什么时候trigger.
1.2.1 自动trigger
covergroup test
(@posedge clk){
coverage specification
}
endgroup:test
test cg_inst
cg_inst = new()
倒数2行创建一个covergroup的实体,创建之后,第2行在clk的上升沿就会去收集这个covergroup的覆盖率数据。
1.2.2 sample
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分为静态的和动态的:
- 1 静态的covergroup在配置完成之后就可以sample,里面的功能点是仿真刚开始的时候就确定好了,仿真过程中几乎不会改变,这样一次sample就可以把我们想要的数据都收集完毕,完全没必要一直重复的去收集。
- 2 动态的covergroup一般是针对数据通路,在仿真过程中一直在变换,我们要权衡启动条件,尽可能的保证数据不遗漏(即使数据遗漏也没关系,顶多就是某一个coverpoint或者cross可能case已经跑到,但是因为收集的次数不够而导致报告没有覆盖到,我们再造一个定向case就可以了,但是如果说每次跑regression都去重复不断的去收集这个covergroup里的功能点,regression的时间可能是不收集功能覆盖率的几十倍甚至上百倍,这样就得不偿失了),也要保证我们的仿真时间跟不收集覆盖率的时候不要差别太大。
1.3 covergroup
covergroup里一般包含coverpoint和cross,coverpoint和cross里又包含bins
?1.3.1 coverpoint
一个coverpoint一般是对某个变量的描述,如该变量的最大值/最小值,某些特定值是否能cover等。当然两个变量的比较关系也是一种特殊的coverpoint。
1.3.2 cross
每一个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。可以很明确的说,这些代码不用我们自己写。后面我会详细的介绍。
1.3.3 bins
1.3.3.1 scaler bins
bins r0 = {0,13,64}
bins r1 = {[10:$]} // 10 to MAX
1.3.3.2 vector bins
bins r[] = {0,13,64} // r[0]= 0/r[1]=13/r[2]=64
1.3.3.3 transitions bins
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) //自动分为很多仓
1.3.3.4 wildcard bins?
只关注最低2bit位,其余的bit位是0是1都可以接受。
wildcard bins a ={7'b?????01};
1.3.3.5 ignore bins
//忽略1/2/3
bins legal={[0:15]}
ignore_bins ignore ={1,2,3}
1.3.3.6 illegal bins
illegal_bins a ={4=>5} //出现4=>5平台会报error
2 脚本工具使用
功能覆盖率代码有一定的格式,本着手动写既浪费时间又容易出错的原则,所以自动产生func_cov的代码很有必要。把功能点写到Excel表格里,用一个脚本自动产生对该Excel表格的功能覆盖率代码。这便是我们后面章节重点要说的内容。通过第一张的内容,我们只需要理解功覆盖率文件中的一些语法即可,接下来就是如何用脚本生成代码的事情了。
2.1 表格格式
下面这幅图只是简单的说明。
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掉部分仓 |
3 IMC
需要用到 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中:你的验证用例功能的不完善;或者是你的随机的次数太少,没有覆盖到这种情况。通常都是后者导致的,所以要是收集代码覆盖率的时候,可以让随机的次数多一些,结果会理想的很多。
脚本的介绍将会在以后的文章中提到!欢迎大家随时讨论交流!
?
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!