SV之Assertions 断言

SV之Assertions 断言目录 SV 中的断言 Buildingbloc 断言中的内建块 SVASequence 和 propertyImpl 关联操作 SVAbuiltinme 中的可变延时多时钟 Mul

SVA简介

SVA是systemverilog的一个子集,主要用来验证设计的行为,一条断言是嵌入的一条检查语句,可以在特定条件或事件序列的故障上生成警告或错误;断言一般跟在RTL代码后面,如下:

module ABC (); rtl 代码 SVA断言 endmodule //注意:不要将SVA写在enmodule外面

也可以将断言封装成一个module,然后通过 bind 的方式链接到不同的设计点中,格式如下:

bind rtl实例名 断言模块名 断言实例名(signal1,signal2...);

断言被用来:

(1)检查特定条件或事件序列的发生;

(2)提供功能覆盖(functional coverage),使用 cover 关键字 ;

存在两种断言:立即断言和并发断言;

(1)立即断言  Immediate Assertions–用的很少

立即断言在当前仿真时间检查条件,类似于if…else语句,但是断言带有控制.立即断言必须放在过程块定义中.

下面展示一个简单的断言:

assert (a && b )

SV之Assertions 断言

断言的格式如下:

assert(condition) $display(“Condition is True”); else $display(“Condition is False”); assert(condition) $display(“Condition is True”); assert(condition) $(“Condition is True”); else $fatal(“Condition is False”); assert(condition) else begin ……. ……. $fatal(“Condition is False”); end assert(condition) else $warning(“Condition is False”); //推荐使用的格式 label: assert(condition) $(“Condition is True”); else $warning(“Condition is False”);

如果断言失败,并且没有指定任何其他else子句,则默认情况下,该工具将调用$error;

(2)并发断言  Concurrent Assertions–与时序相关,常用

并发断言可以认为是一个连续运行的模块,为整个仿真过程检查信号,所以需要在并发断言内指定一个采样时钟。

需要指出的是:

  • 并发断言只有在时钟沿才会执行;
  • 可以在过程块、module、interface和program块内定义并发断言;

看下面例子:

c_assert: assert property(@(posedge clk) not(a && b)); //下面为通用格式 断言名:assert property (判断条件);

SVA的层次结构

SVA中可以存在内建的单元,这些单元可以是以下的几种: 

Boolean expressions 布尔表达式

布尔表达式是组成断言的最小单元,断言可以由多个逻辑事件组成,这些逻辑事件可以是简单的布尔表达式.在SVA中,信号或事件可以使用常用的操作符,如:&&, ||, !, ^,&

Sequence序列

sequence是布尔表达式更高一层的单元,一个sequence中可以包含若干个布尔表达式,同时在sequence中可以使用一些新的操作符,如 、重复操作符、序列操作符等;sequence的定义格式如下:

sequence name_of_sequence(参数列表); …… endsequence

Property 属性

property是比sequence更高一层的单元,也是构成断言最常用的模块,其中最重要的性质是可以在property中使用蕴含操作符(|-> |=>);property的定义格式如下:

property name_of_property(参数列表); 测试表达式或复杂的sequence; endproperty

property就是SVA中需要用来判定的部分,用来模拟过程中被验证的单元,它必须在模拟过程中被断言来发挥作用,SVA提供了关键字 assert 来检查属性,assert的基本语法是:

assertion_name: assert property(property_name) else $display("SVA error"); //else语句只有在断言失败时才会触发,可以不写

所以综上可以描述出创建一个断言的步骤

SV之Assertions 断言

property与sequence的相同和不同之处:

  1. 任何在sequence中的表达式都可以放到property中;
  2. 任何在property中的表达式也可以搬到sequence中,但是只有在property中才能使用蕴含操作符
  3. property中可以例化其他property和sequence,sequence中也可以调用其他的sequence,但是不能例化property;
  4. property需要用cover /assert/assume 等关键字进行实例化,而sequence直接调用即可;

序列sequence

在任何设计中,功能总是由多个逻辑事件的组合来表示,这些事件可以是简单的同一个时钟沿被求值得布尔表达式,也可以是经过几个时钟周期的求值事件,SVA用关键字 sequence来表示这些事件,sequence可以让断言易读,复用性高;

sequence具有如下特性:

  • 可带参数;
  • 可以在 property 中调用;
  • 可以使用局部变量;
  • 可以定义时钟周期;
  • 可以使用序列方法,如 ended、matched、triggered,这些序列方法只能在sequence中使用;

看个简单的例子:

SV之Assertions 断言

module asertion_ex; bit clk,a; always #5 clk = ~clk; //clock generation //generating 'a' initial begin a=1; #15 a=0; #10 a=1; #10 a=0; #10 a=1; #10; $finish; end //assertion sequence SVAsequence sequence seq_1; @(posedge clk) a==1; endsequence //calling assert property a_1: assert property(seq_1);//SVA 也就是说在断言的property中调用sequence //wave dump initial begin $dumpfile("dump.vcd"); $dumpvars; end endmodule

结果:

 SV之Assertions 断言

带逻辑关系的sequence

sequence seq_2; @(posedge clk) a || b;//如果a和b都为0,则断言失败 endsequence

带参数的sequence

sequence在定义时可以带形参,这样可以让sequence复用;看下面的例子:

sequence seq_lib (a, b) a || b ; endsequence //可以在一个sequence中调用另一个sequence sequence s_lib_inst seq_lib(req1,req2);//在当前sequence中调用 seq_lib endsequence

带时序关系的sequence 

在SVA中时钟延时用符号””来表示,如“2”表示延时两个时钟周期;看例子:

sequence seq; @(posedge clk) a 2 b; //在时钟上升沿到来是检查a是否为1,若不为1则断言失败 //若a为1,则检查两个周期之后b是否为1,若不为1,断言失败 endsequence

SV之Assertions 断言

请注意,sequence只有在时钟上升沿到来后检查a是否为1才会继续检查后面的b

也可以在property中调用sequence:

sequence seq; a 2 b; endsequence property p; @(posedge clk) seq; endproperty a_1 : assert property(p); 

请注意在断言中调用一个property,并且再定义时钟是非法的,如下是非法的:

a_3: assert property(@(posedge clk) p) ; //不允许

Forbidding a property  禁止一个property 

sequence seq; @(posedge clk) a 2 b; endsequence property p; not seq;//not表示对sequence取反,即sequence成功时,property失败 endproperty a_1: assert property(p);

Binary Operators 双目操作符

  • and : 断定两个事件同时发生
  • intersect :断定两个事件同时发生和结束
  • or :断定两个事件至少有一个发生
  • if….else
sequence s1; $past(!req,1) 1 ($rose(gnt) and $past(!gnt,1)); endsequence sequence s2; $past(!req,1) 1 $rose(gnt) 1 $fell(gnt); endsequence sequence s3; req 1 gnt 1 busy 1 (!req and !gnt and !busy); endsequence sequence s4; req [1:3] gnt; endsequence property and_prop; @ (posedge clk) req |-> s1 and s2; endproperty property intersect_prop; @ (posedge clk) req |-> s1 intersect s3; endproperty property or_prop; @ (posedge clk) req |-> s1 or s4; endproperty property ifelse_prop; @ (posedge clk) if (check)//如果check=1,判断delay1,否则判断delay2 delay1 else delay2; endproperty

Match Operators 匹配操作符 

  • a within b   :断定b事件发生的时间段里包含a事件发生的时间段
  • c throughout  a :断定在a事件成立的过程中,c事件“一直”成立
  • firstmatch(a b c) :只要判断a成立就不需要再判断后面的b、c了
property first_match_prop; @ (posedge clk) $rose(burst_enable) |=> first_match(burst_enable [0:4] !master_busy); endproperty property throughout_prop; @ (posedge clk) $rose(burst_enable) |-> (burst_enable) throughout ( 2 (!slave_busy && !master_busy) [*6]); endproperty property within_prop; @ (posedge clk) $rose(burst_enable) |=> (!slave_busy[*6]) within (($fell(master_busy)) 1 !master_busy[*7]); endproperty

Clocks in Sequence  

sequence的时钟有两种,一种是直接在sequence内部定义时钟,另一种是使用外部property的时钟,如下:

// Sequence Layer // Here clock is specified inside the sequence //================================================= sequence req_gnt_seq; @ (posedge clk) (~req & gnt) 1 (~req & ~gnt); endsequence //================================================= // Property Specification Layer // Still requires clock for the property //================================================= property req_gnt_prop; @ (posedge clk) disable iff (reset) req |=> req_gnt_seq; endproperty //================================================= // Assertion Directive Layer //================================================= req_gnt_assert : assert property (req_gnt_prop) else $display("@%0dns Assertion Failed", $time);

 Sequence Arguments sequence中的参数

在定义sequence时允许带参数,参数可以定义数据类型也可以不定义,带参数的好处是允许向sequence传递参数,从而可以使sequecne达到类似函数的效果.如下:

logic clk = 0; logic req,gnt; logic a,b; //================================================= // Sequence Layer with args (NO TYPE) //================================================= sequence notype_seq (X, Y); (~X & Y) 1 (~X & ~Y); endsequence //================================================= // Sequence Layer with args (NO TYPE) //================================================= sequence withtype_seq (logic X, logic Y); (~X & Y) 1 (~X & ~Y); endsequence //================================================= // Property Specification Layer //================================================= property req_gnt_notype_prop(M,N); @ (posedge clk) req |=> notype_seq(M,N); endproperty property a_b_type_prop(logic M, logic N; @ (posedge clk) a |=> withtype_seq(M,N); endproperty //================================================= // Assertion Directive Layer //================================================= req_gnt_notype_assert : assert property (req_gnt_notype_prop(req,gnt)); a_b_type_assert : assert property (a_b_type_prop(a,b));

 Local Variables 

sequence当中允许定义本地变量,如下:

sequence local_var_seq; logic [7:0] lport; (in_en, lport = portin) [1:5] (out_en and lport == portout); endsequence //================================================= // Property Specification Layer //================================================= property local_var_prop; @ (posedge clk) in_en |-> local_var_seq; endproperty //================================================= // Assertion Directive Layer //================================================= local_var_assert : assert property (local_var_prop);

此外,在sequence中还可以调用方法.

 Recursive Property

如果在property中调用自身,则这种property称为递归property.如下:

property recursive_prop(M); M and (1'b1 |=> recursive_prop(M)); endproperty //================================================= // Assertion Directive Layer //================================================= recursive_assert : assert property (recursive_prop(req));

Implication operator 关联操作

首先看下面的例子:

sequence seq; @(posedge clk) a 2 b; endsequence

在每一个时钟的上升沿来临时sequence都会启动,检查a是否为1,若不为1,则检查失败;如果我们想sequence只在a为1的情况下被检查,这就需要用到关联操作.

关联(implication)的意思等价于if…then结构,关联左边的先行词,右边的为后继;只有先行词判断为真时,后继才会被检测。 

implication结构只能用在property定义中,不能用于sequence

存在两种implication:

  • Overlapped implication
  • Non-overlapped implication

(1)overlapped implication

 overlapped implication采用”|->“操作符,只有先行词判断为真后,后继才会在同一个时钟沿被检测.例子:

property p; @(posedge clk) a |-> b;//在上升沿到来时,若a=1,则在同一个时钟周期继续检查b是否为1,若为1,则判断为真 endproperty a: assert property(p);

 (2)Non-overlapped implication

 Non-overlapped implication采用”|=>“操作符,只有先行词判断为真后,后继才会在下一个时钟沿被检测.例子:

property p; @(posedge clk) a |=> b;//当时钟沿到来时检测a是否为1,若为1,则在下一个时钟沿继续检测b endproperty a: assert property(p);

 Implication with a fixed delay on the consequent  在implication的后继上加上延时

property p; @(posedge clk) a |-> 2 b;//如果在当前时钟沿检查到a=1,则再经过两个时钟沿后检测b是否为1 endproperty a: assert property(p);

Implication with a sequence as an antecedent  使用sequence作为implication的先行词和后继

sequence seq_1; (a && b) 1 c; endsequence sequence seq_2; 2 !d; endsequence property p; @(posedge clk) seq_1 |-> seq_2;//在当前时钟沿若seq_1为真,则继续检测seq_2(2个时钟沿后,检测d=0) endpeoperty a: assert property(p);

Timing windows in SVA Checkers  SVA带时间窗口 

property p; @(posedge clk) a |-> [1:4] b;//在当前时钟沿检查到a=1后,检测接下来的1~4个时钟周期内b=1 endproperty a: assert property(p); property p; @(posedge clk) a |-> [0:4] b;//在当前时钟沿检查到a=1后,检测接下来的0~4个时钟周期内b=1,也就是在当前时钟沿b也必须为1 endproperty a: assert property(p); property p; @(posedge clk) a |-> [1:$] b;//在当前时钟沿检查到a=1后,检测下一个时钟周期到仿真时间结束b=1 endproperty a: assert property(p);

Repetition Operators   重复操作

property p; @(posedge clk) a |-> 1 b 1 b 1 b;//在当前时钟沿若a=1,则在接下来的3个时钟b=1 endproperty a: assert property(p);

上面的重复操作写的比较繁琐,SVA提供了Repetition Operators重复操作符 来代替上面的写法,格式如下:

signal [*n] 或 sequence [*n]

所以上面的语句可以重写为:

property p; @(posedge clk) a |-> 1 b[*3]; endproperty a: assert property(p);

go-to repetition   非连续周期的重复

格式如下:

signal [->n] //重复n次,且不必是连续时钟周期
property p; @(posedge clk) a |-> 1 b[->3] 1 c;//在当前时钟沿若a=1,则在接下来的时钟沿b=1必须满足3个时钟周期,这3个周期不一定连续 //检测到3个b=1后,下一个时钟沿c=1 endproperty a: assert property(p);

 Non-consecutive repetition  非连续周期重复 

它与上面go-to类似,唯一的区别就是它不要求信号重复的最后一次匹配发生在整个序列匹配结束之前的时钟周期中,格式如下:

signal [=n] [=n]和[->n]的区别: a 1 b[->1:3] 1 c // E.g. a !b b b !b !b b c //也就是说最后一次必须匹配 a 1 b [=1:3] 1 c // E.g. a !b b b !b !b b !b !b c //在跳变到c之前的最后一次不一定要匹配

注意sequence不能使用go-to和 Non-consecutive 重复结构,只有表达式可以使用!

SVA built in methods

 $rose 

格式:

$rose(boolean expression or signalname);//如果在时钟有效沿,布尔表达式或signal跳变为true或1,则返回true,否则返回false //也就是该方法是检测信号的上升沿跳变的
sequence seq_rose; @(posedge clk) $rose(a);//如果在时钟有效沿a跳变为1,则断言成功 endsequence

 $fell  

格式:

$fell( boolean expression or signalname);//如果在时钟有效沿,布尔表达式或signal跳变为false或0,则返回true,否则返回false //也就是说该方法是检测信号的下降沿跳变的

$fell类似于取反操作,和$rose正好相反.

sequence seq_fell; @(posedge clk) $fell(a);//如果在时钟有效沿a=0,则断言成功 endsequence

$stable 

格式: 

$stable(boolean expression or signalname) ;//在时钟沿到来时,如果信号没有发生跳变,则返回1,否则返回0; //该方法是用来检测信号是否稳定的
sequence seq_stable; @(posedge clk) $stable(a);//在时钟沿到来时,若a不发生跳变,则断言成功 endsequence

$past 

格式:

$past(signal_name, number of clock cycles);//将前number个周期时的值赋给信号signal_name
property p; @(posedge clk) b |-> ($past(a,2) == 1);//当时钟沿到来时,检测b=1,若为1,则将前2个周期时的a值赋给a //若前2个周期时的a=1,则断言成功 endproperty a: assert property(p);

$past construct with clock gating  带时钟门控

格式:

$past (signal_name, number of clock cycles, gating signal);//如果gating signal为真 //则将前number个周期时的signal_name的值赋给signal_name
Property p; @(posedge clk) b |-> ($past(a,2,c) == 1);//在时钟沿到来时,若b=1且c=1 //则将前2个周期时的a值赋给a,若a=1,则断言成功 endproperty a: assert property(p);

Built-in system functions  内建的函数

$onehot(expression) //检查表达式的结果是否为one-hot,即只有一个bit为1,其余为0,若是则返回1 - checks that only one bit of the expression can be high on any given clock edge. $onehot0(expression) //检查表达式的结果是否为one-hot或者全部bit为0,若是则返回1 - checks only one bit of the expression can be high or none of the bits can be high on any given clock edge. $isunknown(expresslon) //检查表达式的结果的bit位中是否存在X或Z,若存在则返回1 - checks if any bit of the expression is X or Z. $countones(expression) //返回表达式结果的bit位中为1的位数 - counts the number of bits that are high in a vector.
a_1: assert property( @(posedge clk) $onehot(state) );//断言state为one-hot码 a_2: assert property( @(posedge clk) $onehot0(state) );//断言state为全零码或one-hot码 a_3: assert property( @(posedge clk) $isunknown(bus) ) ;//断言bus中存在X或Z等不定值 a_4: assert property( @(posedge clk) $countones(bus)> 1 );//断言bus中为1的bit数大于1 

disable iff and ended construct 

disable iff  

在某些设计条件下,如果某些条件为真,我们不希望继续进行检查。这可以通过使用disable iff实现。

property p; @(posedge clk) disable iff (reset) a |-> 1 b[->3] 1 c; endproperty a: assert property(p); //在正常的情况下当时钟沿到来后若a=1,则在接下来的3个周期b=1,且在下1个周期,c=1,则断言为真; //但是当时钟沿到来后,如果reset=1,则不再执行后面的检查

 ended

在级联sequence的时候,sequence的结束点可以用作同步点,这通过将关键字”ended”附加到sequence名称后来实现.

sequence seq_1; (a && b) 1 c; endsequence sequence seq_2; d [4:6] e; endsequence property p; @(posedge clk) seq_1.ended |-> 2 seq_2.ended;//当时钟沿到来后,检查seq_1,两个时钟后再检查seq_2,最后将两个sequence的结束点做同步 endpeoperty a: assert property(p); 

Variable delay in SVA  SVA中的可变延时 

 Static Delay

a 2 b;//在时钟沿到来后a=1,且在延时2个周期后b=1

Variable Delay 

int v_delay; v_delay = 4; a v_delay b;//这样写会报错,因为在断言中不能使用变量!
module asertion_variable_delay; bit clk,a,b; int cfg_delay; always #5 clk = ~clk; //clock generation //generating 'a' initial begin cfg_delay = 4; a=1; b = 0; #15 a=0; b = 1; #10 a=1; #10 a=0; b = 1; #10 a=1; b = 0; #10; $finish; end //calling assert property a_1: assert property(@(posedge clk) a cfg_delay b);//利用变量作为延时周期数会报错 endmodule

 SV之Assertions 断言

用非常量表达式作为property、sequence、assertion的延时数或复制范围是非法的

下面的例子是合法的:

module asertion_variable_delay; bit clk,a,b; int cfg_delay; always #5 clk = ~clk; //clock generation //generating 'a' initial begin cfg_delay = 4; a=1; b = 0; #15 a=0; b = 1; #10 a=1; #10 a=0; b = 1; #10 a=1; b = 0; #10; $finish; end //delay sequence sequence delay_seq(v_delay); int delay; (1,delay=v_delay) 0 first_match((1,delay=delay-1) [*0:$] 0 delay <=0); endsequence //calling assert property a_1: assert property(@(posedge clk) a |-> delay_seq(cfg_delay) |-> b); endmodule

 SV之Assertions 断言

多时钟 Multi Clock

sva允许序列或属性使用多个时钟来采样独立的信号,sva会自动同步不同信号或者子序列使用的时钟域,如下面的例子:

property multi; @(posedge clk1) a 1 @(posedge clk2) b; endproperty

当信号 a 在clk1 的上升沿为1时,属性开始匹配,接着 1 会将检验时间转移到 clk2 最近的一个上升沿去检查 b 是否为1;

注意:当在一个序列或属性中使用了多个时钟信号时,只允许使用 1 的延时构造;上面的例子换成 2或者 0 都是不允许的,因为使用 0 会产生混淆,即在 a 匹配后究竟哪个时钟信号才是最近的时钟,这将引起竞争,而如果换成 2 ,则无法同步到 clk2 最近的上升沿;

上面的 1 可以用非交叠蕴含来代替,也就是说:

@(posedge clk1) a |=> @(posedge clk2) b;

这两个操作是等效的,需要注意的是上面的 |=> 不能用 交叠蕴含 |-> 来代替,因为 |->同样会引起竞争;

matched 构造

如果一个序列定义了多个时钟, matched 可以用来监测第一个子序列的结束点,如下所示:

sequence s_a; @(posedge clk1) $rose(a); endsequence sequence s_b; @(posedge clk1) $rose(b); endsequence property p_match; @(posedge clk2) s_a.matched |=> s_b; endproperty

注意:matched 方法只有 sequence 才能调用!!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/212759.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 下午7:20
下一篇 2026年3月18日 下午7:20


相关推荐

  • MD5 编码 转换

    MD5 编码 转换

    2021年5月9日
    224
  • Java零基础学习难吗「建议收藏」

    Java零基础学习难吗「建议收藏」  java编程是入行互联网的小伙伴们大多数的选择,那么对于零基础的小伙伴来说Java零基础学习难吗?如果你是初学者,你可以很好的理解java编程语言。并不困难。如果你的学习能力比较高,那么你对Java的理解会更快。而如果你恰巧已经掌握了c或c++语言编程的全部知识,那么学起Java来就会更简单了。但这是没有必要的,如果你的思维逻辑还可以,那么你是可以很好的成为一名Java程序员的。  Java零基础学习难吗?Java是一门直截了当的语言。边练习边学,越多的练习会让你有更大的进步,你会感觉很棒。你会

    2022年6月20日
    39
  • 冒泡排序法_GUI斗地主小游戏源码java

    冒泡排序法_GUI斗地主小游戏源码java看图秒懂代码!

    2025年8月24日
    4
  • SQLyog详细使用教程[通俗易懂]

    SQLyog详细使用教程[通俗易懂]SQLyog详细使用教程

    2022年4月18日
    94
  • Windows 环境下查看 Redis 版本号命令「建议收藏」

    Windows环境下查看Redis版本号命令://Redis客户端输入infoserver//结果#Serverredis_version:3.2.100redis_git_sha1:00000000redis_git_dirty:0redis_build_id:dd26f1f93c5130eeredis_mode:standaloneos:Window…

    2022年4月9日
    472
  • vim撤销、回退操作「建议收藏」

    vim撤销、回退操作「建议收藏」打个广告,请有意向加入腾讯的前端,将简历发送至mzxbupt@gmail.com在vi中按u可以撤销一次操作u  撤销上一步的操作Ctrl+r恢复上一步被撤销的操作注意:如果你输入“u”两次,你的文本恢复原样,那应该是你的Vim被配置在Vi兼容模式了。重做如果你撤销得太多,你可以输入CTRL-R(redo)回退前一个命令。换句话说,它撤销一个撤销。要看执行的…

    2022年6月16日
    411

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号