断言(assertion)一般可以放到RTL设计代码中,比较方便我们在仿真出现异常时查看它所报警的东西。通常意义上的断言具有:1)检查特定条件或事件序列的出现情况,提供功能覆盖。
立即断言会检查当前仿真时间的条件,需要放到过程块中。语法是labels:assert(expression) action_block;
actioin_block:pass_statement;else fail_statement
asser(expression)$display("express evaluates to ture");
else $fatal("expression evaluates to false");
module top_tb;
bit clk,a,b;
always #5 clk = !clk;
initial begin
a = 1;
b = 1;
#15 b = 0;
#10 b = 1;
a = 0;
#20 a = 1;
#20;
$finish;
end
always@(posedge clk)
check_a_and_b:assert(a&&b);//2:$display("a&&b is ture");else $fatal("a&&b is false");
//3.:$display("a&&b is ture");else $error("a&&b is false");
endmodule
第2种(带有action_block)
第3种(使用error)
并发断言可以检查多个时钟周期的时间序列,可以将并发断言看成是一个连续运行的模块,为整个仿真过程检查信号
always@(posedge clk)begin//ime
check_a_and_b:assert(a&&b)$display("a&&b is ture");
else $error("a&&b is false");
end
check_a_and_b:assert property@(posedge clk)(a&&b))
SVA可以存在内建的单元,
在任何设计中,功能总是由多个逻辑事件的组合来表示,这些事件可以是简单的同一个时钟沿被求值得布尔表达式,也可以是经过几个时钟周期的求值事件,SVA用关键字 sequence来表示这些事件,sequence可以让断言易读,复用性高;
sequence name_of_sequence(参数);
...
endsequence
特点:
check_a_and_b:assert property@(posedge clk)(a&&b)$display("a&&b is ture");
else $error("a&&b is false");
sequence seq_a_and_b;
@(posedge clk)a&&b;
endsequence
//property中调用sequence
check_a_and_b:assert property(seq_a_and_b);
check_a_and_b:assert property(seq_a_and_b)$display("a&&b is ture");
else $error("a&&b is false);
1、sequence还可以通过参数去给其他的调用
//带参数的sequence
sequence seq1(sig1,sig2);
@(posedge clk)sig1&sig2;
endsequence
//在断言property中调用sequence
check_a_and_b:assert property(seq1(a,b));
check_a_and_b:assert property(seq1(a,b))$display("a&&b is ture");
else $error("a&&b is false");
2、sequence内可以调用其他sequence;
sequence seq1;
@(posedge clk)a&&b;
endsequence
sequence seq2;
seq1;
endsequence
3、带时序关系的sequence :在SVA中时钟延时用符号"##“来表示,如”##2"表示延时两个时钟周期;
sequence seq2;
@(posedge clk)a ##2 b;//a成立后两个时钟后b也成立,如果a没有成立则这个不算成立
endsequence
check_a_and_b:assert property(seq2);
property和sequence的异同
property name_of_property(var);
测试表达式或是复杂的sequence;
endproperty
交叠蕴含
运算操作符|->如果满足条件,则评估后续算子序列;如果条件不满足,则表示为空成功,不执行后续算子。
property p_req_ack;
@(posedge clk) mem_en |-> (req ##2 ack);
//当men_en为高时,此时req为1 ,过两拍,ack要为拉高
endproperty
/*
【注意】
*断言成功:左边算子成功,右边算子成功
*断言失败:左边算子成功,右边算子失败
*/
非交叠蕴含
运算操作符 |=>如果满足条件,则在下一个周期评估后续算子序列;如果条件不满足,则表示为空成功,不执行后续算子。
property p_req_ack;
@(posedge clk) mem_en |=> (req ##2 ack);
//当men_en为高时,下一拍的req为1 ,过两拍,ack要为拉高
endproperty
operator | description | example |
---|---|---|
##n | n cycle delay | req ##2 grant |
##[m:n] | m~n cycle delay | req##[1:2]grant |
##[*] | ##[0:$] | req ##[*] ack //when req, gnt should come eventually |
##[+] | ##[1:$] | req ##[+] ack //after req (next cycle), ack should come eventually |
a[*3] | a ##1 a ##1 a | Consecutive Repetition,a连续3个cycle都成立 |
a[->2] b | a ##[+] a ##1 b | a成立2次(不要求在连续的2个cycle内),1个cycle后b成立 |
a[=2] b | a ##[+] a ##[+] b | a成立2次(不要求在连续的2个cycle内),b不必匹配连续的时钟周期 |
判断多个事件/信号得行为关系
operator | description |
---|---|
intersect(a,b) | 断定a和b两个事件同时产生,且同时结束 |
a within b | 断定b事件发生得时间段里包含a事件发生得时间段 |
a ##2 b | 断定a事件发生后2个时间内b事件一定会发生 |
c throughout(a ##b) | 断定a事件成立到b事件成立的过程中,c事件“一直“成立 |
@(posedge clk)a /->b | 断定clk上升沿后,a事件”开始发生”,同时,b事件发生 |
@(posedge clk)a[*3] | 断定在3个时钟周期内都成立 |