assertion用于设计功能和时序做比较的属性描述。
断言(assertion)可以用来完成:
用来检查算法模型的断言在形式验证(formal verification)中可以穷尽计算,找出可能的违例(violation)
可以自由地打开或关闭
一小部分子集甚至可以用来综合或者移植到emulation中,用来完成跨平台的移植
仿真工具可以报告断言覆盖率,来指示哪些断言没有被触发?
帮助检查是否验证计划捕捉到了所有需要的覆盖率
断言覆盖率和功能覆盖率可以共同量化验证进度
断言语言
在verilog中不支持断言,因此需要写过程语句来做代替
一些支持断言的语言:
Sugar(IBM)进化为PSL(Property Specification Language)
OVA-Vera
Specman/e
ForSpec(intel)
上述语言的有点功能进化为SVA,因此SVA作为SV相对独立的语言分支,值得我们花足够的精力来学习掌握它。
== 立即断言(immediate assertion)==
[name: ] assert (expression) [pass_statement] [else fail_statement]
time t;
always@(posedge clk)
if(state == REQ)
assert (req || req2)
else begin
t = $time;
#5 $error("assert failed at time %0t", t);
end
立即断言可以结合$ fatal/$ error/$ warning/$info给出不同严重级别的消息提示。
assert (myfunc(a,b)) count1 = count + 1; else ->event1;
assert (y==0) else flag = 1;
always @ (state)
assert (state == $onehot) else $fatal;
base_rule1: assert property (cont_prop (rst, in1, in2)) pass_stat else fail_state;
Request-Grant协议描述:request拉高,在2个周期后,grant拉高,在1个周期后,request拉低,在1个周期后,grant拉低。
property req_grant_prop
@(posedge clk) req ##2 gnt ##1 !req !gnt;
endproperty
assert property req_grant_prop else $error("Req-Gnt Protocol violation");
并行断言只会在时钟边沿激活,变量的值是采样到的值。
并行断言的执行阶段
SV的仿真调度机制如下图,并行断言的执行如下:
在preponed阶段采样稳定的变量值
在observe阶段执行并行断言
在reactive区域执行pass/fail语句
通过这种当时保证并行断言执行会采样的稳定的设计信号变量。
assert property(@(posedge clk)
disable iff(!reset)
a |=>b ##1 c);
assert property(my_prop);
property my_prop;
@(posedge clk)
disable iff (!reset)
a |=>b ##1 c;
endproperty
在property内部可以有条件地关闭
property块可以直接包含sequence
复杂的property也可以独立声明多个sequence
sequence s1;
@(posedge clk) a ##1 b ##1 c;
endsequence
sequence s2;
@(posedge clk) a ##1 c;
endsequence
property p1;
@(posedge clk) disable iff(!reset)
s1 |=> s2;
endproperty
sequence是用来表示在一个或者多个时钟内的时序描述。
sequence是property的基本构建模块,并经过组合来描述复杂的功能属性。
sequence s1;
@(posedge clk) a ##1 b ##1 c;
endsequence
sequence t1;
(a ##[2:3] b) or (c ##[1:2] d);
endsequence
sequence用来提供下列场景描述:
(1) 第一个时钟周期,第一个表达式成立的。
(2) 接下来在若干个时钟周期后,第二个表达式也成立。
(3) 以此类推,在接下来的若干个时钟周期,后续表达式也成立。
sequence可以在module、interface、program、clocking块和package中声明,一般在interface中声明。
sequence也可以提供形式参数,用来提高复用性
sequence s20_1(data, en);
(!frame && (data==data_bus)) ##1 (c_be[0:3]==en);
endsequence
蕴含(implication)操作符用来表示,如果property中左边的先行算子(antecedent)成立,那么property右边的后续算子(consequent)才会被计算。
如果线性算子不成功,那么整个属性就默认地被认为成功,这叫做“空成功”(vacuous success)。
蕴含结构只能用在属性定义中,不能再序列中使用。
蕴含可以分为两类:交叠蕴含(overlapped implication)和非交叠蕴含(non-overlapped implication)。
(1)|->交叠操作符
如果条件满足,则评估其后续算子序列。
如果条件满足,则在下一个周期评估其后续算子序列。
1.##用来表示周期延迟符号,例如##n表示在n个时钟周期后,##0表示在当前周期,即交叠周期。
sequence a_b;
@(posedge clk) a ##1 b;
endsequence
2.##[min : max]表示在一个范围内的时钟周期延迟。min、max必须是非负数,序列会在min到max时间窗口中最早的时间来匹配。
sequence a_b;
@(posedge clk) a ##[1:5] b;
endsequence
3.$ 用来表示无穷大的周期(在仿真结束前),但是一般我们不建议这么做,因为他会增大仿真评估序列的负担。
时间也可以通过[*n]操作符来表示重复。n必须为非负数,其不能为$。
sequence a_b;
@(posedge clk) a ##[1:$] b;
endsequence
4.时间也可以通过[*n]操作符来表示重复。n必须为非负数,其不能为$。
sequence a_b;
@(posedge clk) a ##1 b[*2];
endsequence
5.类似的,也可以使用[*m:n]来标识一定范围内的重复事件。
sequence a_b;
@(posedge clk) a ##1 b[*2:5];
endsequence
6.[=m]用来表示一个事件的连续新,需要重复发生m次,但是并不需要在连续周期内发生。
b[=3]表示b必须在3个周期内为1,但是并不需要是连续的3个周期。
sequence a_b;
@(posedge clk) a ##1 b[=3];
endsequence
7.例如,执行了一次burst read操作,期望读的数据和ack信号在接下来的四个周期内返回,但是不需要连续的四个周期,即可以用[=4]来表示。
8.类似的,[=m:n]用来表示从最小m到最大n的重复发生的非连续周期次数。
9.a[*0]用来表示没有任何正数时钟周期内有效。
10.例如a[*0:3] ##1 b ##1 c与哪些情形匹配?
用法:seq1 and seq2
下列情形满足此操作符:
12.intersect操作符
用法:seq1 intersect seq2
需要两边的序列在同意时钟周期内匹配
需要在同一时钟周期结束
13.or操作符
用来表示两个序列至少需要有一个满足
用法:seq1 or seq2
下列情形满足此操作符:
property BurstLengthValid
@(posedge clk) disable iff (!rst)
((burstLen==4) |->
(wrlen==1) or (wrlen==2) or (wrlen==4));
endproperty
assert property(BurstLengthValid)
15.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 t1;
first_match(te1 ##[2:5] te2);
endsequence
此序列用来选择第一次匹配的时刻。
16.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
17.within操作符
可以用来检查一个序列与另一个序列在部分周期长度上的重叠
用法:seq1 within seq2
如果当seq1满足在seq2的一部分连续时钟周期内成立,seq1 within seq2成立。
例如,trdy需要在irdy下拉的一个周期后保持7个周期为低,同时irdy也将保持8个周期为低,一下序列会在第11个周期满足。
!trdy[*7] within (($fell irdy) ##1 !irdy[*8])
18.if操作符
可以在sequence中使用if…else
例如当master_req为高时,下一个周期,req1或者req2应该为高,如果req1为高,则下一个周期ack1为高,如果req2为高,则下一个周期ack2为高。
property master_child_regs;
@(posedge clk) master_req ##1 (req1 || req2)
if(req1)
(##1 ack1)
else
(##1 ack2);
endproperty
19.检测序列的终点
用法:seq.ended
在某一时刻,序列如果及时抵达终点,那么条件满足。
例如,在inst为高的下一个周期,序列e1应该结束或者已经结束。
seqence e1;
@(posedge sysclk) $rose(ready) ##1 proc1 ##1 proc2;
endsequence
seqence rule;
@(posedge sysclk) reset ##1 inst ##1 e1.ended ##1 branch_back;
endsequence
20.局部变量
局部变量可以在sequence或者property中使用
这些变量会伴随这sequence、property动态创建
每一个sequence实例都会有自己的变量拷贝
例如在cache rdDone拉高后,读出的rdData会在2个周期后,在其基础上加1,并作为wrData写入。
sequence rd_cache_done;
##[1:5] rdDone;
endsequence
sequence check_reg_wr_data;
int local_data;
(rd_cache_done, local_data=cache_rd_data) ##2 (reg_wr_data==(local_data+1));
endsequence
21.调用方法
在序列匹配时,可以调用task、void function和系统函数
例如,可以在s1序列末尾,分别打印出e和f变量被采样的数值。
sequence s1;
logic v,w;
(a,v=e) ##1
(b[->1],w=f, $display("b after a with v = %h, w=%h\n",v,w))
endsequence
22.访问采样方法
(1)用来访问当前周期采样值
(2)用来访问上一个采样周期
(3)用来检测采样变量的变化
$ 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(req,2);
endproperty
$rose, $fell, $stable也可以在过程怪语句和连续赋值中使用
always @(posedge clk)
TestDone <= stimulus_over & $rose(unit_done);
always@(posedge clk)beign
if($stable(my_sig))begin
$display($time, "my_sig is stable from previous clk");
end
end
assign intr_clear = $fell(intr, @(posedge clk));
assign intr_set = $rose(intr,@(posedge clk));
23.系统函数和方法
类似于之前的访问采样方法,我们还可以使用其他一些系统函数和方法,在sequence/property/assertion中使用:
在assertion或者property中,可以通过“disable iff”来给assertion做局部的条件控制。
在全局控制仿麦呢,我们也可以通过系统函数对property模块或者实例做出控制:
结合sequence(序列)对时序和逻辑的描述,property(属性)可以用来描述设计的确切行为。
Property可以在验证中用来做assumption,checker或者coverage:
Property也可以同sequence一样具备形式参数。
共有七种property:
对于sequence类型的property,只有出现满足该sequence条件时,property才可以通过
2.negation类型
对于negation类型,即not property_expr。如果property_expr不满足,那么negation类型的property即通过。
property rule;
@(clkev) disable iff(foo) a |-> not (b ##1 c ##1 d);
endproeprty
3.disjunction(or)
用法:property_expr1 or property_expr2,当至少一个property_expr满足条件时,property即通过。
property rule;
@(posedge clk) a[*2] |-> ((##[1:3] c) or (d |-> e));
endproperty
4.conjunction(and)
用法:property_expr1 and property_expr2,当至少一个property_expr满足条件时,property即通过。
property rule;
@(posedge clk) a[*2] |-> ((##[1:3] c) and (d |-> e));
endproperty
5.if(expression) property_expr1 else property_expr2
6.implication蕴含,同sequence中用法一致,sequence_expr{|->,|=>} property_expr
7.instantiation用法即一个命名后的property可以在另一个property_expr中所使用。
property rule1(x,y);
##! |-> y;
endproperty
property rule2;
@(posedge clk)
a ##1 (b || c)[->1] |->
if(b)
rule1(d,e)
else
f;
endproperty
————————————————
版权声明:本文为CSDN博主「Nodal Analysis」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44381276/article/details/121618400