目录
1.3 assertion property sequence
1 Assertion介绍
断言是设计的属性的描述。
- 如果一个在模拟中被检查的属性property不像我们期望的那样表现,那么这个断言失败。
- 如果一个被禁止在设计中出现的属性在模拟过程中发生,那么这个断言失败。
1.1 类型划分
立即断言 Immediate assertion:
- - 非时序的
- - 执行时如同过程语句
- - 可以在initial/always过程块或者task/function中使用
- - 只能用于动态模拟
并行断言 Concurrent assertion:
- - 时序性的,只会在时钟边沿激活
- - 关键词property用来区分立即断言和并行断言
- - 并行是因为它们与设计模块一同并行执行
- - 可以被放在过程快、模块module、接口interface或者一个程序program的定义中
- - 可以在静态(形式的)验证和动态验证(模拟)工具中使用
1.2 并行断言的执行阶段
- - 在preponed阶段采样稳定的变量值
- - 在observe阶段执行并行断言,计算表达式
- - 在reactive区域执行pass/fail语句
1.3 assertion property sequence
在任何设计模型中,功能总是由多个逻辑事件的组合来表示的。这些事件可以是简单的同一个时钟边缘被求值的布尔表达式,或者是经过几个时钟周期的求值的事件。SVA用关键词“sequence”来表示这些事件。序列(sequence)的基本语法是:
sequence name_of_sequence;
<test expression>
endsequence
许多序列可以逻辑或者有序地组合起来生成更复杂的序列。SVA提供了一个关键词property来表示复杂的有序行为。属性property的基本语法是:
property name_of_property;
<test expression>; or
<complex sequence expressions>;
endproperty
- property块可以直接包含sequence
- 复杂的property也可以独立声明多个sequence
- sequence可以在module、interface、program、clocking块和package中声明
1.4 蕴含Implication操作符
- 蕴含implication操作符用来表示,如果property中左边的先行算子(antecedent)成立,那么property右边的后续算子(consequent)才会被计算。
- 如果先行算子不成功,那么整个属性就默认地被认为成功,为“空成功”(vacuous success)。
- 蕴含结构只能用在属性定义中,不能在序列中使用。
- 蕴含可以分为两类:交叠蕴含 overlapped implication 和非交叠蕴含 non-overlapped implication
1.4.1 |-> 交叠交错符号:
- -如果条件满足,则评估其后续算子序列
- - 如果条件不满足,则表现为空成功,不执行后续算子
1.4.2 |=> 是非交叠蕴含操作符
- 如果条件满足,则在下一周期评估其后续算子序列。
- 如果不满足,则表现为空成功,不执行后续算子。
2 Sequence定义
2.1 基本操作符号【* = ->】
- ## 用来表示周期延迟符号,例如##n表示在n个时钟周期后,##0 表示在当前周期,即交叠周期
- ##[min,max] 表示在一个范围内的时钟周期延迟。min、max必须是非负数,序列会在从min'到max时间窗口中最早的时间来匹配。
- $用来表示无穷大的周期(在仿真结束前),但是一般我们不建议这么做,因为它会增大仿真评估序列的负担。
- 事件也可以通过[*n] 操作符号来表示重复。n须为非负数,其不能为$。
- 类似地,也可以使用[*m:n]来表示一定范围内的重复事件。
a ## 1 b[*2:5] is equivalent to
a ##1 b ##1 b
a ##1 b ##1 b ##1 b
a ##1 b ##1 b ##1 b ##1 b
a ##1 b ##1 b ##1 b ##1 b ##1 b
- [=m]用来表示一个事件的连续性,需要重复发生m次,但是并不需要在连续周期内发生
- b[=3] 表示b必须在3个周期内为1,但是并不需要是连续的三个周期
- 类似地,[=m:n]用来表示从最小m到最大n的重复发生的非连续周期次数。
- [->m]:指定表达式匹配指定的次数,而不必匹配连续的时钟周期,与=不同的是,表达式的最后一个匹配项应在整个序列匹配结束之前的时钟周期内发生
-
property goto_repetition_p;
-
@(posedge clk) $rose(a) |-> b[->3] ##1 c;
-
endproperty
通过的例子:
!a a !b !b b !b !b b !b b c
失败的例子
!a a !b !b b !b !b b !b b !b c
2.2 and操作符号
- and用来表示两个序列需要保持匹配
- 用法:SEQ1 and SEQ2
- 下列情形将满足此操作符:
- 在从同一个起始点开始后,seq1和seq2均满足
- 满足的时刻发生在两个序列都满足的周期,即稍晚序列的满足时刻。
- 两个序列的满足时间可以不同。
- 如果操作符两边的序列都是用来衡量采样信号而非事件时序,那么则要求在相同周期内,and左右两边的序列都应该满足条件。
2.3 intersect操作符号
- 与and操作符类似,只是需要两边的序列时序在同一时钟周期内匹配。
2.4 or操作符号
- or 用来表示两个序列至少需要有一个满足。
- 用法:SEQ1 or SEQ2
- 下列情形将满足此操作符:
- seq1和seq2都从同一个时刻被触发
- 最终满足seq1或者满足seq2
- 每一个序列的结束时间可以不同,结束时间以序列满足的最后一个序列时间为准。
2.5 first_match操作符号
- first_match 用来从多次满足的序列中选择第一次满足时刻,从而放弃其它满足的时刻。
sequence t1;
te1 ##[2:5] te2;
endsequence
- t1序列可以用来匹配te1 ##2 te2,te1 ##3 te2,te1 ##4 te2 或者te1 ##5 te2。
sequence ts1;
first_match(te1 ##[2:5] te2);
endsequence
- 此序列则用来选择第一次匹配的时刻。
- 每一次PCI总线进入idle状态时,状态机也应该返回IDLE状态。由此,在时序信息上要求,如果frame和irdy信号保持至少两个周期以上为高时,系统的状态应该为idle状态。
sequnce checkBusIdle
(##[2:$](frame && irdy));
endsequence
property first_match_idle
@(posedge clk) first_match(checkBusIdle)l->(state==busidle) ;
endproperty
2.6 throughout操作符号
- 可以用来检查一个信号或者一个表达式在贯穿( throughout)一个序列时是否满足要求。
- 用法: Sig1/Exp1 throughout Seq
- 例如,在burst模式信号拉低以后的2个周期时,irdy/trdy也应该在连续7个周期内保持为低,同时burst模式信号也应该在这一连续周期内保持为低。
sequence burst_rule1;
@(posedge mclk)
$fell (burst_mode) ##0
(!burst_mode) throughout (##2 ((trdy==0 ) && (irdy==0))[*7]) ;
endsequence
2.7 within 操作符号
- 可以用来检查一个序列与另外一个序列在部分周期长度上的重叠。
- 用法: SEQ1 within SEQ2
- 如果当seq1满足在seq2的一部分连续时钟周期内成立,seq1 within seq2成立。
- 例如,trdy需要在irday下拉的1个周期后保持7个周期为低,同时irday也将保持8个周期为低,以下序列会在第11个时钟周期满足。、
2.8 if操作符号
- 例如,当master_req为高时,下一个周期,req1或者req2应该为高,如果req1为高,则下一个周期ack1为高,如果req2为高,则下一个周期ack2为高。
property master child reqs;
@(posedge clk) rmaster_req ##1 (req1 || req2)
if(req1)
(##1 ack1);
else
(##1 ack2);
endproperty
2.9 Ended检测序列的终点
- 用法:SEQ.ended
- 在某一时刻,序列如果及时抵达终点,那么条件满足。
- 例如,在inst为高的下一个周期,序列e1应该结束或者已经结束。
sequence e1 ; @(posedge sysclk) $rose(ready) ##1 proc1 ##1 proc2; endsequence sequence rule; @(posedge sysclk) reset ##1 inst ##1 e1.ended ##1 branch_back; endsequence
-
在c拉起的下一个周期,a拉低b拉高的序列也应该结束。
2.10 局部变量
- 局部变量可以在sequence或者property中使用。
- 这些变量会伴随着sequence、property动态创建。
- 每一个sequence实例都会有它自己的变量拷贝。
- 例如,在cache rdDone拉高后,读出的rdData会在2个周期后,在其基础上加1,并作为wrData写入。
- 例如,如果read拉高,伴随readld,则下一次read必须在这一次read对应的readAck返回之后,才可以发起。
- 需要先记录上一次read的readld,继而在接下来的周期,检查没有相同readld的read发起,直到对应readld的上一次read的readAck拉起,并且readAckld与之相同。
2.11 调用方法
- 在序列匹配时,可以调用task,void function和系统函数。
- 例如,可以在s1序列末尾,分别打印出e和lf变量被采样时的数值。
2.12 访问采样方法
- 一些系统函数可以用来访问指定类型的变量采样:
- 用来访问当前周期采样值。
- 用来访问上一个采样周期值。
- 用来检测采样变量的变化。
- $rose(expression[, clocking_event])和$fell(expression[,clocking_event])用来表示与上一个采样周期相比,变量最低位是否跳变为1或者0,满足条件返回1,否则返回0。
- clocking_event在sequence中不需要单独提供,因为sequence中一般会指定采样时钟。
- $stable(expression[, clocking_event]),用来表示在连续两个采样周期内,表达式的值保持不变,如果满足,返回1,否则,返回0。
- $past(expr[, num_cycles][, gating_expr][, clocking_event])用来访问在过去若干采样周期前的数值。
- 默认情况下,num_cycles=1,即采样1个周期前的数值。
- 例如,在ack拉高时的前两个周期,req信号应该为高。
property ReqCausedAck;
@(posedge clk) $rose(ack) |-> $past (reg,2);
endproperty
- $rose/$fall/$stable也可以在过程块语句和连续赋值中使用。
2.13 系统函数和方法
- 类似于之前的访问采样的方法,我们还可以使用其它一些系统函数和方法,在sequence/property/assertion中使用:
- $countbits
- $onehot
- $isunknown
- $countones
- 这些系统函数也可以用在一般的过程语句块和赋值语句中。
- $countbits(expression, control_bit)用来计算expression中匹配control_bit数值的位数。
- $countones(expression)与$countbits(expression, '1)一致,即计算expression中为1的位数。
- $onehot(expression)与$countbits(expression, '1)==1一致,即检查expression中是否有且只有1位为1。
- $isunknown(expression)与$countbits(expression, 'x,'z)!=O一致,即检查expression中是否有x或者z。
- 在assertion或者property中,可以通过"disable iff"来给assertion做局部的条件控制。
- 在全局控制方面,我们也可以通过系统函数对property模块或者实例做出控制:
- $asserton,默认控制,用来打开所有的assertion。
- $assertoff,暂时停止assertion运行。
- $assertkill,终止所有执行的assertion。
- level=0,表示当前模块或者层次下的所有assertion。
- level=n,表示当前模块或者层次下n层范围中的assertion。
- assertion_identifier表示property的名字或者assertion的label。