SVA中的序列表达式操作符
1 intersect
intersect两侧的表达式都是sequence,不能是property,使用intersect时需要确保其两侧的sequence必须同时开始,且当两个sequence最终同时匹配时才认为两个序列的intersect匹配,即两个sequence匹配的长度必须相同,intersect操作符和and操作符很相似,但是and没有要求两个序列最终匹配时同时匹配。intersect使用示意图如下:
`timescale 1 ns / 1 ps module top_tb; logic clk; logic sig0,sig1,sig2,sig3,sig4; initial begin clk = 1'b0; forever #1 clk = ~clk; end initial begin sig0 = 1'b0;sig1 = 1'b0;sig2 = 1'b0; sig3 = 1'b0;sig4 = 1'b0; #4 sig0 = 1'b1; #2 sig0 = 1'b0;sig1 = 1'b1;sig3 = 1'b1; #2 sig3 = 1'b0;sig1 = 1'b0;sig2 = 1'b1; #2 sig3 = 1'b0; #2 sig2 = 1'b1;sig4 = 1'b1; #2 sig2 = 1'b0;sig4 = 1'b0; #2 $stop; end sequence s1; sig1 ##[1:5] sig2; endsequence // s1 sequence s2; sig3 ##[2:4] sig4; endsequence // s2 property p; @(posedge clk) $rose(sig0) |-> ##1 (s1 intersect s2); endproperty // p property p1; @(posedge clk) $rose(sig0) |-> ##1 s1; endproperty // p1 property p2; @(posedge clk) $rose(sig0) |-> ##1 s2; endproperty // p2 a : assert property(p) $display("@%0t | p : PASSED!",$time); else $display("@%0t | p : FAILED!",$time); a1 : assert property(p1) $display("@%0t | p1 : PASSED!",$time); else $display("@%0t | p1 : FAILED!",$time); a2 : assert property(p2) $display("@%0t | p2 : PASSED!",$time); else $display("@%0t | p2 : FAILED!",$time); endmodule // top_tb【仿真结果】
2 within
within右侧sequence的起止点必须位于左侧sequence的起止点之内,当然within左右两侧sequence的起止点可以一样,整个“sequence_1 within sequence_2”匹配成功的结束点与右侧sequence的结束点一致。within使用示意图如下:
`timescale 1 ns / 1 ps module top_tb; logic clk; logic sig0,sig1,sig2,sig3,sig4; initial begin clk = 1'b0; forever #1 clk = ~clk; end initial begin sig0 = 1'b0;sig1 = 1'b0;sig2 = 1'b0; sig3 = 1'b0;sig4 = 1'b0; #4 sig0 = 1'b1; #2 sig0 = 1'b0;sig1 = 1'b1; #2 sig1 = 1'b0; #2 sig3 = 1'b1; #2 sig3 = 1'b0; #4 sig4 = 1'b1; #2 sig4 = 1'b0;sig2 = 1'b1; #2 sig2 = 1'b0; #2 $stop; end sequence s1; sig1 ##[1:6] sig2; endsequence // s1 sequence s2; sig3 ##[3:4] sig4; endsequence // s2 property p; @(posedge clk) $rose(sig0) |-> ##1 (s2 within s1); endproperty // p property p1; @(posedge clk) $rose(sig0) |-> ##1 s1; endproperty // p1 property p2; @(posedge clk) $rose(sig0) |-> ##3 s2; endproperty // p2 a : assert property(p) $display("@%0t | p : PASSED!",$time); else $display("@%0t | p : FAILED!",$time); a1 : assert property(p1) $display("@%0t | p1 : PASSED!",$time); else $display("@%0t | p1 : FAILED!",$time); a2 : assert property(p2) $display("@%0t | p2 : PASSED!",$time); else $display("@%0t | p2 : FAILED!",$time); endmodule // top_tb【仿真结果】
3 throughout
在SVA中有时需要某些信号在一个序列的检查过程中一直保持一个状态,此时就可以使用throughout操作符,当这些信号的状态发生不期望的变化时,序列的检查即认为失败。throughout使用示意图如下:
`timescale 1 ns / 1 ps module top_tb; logic clk; logic sig0,sig1,sig2,sig3; initial begin clk = 1'b0; forever #1 clk = ~clk; end initial begin sig0 = 1'b0;sig1 = 1'b0;sig2 = 1'b0;sig3 = 1'b0; #2 sig0 = 1'b1; #2 sig0 = 1'b0;sig1 = 1'b1;sig2 = 1'b1; #2 sig2 = 1'b0; #6 sig3 = 1'b1; #2 sig3 = 1'b0;sig1 = 1'b0; #4 sig0 = 1'b1; #2 sig0 = 1'b0;sig1 = 1'b1;sig2 = 1'b1; #2 sig2 = 1'b0; #2 sig1 = 1'b0; #2 sig1 = 1'b1; #2 sig3 = 1'b1; #2 sig3 = 1'b0;sig1 = 1'b0; #2 $stop; end sequence s; sig2 ##[1:6] sig3; endsequence // s property p; @(posedge clk) $rose(sig0) |-> ##1 (sig1 throughout s); endproperty // p a : assert property(p) $display("@%0t | p : PASSED!",$time); else $display("@%0t | p : FAILED!",$time); endmodule // top_tb【仿真结果】
这里需要注意,在SVA中还存在着另一种操作符“disable iff”其功能与throughout非常类似,但是在使用时还需要注意两者的差异。
【示例】
`timescale 1 ns / 1 ps module top_tb; logic clk,rst; logic sig0,sig1,sig2,sig3; initial begin clk = 1'b0; forever #1 clk = ~clk; end initial begin sig0 = 1'b0;sig1 = 1'b0;sig2 = 1'b0;sig3 = 1'b0;rst = 1'b0; #2 rst = 1'b1; #2 sig0 = 1'b1; #2 sig0 = 1'b0;sig1 = 1'b1;sig2 = 1'b1; #2 sig2 = 1'b0; #6 sig3 = 1'b1; #2 sig3 = 1'b0;sig1 = 1'b0; #4 sig0 = 1'b1; #2 sig0 = 1'b0;sig1 = 1'b1;sig2 = 1'b1; #2 sig2 = 1'b0;rst = 1'b0; #2 sig1 = 1'b0; #2 sig1 = 1'b1; #2 sig3 = 1'b1; #2 sig3 = 1'b0;sig1 = 1'b0; #2 $stop; end sequence s; sig2 ##[1:6] sig3; endsequence // s property p; @(posedge clk) $rose(sig0) |-> ##1 (sig1 throughout s); endproperty // p property pr; disable iff(!rst) @(posedge clk) $rose(sig0) |-> ##1 (sig1 throughout s); endproperty // pr a : assert property(p) $display("@%0t | p : PASSED!",$time); else $display("@%0t | p : FAILED!",$time); a0 : assert property(pr) $display("@%0t | pr : PASSED!",$time); else $display("@%0t | pr : FAILED!",$time); endmodule // top_tb【仿真结果】
示例中,通过属性p可以看到,p中throughout两侧序列和相关信号的采样都是基于采样事件的,throughout的作用范围限于其两侧序列和信号的被检查时间。Pr中的disable iff作用时间与当前属性的时间相同,并且当其中条件满足时后续的检查将会被终止并产生空成功(vacuous success),如图中24ns处所示。而且disable iff中的信号不像throughout两侧的表达式是基于采样事件的,disable iff信号可以异步于采样事件存在。由此可见,disable iff和throughout区别可总结如下:
disable iff | throughout |
作用时间等同于当前property | 作用时间为其两侧序列和信号被检查的时间 |
可以异步于当前采样事件 | 与当前采样事件同步 |
如果iff后的条件发生,将终止当前序列表达式的检查,产生空成功 | 如果其两侧的序列或者信号不匹配,那么当前序列会失败 |
4 first_match
在对一些指定时序窗口同时发生的多个序列进行检查时,使用first_match可以检查这些同时发出的序列进程中第一个完成匹配的序列,然后丢弃对于其他未完成序列进程的检查。
【示例】
`timescale 1 ns / 1 ps module top_tb; logic clk; logic sig0,sig1,sig2,sig3; initial begin clk = 1'b0; forever #1 clk = ~clk; end initial begin sig0 = 1'b0;sig1 = 1'b0;sig2 = 1'b0;sig3 = 1'b0; #2 sig0 = 1'b1;sig1 = 1'b1; #2 sig0 = 1'b0;sig1 = 1'b0;sig2 = 1'b1; #6 sig2 = 1'b0; #2 sig3 = 1'b1; #2 sig3 = 1'b0; #2 $stop; end property p1; @(posedge clk) $rose(sig0) |-> sig1 ##1 sig2[*1:4] ##2 sig3; endproperty // p1 property p2; @(posedge clk) $rose(sig0) |-> sig1 ##1 first_match(sig2[*1:4]) ##2 sig3; endproperty // p2 a1 : assert property(p1) $display("@%0t | p1 : PASSED!",$time); else $display("@%0t | p1 : FAILED!",$time); a2 : assert property(p2) $display("@%0t | p2 : PASSED!",$time); else $display("@%0t | p2 : FAILED!",$time); endmodule // top_tb【仿真结果】
5 ended
详见“SVA中被抛弃的ended”
6 matched
在一些场景,可能会碰到这样的情况:在一个属性中不同序列基于不同的采样事件,那么如何在基于不同采样事件的序列之间进行交互呢?在SVA中使用matched可以用来检测其中一个子序列的结束点,从而实现基于不同采样事件的序列之间的同步交互。与ended结构类似,使用matched的序列必须要有自己的采样事件,不同的是matched序列使用的采样事件可以与调用其的属性使用的采样事件不同。
【示例】
`timescale 1 ns / 1 ps module top_tb; logic clk1,clk2; logic sig1,sig2; initial begin clk1 = 1'b0;clk2 = 1'b0; fork forever #1 clk1 = ~clk1; forever #2 clk2 = ~clk2; join end initial begin sig1 = 1'b0;sig2 = 1'b0; #2 sig1 = 1'b1; #2 sig1 = 1'b0; #2 sig2 = 1'b1; #4 sig2 = 1'b0; #2 sig1 = 1'b1; #2 sig1 = 1'b0; #2 sig2 = 1'b1; #4 $stop; end sequence s1; @(posedge clk1) $rose(sig1); endsequence // s1 sequence s2; @(posedge clk2) $rose(sig2); endsequence // s2 property p; @(posedge clk2) s1.matched |-> ##1 s2; endproperty // p a : assert property(p) $display("@%0t | p : PASSED!",$time); else $display("@%0t | p : FAILED!",$time); endmodule // top_tb【仿真结果】
【示例】
`timescale 1 ns / 1 ps module top_tb; logic clk1,clk2; logic sig0,sig1,sig2; initial begin clk1 = 1'b0;clk2 = 1'b0; fork forever #1 clk1 = ~clk1; forever #2 clk2 = ~clk2; join end initial begin sig0 = 1'b0;sig1 = 1'b0;sig2 = 1'b1; #4 sig1 = 1'b1; #1 sig0 = 1'b1; #1 sig2 = 1'b0;sig1 = 1'b0; #8 $stop; end sequence s; @(posedge clk1) $rose(sig1) ##1 $fell(sig2); endsequence // s property p1; @(posedge clk2) $rose(sig0) |=> s.matched; endproperty // p1 property p2; @(posedge clk2) $rose(sig0) |=> @(posedge clk1) s.matched; endproperty // p2 a1 : assert property(p1) $display("@%0t | p1 : PASSED!",$time); else $display("@%0t | p1 : FAILED!",$time); a2 : assert property(p2) $display("@%0t | p2 : PASSED!",$time); else $display("@%0t | p2 : FAILED!",$time); endmodule // top_tb【仿真结果】
示例中,序列s在7ns处匹配成功,s.matched结果将会保存着。$rose(sig0)在6ns时基于clk2匹配成功,即属性p1中“|=>”先行算子$rose(sig0)匹配,但是后续算子在属性p1中并没有明确指定采样事件,所以此处属性的匹配将在基于clk2的先行算子匹配后的一个采样周期
匹配成功。在属性p2中,后续算子指定了采样事件为clk1,此时前后算子基于不同的采样事件,在基于clk2采样事件的先行算子满足要求之后,在距离其最近的基于clk1采样事件的时刻检查s.matched是否匹配,而示例中s.matched在7ns时满足要求,所以此时整个属性匹配成功。这里需要注意,SVA会自动同步不同信号或者子序列使用的时钟域,并且当序列中使用了多个时钟信号时,只允许在其中使用“##1”进行延迟,关于多时钟在SVA中的应用可参考“SVA中的multi-clock”一文。