文章目录
功能覆盖率
验证证的目的就是为了确保设计在实际环境中的行为正确。
功能覆盖率是对测试执行了设计的哪些功能/特性的度量,这在约束随即验证(CRV)中很有用,可以了解回归中的一组测试已经覆盖了哪些特征。
覆盖组 covergroup
systemverilog covergroup时一种用户定义的类型,它封装了覆盖模型的规范。特们可以定义一次,并通过new函数在不同的地方实例化多次。
covergroup 可以在包、模块、程序、接口或类中定义,通常封装以下信息:
1、一组覆盖点
2、覆盖点之间的交叉覆盖
3、定义何时对覆盖组进行采样的事件
4、配置覆盖对象的其他选项
module tb;
// Declare some variables that can be "sampled" in the covergroup
bit [1:0] mode;
bit [2:0] cfg;
// Declare a clock to act as an event that can be used to sample
//coverage points within the covergroup
bit clk;
always #20 clk = ~clk;
// "cg" is a covergroup that is sampled at every posedge clk
covergroup cg @(posedge clk);
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();
// Stimulus:Simply assign random values to the coverage variables
// so that different values can be sampled by the covergroup object
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
覆盖点 coverpoint
一个covergroup可以包含一个或者多个覆盖点,一个覆盖点指定需要覆盖的整数表达式。coverpoint对表达式进行评估时covergroup会进行采样。SV中覆盖点可以选择用冒号标记:。
module tb;
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);
// Coverpoint can optionally have a name before a colon ":"
cp_mode : coverpoint mode;
cp_cfg_10 : coverpoint cfg[1:0]
cp_cfg_1sb : coverpoint cfg[0];
cp_sum : coverpoint (mode + cfg)
endgroup
// Create an instance of the covergroup
cg cg_inst;
initial begin
//Instantiate the covergroup object similar to a class object
cg_inst = new();
// Stimulus:Simply assign random values to the coverage variables
// so that different values can be sampled by the covergroup object
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
仓 bins
bins允许为覆盖点变量给定可能值范围内的每个值创建单独的bin
用法
...
coverpoint mode {
// manully create a separeta bin for each value
bins zero = {0};
bins one = {1};
//Allow SystemVerolog to automatically create separate bins for each value
// values from 0 to max possible value is split into separate bins
bins range[] = {[0:$]};
//Create automatic bins for both the given ranges
bins c[] = {[2:3], [5:7]};
//Use fixed number of automatic bins. Entire range is broken up into 4 bins
bins range[4] = {[0:$]};
// If the number of bins cannot be equally divided for the given range, then
// the last bin will include remaining items; Here there are 13 values to ber
// distributed into 4 bins which yields:
// [1,2,3] [4,5,6] [7,8,9] [10, 1, 3, 6]
bins range [4] = [[1:10], 1, 3, 6);
// A single bin to store all other values that don't belong to any other bin
bins others = default;
}
例子
module tb;
bit [2:0] mode;
//This covergroup does not get sample automatically because
//the sample event is missing in declaration
covergroup cg;
coverpoint mode {
bins one = {1};
bins five = {5};
}
endgroup
//Stimulus:simply randomize mode to have different values and manually sample each time
initial begin
cg cg_inst = new();
for(int i = 0; i < 5; i++)begin
#10 mode = $random;
$display("[%0t] mode = 0x%0h", $time, mode);
cg_inst.sample();
end
$display("Coverage = %0.2f %%", cg_inst.get_inst_coverage());
end
endmodule
综合说明
翻转覆盖率
coverpoint也可以用来记录变量从A值到B值的跳转情况
除了在bins中定义数值,还可以定义数值之间的跳转,操作符 =>
covergroup CoverPort;
coverpoint port{
//满足其中任何一个,就会记录一次
bins t1 = (0 =>1), (0 => 2), (0 => 3);
//跳转次序为3->4->5,如果没有执行这个次序,则这个bins没有覆盖
bins t2 = (3 => 4 => 5);
}
endgroup
wildcard覆盖率
除操作符外,还可使用关键词wildcard和通配符 ? 来表示状态和状态跳转;
wildcard来创建多个状态或者翻转
在表达式中,任何x,z或者 ? 都会被当成0或1的通配符
wildcard bins abc = {2'b1?};//覆盖10,11
//覆盖 10=>00, 10=>10,11=>00,11=>10
wildard bins abc = {2'b1x => 2'bx0};
bit [2:0] port;
covergroup CoverPort;
coverpoint port{
wildcard bins even = {3'b??0};//偶数
wildard bins odd = {3'b??1};//奇数
}
endgroup
忽略的bin
有些coverpoint可能始终无法得到全部的阈值
对于那些不计算功能的阈值可以使用ignore_bins来排除,最终它们并不会计入coverpoint的覆盖率
coverpoint port{
ignore_bins hi = {[6,7]};//忽略数值6~7
}
非法的bin
有些采样值不仅想要忽略,并且出现还应该报错,可以用illegal_bins
coverpoint port{
illegal_bins hi = {[6,7]};//出现6~7就停止仿真,报错
}
限制自动建仓上限
SV会自动创建仓,当可能取值过大时只会建64个仓,并将变量取值平均分配到这些仓中。我们可以手动限制。
covergroup CovPort;
options.auto_bin_max = 8; //所有的coverpoint auto_bin数量是8
coverpoint tr.port
{ option.auto_bin_max = 2} //特定的covepoint auto_bin数量2
endgroup
交叉覆盖率
- coverpoint是记录单个变量或者表达式的观测值。
- 如果像记录在某一时刻,多个变量之间值的组合情况,需要使用交叉(cross)覆盖率。
- cross 语句只允许带coverpoint或者简单的变量名
class Transaction ;
rand bit [3:0] kind;
rand bit [2:0] port;
endclass
Transaction tr;
covergroup CovPort;
kind: coverpoint tr.kind;
port: coverpoint tr.port;
cross kind, port;
endgroup
排除部分cross bin
- 通过使用 ignore bins、binsof 和 intersect 分别指定coverpoint口值域,这样可以清除很多不关心的cross bin。
covergroup covport;
port: coverpoint tr.port{
bins port[] = { [O:$] };
}
kind: coverpoint tr.kind{
bins zero = { 0 };
bins lo = { [1:3] };
bins hi[] = { [8:$] };
bins misc = default;
}
cross kind, port{
ignore_bins hi = binsof(port)intersect { 7 };
ignore_bins md = binsof(port)intersect { 0 } &&
binsof(kind) intersect { [ 9:11] };
ignore_bins lo = binsof(kind.lo);
}
endgroup
精细的交叉覆盖率指定
- 随着cross覆盖率越来越精细,可能需要花费不少的时间来指定哪些bin应该被使用或者被忽略。
- 更适合的方式是不使用自动分配的cross bin,而自己声明感兴趣的cross bin。
- 假如有两个随机变量a和b,它们带着三种感兴趣的状态,{ a=0,b=0}、{ a=1,b=0}和{b=1}。
class Transaction;
rand bit a, b;
endclass
covergroup CrossBinNames;
a : coverpoint tr.a
{bins a0 = { 0 };
bins a1 = { 1 };
option.weight=0;} //权重设置为0,忽略覆盖点的采样
b: coverpoint tr.b
{bins b0 = { 0 };
bins b1 = { 1 };
option.weight=0;} //权重设置为0,忽略覆盖点的采样
ab: cross a, b
{bins a0b0 = binsof( a.a0) && binsof ( b.b0 );
bins a1b0 = binsof( a.a1) && binsof ( b.b0 );
bins b1 = binsof( b.b1 );}
endgroup
class Transaction;
rand bit a, b;
endclass
covergroup CrossBinsofintersect;
a : coverpoint tr.a
{ option.weight=0 ; }//Do not count this coverpoint
b: coverpoint tr.b
{ option.weight=0; } //Do not count this coverpoint
ab : cross a, b
{ bins a0b0 = binsof(a) intersect{0} && binsof(b) intersect{0};
bins alb0 = binsof(a) intersect{1} && binsof(b) intersect{0};
bins b1 = binsof(b) intersect{1};
}
endgroup
采样触发
covergroup由采样的数据和数据被采样的事件构成,两个条件都准备好,测试平台便会触发covergroup
直接使用 sample() 函数完成
class myCov;
covergroup CovGrp;
...
endgroup
function new ();
CovGrp = new; // Create an instance of the covergroup
endfunction
endclass
module tb_top;
myCov myCov0 = new ();// Create an instance of the class
initial begin
myCov0.CovGrp.sample();
end
endmodule
事件触发
与直接调用sample()相比,使用事件触发的好处在于你能够借助已有的事件
covergroup CovGrp @ (posedge clk); // Sample coverpoints at posedge clk
covergroup covGrp @ (eventA); // eventA can be triggered with ->eventA
有条件覆盖方法
有两种方法可以有条件地启用覆盖
- 使用iff
covergroup CovGrp;
coverpoint mode iff (!_if.reset){
// bins for mode
}
endgroup
- 使用start和stop功能
CovGrp cg = new;
initial begin
#1 _if.reset = 0;
cg.stop();
#10 _if.reset = 10;
cg.start();
end