提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- 一、Coverage 覆盖率是什么?
- 二、代码覆盖率
- 三、功能覆盖率
- 总结
前言
本章主要介绍覆盖率
一、Coverage 覆盖率是什么?
覆盖率用来衡量设计中已经被测部分和未测部分的比例,通常被定义为已达到所需验证部分的百分比
目标覆盖率是指在验证计划中规定的需要验证点的目标值。 在验证计划中, 当验证点实际覆盖率没有达到 100% 的时候, 说明验证工作还未完成目标方案。 没有达到 100% 的项目需要通过添加测试用例或者修改约束等来对其进行充分的验证;
验证计划中列出的项目都要一一被测试, 当然这需要一个比较全面和完整的验证计划。为此, 在验证环境搭建的前期, 制定验证计划, 明确验证点并确定目标覆盖率是一项艰巨而且细致的工作;
制定验证计划中的功能点的时候, 需要考虑如下三个问题:
1) 哪些功能点需要检查?
2) 这个功能点的哪些数据需要检查?
3) 如何对这些数据进行采样?
哪些功能点需要检查呢? 这要根据设计的具体情况而定, 一般情况下, 以下几类是参考的对象: 功能要求、 接口要求、 系统规范、 协议规范等。 具体验证计划中可能表现为:FIFO是否溢出和空读、 外部接口是否遵从以太网物理层的传输协议、 是否满足系统规范要求的支持发送超长包、 内部的 AMBA 总线是否符合协议要求等;
在把这些功能点具体化到设计代码中的时候, 我们可能会做一些折中的考虑, 如何划分数据类别, 例如, 对于有一个以太包的包长的功能点, 我们当然希望能够把所有的包长都测试一遍, 假如时间有限, 我们也可以把包长划分为最短包长、 最长包长、 合法包长(在最长和最短之内)、 非法包长 (在最长和最短以外), 这就具体化了, 可以容易得知哪些数据需要检查。 因为验证空间是无穷大的, 抽象并且量化验证功能点是必须引起我们关注的问题;
存在两种覆盖率:
- Code Coverage 代码覆盖率
- Functional Coverage 功能覆盖率
二、代码覆盖率
代码覆盖率指的是设计代码的执行量,它包括行覆盖率、FSM状态机覆盖率、分支覆盖率、条件覆盖率 和path路径覆盖率。仿真工具将自动从设计代码中提取代码覆盖率.代码覆盖率就算达到100%,这并不意味着不存在bug.
- 行覆盖率: 检查某行代码是否被执行过
- 分支覆盖率: 检查条件分支是否都被执行过
- 条件覆盖率, 表达式覆盖率:通过真值表分析表达式各种逻辑组合
- 有限状态机覆盖率: 检查每个状态是否被覆盖, 状态之间的跳转是否被执行
三、功能覆盖率
功能覆盖率(FunctionalCoverage)是一种用户定义的度量,它用来衡量在验证中执行了多少设计规范.
功能覆盖率分为两种:
- 面向数据的覆盖率(Data-oriented Coverage)-对已进行的数据组合检查.我们可以通过编写覆盖组(coverage
groups)、覆盖点(coverage points)和交叉覆盖(cross coverage)获得面向数据的覆盖率. - 面向控制的覆盖率(Control-oriented Coverage)-检查行为序列(sequences of
behaviors)是否已经发生.通过编写SVA来获得断言覆盖率(assertion coverage).
1.定义覆盖模型
使用覆盖组结构定义覆盖模型,覆盖组结构(covergroup construct)是一种用户自定义的类型,一旦被定义就可以创建多个实例就像类一样,也是通过new()来创建实例的,覆盖组可以定义在module、program、interface以及class中
每一个覆盖组都必须明确一下内容:
- 覆盖点(coverage points),也就是需要测试的变量;
- 一个时钟事件以用来同步对覆盖点的采样(sampling of coverage points);
- 可选的形式参数(Optional formal arguments);
- 覆盖点之间的交叉覆盖(Cross coverage between coverage points);
- 覆盖选项(Coverage options);
覆盖点的采样时间:用时钟来确定
covergroup cov_grp @(posedge clk);
cov_p1: coverpoint a;//定义覆盖点
endgroup
cov_grp cov_inst = new();//实例化覆盖组
内建sample方法来触发覆盖点的采样
covergroup cov_grp;
cov_p1: coverpoint a;//cov_p1为覆盖点名,a为覆盖点中的变量名,也就是模块中的变量名
endgroup
cov_grp cov_inst = new();
@(abc) cov_inst.sample();
覆盖组中允许带形式参数,外部在引用覆盖组时可以通过传递参数,从而对该覆盖组进行复用,如下:
covergroup address_cov (ref logic [7:0] address,
input int low, int high) @ (posedge ce);
ADDRESS : coverpoint address {
bins low = {
0,low};
bins med = {
low,high};
}
endgroup
address_cov acov_low = new(addr,0,10);
address_cov acov_med = new(addr,11,20);
address_cov acov_high = new(addr,21,30);
2.定义覆盖点
一个覆盖组可以包含多个覆盖点,一个覆盖点可以是一个整型变量也可以是一个整型表达式(integral variable or an integral expression);在验证环境中,覆盖点可以放置在下面四个位置:
推荐覆盖点一般放在DUT的输入输出的接口位置,也就是上图中的F2和F4
每一个覆盖点都与"bin(仓)"关联,在每一个采样时钟仿真器都会自增关联的bin值(increment the associated bin value);
bin可以自动创建或者显示定义:
自动或隐式bin (Automatic Bins or Implicit Bins)
对于覆盖点变量范围内的每一个值都会有一个对应的bin,这种称为自动或隐式的bin,例如,对于一个位宽为n bit的覆盖点变量,2^n个自动bin将会被创建.看下面例子:
module cov;
logic clk;
logic [7:0] addr;
logic wr_rd;
covergroup cg @(posedge clk);
c1: coverpoint addr;
c2: coverpoint wr_rd;
endgroup : cg
cg cover_inst = new();
...
endmodule
对于覆盖点addr,将会有c1.auto[0] c1.auto[1] c1.auto[2] … c1.auto[255]等256个bin被自动创建;
对于覆盖点wr_rd,将会有c2.auto[0] c2.auto[1]被创建;
完整示例如下:
module tb;
// Declare some variables that can be "sampled" in the covergroup
bit [1:0] mode;
bit [2:0] cfg;
bit clk;
always #20 clk = ~clk;
// "cg" is a covergroup that is sampled at every posedge clk
covergroup cg @ (posedge clk);//覆盖组中只有mode,取值范围为0~3,而且没有创建bin,这样系统自动创建4个bin
coverpoint mode;
endgroup
// Create an instance of the covergroup
cg cg_inst;
initial begin
// Instantiate the covergroup object similar to a class object
cg_inst= new();
for (int i = 0; i < 5; i++) begin
@(negedge clk);
mode = $random;
cfg = $random;
$display ("[%0t] mode=0x%0h cfg=0x%0h", $time, mode, cfg);
end
end
// At the end of 500ns, terminate test and print collected coverage
initial begin
#500 $display ("Coverage = %0.2f %%", cg_inst.get_inst_coverage());
$finish;
end
endmodule
显示bin
"bins"关键字被用来显示定义一个变量的bin,可以为给定范围内的变量的每个值创建单独的bin,也可以将一个或多个bin指向变量的某个范围,用显示bin,也就是用户自定义bin可以增加覆盖的准确度!它可以将变量的取值范围限定在你感兴趣的区域内!
显示bin紧跟在对应的覆盖点后面,用{ }包围起来,关键字"bins"后跟着bin名以及变量的值或范围。
covergroup 覆盖组名 @(posedge clk);//时钟可以没有
覆盖点名1: coverpoint 变量名1{
bins bin名1 = (覆盖点取值范围);
bins bin名2 = (覆盖点取值范围);
bins bin名3 = (覆盖点取值范围);
.......
}//一般会将bin的数目限制在8或16
覆盖点名2: coverpoint 变量名2{
bins bin名1 = (覆盖点取值范围);
bins bin名2 = (覆盖点取值范围);
bins bin名3 = (覆盖点取值范围);
.......
}
。。。。。。
endgroup : 覆盖组名
//注意对coverpoint的bin的声明使用的是{},这是因为bin是声明语句而非程序语句,后者才用begin..end
//围起来,而且{}后也没有加分号,这和end是一样的
举例如下:
module cov;
logic clk;
logic <