一言以蔽之:断言是设计属性的描述。
如果一个在模拟中被检查的属性(property)不像我们期望的那样表现,那么这个断言失败。
如果一个被禁止在设计中出现的属性在模拟过程中发生,那么这个断言失败。
一系列的属性可以从设计的功能描述中推知,并且被转换成断言。这些断言能在功能的模拟中不断地被监视,从而可以得知设计的功能是否正确。
SV断言可以作为checker检查DUT中某些电路的正确性,SV断言可以收集DUT中某些行为,即收集功能覆盖率;
断言是一个“观测员”,它可以观测程序的状态,但它不会改变代码本身。
SystemVerilog集成了断言并且能够将它们与设计余下的部分或验证代码紧密地结合起。SystemVerilog断言的一一个主要特点就是它们是语言本身的组成部分。这也就意味着我们可以将它们与其它语言结构内联使用,而不需要产生特殊的程序及其它类似的限制。另外,SystemVerilog中的断言还可以用来提供功能覆盖。
SystemVerilog具有两种类型的断言并发断言和即时断言。
即时断言就像过程块中的一条语句一 样执行。
基于模拟事件的语义。测试表达式的求值就像在过程块中的其他Verilog的表达式一样。它们本质不是时序相关的,而且立即被求值。必须放在过程块的定义中。
只能用于动态模拟。
并发断言:
基于时钟周期
在时钟边缘根据调用的变量的采样值计算测试表达式
变量的采样在预备阶段完成,而表达式的计算在调度器的观察阶段完成
可以被放到过程块(procedural block)、模块(module)、 接口(interface), 或者一个程序(program)的定义中。
序列由sequence… endsequence声明
功能特性经常由有序的行为构建,sequence功能提供了一种能力来构建和处理有序的行为。
在一系列的布尔逻辑表达式中,如果每个布尔表达式的计算都为真,那么关于这个序列的断言为真,否则为假。
sequence s1;//无参数
@(posedge clk) a ##1 b ##1 c;//##1指的是延时一个周期
endsequence//上面的意思是先a是1,一个周期后b是1,一个周期c是1
sequence s2(data,en);//带参数
@(posedge clk)(!a && (data == data_bus) ##1 c[0:3] == en )
endsequence
SVA也内嵌了边缘表达式,以便用户监视信号值从一个时钟周期到另一时钟周期的跳变。这使得用户能检查边沿敏感的信号。(前后信号不一致才是属于跳变)
$rose(boolean expression or signal name):当信号/表达式为1时返回真。
$fell(boolean expression or signal_ name):当信号/表达式为0时返回真。
$stable(boolean"expression or signal_ name):当信号/表达式不发生变化时返回真。
时钟关系的序列
很多时候,我们关心的是检查需要几个时钟周期才能完成的事件。也就是所谓的“时序检查”。在SVA中,时钟周期延迟用"#" 来表示。例如,#3表示3个时钟周期。举个例子:
sequence s1;
@(posedge clk) a ##2 b;
endsequence
序列s4检查信号"a"在一一个给定的时钟上升沿是否为高电平:
如果信号"a"不是高电平,序列失败,断言失败。
如果信号"a"在任何一一个给定的时钟上升沿为高电平,信号"b” 在两个时钟周期后为高电平,则断言成功。
如果信号"a"在任何一一个给定的时钟上升沿为高电平,信号"b" 在两个时钟周期后为不为高电平,断言失败。
在仿真后结果显示中,成功的序列总是标注在序列开始的位置
许多序列可以有序地组合起来生成更复杂的序列。SVA 提供了一个关键词"property" 来表示这些复杂的有序行为。属性(property)的基本语法是:
property name_ of_ property;
; or
;
endproperty
属性是在模拟过程中被验证的单元。它必须在模拟过程中被断言来发挥作用。 SVA提供了关键"assert"来检查属性。断言(assert)的基本语法是:
assertion_ name: assert property (property_ name);
arb为带形参的属性,通过形参可以重用一些常用的属性,假设a b c d四个信号是相似设备上,相同功能的信号,那么通过形参重用属性arb是一个不错的选择。
定义一个序列并不能发挥作用,它必须被断言才能发挥作用。例如:
上例中在序列s5中指定了时钟。SVA在序列、 属性,甚至一个断言的语句中都可以定义时钟。例如:
通常情况下,在属性(property)的定义中指定时钟,并保持通常情况下,在属性(property)的定义中指定时钟,并保持可以提高基本序列定义的可重用性。在sequence描述行为,在property描述时钟;
属性可以禁止发生,即我们期望属性永远为假,永远不要为真,当属性为真时,断言失败。
序列s6检查当信号"a"在给定的时钟上升沿为高电平,那么两个时钟周期以后,信号"b"不允许是高电平。关键词"not" 用来表示属性应该永远不为真。
SystemVerilog 语言被定义成每当一个断言检查失败,模拟器在默认情况下都会打印出一条错误信息。模拟器不需要对成功的断言打印任何东西。读者同样可以打印自定义自定义的成功或失败信息。
断言有可选的 then 和 else 分句,可以定制你自己的输出消息,例如创建一个定制的错误消息:
u_assert: assert(u_bus.u_clocking.grant==2'b01)
grants_rec++; //成功则运行这句
else
$error("grant not asserted !"); //否则输出错误信息
对于@(posedge clk) a #2 b这样的属性,它在每个时钟上升沿检查信号"a" 是否为高。寻找是否为一个断言的有效开始。
如果信号"a"在给定的任何时钟上升沿不为高,检验器将产生一个错误信息。这并不是一个有效的错误信息因为我们不只关心a,更加关心a和b的关系。这个错误只表明这个时钟周期没有得到有效起始点。它们会在一段时间内产生大量的错误信息。
基于以上问题,SVA提供了蕴含操作。
蕴含等效于一个if-then结构。蕴含的左边叫作“先行算子”,右边叫作"后续算子”。当先行算子成功时,后续算子才会被计算。如果先行算子不成功,那么整个属性就默认地被认为成功。这叫作"空成功”
蕴含结构只能被用在属性定义中,不能在序列中使用。
蕴含分为两类:交叠蕴含和非交叠蕴含。
交叠蕴含用符号"|->” 表示。如果先行算子匹配,在同一个时钟周期计算后续算子表达式。例如:
当信号"a" 为高,而且信号"b" 在同一个时钟沿也为高,这是一个真正的成功。若信号"a"不为高,断言默认自动成功,称为空成功。信号"a" 为高且,并且在同一个时钟沿信号"b" 未能检测为有效的高电平,则断言失败。
非交叠蕴含用符号(“I=>”)表示。如果先行算子匹配,那么在下一个时钟周期计算后续算子表达式。后续算子表达式的计算总是有一个时钟周期的延迟。 例如:
蕴含操作
SVA允许使用嵌套的蕴含。当我们有多个门限条件指向一个最终的后续算子时,这种构造十分有用。例如:
.上例中,如果不使用f…else,那么需要使用三个独立的属性来实现。
SVA的延迟可以支持固定的正延迟,也可以支持一个时间窗口。例如:
p12先行算子在任何给定的时钟上升沿为真,那么在接下去的1~3周期内,信号"c" 应该至少在一个时钟周期为高,SVA允许使用时序窗口来匹配后续算子。时序窗口表达式左手边的值必须小于右手边的值。每声明一个时序窗口,就会在每个时钟沿上触发多个线程来检查所有可能的成功。p12 实际上展开了三个线程。
如下例所示,后续算子时序窗口中,左边最小值为0,表示后续算子在先行算子成功的同一个时钟沿开始计算。
默认情况下,多重sequence的组合是以sequence的起始时间作为同步标志的,就是以序列的起始点作为同步点,来组合成时间上连续的检查。
SVA提供ended结构以sequence的结束时间作为序列同步点。关键字ended存储一 个反映在指定时钟处序列是否匹配成功的布尔值。
ended代表匹配的完成,是匹配的结束点,而不是匹配的起点。
默认情况下,多重sequence的组合是以sequence的起始时间作为同步标志的,就是以序列的起始点作点作为同步点,来组合成时间上连续的检查。SVA 还提供了另一种使用序列的结束点作为同步点的连接机制。
使用true表达式,可以在时间上延长SVA检验器。这代表一种忽略的状态,它使得序列延长了几个时钟周期。这可以用来实现同时监视多个属性且需要同时成功的复杂协议。
与断言a18比较,断言a18_ ext 的起始点被推迟了-一个时钟周期。
SVA提供了一个内嵌的系统任务"$past", 它可以得到信号在几个时钟周期之前的值。在默认情况下,它提供信号在前一个时钟周期的值。结构的基本语法如下:
$past (signal name, number of clock cycles)
这个任务能够有效地验证设计到达当前时钟周期的状态所采用的通路是正确的。
只有当控制信号’'e"在任意给定的时钟上升沿有效时检验才被激活。
如下断言代码用例检查c连续或间断之后3次和4次为高的断言,波形如下面图所示:
property syp_test_2;
@(posedge clk_zy) disable iff(~en)
$rose(a) |-> b throughout c[->3] ;
endproperty
sva_test_2: assert property(syp_test_2);
property syp_test_2_1;
@(posedge clk_zy) disable iff(~en)
$rose(a) |-> b throughout c[->4] ;
endproperty
sva_test_2_1: assert property(syp_test_2_1);
下面这个断言代码等待c 2个时钟周期为高后又过1个时钟周期检查d是否为高,波形如下面所属,可以看到第一次检查失败了,后面2次检查都成功了;
property syp_test_4_1;
@(posedge clk_zy) disable iff(~en)
$rose(a) |-> b throughout c[->2] ##1 d;
endproperty
sva_test_4_1: assert property(syp_test_4_1);
本文部分资料参考来源网络,以示致谢,如有侵权,请联系本人!
《SystemVerilog Assertion 设计、调试、测试总结(1)》
————————————————
版权声明:本文为CSDN博主「龙卷风席卷停车场」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/xiyieba/article/details/106797416