SVA 断言翻译笔记 16.13多时钟序列语法(九)

16.13 Multiclock support(多时钟支持)

目录

16.13 Multiclock support(多时钟支持)

1、多时钟序列

2、多时钟属性

3、时钟流

4、例子

5、在多时钟上下文发现和使用序列的结束点


1、多时钟序列

        多时钟通过使用单延迟连接运算符 ##1或者零延迟运算符 ##0 连接单时钟子序列而建立,由##1指示的单个延迟被理解为,从第一个序列的端点(发生在第一个时钟的一个时钟节拍)到第二个时钟最近的严格后续时钟节拍(第二个序列从这里开始),##0表示的零延迟被理解为从第一个序列的端点(发生在第一个时钟的一个节拍处)到第二个时钟的最近可能重叠的节拍(第二个序列从这里开始)

//例1
@(posedge clk0) sig0 ##1 @(posedge clk1) sig1

        上述例子显示,此序列的匹配从posedge clk0处的sig0匹配开始,然后##1将时间移动到最近的严格后续posedge clk1,序列的匹配在该点以sig1的匹配结束。如果clk0和clk1不相同,则该序列的时钟事件在##1改变,如果clk0和clk1相同,则时钟事件在##1之后不会改变,且上述序列相当于单时钟序列,如下所示:

@(posedge clk0) sig0 ##1 sig1
//例2
@(posedge clk0) sig0 ##0 @(posedge clk1) sig1

        上述例子,序列的匹配从posedge clk0处的sig0匹配开始,##0 将时间移动到最近的可能重叠的posedge clk1,序列的匹配在该点以sig1的匹配结束,如果posedge clk0posedge clk1同时发生,则时间不会在##0处移动,否则,其行为类似于##1。如果clk0clk1不相同,则该序列的时钟事件在##0 之后改变,如果clk0clk1相同,时钟事件在##0 之后不改变,上述序列等价于下列序列:

@(posedge clk0) sig0 ##0 sig1

等价于

@(posedge clk0) sig0 && sig1

当连接不同时钟序列时,最大单时钟子序列只允许非空匹配,如果不将单时钟序列更改为多时钟序列或属性,则不能通过吸收任何周围的运算符及其参数来扩大该序列。

        如果s1,s2是没有时钟事件的序列表达式,则多时钟序列如下所示仅当s1和s2都不匹配为空时是合法的:

//例3
@(posedge clk1) s1 ##1 @(posedge clk2) s2

        时钟事件@(posedge clk1)应用于s1的整个匹配过程,而时钟事件@(posedge clk2)应用于s2的整个匹配过程,因为s1的匹配为非空所以在posedge clk1处有一个匹配的终点,##1在这个结束点和紧随其后的posedge clk2的第一次出现之间进行同步,posedge clk2的出现时s2匹配的起点。

      因为最大单时钟子序列与空字不匹配的限制, 多时钟序列具有定义良好的开始和结束时钟事件以及定义良好的时钟变化,如果clk1和clk2不相同,则序列如下是非法的,因为sig1[*0:1]可能存在空匹配,这会使结束时钟事件不明确是@(posedge clk0)还是@(posedge clk1)。

@(posedge clk0) sig0 ##1 @(posedge clk1) sig1[*0:1]

        不同时钟或多时钟序列操作数不能与除##1##0以外的任何序列运算符组合。例如,如果clk1和clk2不相同,则以下内容是非法的:

//例4
@(posedge clk1) s1 ##2 @(posedge clk2) s2
@(posedge clk1) s1 intersect @(posedge clk2) s2

2、多时钟属性

      时钟可以用任何属性显式指定,如果属性的某些子属性具有与属性时钟不同的时钟,或者属性的某些子属性是多时钟序列,则属性为多时钟。

        与单时钟属性的情况一样,评估多时钟属性的结果要么为真,要么为假,多时钟序列本身就是多时钟属性,如下:

//例5
@(posedge clk0) sig0 ##1 @(posedge clk1) sig1

        如果多时钟序列像从某点开始的属性那样进行评估,则当且仅当从该点开始的多时钟序列匹配时,评估才会返回true。

        下例显示如何使用布尔值属性运算符产生多时钟属性:

//例6
(@(posedge clk0) sig0) and (@(posedge clk1) sig1)

        这是一个多时钟属性,不是多时钟序列,当且仅当两个序列@(posedge clk0) sig0和@(posedge clk0) sig1都从该点开始匹配时,属性评估为真。

        多时钟非重叠蕴涵的含义与单时钟非重叠蕴涵的含义相似,例如,如果s0和s1都是无时钟事件的序列,则:

//例7
@(posedge clk0) s0 |=> @(posedge clk1) s1

        |=>在posedge clk0和posedge clk1之间同步,从蕴涵被被评估的点开始,对于clk0计时的每个s0匹配,时间从匹配的终点提前到最近的posedge clk1的未来发生点,并且从该点开始,必须存在clk1计时的s1匹配。

        下例显示了使用蕴涵和布尔值属性运算符的不同时钟属性的组合:

//例8
@(posedge clk0) s0 |=> (@(posedge clk1) s1) and (@(posedge clk2) s2)

        多时钟重叠蕴涵 |-> 有如下的含义:在前一个时钟的末尾,等待下一个时钟最近的节拍;如果结果时钟发生在先行项的末尾,则立即开始检查结果,否则,多时钟重叠蕴涵与多时钟非重叠蕴涵的含义相同。下例,s0和s1是无时钟事件序列:

//例9
@(posedge clk0) s0 |-> @(posedge clk1) s1

        在s0每次匹配中,等待最近的posedge clk1,如果其立即发生,则立即检查s1,否则其检查在下一个posedge clk1开始,像|=>的一样。在这两种情况下,s1的评估都由posedge clk1控制。

        多时钟if/if-else运算符的语义与重叠蕴涵的语义相似,例如,如果s1和s2是无时钟事件的序列,则具有以下含义:条件b在posedge clk0被检查,如果b是真,则在最近的可能重叠的posedge clk1处检查s1,否则在最近的非严格子序列posedge clk2处检查s2.

//例10
@(posedge clk0) if (b) @(posedge clk1) s1 else @(posedge clk2) s2

3、时钟流

        下面c,d表示时钟事件表达式,v,w,x,y,z表示无时钟事件序列。

        时钟流允许时钟事件的范围,以自然方式扩展到多时钟序列和属性的各个部分,并减少必须指定相同时钟事件的位置数。时钟流提供了在多时钟序列或属性中,时钟事件的范围从左到右流经线性运算符(例如,重复、串联、否定、蕴涵、后跟和下一个时间、始终、最终运算符),并分布到分支运算符的操作数(例如,合取、析取、交集、if–elseuntil运算符),直到它被一个新的时钟事件所取代。

//例11
@(c) x |=> @(c) y ##1 @(d) z

能被简写成

@(c) x |=> y ##1 @(d) z

        时钟流还使多时钟属性的连接和蕴涵之间的伴随关系变得清晰:

@(c) x ##1 y |=> @(d) z

等价于

@(c) x |=> y |=> @(d) z

下例

@(c) x ##0 y |=> @(d) z

等价于

@(c) x |-> y |=> @(d) z

        时钟事件的作用域流入括号内的子表达式,如果子表达式是序列,则也从左向右流过括号内的子表达式。如:

//例12
@(c) w ##1 (x ##1 @(d) y) |=> z

        上例中,w,x,z是在时钟c作用下,y在时钟d作用,时钟c在##1,括号内的子序列(x##1@(d)y),以及|=>之间流动,时钟c也会流进括号内的子序列,但不流过@(d),时钟d不从圆括号中流出。

        

//例13
@(c) v |=> (w ##1 @(d) x) and (y ##1 z)

        v,w,y,z由时钟c作用,x由时钟d作用,时钟c流过|=>,分配给and的两个操作数,流进每一个括号里面的子表达式,在(w ##1 @(d) x)中,c流过##1,但是不流过@(d),时钟d不流出其圆括号,在(y ##1 z)中,c流过##1。

        时钟事件的范围不会流进disable iff的禁用条件。

//例14
@(d) @(c) x

等价于

@(c) x

因为,时钟d的流会立即被时钟c覆盖。

4、例子

        多时钟规范:

//例1
sequence s1;
a ##1 b; // 无时钟序列
endsequence
sequence s2;
c ##1 d; // 无时钟序列
endsequence

//多时钟序列
sequence mult_s;
@(posedge clk) a ##1 @(posedge clk1) s1 ##1 @(posedge clk2) s2;
endsequence

//具有多时钟序列的属性
property mult_p1;
@(posedge clk) a ##1 @(posedge clk1) s1 ##1 @(posedge clk2) s2;
endproperty

//具有已命名多时钟序列的属性
property mult_p2;
mult_s;
endproperty

//具有多时钟蕴涵的属性
property mult_p3;
@(posedge clk) a ##1 @(posedge clk1) s1 |=> @(posedge clk2) s2;
endproperty

//具有蕴涵的属性,前件和后件被命名多时钟序列
property mult_p6;
mult_s |=> mult_s;
endproperty

//使用时钟流和重叠蕴涵的属性
property mult_p7;
@(posedge clk) a ##1 b |-> c ##1 @(posedge clk1) d;//a,b,c都由posedge clk作用
endproperty

//使用时钟流和if-else的属性
property mult_p8;
@(posedge clk) a ##1 b |->
if (c)
(1 |=> @(posedge clk1) d)
else
e ##1 @(posedge clk2) f ;
endproperty    //a,b,c,e和常数1都由posedge clk作用


5、在多时钟上下文发现和使用序列的结束点(端点)

      触发的方法(triggered)能用于发现多时钟序列的结束点,触发的方法(triggered)也能用于从多锁序列中检测序列的结束点,在这两种情况下,应用触发的序列实例的结束时钟,应与应用触发方法的上下文中的时钟相同。

      当源序列的时钟不同于目标序列时,为了检测序列的端点,使用在源序列上匹配的方法,只要序列的表达式上有匹配项,就可以到达序列的终点。

        为了检测序列的端点,匹配方法可以用于已命名带或者不带参数的序列实例,为了检测端点,匹配的方法可以应用于命名序列实例,有参数或无参数、非类型化形式参数或序列类型的形式参数(如果允许),如下所示:

sequence_instance.matched
or
formal_argument_sequence.matched

        matched是序列上返回真(1'b1)或假(1'b0)的方法,与triggered不同,matched在两个时钟之间使用同步,通过存储源序列匹配的结果,直到匹配后第一个目标时钟节拍到达matched的结果不取决于源序列的起点。

        与triggered一样,matched能用于有形式参数的序列:

sequence e1(a,b,c);
@(posedge clk) $rose(a) ##1 b ##1 c ;
endsequence
sequence e2;
@(posedge sysclk) reset ##1 inst ##1 e1(ready,proc1,proc2).matched [->1]
##1 branch_back;
endsequence

        在上例中,源序列e1在时钟clk处评估,同时目的序列e2在时钟sysclk处评估,在e2中,实例e1(ready,proc1,proc2)的端点,被测试为在inst发生之后的某个时间发生,注意:matched的方法仅测试e1(ready,proc1,proc2)的端点,与e1(ready,proc1,proc2)的起点无关。

6、序列方法

       triggeredmatched的方法能定义序列的端点,操作数sequence会是一个命名的序列实例,有参数或无参数、非类型化形式参数或序列类型的形式参数(在此类参数合法的上下文中)。

        使用以下语法调用这些方法:

sequence_instance.sequence_method
or
formal_argument_sequence.sequence_method

        这些运算的结果是真(1'b1)或假(1'b0),且不取决于其操作数序列匹配的起点,这些方法可以在具有形式参数的序列上调用,这些方法的采样值会被定义为当前值。

        如果操作数序列已经在特定时间点到达其端点,则triggered的方法的值评估为true(1'b1),否则评估为false(1'b0),序列的触发状态在观察区被确立,序列的触发状态在观察区域内设置,并在剩余的时间步长内持续。除了在断言语句中使用这个方法,还可以在wait语句或序列上下文以外的布尔值表达式中使用,在将其形式参数视为局部变量的序列上,在序列上下文之外调用此方法将被视为错误。如果序列的形式变量,在运算符赋值或序列匹配项中的inc_或dec_表达式中用作左值,则序列将其形式变元视为局部变量。由于使用触发式传感器,序列之间不得存在循环依赖关系。如果形式变量在sequence_match_item中的operator_assignmentinc_or_dec_expression中用作左值,则序列将其形式变元视为局部变量,由于使用触发器,序列之间不应存在循环依赖关系。

     matched的方法用于检测在多时钟序列(目的序列)中推断的序列(源序列)的端点,仅能用在序列表达式,与triggered不同,matched在两个时钟之间使用同步,通过存储源序列匹配的结果,直到匹配后第一个目标时钟节拍到达,序列的匹配状态在观察区中设置,且持续到到匹配后目标序列第一个时钟节拍到达的观察区。

        在采样值函数中使用序列matched的方法是错误的。

        在序列中使用上述方法:

sequence e1;
@(posedge sysclk) $rose(a) ##1 b ##1 c;
endsequence
sequence e2;
@(posedge sysclk) reset ##1 inst ##1 e1.triggered ##1 branch_back;
endsequence
sequence e3;
@(posedge clk) reset1 ##1 e1.matched ##1 branch_back1;
endsequence
sequence e2_with_arg(sequence subseq);
@(posedge sysclk) reset ##1 inst ##1 subseq.triggered ##1 branch_back;
endsequence
sequence e4;    //e4语义上等价于e2
e2_with_arg(@(posedge sysclk) $rose(a) ##1 b ##1 c);
endsequence
program check;
initial begin
wait (e1.triggered || e2.triggered);
if (e1.triggered)
$display("e1 passed");
if (e2.triggered)
$display("e2 passed");
L2: ...
end
endprogram

        上例中,序列e2使用triggered的方法,测试序列e1的端点,因为两个序列都使用相同的时钟;序列e3用matched的方法,测试序列e1的端点,因为e1和e3使用不同的时钟,序列e4在语义上等价于e2,且显示了序列triggered的方法在sequence类型的形式参数上的应用。程序中的initial程序等待e1或e2的端点,当e1或e2评估为真时,wait语句将取消阻止初始进程,然后,该进程显示导致其取消阻塞的序列,然后继续在标记为L2的语句处执行。

        如果默认的实际参数,如果为序列的形式参数指定了默认实际参数$inferred_clock,并且未向应用方法的序列实例提供实际参数。

        如果一个序列定义了多个时钟, matched 可以用来监测第一个子序列的结束点,matched 方法只有 sequence 才能调用。

       下例说明:当方法应用于序列时,时钟怎样由序列推断:

module mod_sva_checks;
logic a, b, c, d;
logic clk_a, clk_d, clk_e1, clk_e2;
logic clk_c, clk_p;
clocking cb_prog @(posedge clk_p); endclocking
clocking cb_checker @(posedge clk_c); endclocking
default clocking cb @(posedge clk_d); endclocking
sequence e4;
$rose(b) ##1 c;
endsequence

// e4根据时钟流规则推断为posedge clk_a
a1: assert property (@(posedge clk_a) a |=> e4.triggered);

sequence e5;
// e4根据时钟流规则推断为posedge clk_e1,无论e5在何处实例化(带或不带有方法)
@(posedge clk_e1) a ##[1:3] e4.triggered ##1 c;
endsequence

// 在e5中使用e4,从e5中推断为posedge clk_e1
a2: assert property (@(posedge clk_a) a |=> e5.matched);

sequence e6(f);
@(posedge clk_e2) f;
endsequence

// e4根据时钟流规则推断为clk_e2 
a3: assert property (@(posedge clk_a) a |=> e6(e4.triggered));

sequence e7;
e4 ##1 e6(d);
endsequence

// e7的前导时钟根据时钟流规则为posedge clk_a
a4: assert property (@(posedge clk_a) a |=> e7.triggered);

// 在禁用条件下非法使用,e4不显示时钟事件
a5_illegal: assert property (
@(posedge clk_a) disable iff (e4.triggered) a |=> b);

always @(posedge clk_a) begin
//e4推断默认时钟cb,而不是posedge clk_a,因为此过程中有多个事件控件
@(e4);
d = a;
end

program prog_e4;
default clocking cb_prog;
initial begin
// e4推断默认时钟cb_prog
wait (e4.triggered);
$display("e4 passed");
end
endprogram : prog_e4

checker check(input in1, input sequence s_f);
default clocking cb_checker;
always @(s_f)
$display("sequence triggered");
a4: assert property (a |=> in1);
endchecker : check
// e4推断check的默认时钟cb_checker
check c1(e4.triggered, e4);
//连接到模块实例端口的e4推断默认时钟cb
mod_adder ai1(e4.triggered);
endmodule : mod_sva_checks

7、局部变量初始化赋值

        对于单时钟序列和属性,当评估尝试开始时,将为已命名序列或属性的实例的评估尝试执行局部变量初始化赋值。这样的评估尝试总是从一个时间步开始,在这个时间步中,只有一个管理时钟节拍。

        对于多时钟序列和属性,。对于具有单个语义前导时钟的命名序列或属性实例的评估尝试,应在评估尝试开始时或之后的语义前导时钟的最早刻度处执行局部变量初始化赋值。如果命名属性的实例有两个或多个不同的语义前导时钟,则应为每个语义前导时钟创建局部变量的单独副本。对于局部变量的每个副本,应在评估尝试开始时或之后的相应语义前导时钟的最早节拍处执行初始化赋值,并且该局部变量的副本应用于评估与相应语义前导时钟相关联的子属性。

property p;
logic v = e;
(@(posedge clk1) (a == v)[*1:$] |-> b)
and
(@(posedge clk2) c[*1:$] |-> d == v)
;
endproperty
a1: assert property (@(posedge clk) f |=> p);

         logic类型,在断言a1中,p的实例有两个语义前导时钟,posedge clk1posedge clk2,为受这些时钟控制的两个子属性创建局部变量v的单独副本。设 t0 为posedge clk发生的时间步,其中 f 的采样值为真,根据a1的结构,对p 实例的评估尝试严格在t0后开始;设 t1 为在t0发生之后posedge clk1的最早时间步,设t2为t0发生之后posedge clk2的最早时间步。在t1中执行声明赋值 v=e ,并将该值赋值给与posedge clk1关联的v的副本,此值用于评估子属性(a == v)[*1:$] |-> b;同样,在t2中执行声明赋值 v=e,并将该值赋值给与posedge clk2关联的v的副本,此值用于评估子属性c[*1:$] |-> d == v

        不使用局部变量声明赋值的p的等价声明如下:

property p;
logic v;
(@(posedge clk1) (1, v = e) ##0 (a == v)[*1:$] |-> b)
and
(@(posedge clk2) (1, v = e) ##0 c[*1:$] |-> d == v)
;
endproperty

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值