日常记录(70)9章功能覆盖率
验证导向
提高覆盖率流程
无法达到100%功能覆盖率时候:
- 更多的种子,测试现有程序。
- 建立新的约束
- 定向测试
建议
- 收集信息为导向,而不是数据(如所有的数据包)
- 只监控将要使用的数据,提高运行速度
- 保存那些能够获得更高覆盖率的测试和种子,以备回归
- 注意覆盖率测量结果、漏洞率的情况和趋势,漏洞出现是因为意外发现还是特意检查。(意外发现问题可能严重一点。)
- 覆盖组应该名称足够长,能够说明该覆盖率收集的详细信息
代码覆盖率、功能覆盖率
- 功能覆盖率很高,但是代码覆盖率不够,则功能覆盖率的验证计划可能有问题,需要更新
- 功能覆盖率不够,但是代码覆盖率很高,则检查测试用例,完备的情况下,可能需要形式验证工具,提取状态、创建激励。
行覆盖率等选项设置
Makefile文件
编译和运行
- 其中的编译和运行,都需要添加-cm选项,才能在编译的时候出现-cm_dir指定的功能覆盖率文件
- +ntb_random_seed在这里没有作用,配置seed选用程序内的代码,并注意细节。
覆盖率合并
使用urg的-dir,配合-dbname,输出一个合并后的覆盖率。
set -e
set -e是bash的命令,不能放到Makefile开头。set -e用于报错后不再往下执行。
seed_value=101
seed0=+ntb_random_seed=$(seed_value) -cm_dir seed$(seed_value).vdb
all: compile run
compile:
vcs -sverilog -cm line -debug_all taa.sv -cm line+cond+fsm+branch+tgl+assert $(seed0)
compile_b:
vcs -sverilog -cm line -debug_all tbb.sv -cm line+cond+fsm+branch+tgl+assert $(seed0)
run:
./simv -cm line+cond+fsm+branch+tgl+assert
cov:
dve -covdir simv.vdb &
clean:
@rm -rf *.log simv* *.key csrc DVEf* work tags *.vdb urgReport
merge:
urg -dir seed101.vdb seed10.vdb -dbname merge.vdb
tcc:
set -e
vcs -sverilog -cm line -debug_all tcc.sv
./simv
dve -covdir simv.vdb &
tdd:
set -e
vcs -sverilog -cm line -debug_all tdd.sv
./simv
dve -covdir simv.vdb &
功能覆盖率与小型工程
- 下面的taa是DUT,test是驱动,top是上层连接。使用的.*进行了默认连接过程
- tr.tr.srandom(022)更改,seed变更,其中的随机化过程会变动。但是不影响$random
- $srandom(111)变更,对什么也不影响。
- \(display(\)random(11));中的seed变更,则对后续的$random产生影响。
- class中定义功能覆盖率,无需再次指定实例化名称,直接将类实例化,而下述在module/program中的cg,则需要再指定实例化名称,再进行实例化。
module taa (data, addr, clk, rst_n);
input clk, rst_n;
input [3:0] data;
output reg [4:0] addr;
integer count;
always @(posedge clk, rst_n) begin
if(!rst_n) begin
addr <= 0;
count <= 0;
end
else begin
addr <= data+count;
count <= count + 1;
end
end
endmodule
program automatic test (data, addr, clk, rst_n);
input clk, rst_n;
output reg [3:0] data;
input [4:0] addr;
class Transaction;
// data or class properties
rand bit [3:0] data;
rand bit [4:0] addr;
endclass : Transaction
Transaction tr=new;
covergroup CovData;
coverpoint tr.data;
endgroup
initial begin
CovData cd=new;
tr.srandom(022);
$srandom(111);
repeat(32) begin
tr.randomize();
data = tr.data;
$display("data random is :%d", data);
@(posedge clk);
tr.addr = addr;
cd.sample();
end
repeat (10) begin
$display($random(1));
end
$display($random(11));
repeat (10) begin
$display($random());
end
$display("finished!");
$display("final cov value: %f", cd.get_coverage());
end
endprogram : test
module top ();
reg clk, rst_n;
reg [4:0] addr;
wire [3:0] data;
initial begin
clk = 0;
forever begin
#10 clk = ~clk;
end
end
initial begin
rst_n = 0;
#30
rst_n = 1;
#500
rst_n = 0;
#10
rst_n = 1;
end
taa dut(.*);
test tb(.*);
endmodule
覆盖率的事件触发
直接使用事件触发
- 定义好cg,然后在其中定义好@的量,sample_a中实现了事件触发
断言触发
- 使用cover property(@(posedge clk) xxx),等待断言满足条件,触发一个事件,出现覆盖率收集。
module tbb ();
bit clk;
event evt_as;
bit b_value;
bit [3:0] c;
cover_name: cover property
(@(posedge clk) b_value==1)
-> evt_as;
covergroup groe @(evt_as);
coverpoint c;
endgroup : groe
class cov_test;
// data or class properties
bit [2:0] a;
bit clk;
event evt;
covergroup test_cg @(evt);
coverpoint a;
endgroup : test_cg
function new();
test_cg = new();
endfunction: new
function void sample_a();
a = 1;
-> evt;
a = 0;
-> evt;
endfunction: sample_a
endclass : cov_test
initial begin
clk = 0;
fork
begin
forever begin
#1 clk=~clk;
end
end
begin
b_value = 0;
#10
c = 1;
b_value = 1;
#3
c = 2;
#3
c = 3;
#10;
b_value = 1;
end
join_none
end
initial begin
cov_test ct = new();
groe gr = new();
ct.sample_a();
#100;
$finish;
end
endmodule
结果:
覆盖率选项
设置最大的bin的个数
option.auto_bin_max
设置最大的bin的个数,而默认是64
设置某些情况下才进行覆盖率收集
iff(!a==0)
手动设置bins
使用bins bin_name = {range_, [range_]}
设置除外后的其它bins
使用bins xxx = default在手动设置bin中
设置翻转覆盖率收集
例如:
bins t1 = (0=>1),(0=>[8:15]),([0:8]=>[8:15]);
使用通配符
?表示0或者1,以下是一个偶数的bin覆盖。wildcard作为说明关键字
wildcard bins even = {3'b??0};
small large
是sv/v的关键字,不可使用。
忽略一些取值范围
使用ignore_bins,和bins是同级的用法
声明非法的bins
使用illegal_bins,得到非法值则终止程序
交叉覆盖率取消一些排列组合
- ignore_bins ig1 = binsof(a4)intersect{0};取消了a4的数字0的排列组合。
- ignore_bins ig3 = binsof(a4.a05) &&binsof(a5.a20);取消a4.a05和a5.a20的排列组合
- binsof(a4)intersect{[2:7]} && binsof(a5)intersect{1};取消a4的数字2-7与a5的数字1的相关排列组合。
stop和start
暂停和启动覆盖率收集功能。
module tcc ();
class cov_test;
// data or class properties
bit [3:0] a;
int b;
int c;
covergroup cgxx ;
option.auto_bin_max = 4;
coverpoint a;
coverpoint b;
coverpoint a+b;
coverpoint c iff(!a==0);
c2:coverpoint c
{
bins small1 = {[$:0]};
bins array[4] = {[0:99999000]};
bins large1 = {[99999:$]};
bins misc=default;
// don't have effect
/* option.weight = 0; */
// option.goal = 50;
}
a2:coverpoint a{
bins t1 = (0=>1),(0=>[8:15]),([0:8]=>[8:15]);
bins t2 = (3,[4:10] => 2,3,4,5,6);
wildcard bins even = {3'b??0};
wildcard bins odd = {3'b??1};
}
a3:coverpoint a{
option.auto_bin_max = 4;
ignore_bins high = {[10:$]};
/* illegal_bins high_ill = {9}; */
}
a4:coverpoint a{
bins a00 = {[0:1]};
bins a01 = {[2:3]};
bins a02 = {[4:5]};
bins a03 = {[6:7]};
bins a04 = {[8:9]};
bins a05 = {[10:11]};
}
a5:coverpoint b{
bins a20 = {[$:0]};
bins a21 = {[0:$]};
}
crs:cross a4, a5{
ignore_bins ig1 = binsof(a4)intersect{0};
ignore_bins ig2 = binsof(a4)intersect{[2:7]} && binsof(a5)intersect{1};
ignore_bins ig3 = binsof(a4.a05) &&binsof(a5.a20);
}
weight_a: coverpoint a{
bins low = {[0:8]};
bins high = {[9:15]};
bins none = {[16:20]};
}
endgroup : cgxx
// initialization
function new();
cgxx = new();
endfunction : new
function void sample();
/* cgxx.stop(); */
/* cgxx.start(); */
repeat (100) begin
{a, b, c} = {$random(), $random(), $random()};
cgxx.sample();
end
repeat (100) begin
{a, b, c} = {$random(), $random(), $random()};
a = 0;
cgxx.sample();
end
endfunction: sample
endclass : cov_test
initial begin
cov_test ct = new();
ct.sample();
end
endmodule
weight使用
- 设置了per_instance为1,
- 使用option.weight = 0;
- 最终的cg_inst1.get_inst_coverage()的结果为100.
module tb;
bit [3:0] mode1, mode2;
covergroup cg;
option.per_instance=1;
/* option.per_instance=0; */
m1: coverpoint mode1 {
bins range1[] = {[0:1],[2:3],[4:15]};
}
m2: coverpoint mode2 {
bins range2[] = {[0:1],[2:3],[4:15]};
}
m1xm2:cross m1,m2{
option.weight = 0;
}
endgroup
initial begin
cg cg_inst1 = new();
for (int i = 0; i < 50; i++) begin
#10
mode1 = i;
mode2 = 5-i;
cg_inst1.sample();
end
$display("coverage result b is %f",cg_inst1.get_coverage());
$display("coverage result d is %f",cg_inst1.get_inst_coverage());
$display("coverage result f is %f",$get_coverage());
end
endmodule
输出:
weight是生效了。
coverage result b is 68.750000
coverage result d is 100.000000
coverage result f is 68.750000
Le vent se lève! . . . il faut tenter de vivre!
Le vent se lève! . . . il faut tenter de vivre!