SVA
文章目录
概述
断言是设计的属性的描述,主要用于验证设计的行为。此外,断言可以用来提供功能覆盖,并标记输入激励,用于验证不符合假设的要求。
- 如果一个在模拟中被检查的属(property)不像我们期望的那样表现,那么这个断言失败。
- 如果一个被禁止在设计中出现的属性在模拟过程中发生,那么这个断言失败。
即时断言
即时断言(immediate assertions)
- 基于模拟事件的语义。
- 测试表达式的求值就像在过程块中的其他Verilog的表达式一样。
- 它们本质不是时序相关的,而且立即被求值。
- 必须放在过程块的定义中。
- 只能用于动态模拟
当语句在过程块中被执行时,即时断言语句是对被执行表达式的测试。该表达式是非时态的,可以理解为与程序中if语句的条件下的表达式相同。换句话说,如果表达式计算结果是X、Z或0,那么它被解释为错误,断言语句被认为失败。否则,表达式将被解释为真,断言语句被认为通过,或者等效地,成功。
always_comb
begin
a_ia: assert (a && b); //当信号a或信号b发生变化时,always块被执行
end
并发断言
并发断言(concurrent assertions)
-
基于时钟周期。
-
在时钟边缘根据调用的变量的采样值计算测试表达式。
-
变量的采样在预备阶段完成,而表达式的计算在调度器的观察阶段完成。
-
可以被放到过程块(procedural block)、模块(module)、接口(interface),或者一个程序(program)的定义中。
-
可以在静态(形式的)验证和动态验证(模拟)工具中使用。
a_cc: assert property(@(posedge clk) not(a && b));
SystemVerilog断言的目标之一是为断言提供一个通用语义,以便它们可以用于驱动各种设计和验证工具。例如形式化验证工具,使用基于周期的语义来计算电路描述,通常依赖于一个或多个时钟信号来驱动电路的计算。任何时钟边沿之间的计时或事件行为都被提取出来。并发断言包含这个时钟语义。虽然这种方法通常简化了电路描述的计算,但在许多场景中,这种基于周期的计算提供了不同于SystemVerilog基于事件计算标准的行为。
在形式化验证中,一般只采用并发断言,因此以下内容只介绍并发断言。
区别即时断言和并发断言的关键词是”property“。
SVA语法
一条SVA并发断言可以看成是由四种不同层次的结构组成:
- 布尔表达式(booleans)
- 序列(sequence)
- 属性(property)
- 断言声明(assertion statements)
布尔表达式是构成SVA的最基本单元。其一般形式为标准的SystemVerilog的布尔表达式,它由信号及其逻辑关系运算符构成,用以表示某个逻辑事件的发生
序列 sequence
序列是布尔表达式在时间上的组合
SVA用关键词“sequence”来表示这些事件。
序列(sequence)的基本语法是:
sequence name_of_sequence;
<test expression>;
endsequence
eg:
sequence s1
@(posedge clk) a;
endsequence
序列s1检查信号“a”在每个时钟上升沿都为高电平。如果信号“a”在任何一个时钟上升沿不为高电平,断言将失败。这相当于“a == 1’b1”。
SVA提供带有边沿检测的原语序列用于监控边沿变化:
- $rose(boolean expression or signal_name):当信号的LSB从低变为高时返回真。
- $fell(boolean expression or signal_name):当信号的LSB从高变为低时返回真。
- $stable(boolean expression or signal_name):信号不发生变化时返回真
sequence s2;
@(posedge clk) $rose(a);
endsequence
s2将在每个时钟上升沿检查a是否跳变为1
序列可通过带有形式参数的参数列表进行复用。设计中的一些公共属性(如独热码状态机,奇偶校验等)可设置带参数的序列库进行重用。
equence s3_lib(a,b);
a||b;
endsequence
#s3_lib可复用在任何两个信号中
sequence s3_lib_inst1;
s3_lib(req1,req2);
endsequence
跨时钟周期的序列
在SVA中,时钟延迟用符号“##”表示。##3代表三个时钟周期。
sequence s4;
@(posedge clk) a ##2 b;
endsequence
s4在每个时钟沿检测a是否为高,若是则检测两个时钟周期后b是否为高,若是则断言成功
属性 property
属性是在仿真或者形式验证中被验证的单元。属性将序列通过逻辑或者有序地组合起来生成更复杂的序列,SVA提供关键词“property”来表达这些复杂的有序行为。其语法为:
property name_of_property;
<test expression>;or
<complex sequence expressions>;
endproperty
SVA在仿真过程中,sequence和property本身是不做任何事的,要想是他们有效,必须通过assert进行声明。 SVA时钟可以在sequence,property甚至assert中进行定义,但应注意: 时钟最好在property中进行定义而不要在sequence中定义,从而保证sequence的独立性,也方便复用。 可以在assert中同时定义时钟和使用sequence,但不允许同时定义时钟和使用property
断言 assert
断言基本语法:
assertion_name: assert property (property_name);
sequence s5a;
a ##2 b;
endsequence
property p5;
@(posedge clk) s5;
endproperty
a5: assert property (p5);
禁止属性的定义
关键词"not"用来表示属性应该永远不为真。
sequence s6;
@(posedge clk) a ##2 b;
endsequence
property p6;
not s6;
endproperty
a6: assert property (p6);
例中若在某时钟沿a为高点平,且两个时钟后b为高电平则断言失败,否则断言成功。
SVA执行块
systemverilog语言被定义成每当一个断言失败,模拟器在默认情况下都会打印出一条错误信息。模拟器不需要对成功的断言打印任何东西,当然我们可以自定义打印的成功或失败的信息。
property p7;
@(posedge clk) a ##2 b;
endproperty
a7 : assert property(p7)
$display("property p7 ok");
else
$display("property p7 failed");
蕴含操作符
上述断言中,SVA会在每个时钟沿进行检测,若不符合情况则断言失败,但有时往往关注某信号发生变化后的时序关系,这将导致大量并非我们所关心的断言失败情况产生。为避免这种情况,SVA引入蕴含操作符(Implication)来起一个门控作用。
蕴含操作符类似于if-then结构。蕴含操作符左侧称之为先验部分(antecedent),右侧称之为后验结果(consequent)。若先验部分验证成功,后验结果才进行检查,否则若先验部分验证失败,则认为是“伪成功”。蕴含操作符用于property中,不可用于sequence中!
蕴含操作符包含:交叠蕴含操作符和非交叠蕴含操作符
交叠蕴含操作符(Overlapped implication)
交叠蕴含操作符符号为 |->
交叠蕴含操作符中,若先验部分验证成功,则后验结果在同一时钟进行验证。如下例所示,若某时钟处a变为高电平,则同一时刻b也应为高电平。
property p8;
@(posedge clk) a |-> b
endproperty
a8:assert property (p8);
非交叠蕴含操作符(Overlapped implication)
非交叠蕴含操作符符号为|=>
非交叠蕴含操作符在先验部分验证匹配后,在下个时钟沿才进行后验部分的检查匹配。相对于蕴含操作符后验部分有一个时钟的滞后。如下例所示,在时钟边沿a为高电平则一个时钟后b也应为高电平。
property p9;
@(posedge clk) a |=> b;
endporperty
a9:assert property(p9);
后续算子带固定延迟的蕴含
property p10;
@(posedge clk) a |-> ##2 b;
endporperty
a10 : assert property(p10);
使用序列最为先行算子的蕴含
sequence s11a;
@(posedge clk) (a&&b) ##1 c;
endsequence
sequence s11b;
@(posedge clk) ##2 !d;
endsequence
property p11;
s11a |-> s11b;
endproperty
a11:assert property(p11)
SVA时序窗口
之前示例中时钟延时往往是固定格式的,SVA允许时间窗的引入,其表示形式为##[minperiod : max_period],表示后续部分在min_period到max_period个时钟周期内验证成功则断言通过。示例如下:
property p12;
@(posedge clk) a && b |-> ##[1:3] c;
endproperty
a12: assert property(p12);
上述断言在时钟沿处若a和b同时为高,则在1至3个时钟周期内c应为高电平。
延时时间上线可以设置为$表示不设上限,将一直检测到断言成功或仿真结束为止 。
property p12;
@(posedge clk) a&&b |-> ##[1:$] c;
endproperty
a12: assert property(p12);
SVA ended
默认情况下,多重sequence的组合是以个sequence的起始时间作为同步标志的,SVA提供ended结构以sequence的结束时间作为序列同步点。ended的用法如下:
sequence_name.ended
若使用ended,则sequence必须定义时钟。关键字ended存储一个反映在指定时钟处序列是否匹配成功的布尔值。该布尔值尽在同一时钟内有效。
sequence s1;
@(posedge clk) a ##1 b;
endsequence
sequence s2;
@(posedge clk) c ##1 d;
endsequence
property p1;
s1|=>s2; //s1的成功匹配点滞后一时钟周期是s2匹配的起点
endproperty
property p2;
s1|=>##1 s2.ended; //s1成功匹配点滞后两个时钟周期是s2成功匹配点,即s1匹配成功则再过两个时钟周期s2必须匹配成功
endproperty
property p3;
s1.ended|=>s2; //s1的成功匹配点滞后一时钟周期是s2匹配的起点
endproperty
property p4;
s1.ended|=> ##1 s2.ended;//s1成功匹配点滞后两个时钟周期是s2成功匹配点,即s1匹配成功则再过两个时钟周期s2必须匹配成功
endproperty
SVA参数(parameter)列表
SVA允许在sequence或property中使用parameter参数以重定义或适用于不同的场景。
module generic_chk(input logic a,b,clk);
parameter delay=1;
property p16;
@(posedge clk) a|->##delay b;
endproperty
a16:assert property(p16);
endmodule
module top();
logic a,b,c,d;
generic_chk #(.delay(2))i1(input logic a,b,clk);
generic_chk i2(input logic c,d,clk);
endmodule
选择运算符
property p17;
@(posedge clk) c ? d==a : d==b;
endporperty
p17在上升沿检测c点评,为高时判定d是否等于a,为低时判定d是否等于b。
真值表达式
真值表达式: ture (需自己定义
defien true 1)
使用true表达式,可以在时间上延长SVA检验器,能够使序列的结束点延长一个时钟周期,这可以用来实现同步检测多个属性且需要同时成功检测的复杂协议。
`ddefine true 1
sequence s18a;
@(posedge clk) a ##1 b;
endsequence
sequence s18a_ext;
@(posedge clk) a ##1 b ##1 `true;
endsequence;
sequence s18b;
@(posedge clk) c ##1 d;
endsequence;
property p18;
s18a.ended |-> ##2 s18b.ended;
endproperty
property p18_ext;
s18a_ext.ended |=> s18b.ended;
endproperty
a18 : assert property(p18);
a18_ext: assert property(p18_ext);
前向检测$past
SVA提供内建任务$past用于获取之前时钟沿某处的值。其原语为:
$past(signalname,numberof_clock_cycles)
默认缺省情况下,SVA提供前一个时钟沿处的信号值。
property p19;
@(posedge clk) (c && d) |-> ($past((a && b), 2)==1);
endproperty;
a19:assert property(p19);
a19检测在时钟沿处若c和d同时为1,则在前溯第二个时钟沿处a&&b应为1。
$past允许使用带有时钟门控信号的检测匹配。
$past(signal_name,number_of_clock_cycles,gating_signal);
property p20;
@(posedge clk) (c&&d)|->($past((a&&b),2,enable)==1);
endproperty
a20:assert property(p20);
a20同a19类似,不过若c和d同时为1,则前溯第二个时钟沿处使能信号enable必须为高且a和b必须为高。