目录
1. 覆盖率的意义
2. 覆盖率的分类
2.1 代码覆盖率
2.2 断言覆盖率
2.3 功能覆盖率
3.功能覆盖率策略
3. 覆盖组
4. 数据采样
4.1 bin和总体覆盖率
4.2 bin的创建和应用
4.3 命名coverpoint和bin
4.4 条件覆盖率
4.5 枚举类型覆盖率
4.6 翻转覆盖率
4.7 wildcard覆盖率
4.8 忽略的bin
4.9 非法的bin
4.10 交叉覆盖率
5. 覆盖选项
6. 数据分析
覆盖率是定量分析验证完备性的指标,随着测试不断进行,覆盖率会逐渐提高。通过分析覆盖率没有覆盖到的点,可以查找验证盲区,通过增加新的激励或者修改现有激励来进一步提升覆盖率,达到覆盖率驱动验证的效果。
代码覆盖率可以分为行覆盖率、翻转覆盖率、状态机覆盖率、条件覆盖率、分支覆盖率。
行覆盖率:对有多少行代码已经被执行过。
翻转覆盖率:哪些单比特变量的值位0或1,如0从1的跳转,1到0的跳转。
状态机覆盖率:哪些状态或状态转换已经被访问过。
条件覆盖率:记录各个条件中的逻辑操作数被覆盖的情况。
分支覆盖率(路径覆盖率):在诸如if、case、for、forever等语句各个分支的执行情况。
代码覆盖率是衡量对于设计规范实现多彻底的指标,并非针对验证计划,没有覆盖到的点可能是对应功能点没有测试到,也可能仅仅是冗余的代码。
条件覆盖率和分支覆盖率的区别:
条件覆盖只考虑代码中的一些布尔表达式中各个条件是否都执行到,不考虑语句的结果。而分支覆盖率是条件下的不同分支语句的校验。
断言是用于一次性地或在一段时间内对一个或者多个设计信号在逻辑或者时序上地声明性代码。
断言可以跟随设计和测试平台仪器仿真,也可以被形式验证工具所证实,可以通过SVA来表达断言,通过property、sequence等语句声明。
示例:
property p_psel_rose_next_cycle_penable_rise; //声明property块
@(posedge clk) $rose(psel) |=> $rose(penable); //APB2.0协议 psel拉高后下一拍enable拉高
endproperty: p_psel_rose_next_cycle_penable_rise
assert property(p_psel_rose_next_cycle_penable_rise) else `uvm_error("ASSERT", "PENABLE not rose after 1 cycle PSEL rose") //观测这个property块 断言失效则报错
initial begin: assertion_control
fork
forever begin
wait(rstn == 0);
$assertoff();
wait(rstn == 1); //复位信号控制断言的开关
$asserton();
end
join_none
end
功能描述文档说明了设计如何运行,拥有什么功能。验证计划则需列出相应的功能测试点,并考虑如何激励、验证和测量。当需要收集设计功能是否已经被测量到时,就是在计算功能覆盖率。
每一次仿真都会产生一个待覆盖率的数据库,将这些不同信息合并就得到功能覆盖率,可以通过画覆盖率曲线。通过分析功能覆盖率可以决定如何修改回归测试集。
功能覆盖率策略一般有以下三种情况:
功能覆盖率通常结合代码覆盖率来分析验证的完备性。
如果功能覆盖率高而代码覆盖率低。可以是没有给出合适的激励测试相应功能点,需要回顾功能文档,针对未测试点添加测试激励。
如果代码覆盖率高而功能覆盖率低,需要检验设计是否实现了所有功能,如果实现了,但功能测试不到可能需要通过形式验证来提取设计状态并给予适当激励。
如果代码覆盖率高而功能覆盖率高,是否就能证明验证完备性了。相对来讲,设计的状态达到一个较为稳定的状态。但验证是没有完备一说的,可能还有一些边界条件或者通过回归测试不能覆盖到功能点没有测试。需要尝试一些错误组合对设计会不会产生新的影响。
covergroup是定义关于采样信息和采样形式的声明语句,和class类似,声明了covergroup后需要在合适的地方例化才能起作用。
covergroup包括覆盖点、选项、形式参数和可选触发,它可以定义在类中,也可以定义在模块和程序块上,覆盖组的名称尽量清晰易懂,以便阅读覆盖率报告时能明白测试点。
示例:
class rkv_ahbram_cov extends rkv_ahbram_subscriber;
……
//对地址信息进行采样,后面为添加的形式参数限定地方范围,sample函数可以传入采样
covergroup rkv_ahbram_t1_address_cg(bit [31:0] addr_start, bit [31:0] addr_end) with function sample(bit [31:0] addr);
option.name = "T1 AHBRAM address range coverage"; //可选选项
//定义coverpoint
ADDR: coverpoint addr {
bins addr_start = {[addr_start : addr_start+3]};
bins addr_end = {[addr_end-3 : addr_end]};
bins addr_out_of_range = {[addr_end+1 : 32'hFFFF_FFFF]};
bins legal_range[16] = {[addr_start : addr_end]};
}
endgroup
function new (string name = "rkv_ahbram_cov", uvm_component parent);
super.new(name, parent);
rkv_ahbram_t1_address_cg = new(32'h0000, 32'hFFFF); //在类中例化不需要另起名字 例化时传递参数
endfunction
function void write(lvc_ahb_transaction tr);
rkv_ahbram_t1_address_cg.sample(tr.addr); //通过monitor的AP端把监测数据写入到cov
endfunction
endclass
覆盖组的触发:
覆盖组触发方式主要有两种,一种是通过上文所述的sample()函数,另一种则是借助event来触发,event触发的好处在于能借助已有的事件进行采样。
sample函数:
示例:
covergroup sample_trigger;
coverpoint tr.addr;
endgroup
function new();
sample_trigger = new();
endfunction
task valid_data();
……
sample_trigger.sample();
endtask
event触发
示例:
event trigger_event;
covergroup event_trigger @(trigger_event);
coverpoint tr.addr ;
endgroup
一个covergroup包含多个coverpoint,而coverpoint又包含多个bin来记录每个数值被捕捉到的数值,覆盖率就是这样采样到的bin除以域中bin的个数计算得来的。所有的coverpoint便构成了一个covergroup的覆盖率,把这些covergroup的覆盖率组合在一起,就构成了整体的覆盖率。
bin(仓):衡量功能覆盖率的基本单位。
域:一个覆盖点上所有可能的数值。
单个coverpoint的覆盖率 = 采样到的数值(bin)/coverpoint的域
如2bit变量范围为0:3,若采样到3个bin,则这个coverpoint 的覆盖率 = 3/4 =75%
如不声明bin的个数,对于位宽为N的表达式,默认创建2^N的仓。自动创建仓的个数为64,可以通过auto_bin_max来声明 自动创建仓的最大个数,auto_bin_max在收集枚举类型覆盖率时不生效。
covergroup cov_simple;
option.auto_bin_max = 15; //所有coverpoint auto_bin为15
coverpoint tr.addr { option.auto_bin_max = 7;} //特定coverpoint auto_bin为7
endgroup
covergroup name_bin ;
coverpoint tr.kind {
bins zero = {0}; //1个bin 代表kind = 0
bins low = {[1:3],7}; // 1个bin 代表1:3 或者7
bins high[] = {[8:$]}; // (tr.kind最大值-8) 个bin
bins rem = default; // 剩余数值属于1个bin
}
endgroup
通过iff来给coverpoint添加条件
示例:
covergroup iff_cov;
coverpoint tr.data iff(!vif.reset) ; //复位时不采样
endgroup
通过start和stop来开启关闭覆盖率的收集
示例:
initial begin
iff_cov if_c= new(); // 不在类中例化需要声明covergroup名字
……
if_c.stop(); //关闭采样功能
#100ns ;
if_c.start(); //开启采样功能
……
end
SV会为枚举类型每个可能值创建一个bin,如果想要把多个数值放在单个bin内需要自定义bin,在枚举数值之外的bin都会被忽略。
coverpoint可以记录不同值的跳转情况,以及翻转次数。
示例:
covergroup jump_cov;
coverpoint jump {
bins t1 = (0 => 1),(1 => 2),(2 => 3); //0到1 1到2 2到3的跳转 ()而不是{}
bins t2 = (4,5 => 6,7) ; // 4到6,7的跳转 ,5到6,7的跳转
bins t3 = (8 => 9[*3]) ; //重复三次,等价于8 => 9 => 9 => 9
}
endgroup
用关键词wildcard创建多个状态或翻转,wildcard声明后任何X,Z、?都会被当为0或1的通配符。
示例:
bit [2:0] wi_cd;
coverpoint willcard_cov;
coverpoint wi_cd {
wildcard bins even = {3'b??0};
wildcard bins odd = {3'b??1};
}
endgroup
通过ignore_bins忽略不关心的值。
bit [3:0] ign_value;
covergroup ign_cov;
coverpoint ign_value {
ignore_bins t1= {13:15} ; //忽略最后3个bin 域为13
}
endgroup
通过illegal_bins声明非法的bins,若采样到这些状态就i会报错。
bit [3:0] illegal_value;
covergroup illegal_cov;
coverpoint illegal_value {
illegal_bins t1= {2,3} ; //采样到2和3就报错
}
endgroup
coverpoint是观测单个变量或表达式的值,如果想要直到多个变量之间的组合情况,就要使用交叉(cross)覆盖率。
cross语句只允许带coverpoint或者简单的变量名。
示例:
class transaction;
rand bit [2:0] type;
rand bit [2:0] kind;
endclass
transaction tr;
covergroup cross_type_kind;
type : coverpoint tr.type;
kind : coverpoint tr.kind;
cross type,kind; //一共创建8*8个bin
endgroup
更加精细的交叉覆盖率控制可以通过binsof()、intersect、ignore_bins来限定范围,只采样感兴趣的bin。
示例:
covergroup cross_type_kind;
type : coverpoint tr.type;
kind : coverpoint tr.kind;
cross type,kind{
//忽略type为5与kind的组合 共5个bin
ignore_bins t1 =binsof(type)intersect{5};
//忽略type为2和kind为1和3的组合 共2个bin
ignore_bins t2 =binsof(type)intersect{2} && binsof(kind)intersect{[1:2]};
//binsof用的()而intersect用的是{}
}
endgroup
如果只想关注交叉覆盖率,而不想关注单个coverpoint,可以通过设置权重option.weight = 0来将coverpoint的覆盖率忽略。
示例:
covergroup cross_type_kind;
type : coverpoint tr.type {option.weight = 0}
kind : coverpoint tr.kind {option.weight = 0}
cross type,kind{
ignore_bins t1 =binsof(type)intersect{5};
}
endgroup
覆盖率选项可以分为实例选项和类型选项。
实例选项:用于特定的覆盖组实例。
类型选项:用于所有的覆盖组实例。
单个实例的覆盖率:option.per_instance = 1
如果多一个覆盖组多此实例化,会把所有实例的覆盖率数据汇集到一起,如果要看单独的报告就要加上per_instance选项,该选项只能放在覆盖组里,不饿能用于覆盖点或交叉点。
覆盖组的注释:option.comment
可以为多次例化的实例添加单独的注释,前提是使用per_instance选项。
示例:
covergroup cov_cmt(int day ,month ,string comment);
option.comment = comment ;
option.per_instance = 1 ;
coverpoint port {
bins port = {[month:day]};
}
endgroup
……
cov_cmt cov_cmt_1 = new(4,8,“Today is Chinese Valentine's Day”)
cov_cmt cov_cmt_2 = new(3,11,"Today is my birthday")
覆盖次数限定:option.at_least
每个bin的最少采样次数,如果低于at_least数值,则不会被计入bin中。可以在covergroup声明也可以在coverpoint声明。
覆盖率目标:option.goal
一般来将覆盖组目标为100,可以通过goal选项设低,这只影响覆盖率报告。
covergroup方法
sample() :采样
get_coverage()/get_inst_coverage():获取覆盖率,返回0-100的real数值。
set_inst_name(string):设置covergroup的名称。
start()/stop():使能或关闭覆盖率的收集。
使用$get_coverage得到所有覆盖组的总覆盖率。也可以通过covergroup_inst.get_inst_coverage()来获得单个coverpoint实例的覆盖率。使用这些函数来监测覆盖率的变化。
如果覆盖率水平在一段水平之后没有提高,那么这个测试应该停止。
可以通过使用新的随机种子或者测试来提高覆盖率。