[361] 什么是covergroups和bins?
覆盖点(coverpoint)是用于指定需要收集覆盖率的目标。Covergroup可以具有多个覆盖点以覆盖不同的表达式或变量。每个覆盖点还包括一组bin,这些bin是该覆盖点不同采样值。bin可以由用户定义,也可以缺省自动创建。在下面的示例中,有两个变量a和b,covergroup有两个coverpoint,他们会检查a和b的值。Coverpoint cp_a是用户定义的,bins values_a检测a是否覆盖到特定的值。Coverpoint cp_b是自动的,bin是自动生成的,会检测b是否覆盖到所有的可能性
bit [2:0] a;
bit [3:0] b;
covergroup cg @(posedge clk);
cp_a coverpoint a {
bins values_a = { [0,1,3,5,7 };
}
cp_b coverpoint b;
endgroup
bit[3:0] var_a;
covergroup test_cg @(posedge clk);
cp_a : coverpoint var_a {
bins low_bins[] = {[0:3]};
bins med_bins = {[4:12]};
}
endgroup
lowbins[]创建了四个bin,对应检查是否覆盖到0,1,2,3,med_bins创建里一个仓,检查是否覆盖到4-12之间的值。因此,一共创建了5个仓
ignore_bins用于指定与覆盖点关联的一组值或者翻转行为,这些值或者翻转行为可以明确从覆盖范围中排除。例如,以下将忽略变量a的所有采样值7和8。
coverpoint a {
ignore_bins ignore_vals = {7,8};
}
illegal_bins用于指定与覆盖点关联的一组值或者翻转行为,这些值或者翻转行为被标记为非法。例如,以下会将所有1、2、3采样值标记为非法。
covergroup cg3;
coverpoint b {
illegal_bins bad_vals = {1,2,3};
}
endgroup
当采样到illegal_bins时,仿真会报错,并且illegal_bins的优先级高于其他bin,即使其他bin和illegal_bins的范围有重叠,也会导致报错。
翻转覆盖率指定为“ value1 => value2”,其中value1和value2是在两个连续采样点上的表达式的采样值。例如,在coverpoint之下,在clk的三个连续正边缘中寻找变量v_a的值4、5和6的翻转行为。
covergroup cg @(posedge clk);
coverpoint v_a {
bins sa = (4 => 5 => 6),
}
endgroup
coverpoint my_variable {
bins trans_bin[] = ( a,b,c => x, y);
}
a=>x, a=>y, b=>x, b=>y, c=>x, c=>y
covergroup test_cg @(posedge clk);
coverpoint var_a {
bin hit_bin = { 3[*4]};
}
endgroup
[* N]指的是连续的重复操作。因此,上面的bin覆盖的是连续4次采样都是3的翻转覆盖率
wildcard bins可以让bin在定义时使用x、z和?作为0或者1的通配符。下面的例子中,并不关心低两位是多少,只要高两位为11就在覆盖范围内。
coverpoint a[3:0] {
wildcard bins bin_12_to_15 = { 4'b11?? };
}
coverage可以指定两个或多个coverpoint或变量之间的cross coverage。cross coverage使用cross进行指定的。交叉覆盖率的仓数,等于交叉目标仓数的乘积,因为要覆盖到两者的所有可能组合。
bit [31:0] a_var;
bit [3:0] b_var;
covergroup cov3 @(posedge clk);
cp_a: coverpoint a_var {
bins yy[] = { [0:9] };
}
cp_b: coverpoint b_var;
cc_a_b : cross cp_b, cp_a;
endgroup
cp_a有10个bin,cp_b有16个bin,因此cc_a_b有160个bin。
交叉覆盖率通常用于不同功能或者事件同时发生的情况,去验证这些事件是否同时发生了。
bit[1:0] cmd;
bit[3:0] sub_cmd;
covergroup abc_cg @(posedge clk);
a_cp: coverpoint cmd;
cmd_x_sub: cross cmd, sub_cmd;
endgroup
cmd和sub_cmd都是二值变量,a_cp有4个bin,sub_cmd默认有16个bin,因此,交叉覆盖率具有64个bin。
int var_a;
covergroup test_cg @(posedge clk);
cp_a: coverpoint var_a {
bins low = {0,1};
bins other[] = default;
}
endgroup
代码对int类型进行覆盖率收集,low的bin数为2,而通过default所创建的数量为
个,数量十分巨大,这会导致仿真器崩溃或者仿真速度下降。应该尽量避免使用default或者不要使用default。
有两种采样方式
covergroup transaction_cg @(posedge clk)
coverpoint req_type;
endgroup
class packet;
byte[4] dest_addr;
byte[4] src_addr;
covergroup pkt_cg;
coverpoint dest_addr;
endgroup
function new();
pkt_cg =new();
endfunction;
endclass
module test;
initial begin
packet pkt =new();
pkt.pkt_cg.sample();
end
endmodule
像定义方法一样,covergroup也可以通过类似的语法进行参数传递,主要使用ref,以便随时检测信号的变化。当我们要对多个信号进行相同类型的覆盖率组定义时,我们可以通过定义参数传递的方法改变采样的信号,而覆盖率的定义只需要进行一次即可。下面是一个例子。
module test;
covergroup xy_cg ( ref int x , ref int y, input string name);
cp_x: coverpoint x;
cp_y: coverpoint y;
cc_x_y: cross cp_x, cp_y;
endgroup
initial begin
xy_cg xy_cg_mod1 = new( top.mod1.x, top.mod1.y, "mod1_cvg");
xy_cg xy_cg_mod2 = new( top.mod2.x, top.mod2.y, "mod2_cvg");
end
endmodule
可以
不可以,只能对当前covergroup的coverpoint定义交叉覆盖率
Covergroup可以实例化多次。如果一个covergroup有多个实例,则默认情况下,SystemVerilog的coverage报告是所有实例的累计coverage。这就是默认的per_type。但是,可以在covergroup中设置一个per_instance选项,那么SystemVerilog将分别报告该Covergroup的每个实例的coverage。
covergroup test_cg @(posedge clk)
option.per_instance =1;
coverpoint var_a;
//and other coverpoints
endgroup
断言是根据规范对设计属性的property,用于验证设计的行为。如果在仿真中检查的property未按照规范运行,则断言失败。类似地,如果禁止在设计中发生的行为,而在仿真期间发生了,则断言也会失败。
使用断言的好处有:
systemvrilog中有两种断言,立即断言和并发断言
立即断言使用表达式进行评估,并且像在过程块中的语句一样执行。,执行后会立即进行评估。立即断言仅用于动态仿真中。以下是一个简单的立即断言的示例,该断言检查“a和b是否始终相等”:
always_comb begin a_eq_b:
assert (a==b) else $error ("A not equal b");
end
并发断言根据所涉及变量的采样值在时钟沿评估测试表达式。它们与其他设计模块同时执行。它们可以放置在模块或接口中。并发断言可以与动态仿真以及静态(形式)验证一起使用。以下是一个并发断言的简单示例,该断言检查“如果c在一个时钟周期内为高,则在下一个周期,a和b的值相等”:
ap_a_eq_b : assert property((@posedge clk) c |=> (a == b));
延迟断言是立即断言的一种特殊类型。简单立即断言立即求值,而无需等待其组合表达式中的变量稳定下来。因此,当组合表达式逐渐趋于稳定时,简单立即断言很容易出现小故障。这可能导致断言多次触发,其中一些断言可能是错误的。为了避免这种情况,定义了延迟断言,仅在时间戳结束时,组合表达式中的变量稳定下来后,才评估这些断言。这意味着将在时间戳的reactive区域中对它们进行评估。
最好使用SVA而非程序代码编写某些类型的checker。SVA具备sequence和property规范的丰富构造,这比使用过程代码或编写基于类的检查器更容易。另一个额外的好处是,相同的断言也可以在静态检查工具(如形式验证工具)中使用,也可以用于提供功能覆盖率。
下面是一些推荐使用SVA的例子: