目录
assertion based verification ABV方法学定义assertion如何被使用,包括:
first_match表示从多次满足的序列中选择第一次满足的时刻,放弃其他时刻
throughout检查一个信号或表达式在贯穿一个seq时是否满足要求
within检查一个seq与另一个seq在部分clk长度上的重叠
assertion断言
什么是assertion?
用来与设计功能和时序做比较的属性描述。???
越短越好!
assertion的作用是什么?
- 检查设计的内容
- 提高设计的可视度和调适能力
- 检查设计特性在验证中是否被覆盖
assertion based verification ABV方法学定义assertion如何被使用,包括:
- 谁写?
- 哪种语言可以写?
- 写在哪里?
- 可以使用哪些断言库Library?
- 如何调试?
- 如何使用形式验证工具?
- 如何使用断言覆盖率?
assertion的分类有哪些?
- 立即断言immediate assertion
- 非时序
- 执行时如同过程语句
- 可以在initial块、always块、task和function中使用
- 并行断言concurrent assertion
- 时序性的
- 关键词property用来区分这两种断言
- 与设计模块一同并行执行,所以称为并行断言
assertion如何编码实现?
[name:] assert(expression)[pass_statement][else fail_statement]
time t;
always @(posedge clk)
if (state==REQ)
assert (req1||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 (steate==$onehot) else $fatal;
base_rule1: assert property (cont_prop(rst, in1, in2)) pass_stat else fail_stat;
//req拉高,2个clk后grant拉高,1个clk后req拉低,1个clk后grant拉低
property req_grant_prop
@(posedge clk) req ## 2 gnt ##1 !req ## !gnt;
endproperty
并行断言只会在clk边沿激活,变量的值是采样到的值
- 可以直接包含一个property,也可以独立声明。
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和sequence的关系
property块可以直接包含sequence
复杂的property可以独立声明多个sequence
sequence是property的基本构建模块,经过组合来描述复杂的功能属性
这里的seq和之前的seq的区别?
描述时序,不是做激励
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;//如果出现s1序列则马上跟着出现s2序列
endproperty
sequence可以在module interface program clocking package中声明
sequence t2;
(a ## [2:3] b) or (c ##[1:2] d);
endsequence
sequence可以提供形式参数,提高复用性
sequence s20_1 (data, en);//参数为data和en
(!frame && (data==data_bus)) ##1 (c_be[0:3] == en);
endsequence
有两个操作符,第一个implication蕴含
表示:如果property中左边的先行算子成立,那么右边的后续算子才会被计算
如果先行算子antecedent不成功,整个属性就默认被认为成功,这是空成功vacuous success
只能在property中定义,不能在seq中定义
分类
-
交叠蕴含overlapped implication
- 符号是|→
- 如果条件满足,则评估后续算子序列;如果不满足,表现为空成功,不执行后续算子
property p_req_ack; @(posedge clk) mem_en |-> (req ##2 ack); endproperty
-
非交叠蕴含noi
- 符号是|=→
- 如果条件满足,则在下一周期评估后续算子序列;如果不满足则同上
sequence序列
##周期延迟符号
##n表示在n个clk后
##0表示在当前周期,即交叠周期,相当于逻辑与&&
sequence a_b
@(posedge clk) a ##1 b;
endsequence
##[min:max]范围内clk延迟
min和max必须是非负数,seq会在从min到max时间窗口中最早的时间来匹配?
在1个clk就出现b,则后面的clk就不会看了,最早的意思就是这样
sequence a_b
@(posedge clk) a ##[1:5] b;
endsequence
$无穷大的周期
将max换成$,增大仿真评估序列的负担,不推荐
[*]重复操作事件
n非负数,不能为$
表示b必须在两个连续的clk为真
sequence a_b
@(posedge clk) a ##1 b[*2];
endsequence
如果是[*2:5],表示b必须在2-5个连续clk为真(相当于逻辑或)
a[*0]表示没有在任何正数clk内有效:如果a不满足,则忽略了,继续找b和c等其他事件
a[*0:3] ##1 b表示:b、a ##1 b、a ##1 a ##1 b、a ##1 a ##1 a ##1 b
[=m]表示一个时间的连续性
需要重复发生m次,但不用在连续的clk发生
例如在实战1中的burst read测试,期望读的data和ack信号在接下来的4个clk内返回,但是不需要连续4个clk
[=m:n]表示从最小m到最大n的非连续clk
and表示两个seq需要保持匹配
SEQ1 and SEQ2
- 两个seq的满足时间可以不同,SEQ1先满足,等待SEQ2满足时,and满足
and左右可以是信号
intersect要求匹配时刻在同一个clk
和and类似,区别在于两个seq时序要在同一个clk内匹配
or表示两个seq至少需要一个满足
SEQ1 or SEQ2,逻辑或||
- 两个seq在同一时刻触发,最终满足至少其中一个
- 每个seq的结束时间可以不同,结束时间以晚结束的seq为准
对于and和or的应用:如果burst write的长度为4,则写的长度可以为1、2或4
property burstlengthvalid
@(posedge clk) disable iff(!rst)
((burstlen==4) |-> (wrlen--1) or (wrlen==2) or (wrlen==4))
endproperty
assert property (bustlengthvalid)
first_match表示从多次满足的序列中选择第一次满足的时刻,放弃其他时刻
sequence t1;
te1 ## [2:5] te2;//2-5次te2,共4种情况
endsequence
sequence ts1;
first_match (te1 ## [2:5] te2);//上述4种情况中的第一次匹配的时刻
endsequence
sequence t2;
(a ## [2:3] b) or (c ## [1:2] b);
endsequence
sequence ts2;
first_match(t2);
endsequence
每一次PCI总线进入idle时状态机也应该返回idle,所以时序要求frame和irdy信号保持至少两个clk以上为高时系统状态为idle
sequence checkbusidle
(## [2:$] (frame && irdy));//宁可写成100也不要$
endsequence
property first_match_idle
@(posedge clk) first_match (checkbusidle) |-> (state==busidle);
endproperty
throughout检查一个信号或表达式在贯穿一个seq时是否满足要求
Sig1/Exp1 throughout Seq,左边和右边不一样
在burst模式信号拉低后2个clk时,irdy/trdy要连续7个clk保持为低,同时burst模式信号在这连续的clk中也为低。(也就是burst模式信号至少比右边seq的时间还要长)
sequence burst_rule1;
@(posedge mclk)
$fell (burst_mode) ##0//看做一个seq:burst_mode在这一拍拉低了
(!burst_mode) throughout (##2 ((trdy==0) && (irdy==0)) [*7]);
endsequence
within检查一个seq与另一个seq在部分clk长度上的重叠
SEQ1 within SEQ2,当seq1满足在seq2的一部分连续clk内成立,则表达式成立
trdy需要再irday下拉的1个clk后保持7个clk为低,同时irday也将保持8个clk为低:
!trdy[*7] within (($fell irdy) ##1 !irdy [*8])
.ended检查序列的重点
SEQ.ended
在某一时刻序列抵达终点,则条件满足
sequence e1;
@(posedge sysclk) $rose(ready) ##1 proc1 ##1 proc2;
endsequence
//在inst为高的下一个clk,e1应该结束或者已经结束
sequence rule;
@(posedge sysclk) reset ##1 inst ##1 e1.ended ##1 branch_back;
endsequence
sequence arbseq (aFell, bRose);
@(posedge clk) $fell(aFell) ##1
$rose(bRose);
endsequence
property endcycle;
@(posedge clk) $rose(c) |=> arbseq(a,b).ended;
endproperty
//这个property是不满足的,因为是在c拉高的时刻才开始这个property,a至少要在下个clk拉低
$rose(c) && $fell(a) |=> $rose(b)
局部变量
可以在sequence或者property中使用,会伴随他们动态创建
每一个sequence实例都会有它自己的变量拷贝
sequence rs_cache_done
##[1:5] rdDone;
endsequence
//在cache rdDone拉高后读出的rdData会在2个clk后,在其基础上加1,并作为wrData写入
sequence check_reg_wr_data;
int local_data;//局部变量
(rs_cache_done, local_data==cache_rd_data) ##2 (reg_wr_data == (local_data+1));
endsequence
property checkreadidack;
int loc_id;
//read拉高,伴随readid,下一次read必须在这一次read对应的readack返回之后才可以发起,用局部变量来存储
($rose(read), loc_id=readid) |=>//满足序列后执行逗号后的表达式
not ($rose(read) && readid==loc_id) ##0 ($rose(readack) && readackid==loc_id);
endproperty
//先满足($rose(readack) && readackid==loc_id)
//not ($rose(read) && readid==loc_id)没有相同readid的read发起
//##0 表示逻辑与
调用方法
序列匹配时可以调用task,void function、系统函数
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));
系统函数用来访问指定类型的变量采样:访问当前和上一个周期采样值,检测采样变量的变化
$rose(expression[, clocking_event])
$fell(expression[, clocking_event])
//与上一个采样周期相比,变量最低位是否跳变为1或0,满足则返回1,否则返回0
//clocking_event在sequence中不需要单独提供,一般会指定采样clk
$stable(expression[, clocking_event])
//表示在连续两个clk内表达式的值保持不变,满足则返回1,否则返回0
$past(expr[, num_cycles][, gating_expr][, clocking_event])
//访问在过去若干个采样周期前的数值,默认num_cycle为1,采样1个clk前的数值
property reqcauseack;
@(posedge clk) $rose(ack) |-> $past(req, 2);
endproperty
//在ack拉高时的前两个clkreq应该为高
property cache_read_chk;
@(posedge clk) (state==CACHE_READ) |-> ($past(state) != CACHE_MISS);
endproperty
//如果当前是CACHE_READ,则上一个状态不应该是miss
$rose fell stable可以在过程块语句和连续赋值中使用
always @(posedge clk)
testdone<=stimulus_over & $rose(unit_done);
always @(posedge clk) begin
if($stable(my_sig)) begin $display(); end
end
assign intr_cleared=$fell(intr, @(posedge clk));//class里面能不能指定clk
assign intr_set=$rose(intr, @posedge clk);
系统函数也可以在seq,pro,assertion中使用
$countbits(expression, control_bit)计算expression中匹配control_bit数值的位数
$countones相当于$countbits(expression, ‘1)
$onehot(expression)相当于$countbits(expression, ‘1)==1
$isunknown(expression)相当于$countbits(expression, ‘x, ‘z)!=0
$assertoff(level, [list of module, instance or assertion_identifier]);
$assertkill(level, [list of module, instance or assertion_identifier]);
$asserton(level, [list of module, instance or assertion_identifier]);
level=0表示当前模块或者层次下所有assertion,level=n表示当前模块或层次下n层范围中的assertion
identifier表示property的名字或者assertion的label
module assert_control();
initial begin
@(negedge top_tb.reset_n) $display();
$assertoff(0, top_tb.cpu_inst1);
@(posedge top_tb.reset_n) $display();
$asserton(0, top_tb.cpu_inst1);
end
endmodule
//在reset阶段停止所有assertion,复位之后开启