断言简介
- 用来检查特定条件或事件序列的出现情况;提供断言覆盖率。
- 分为立即断言和并行断言。
立即断言
很“立即”,直接assert就完事了,比如:
always@(posedge clk) assert (a && b);
检测时钟上升沿到来的时候a和b是不是同时为高。
并发断言
检查跨越多个时钟周期的时间序列,仅在有时钟周期的情况下出现,有关键词 property。长下面这样:
property name;
......
endproperty
a_assert: assert property(name);
立即断言和并发断言的区别
在过程化代码 (initial/program/function/task) 中使用的 assert,其中没有任何时序概念的为立即断言。并发断言是一种基于周期的语法结构,需要采样事件去激发周期性的数值采样,为此对同步时序电路比较有效。区别并发断言和立即断言的关键字是 property 。
断言常见语法
$rose
和$fell
分别指拉高和拉低信号(注意是拉,不是为高)。$isunknown
指某个信号不能为随机态。$stable
指信号保持稳定。$past
指采样过去周期的值(之前的文章里举过栗子了)。- |-> :交叠蕴含,当前这个上升沿进行检查。
- |=>:非交叠蕴含,下一个上升沿进行检查。相当于 |-> ## 1。
重复操作符
- ##:延长多少个周期。
- ##[m:n]:在 m:n 的周期内。
- ##[1:$]:表示 1 到最大一个时间周期。
- [*n]:表示重复 n 个周期。
- [*m:n]:表示一段时间范围的重复。
- [=m:n]:表示 m:n 范围内事件的重复发生,不要求连续。
- [->m]:这个也举个栗子吧(因为不会讲了…)
@(posedge clk) a |-> ##1 b[->3] ##1 c;
意思是 a 为高的下一个上升沿,b 在接下来要有 3 个上升沿为高,而且不一定要连续,但是在 c 为高的前一个上升沿 b 是刚好完成最后一次匹配。
APB总线协议的断言检查的栗子
APB时序图
Write transfer
- psel为高时,paddr不可以为x值
property psel_no_x;
@(posedge clk) psel |-> not ($isunknown(paddr));
endproperty: psel_no_x
a_1: assert property(psel_no_x);
- psel拉高的下一周期,penable必须拉高
property psel_rose_then_penable_rose;
@(posedge) $rose(psel) ##1 $rose(penable);
endproperty: psel_rose_then_penable_rose
a_2: assert property(psel_rose_then_penable_rose);
(上面这两个栗子就能看出来拉高和为高的区别了)
- penable拉高的下一个周期,penable应该拉低
property penable_rose_next_cycle_fell;
@(posedge clk) $rose(penable) ##1 $fell(penable);
endproperty
a_3: assert property(penable_high_then_low);
- psel和pwrite同时保持高时,pwdata需要保持不变
property pwdata_stable_during_trans_phase;
@(posedge clk) ((plse && !penable) ##1 (psel && penabel) ) |-> $stable(pwdata);
endproperty
a_4: assert property(pwdata_stable_during_trans_phase);
- 在下次传输开始前,paddr和pwrite信号应该保持不变
property paddr_stable_until_next_trans;
logic[31:0] addr1, addr2;
@(posedge clk) first_match(($rose(penable),addr1=paddr) ##1 ((psel && !penable)[=1],addr2=$past(paddr))) |-> addr1 == addr2;
endproperty: paddr_stable_until_next_trans
a_5: assert property(paddr_stable_until_next_trans);
property pwrite_stable_until_next_trans;
logic pwrite1, pwrite2;
@(posedge clk) first_match(($rose(penable),pwrite1=pwrite) ##1 ((psel && !penable)[=1],pwrite2=$past(pwrite))) |-> pwrite1 == pwrite2;
endproperty: pwrite_stable_until_next_trans
a_5: assert property(pwrite_stable_until_next_trans);
Read transfer
- 在penable拉高的同一个周期,prdata也应该发生变化
property prdata_available_once_penable_rose;
@(posedge clk) $rose(penable) && !pwrite |-> !$stable(prdata);
endproperty: prdata_available_once_penable_rose
a_6: assert property(prdata_available_once_penable_rose);