【IC每日一题:SVA和覆盖率知识点】
IC每日一题:SVA和覆盖率知识点
- 3 SVA和覆盖率知识点
- 3.1 代码覆盖率、功能覆盖率和断言覆盖率的区别
- 3.2 coverage一般不会直接达到100%,当发现condition未cover到的时候,该怎么做?
- 3.3 function coverage和code coverage的区别,以及他们分别对项目的含义?
- 3.4 代码覆盖率和功能覆盖率,一高一低分别意味着什么?
- 3.5 交叉覆盖率的优点?
- 3.6 covergroup在类中使用和类外分别如何使用?
- 3.7 断言 and 和intersect的区别?
- 3.8 写一个断言:a为高的时候,b为高,且a为高的时候,下一个周期b也为高;
- 3.9 什么是立即断言和并发断言?简述一下assert的用法
- 3.10 a[*3]、a[->3]和a[=3]的区别
【博客首发与微信公众号《漫谈芯片与编程》,欢迎专注一下】
3 SVA和覆盖率知识点
断言:是对设计违例的一种严查,能够在违例时立刻报出错误;
覆盖率:是定量衡量IC验证质量的指标和指导提高验证质量;
3.1 代码覆盖率、功能覆盖率和断言覆盖率的区别
这三个覆盖率是在验证过程中用于定量衡量验证的具体指标;
代码覆盖率:衡量的是设计代码中哪些部分已经被测试到了。
行覆盖率(line):多少行代码被执行。
分支覆盖率(path):代码中的分支被执行到;
翻转覆盖率(toggle):哪些单bit的值为0或1
有限状态机覆盖率(FSM):状态机中哪些状态和状态转换已经被访问过了
功能覆盖率:设计的功能特性是否被充分验证–通过定义一组覆盖点(cover points)来衡量设计的功能特性是否被测试到。
事务覆盖率 (Transaction Coverage): 检查特定类型的事务(如读写操作)是否被执行。
状态覆盖率 (State Coverage): 检查设计的状态机是否遍历了所有可能的状态。
交叉覆盖率 (Cross Coverage): 检查多个功能点之间的组合是否被测试到。
边界覆盖率 (Boundary Coverage): 检查设计在边界条件下的行为是否被测试到。
断言覆盖率:设计中的断言语句被触发的比例。
断言语句用于检查设计的内部状态或信号是否符合预期。
【总结】
代码覆盖率关注的是代码的执行情况,确保每一行代码都被执行过。
功能覆盖率关注的是设计的功能特性是否被充分验证。
断言覆盖率关注的是设计中的断言语句是否被触发,以检查设计的内部状态是否符合预期。
3.2 coverage一般不会直接达到100%,当发现condition未cover到的时候,该怎么做?
查看覆盖率报告去定位哪些条件没有被覆盖到,是因为没有满足该条件的前提条件还是因为根本就遗漏了这些情况,根据这个我们去编写相应的case,进而将其覆盖到。还要找设计人员一块review看一下,看看哪些未覆盖到的点需要怎样构造激励; 当然最暴力的一种方式是:加大种子随机轮数回归;
具体步骤来说:
- 分析未覆盖的条件
确定未覆盖的具体条件:使用覆盖率报告工具提供的详细报告,找出哪些条件未被覆盖。确定这些条件的具体位置和上下文。
理解未覆盖的原因:分析未覆盖条件的原因,可能是由于某些特定的输入组合、状态转换或其他条件难以触发。 - 修改或增强测试用例
增加新的测试用例:根据未覆盖的条件,编写新的测试用例来专门覆盖这些条件。例如,如果某个分支条件未被覆盖,可以编写一个测试用例来触发该条件。
修改现有测试用例:检查现有的测试用例,看看是否可以通过修改输入数据或配置来触发未覆盖的条件。例如,调整随机化约束或增加特定的激励模式。 - 使用约束和定向测试
约束随机化:使用约束来指导随机化生成器,使其更有可能生成能够覆盖未覆盖条件的测试用例。例如,在 UVM 中,可以使用 constraint 来限制随机化生成的值范围,以提高特定条件被覆盖的概率。
定向测试:编写定向测试用例,专门针对未覆盖的条件。例如,手动构造特定的输入序列来触发未覆盖的条件;
3.3 function coverage和code coverage的区别,以及他们分别对项目的含义?
代码覆盖率:关注的是代码的执行情况,确保每一行代码都被执行过。
功能覆盖率:关注的是设计的功能特性是否被充分验证。
功能覆盖率coverpoint和covergroup的代码示例:
// 定义covergroup
covergroup my_covergroup @(posedge clk);// 定义coverpointcoverpoint my_module.a {bins a_values[] = {[0:255]}; // 覆盖a的所有可能值}// 定义另一个coverpointcoverpoint my_module.b {bins b_values[] = {[0:255]}; // 覆盖b的所有可能值}// 定义交叉覆盖率cross a_values, b_values; // 覆盖a和b所有可能的组合
endgroup
3.4 代码覆盖率和功能覆盖率,一高一低分别意味着什么?
1.代码覆盖率低 + 功能覆盖率高
1.1)有可能是cover group写得不完备,进一步地,测试点分解和test plan可能也不完备,遇到这种现象,应当警觉,需要明确是否存在测试点,test plan, cover group不完备的情况。
1.2)DUT中有大量冗余代码。或者集成进来的公共IP只用到其中一部分功能。
2.代码覆盖率高 + 功能覆盖率低
2.1) 功能覆盖率的sample有问题,即相关的场景都打到了,但cover group没有采样到,这个对于新开发的验证环境容易出现。
2.2)cover group中的一些cross bin或者conner点没覆盖到,需要增加direct case,修改随机约束或者增加回归次数。项目经过这个过程是比较正常的。
3.5 交叉覆盖率的优点?
交叉覆盖率(Cross Coverage)是功能覆盖率(Functional Coverage)的一种扩展,它通过组合多个覆盖点(Cover Points)来确保设计的不同部分之间的交互也得到了充分的验证。
3.6 covergroup在类中使用和类外分别如何使用?
covergroup可以在类中使用,也可以在类外使用。在类中使用时,covergroup可以访问类的成员变量和方法;在类外使用时,covergroup可以访问模块或程序块中的信号和变量;一般更多还是在类外使用covergroup;
1.在类内使用covergroup:
在类内定义 covergroup 通常用于将覆盖率模型与特定的验证组件(如监视器、驱动器等)关联起来。这种方式可以更好地封装和管理覆盖率数据。
假设我们有一个总线接口,并且我们想在监视器中定义一个 covergroup 来测量总线事务的功能覆盖率。
class bus_transaction extends uvm_sequence_item;rand bit [31:0] address;rand bit [⅛:0] data;rand bit is_read; // 0 for write, 1 for read`uvm_object_utils_begin(bus_transaction)`uvm_field_int(address, UVM_DEFAULT)`uvm_field_int(data, UVM_DEFAULT)`uvm_field_int(is_read, UVM_DEFAULT)`uvm_object_utils_endfunction new(string name = "bus_transaction");super.new(name);endfunction
endclassclass bus_monitor extends uvm_monitor;`uvm_component_utils(bus_monitor)// 定义覆盖组covergroup bus_cg with function sample(bit [31:0] addr, bit [⅛:0] dat, bit is_rd);// 定义 coverpointcp_is_read: coverpoint is_rd {bins read = {1};bins write = {0};}cp_address: coverpoint addr {bins low = {[0:1023]};bins high = {[1024:2047]};}cp_data: coverpoint dat {bins low = {[0:127]};bins high = {[128:255]};}// 定义交叉覆盖率cp_is_read_x_address: cross cp_is_read, cp_address;cp_is_read_x_data: cross cp_is_read, cp_data;cp_address_x_data: cross cp_address, cp_data;endgroup// 实例化覆盖组bus_cg cg;// 构造函数function new(string name, uvm_component parent);super.new(name, parent);cg = new(); // 实例化覆盖组endfunction// 监视器的主要任务virtual task run_phase(uvm_phase phase);bus_transaction tr;forever begin// 假设这里从总线上捕获事务// 例如:tr = bus_transaction::type_id::create("tr");// tr.address = ...;// tr.data = ...;// tr.is_read = ...;// 更新覆盖组cg.sample(tr.address, tr.data, tr.is_read);endendtask
endclass
2.在类外使用covergroup
在类外定义 covergroup 通常用于更通用的覆盖率模型,或者在多个组件之间共享同一个覆盖率模型。这种方式可以提高覆盖率模型的重用性;
示例:在类外定义 covergroup 通常用于更通用的覆盖率模型,或者在多个组件之间共享同一个覆盖率模型。这种方式可以提高覆盖率模型的重用性。
// 定义覆盖组
covergroup bus_cg with function sample(bit [31:0] addr, bit [⅛:0] dat, bit is_rd);// 定义 coverpointcp_is_read: coverpoint is_rd {bins read = {1};bins write = {0};}cp_address: coverpoint addr {bins low = {[0:1023]};bins high = {[1024:2047]};}cp_data: coverpoint dat {bins low = {[0:127]};bins high = {[128:255]};}// 定义交叉覆盖率cp_is_read_x_address: cross cp_is_read, cp_address;cp_is_read_x_data: cross cp_is_read, cp_data;cp_address_x_data: cross cp_address, cp_data;
endgroupclass bus_monitor extends uvm_monitor;`uvm_component_utils(bus_monitor)// 实例化覆盖组bus_cg cg;// 构造函数function new(string name, uvm_component parent);super.new(name, parent);cg = new(); // 实例化覆盖组endfunction// 监视器的主要任务virtual task run_phase(uvm_phase phase);bus_transaction tr;forever begin// 假设这里从总线上捕获事务// 例如:tr = bus_transaction::type_id::create("tr");// tr.address = ...;// tr.data = ...;// tr.is_read = ...;// 更新覆盖组cg.sample(tr.address, tr.data, tr.is_read);endendtask
endclass
【总结】
在类内使用 covergroup:
优点:更好的封装性,覆盖率模型与特定组件紧密关联。易于管理和维护。
适用场景:当覆盖率模型与特定组件高度相关时。当需要对覆盖率模型进行更多控制和定制时。
在类外使用 covergroup:
优点:更高的重用性,可以在多个组件之间共享。代码更简洁,覆盖率模型与组件分离。
适用场景:当覆盖率模型较为通用,可以在多个地方使用时。当需要在多个组件之间共享同一个覆盖率模型时
3.7 断言 and 和intersect的区别?
断言(Assertions)用于验证设计的正确性,而and和intersect是用于组合多个条件的逻辑运算符;
and运算符:and运算符用于逻辑与操作,它要求所有的条件都为真时,整个表达式才为真。在断言中,and用于连接多个条件,确保它们同时满足
chk_a_and_b: assert property (@(posedge clk) a and b and c);
intersect运算符:intersect运算符用于定义一个时间窗口,在这个窗口内,两个或多个事件必须同时发生。在断言中,intersect用于确保多个事件在特定的时间范围内同时满足;
chk_a_intersect_b: assert property (@(posedge clk) a intersect b);
and用于连接多个条件,确保它们同时满足;而intersect用于定义一个时间窗口,确保多个事件在这个窗口内同时发生。
3.8 写一个断言:a为高的时候,b为高,且a为高的时候,下一个周期b也为高;
// 断言property p_a_high_b_high;@(posedge clk) (a && b) |-> (a && b)[=>1];endpropertyassert property (p_a_high_b_high)else $error("Assertion failed: When a is high, b should be high and in the next cycle as well.");
3.9 什么是立即断言和并发断言?简述一下assert的用法
立即断言 (Immediate Assertions):立即断言是在执行流程中立即计算和检查的断言。它们通常用于在过程块(如 initial 或 always 块)中检查条件。
// 带成功分支的立即断言assert (a == 1) $display("a is 1") // 成立,输出 "a is 1"else $error("a is not 1");assert (b == 1) $display("b is 1") // 不成立else $error("b is not 1"); // 输出错误消息
并发断言 (Concurrent Assertions):并发断言是在仿真过程中始终处于活动状态的断言,在设计的任何地方都可以使用的断言,它们不会阻塞仿真的执行,它们通常用于检查时序行为。并发断言使用 property 和 sequence 语法来描述复杂的行为。
// 序列sequence s_a_high;a ##1 b; // a 发生后的一个周期 b 必须发生endsequence// 属性property p_a_high_b_high;@(posedge clk) s_a_high;endproperty// 并发断言assert property (p_a_high_b_high)else $error("Assertion failed: When a is high, b should be high in the next cycle.");
【总结】
立即断言:在过程块中立即计算和检查。适用于简单的条件检查。
并发断言:在仿真过程中始终处于活动状态。适用于复杂的时序行为检查。
3.10 a[*3]、a[->3]和a[=3]的区别
a[*3]、a[->3]和a[=3]是用于描述序列(sequences)的操作符;
- a[*3]
语法: a[*3]
含义: a 在连续的 3 个周期内保持不变。
解释: 这表示 a 信号在 3 个连续的时钟周期内保持相同的值。这个值可以是 0 也可以是 1,只要在这 3 个周期内保持不变即可。
示例
sequence s_a_stable_3;a[*3];
endsequenceproperty p_a_stable_3;@(posedge clk) s_a_stable_3;
endpropertyassert property (p_a_stable_3) $display("a is stable for 3 cycles");
在这个示例中,a 信号在 3 个连续的时钟周期内必须保持相同的值。
- a[->3]
语法: a[->3]
含义: a 在 3 个连续的周期内至少有一次为 1。
解释: 这表示在 3 个连续的时钟周期内,a 信号至少有一个周期为 1。a 可以在任意一个或多个周期内为 1。
sequence s_a_one_in_3;a[->3];
endsequenceproperty p_a_one_in_3;@(posedge clk) s_a_one_in_3;
endpropertyassert property (p_a_one_in_3) $display("a is 1 at least once in 3 cycles");
在这个示例中,a 信号在 3 个连续的时钟周期内必须至少有一个周期为 1。
- a[=3]
语法: a[=3]
含义: a 在 3 个连续的周期内都为 1。
解释: 这表示 a 信号在 3 个连续的时钟周期内都必须为 1。
sequence s_a_high_3;a[=3];
endsequenceproperty p_a_high_3;@(posedge clk) s_a_high_3;
endpropertyassert property (p_a_high_3) $display("a is high for 3 cycles");
在这个示例中,a 信号在 3 个连续的时钟周期内必须都为 1。
以上是对IC验证中SVA和覆盖率的小结;
【REF】
1.https://blog.csdn.net/graymount/article/details/121391722