简介
断言通常被称为序列监视器或者序列检验器,是对设计应当如何执行特定行为的描述,是一种嵌入设计检查。如果检查的属性(property)不是我们期望的表现,那么在我们期望事件序列的故障上会产生警告或者错误提示。
断言用来检查模拟序列行为或者激励生成的正确性,断言作为功能验证的一种重要手段,可以脱离测试用例而覆盖测试点,所以断言覆盖率可以是功能覆盖率的一部分,完善的断言能为全面的功能覆盖率尺度打下良好的基础。
断言两个重要的时间点:采样时刻和匹配时刻,断言在 preponed 域采样,在observed 域执行检查。如下图所示:
断言可以分为多个层面,包括:
- 设计层面:设计意图相关的断言;
- 接口层面:模块接口相关断言、芯片功能意图相关断言、芯片接口相关断言;
- 性能层面:读取的缓存延迟、数据包处理延迟。如果超过设计时限则请求断言。
断言的两种类型
即时断言(immediate assertions)
在当前时刻断定信号的数值情况。例如
asser_inst:assert (foo) $display("pass");else $display("failed"); //名字:assert(判断语句)若真执行语句1,否则执行语句2
并发断言(concyrrent assertions)
- 在多个周期内断定序列顺序;
- 并发断言是检查跨越多个时钟周期的事件序列;
- 仅在有时钟周期的情况下出现;
- 测试表达式是基于所涉及的采样值在时钟边缘计算的;
- 可以放在过程块、模块、接口或程序定义中;
- 区别并发断言和即时断言的关键字是property;
例如:
断言的基本语法
延时运算符
例:a ##3 b
含义是 a 有效后的第 3 拍(a 有效当拍为第 0 拍),b 也有效。如果 b 在第 3 拍未能有效,则序列匹配失败,如下图所示:
a ##[m:n] b,例如a ##[2:4] b意味着a有效后的第2拍到第4拍之间b有效至少一次则序列匹配成功。
例子:波形为a ##3 b ##0 c,a ##3 b在120ns匹配成功,当拍a ##3 b ##0 c也匹配成功,因为120ns也是c的起点。
连续重复运算符
例1:a[*3],含义是a连续为1重复3拍,即a ##1 a ##1 a,如图所示:
例2:(a ##1 b)[*3],这个序列等同于(a ##1 b) ##1 (a ##1 b) ##1 (a ##1 b) ,如图所示:
例3:a [*m:n] b,如a[*2:4]含义为a信号重复2~4拍后b信号有效均可匹配成功,等同于a [*2] b or a [*3] b or a[*4] b。
非连续跟随重复符
如a [->3],或者叫go-to重复符。含义是a非连续重复3次,只在第3次重复时刻点匹配(跟随的含义)。
例1:a ##1 b[->3] ##1 c,该序列表示在a有效之后,c有效之前,b应该有效3次且最后一次有效的时间应当恰好比c有效早1拍(跟随性),如下图所示:
例2:a [->m:n],对于序列a ##1 b[->2:3] ##1 c,即a重复2次或者3次时均匹配成功,以下两个波形都匹配成功。
非连续(无需跟随)重复操作符
例1:a [=3],含义是a无所谓连续不连续,重复了3次即匹配成功了。波形理解,图中标蓝的点都是匹配成功的点(无需跟随)
而**a[->3]**匹配成功的点,只有一个(跟随)
例2:a ##1 b[=3] ##1 c,对于该序列,以下波形可以匹配成功,注意c无需跟随b[=3]。
and运算符
and运算符用来连接两个事件(多为序列),当两个事件均成功时匹配成功,需要注意的是两个事件必须有相同的起始点,但是可以有不同的结束点。
or运算符
or运算符用来连接两个事件(多为序列),当两个事件任一匹配成功则整体成功,与|的区别和之前类似,or可以连接两个表达式或是两个序列,|只能连接两个表达式
intersect运算符
intersect和and有些类似,均为连接两个事件,两个事件均成功整个匹配才成功。不过intersect多了一个条件,那就是两个事件必须在同一时刻结束(and已经需要保证两个事件同一时刻开始了),换句话说a intersect b能匹配成功,a、b两个序列的长度必须相等。
例如,(a ##[1:2] b) intersect (c ##[2:3] d),如下图。图中黄色点为a ##[1:2] b匹配成功时刻点,蓝色为c ##[2:3] d匹配成功点,根据我们之前的分析,intersect连接的两个序列必须有同样的结束时刻,因此整个序列匹配的时间点一定在黄色和蓝色重合的点中。
within运算符
a within b的含义是在事件b(序列b)匹配期间,事件a(序列a)至少出现1次则匹配成功,否则失败。如(a ##1 b[=3]) within (c ##1 d[->1])。
throughout运算符
throughout运算符和intersect有些接近,区别在于throughout必须连接一个表达式和一个序列,即req throughout seq,含义是在seq匹配起始到结束期间,req都必须成立。例如a throughout (b ##1 c[->1])就要求从b有效开始,直到c第一次有效结束,这段期间a必须始终保持有效,如下波形图60ns~140ns就是一次典型的匹配成功。
SV的内建函数
$rose
$rose()函数即上升沿检测,匹配规则是信号的当拍值为1上拍数据为0。以$rose(a, clk1)为例,如下图所示:
$fell
$fell()函数和$rose函数刚好相反,是检测下降沿的
$change
$fell()函数和$rose函数的结合体,当拍采样值与上一拍不一致则匹配成功
$stable
$stable和$change刚好相反,信号当拍采样值与上一拍一样则匹配成功
$onehot(a)
任意时钟沿,表达式a都只有1bit为高
$onehot0(a)
任意时钟沿,表达式a都只有1bit为高或均为低电平
$isunkown(a)
任意时钟沿,表达式a任意位是否有X态或者Z态,如果有则匹配,没有X态或Z态则报错
$countones(a)
用于返回表达式中高电平的bit数量
蕴含算子
蕴含算子类似代码中的if语句。蕴含算子仅两个:|->和|=>,二者区别也很简单:
- a |-> b的含义是若a事件发生,则从当拍(##0)开始,检查b事件是否会有效(匹配),若b无法匹配则断言失败,若能匹配则成功。
- a |=> b和前者唯一的区别为:|=>是从下一拍(##1)开始检查,等同于a |-> ##1 b。