SVA中的延迟
##m; ##[m:n];
【示例】
`timescale 1 ns / 1 ps module top_tb; logic clk; logic sig0,sig1,sig2; initial begin clk = 1'b0; forever #1 clk = ~clk; end initial begin sig0 = 1'b0; sig1 = 1'b0; sig2 = 1'b0; #2 sig0 = 1'b1;#2 sig1 = 1'b1; sig0 = 1'b0; #2 sig1 = 1'b0;#4 sig2 = 1'b1;#2 sig2 = 1'b0; #4 $stop; end // property property p; @(posedge clk) sig0 |-> ##1 sig1 ##3 sig2; endproperty // p // assertion a : assert property(p) $display("@%0t | p : PASSED!",$time); else $display("@%0t | p : FAILED!",$time); endmodule // top_tb【仿真结果】
示例中,sig0发生一个采样周期后sig1被采样到为高电平,在经过3个采样周期(##3)sig2被采样到高电平,此时序列匹配。这里的##3指的是三个采样周期,不是三个时间单位。当然m不止可以为正数,也可以为0,如下例。
`timescale 1 ns / 1 ps module top_tb; logic clk; logic sig0,sig1,sig2; initial begin clk = 1'b0; forever #1 clk = ~clk; end initial begin sig0 = 1'b0;sig1 = 1'b0;sig2 = 1'b0; #2 sig0 = 1'b1; #2 sig1 = 1'b1;sig0 = 1'b0;sig2 = 1'b1; #2 sig1 = 1'b0;sig2 = 1'b0;#4 $stop; end // property property p; @(posedge clk) sig0 |-> ##1 sig1 ##0 sig2; endproperty // p // assertion a : assert property(p) $display("@%0t | p : PASSED!",$time); else $display("@%0t | p : FAILED!",$time); endmodule // top_tb【仿真结果】
示例中##0表示sig1和sig2必须同时发生才算成功,可见,在具体使用过程中,可以使用##0表示两个事件在同一采样时刻同时发生。
除了使用上例中固定的具体延迟外,还存在一种延迟区间,即时序窗口,如下例。
【示例】
`timescale 1 ns / 1 ps module top_tb; logic clk; logic sig0; logic [4:0] sig1; initial begin clk = 1'b0; forever #1 clk = ~clk; end initial begin sig0 = 1'b0;sig1 = 5'b0_0000; #2 sig0 = 1'b1; #2 sig1 = 5'b0_0001;sig0 = 1'b0; #2 sig1 = 5'b0_0010; #2 sig1 = 5'b0_0100; #2 sig1 = 5'b0_1000; #2 sig1 = 5'b1_0000; #2 sig1 = 5'b0_0000; #4 $stop; end // property p property p(num); @(posedge clk) $rose(sig0) |-> ##[2:4] sig1[num] endproperty // p // assertion genvar i; generate for (i = 0;i < 5;i = i +1) begin : a_loop a : assert property(p(i)) $display("@%0t | p[i] : PASSED!",$time,i); else $display("@%0t | p[i] : FAILED!",$time,i); end endgenerate // a_loop endmodule // top_tb【仿真结果】
序列1:$rose(sig0) |-> ##2 sig1[0];
序列2:$rose(sig0) |-> ##3 sig1[0];
序列3:$rose(sig0) |-> ##4 sig1[0];
仿真过程中,会分别判断上述三个序列,因为对于sig1[0]来说在整个检查的过程中,序列1、序列2和序列3都不匹配,所以整个属性都不匹配,并且从示例中可以看出,属性失败取决于最长的那个序列。
sig1[4]和sig1[0]的情况类似,不再赘述。
sig1[1]和sig1[2]、sig1[3]情况类似,在第一次匹配后整个属性断言成功了,不同的是,这三个信号分别在##2、##3、##4匹配成功。
`timescale 1 ns / 1 ps module top_tb; logic clk; logic sig0,sig1; initial begin clk = 1'b0; forever #1 clk = ~clk; end initial begin sig0 = 1'b0;sig1 = 1'b0; #2 sig0 = 1'b1; #2 sig1 = 1'b1;sig0 = 1'b0; #10 $stop; end // property p property p; @(posedge clk) $rose(sig0) |-> ##[2:4] sig1; endproperty // p // assertion a : assert property(p) $display("@%0t | p : PASSED!",$time); else $display("@%0t | p : FAILED!",$time); endmodule // top_tb【仿真结果】
示例中,可以看到“##[2:4]sig1”虽然对sig1开启了三个并行的检查序列,但是在第一个序列(##2 sig1)检查成功后,不管第二个(##3 sig1)和第三个(##4 sig1)序列是否匹配,对应的进程都会***掉,即“##[m:n]”采取的是“就近匹配”原则,在第一个序列匹配后将不会在进行后续序列的匹配。那么“##[m:n]”中还有必要使用其中的“n”呢?
【示例】
`timescale 1 ns / 1 ps module top_tb; logic clk; logic sig0,sig1,sig2; initial begin clk = 1'b0; forever #1 clk = ~clk; end initial begin sig0 = 1'b0; sig1 = 1'b0;sig2 = 1'b0; #2 sig0 = 1'b1;#2 sig0 = 1'b0;sig1 = 1'b1; #6 sig2 = 1'b1;#2 sig2 = 1'b0;#2 $stop; end // property p property p; @(posedge clk) $rose(sig0) |-> ##[2:4] sig1 ##1 sig2; endproperty // p // assertion a : assert property(p) $display("@%0t | p : PASSED!",$time); else $display("@%0t | p : FAILED!",$time); endmodule // top_tb【仿真结果】
示例中,“##[2:4] sig1”在sig1第一次匹配后并没有结束匹配,而是在每次匹配后不停地检查其后续的表达式是否匹配,如果后续表达式匹配,则认为当前时刻为sig1匹配时刻,当然此时的匹配时刻一定要在“##[2:4]”区间之内,否则不认为匹配成功。
因此,可见对于##[m:n]来说,
-
如果其后续没有表达式,那么其对应的序列采用“就近匹配”原则;
-
如果其后续有表达式,在其匹配区间##[m:n]内,匹配时刻取决于后续表达式匹配的时刻;