文章目录
前言
断言(assertion)是验证工作中常用的自动检查手段,相比于checker或者reference model更加轻量化也更方便移植,同时也是收集功能覆盖率的重要一环。
一、断言分类
1、即时断言 Immediate Assertions
即时断言作用和 if 语句的效果类似,在仿真运行到这句代码时做出判断。
int a;
assert(a) else `uvm_error(get_type_name(), "assert fail");
if(a) else `uvm_error(get_type_name(), "assert fail");
如上两句代码,在验证环境中效果是一样的,都是运行到这行代码时,a非0就报错。
需要注意的是,断言如果违例,默认报错的信息是“ Offending xxx ”,加上 else `uvm_error() 语句会更加方便。
2、并发断言 Concurrent Assertions
并发断言是最常用的,一般和时序强相关的检查都可以用这种形式实现,本文内容也主要描述并发断言。
并发断言需要指定采样时钟,可以在module、interface里实现,在整个仿真周期内都起效。
ast_ack_when_req: assert property(@(posedge clk) disable iff(~rstn) ack |-> req)
else `uvm_error("xxx", "ast_ack_when_req fail");
如上就是一个简单的检查,在rstn为1时生效,每当clk的上升沿判断,如果当拍a为高,检查下一拍b为高,否则报错。
符号|->称为蕴含符,只有当蕴含符前面的条件满足时,才检查后面的时序是否正确。
二、常见用法
1、generate
断言和verilog语句类似,只是多了一些独特的用法和关键词,也支持用generate语句批量产生断言。如果DUT内有一个module例化多份,一个断言规则在这些实例中都适用,那么这个功能就很好用。
`define INST(num) tb_top.dut.inst``num // 宏定义路径,用法详见文章 [宏定义日常用法](https://blog.csdn.net/Zwwang97/article/details/136601241)
generate
for(genvar num=0; num<4; num++) begin: inst_gen
ast_ack_when_req: assert property(@(posedge clk) disable iff(~rstn)
`INST(num).ack |-> `INST(num).req) // 通过路径宏分别索引到各个inst,ack为高的同时req必定为高
else `uvm_error("xxx", "ack when req is 0");
end
endgenerate
2、property 和 sequence
如果有两组信号的检查逻辑是类似的,可以使用property来复用,将两组信号作为参数传入。
property ack_when_req_p(logic ack, logic req);
@(posedge clk) disable iff(~rstn) ack |-> req; // 可以复用的检查逻辑
endproperty
ast_cmd_ack: assert property(ack_when_req_p(cmd_ack, cmd_req));
ast_data_ack: assert property(ack_when_req_p(data_ack, data_req));
如果有一段时序需要复用,可以使用sequence描述这段时序,然后在不同的property内复用。
sequence req_ack_success_s;
req && ack; // req和ack同时为高
endsequence
property no_consecutive_p(logic ack, logic req);
@(posedge clk) disable iff(~rstn)
req_ack_success_s |-> ##1 not req_ack_success_s; // 连续两次req和ack握手成功间隔必须大于1拍
endproperty
3、if else
如果对于cmd_req/ack信号,写命令是当拍回ack,但是读命令是下一拍,可以分开写成两个,也可以使用if else语句写成一个。
ast_ack_when_req: assert property(@(posedge clk) disable iff(~rstn)
cmd_ack |->
if(cmd_type == WR) cmd_req
else if(cmd_type == RD) $past(cmd_req))
else `uvm_error("xxx", "ack when req is 0");
4、变量延迟
断言中只支持##1这种常数delay,但如果delay值是不确定的(如和寄存器配置值有关),可以用以下方法。
ast_ack_after_req: assert property(@(posedge clk) disable iff(~rstn)
int delay;
(req, delay = cfg_delay) ##0 (delay>0, delay=delay-1)[*0:$] ##0 (delay == 0) |-> ack) // req为高后cfg_delay拍,ack必为高
else `uvm_error("xxx", "ast_ack_after_req fail");
总结
以上就是功能覆盖率中写断言时会用到的一些用法。