1. 简介
SystemVerilog断言(SVA)主要是用于验证设计的行为,其主要功能有两点:
- 在特定条件或事件序列的故障上生成警告或错误;
- 收集功能覆盖率的数据。
2. 立即断言(Immediate Assertion)
立即断言执行时如同过程语句,她在程序执行到这个程序块使立即执行,并且可以结合$fatal,$error,$warning和$info函数给出不同级别的消息提示。
断言比if语句更加紧凑,且断言里面的逻辑跟if语句是相反的。设计者应该期望括号内的表达式为真,否则输出一个错误。
//使用if语句检查一个信号
bus.cb.request<=1;
repeat(2) @bus.cb;
if(bus.cb.grant!=2'b01)
$display("Error,grant!=1");
//简单的立即断言
bus.cb.request<=1;
repeat(2) @bus.cb;
al:assert (bus.cb==2'b01);
//定制断言行为
bus.cb.request<=1;
repeat(2) @bus.cb;
al:assert (bus.cb==2'b01)
else $error("Grant not asserted");
3. 并发断言
并发断言可以认为时一个连续运行的模块,他为整个仿真过程检查信号的值,需要在断言内指定一个采样时钟。
例中是一个检查仲裁器request信号的断言,request信号除了在复位期间,其他任何时候都不能是X或Z。
//检查X/Z的并发断言
interface arb_if(input bit clk);
logic[1:0] grant,request;
logic rst;
property request_2state;
@(posedge clk) disable iff(rst);
$isunknown(request)==0; //确保没有z或者x值存在
endproperty
assert_request_2state:assert property(requset_2state);
endinterface
可以在过程块,module,interface和program内定义并发断言,区别并发断言和立即断言的关键字是property。
4. 断言的层次结构
SVA从单元的角度来说可以分为3个层次,分别是:
- Boolean expression布尔表达式
- Sequence序列
- Property属性
4.1 Boolean expression布尔表达式
布尔表达式是组成断言的最小单元,常用的操作符:&&,||,!,^等。
//简单的布尔表达式断言
example_assert: assert property(@(posedge clk) a&&b==1);
4.2 Sequence序列
在任何设计中,功能总是由多个逻辑事件的组合来表示,这些事件可以是简单的同一个时钟沿被求值得布尔表达式,也可以是经过几个时钟周期的求值事件,SVA用关键字 sequence来表示这些事件,sequence可以让断言易读,复用性高;sequence是布尔表达式更高一层的单元。
sequence具有以下特性:
- 可带参数;
- 可以在 property 中调用;
- 可以使用局部变量;
- 可以定义时钟周期;
- 可以使用序列方法,如 ended、matched、triggered,这些只能在sequence中使用;
//简单的Sequence
sequence seq_1;
@(posedge clk) a==1;
endsequence
//调用sequence
a_1: assert property(seq_1);
带逻辑关系的sequence:
//带逻辑关系的Sequence
sequence seq_1;
@(posedge clk) a||b; //如果a和b都为0,则断言失败
endsequence
带参数的sequence:
//带参数的sequence
sequence seq_1 (a, b)
a || b ;
endsequence
sequence seq_2
seq_1(a,b); //在当前sequence调用seq_1
endsequence
带时序关系的sequence:
//带时序关系的sequence
sequence seq;
@(posedge clk) a ##2 b; //在时钟上升沿到来检查a是否为1,若不为1则断言失败
//若a为1,则检查两个周期之后b是否为1,若不为1,断言失败
endsequence
4.3 Property属性
property是比sequence更高一层的单元,也是构成断言最常用的模块。其中最重要的性质是可以在property中使用蕴含操作符(|-> |=>)。
propert可以调用sequence:
//property调用sequence
sequence seq_1;
@(posedge clk) a||b;
endsequece
property p;
seq_1; //调用seq_1
endproperty
a_1: assert property(p);
property与sequence的相同和不同之处:
- 任何在sequence中的表达式都可以放到property中;
- 任何在property中的表达式也可以搬到sequence中,但是只有在property中才能使用蕴含操作符;
- property中可以例化其他property和sequence,sequence中也可以调用其他的sequence,但是不能例化property;
- property需要用cover/assert/assume等关键字进行实例化,而sequence直接调用即可;
5. 断言操作符和系统函数
断言常用的操作符如下:
##n | 表示延时了n和时钟周期; |
##[m:n] | 表示后续事件在n-m周期内出现都可以判定为真 |
$ | 表示无穷大的周期(在仿真结束前),不建议使用 |
[*n] | 表示事件重复n次 |
[*m:n] | 表示一定范围内重复的事件 |
[=m] | 表示一个事件的连续性,需要重复m次,但并不需要在连续周期内发生 |
[=m:n] | 表示一个事件的连续性,需要重复n-m次,但并不需要在连续周期内发生 |
|-> | 交叠蕴含,涵的左边叫做”先行算子“(antecedent),右边叫做”后续算子“(consequent)。如果先行算子匹配,在同一个时钟周期计算后续算子表达式。 |
|=> | 非交叠蕴含,如果先行算子匹配,在下一个时钟周期计算后续算子表达式。 |
常见的系统函数如下:
$rose | $rose(boolean expression or signalname); 信号/表达式的值从0变为1时返回真 |
$fell | $fell( boolean expression or signalname); 信号/表达式的值从1变为0时返回真 |
$stable | $stable(boolean expression or signalname) ; 信号/表达式的值不发生变化时返回真 |
$past | $past(signal_name, number of clock cycles); 访问在过去若干采样周期的值 |
and | 断定两个事件同时发生 |
intersect | 断定两个事件同时发生或结束 |
or | 断定两个事件至少一个发生 |
first_match | 从多次满足的序列中选择第一次满足的时刻,从而放弃其他满足时刻 |
throughout | a throughout b 断定在b事件成立的过程中,a事件“一直”成立 |
within | a within b 断定b事件发生的时间段里包含a事件发生的时间段 |