SVA的动态控制
SVA中提供了一些系统函数,可以在RTL设计代码或者仿真环境中用于控制断言的执行,常用的断言控制函数有:$assertoff,$asserton,$assertkill,这些函数可以指定参数,如果不指定参数那么这些函数的作用域将默认为整个设计。这些函数的使用个数如下:
$assert_task[(level[,list_of_modules_or_assertions])];
其中
assert_task可以是assertionon、assertoff、assertkill中的任何一个;
Level用于指定层以下哪几层设计受到函数的影响,如果level为0,函数将影响指定层以下所有的设计;
list_of_modules_or_assertions指定该函数作用于哪些模块或者断言(不能指向序列,但是可以指向属性);
这几个函数的具体意义如下:
$assertoff暂时关闭所有断言的执行,如果该函数执行时断言正在执行,正在执行的断言不会被终止;
$asserton重新启动断言执行;
$assertkill将会终止设计中所有的断言,包括已经执行的断言。当遇到下一个断言需要开始执行时,该断言不会启动,除非使用$asserton启动;
`timescale 1 ns / 1 ps module top_tb; logic clk; logic sig0,sig1,sig2; initial begin clk = 1'b0; forever #1 clk = ~clk; end // p1 stimulus initial begin sig0 = 1'b0;sig1 = 1'b0;sig2 = 1'b1; #2 sig0 = 1'b1; #2 sig0 = 1'b0;sig1 = 1'b1; #2 sig1 = 1'b0; $assertoff; #2 sig2 = 1'b0; #2 sig2 = 1'b1; #4 sig0 = 1'b1; // new #2 sig0 = 1'b0;sig1 = 1'b1; #2 sig1 = 1'b0; #2 sig2 = 1'b0; #2 sig2 = 1'b1; $asserton; #4 sig0 = 1'b1; // new #2 sig0 = 1'b0;sig1 = 1'b1; #2 sig1 = 1'b0; #2 sig2 = 1'b0; #2 sig2 = 1'b1; #6 $stop; end // instanced dut test u_dut0(clk,sig0,sig1,sig2,2'b00); test u_dut1(clk,sig0,sig1,sig2,2'b01); test u_dut2(clk,sig0,sig1,sig2,2'b10); // sequence sequence s; $rose(sig1) ##2 $fell(sig2); endsequence // s // property property p; @(posedge clk) $rose(sig0) |-> ##1 s; endproperty // p a : assert property(p) $display("@%0t | p : PASSED!",$time); else $display("@%0t | p : FAILED!",$time); endmodule // top_tb module test(clk,sig0,sig1,sig2,num); input clk,sig0,sig1,sig2,num; logic [1:0] num; sequence s; $rose(sig1) ##2 $fell(sig2); endsequence // s // property property p; @(posedge clk) $rose(sig0) |-> ##1 s; endproperty // p a : assert property(p) $display("@%0t DUT%h | p : PASSED!",$time,num); else $display("@%0t DUT%h | p : FAILED!",$time,num); endmodule // test【仿真结果】
示例中,第一次断言在3ns处触发开始,虽然$assertoff发生6ns处,在该断言检查的过程中,但是第一次断言的执行并没有受到$assertoff影响。但是15ns处第二次断言触发,但是在第一次断言执行的过程中已经执行了$assertoff,所以第二次断言被关闭,不会执行;22ns时$asserton执行,重新启动断言检查,所以之后的27ns开始的第三次断言被有效触发执行。因为$assertoff和$asserton中都没有指定任何参数,所以他们的作用域是当前函数调用执行域及其以下所有层次。
【示例】
`timescale 1 ns / 1 ps module top_tb; logic clk; logic sig0,sig1,sig2; initial begin clk = 1'b0; forever #1 clk = ~clk; end // p1 stimulus initial begin sig0 = 1'b0;sig1 = 1'b0;sig2 = 1'b1; #2 sig0 = 1'b1; #2 sig0 = 1'b0;sig1 = 1'b1; #2 sig1 = 1'b0; $assertkill; #2 sig2 = 1'b0; #2 sig2 = 1'b1; #4 sig0 = 1'b1; // new #2 sig0 = 1'b0;sig1 = 1'b1; #2 sig1 = 1'b0; #2 sig2 = 1'b0; #2 sig2 = 1'b1; $asserton; #4 sig0 = 1'b1; // new #2 sig0 = 1'b0;sig1 = 1'b1; #2 sig1 = 1'b0; #2 sig2 = 1'b0; #2 sig2 = 1'b1; #6 $stop; end // instanced dut test u_dut0(clk,sig0,sig1,sig2,2'b00); test u_dut1(clk,sig0,sig1,sig2,2'b01); test u_dut2(clk,sig0,sig1,sig2,2'b10); // sequence sequence s; $rose(sig1) ##2 $fell(sig2); endsequence // s // property property p; @(posedge clk) $rose(sig0) |-> ##1 s; endproperty // p a : assert property(p) $display("@%0t | p : PASSED!",$time); else $display("@%0t | p : FAILED!",$time); endmodule // top_tb module test(clk,sig0,sig1,sig2,num); input clk,sig0,sig1,sig2,num; logic [1:0] num; sequence s; $rose(sig1) ##2 $fell(sig2); endsequence // s // property property p; @(posedge clk) $rose(sig0) |-> ##1 s; endproperty // p a : assert property(p) $display("@%0t DUT%h | p : PASSED!",$time,num); else $display("@%0t DUT%h | p : FAILED!",$time,num); endmodule // test【仿真结果】
该示例中,6ns时$assertkill执行,虽然这时候3ns开始的断言还在执行中,但是会立即被终止其执行,即当前正在执行的断言会被$assertkill终止,而不管其是否正在执行。如果后续的断言还要继续执行,那么需要使用$asserton重新开启断言检查。
【示例】
`timescale 1 ns / 1 ps module top_tb; logic clk; logic sig0,sig1,sig2; initial begin clk = 1'b0; forever #1 clk = ~clk; end // p1 stimulus initial begin sig0 = 1'b0;sig1 = 1'b0;sig2 = 1'b1; #2 sig0 = 1'b1; #2 sig0 = 1'b0;sig1 = 1'b1; #2 sig1 = 1'b0; $assertoff(1,test); #2 sig2 = 1'b0; #2 sig2 = 1'b1; #4 sig0 = 1'b1; // new #2 sig0 = 1'b0;sig1 = 1'b1; #2 sig1 = 1'b0; #2 sig2 = 1'b0; #2 sig2 = 1'b1; $asserton; #4 sig0 = 1'b1; // new #2 sig0 = 1'b0;sig1 = 1'b1; #2 sig1 = 1'b0; #2 sig2 = 1'b0; #2 sig2 = 1'b1; #6 $stop; end // instanced dut test u_dut0(clk,sig0,sig1,sig2,2'b00); test u_dut1(clk,sig0,sig1,sig2,2'b01); test u_dut2(clk,sig0,sig1,sig2,2'b10); // sequence sequence s; $rose(sig1) ##2 $fell(sig2); endsequence // s // property property p; @(posedge clk) $rose(sig0) |-> ##1 s; endproperty // p a : assert property(p) $display("@%0t | p : PASSED!",$time); else $display("@%0t | p : FAILED!",$time); endmodule // top_tb module test(clk,sig0,sig1,sig2,num); input clk,sig0,sig1,sig2,num; logic [1:0] num; sequence s; $rose(sig1) ##2 $fell(sig2); endsequence // s // property property p; @(posedge clk) $rose(sig0) |-> ##1 s; endproperty // p a : assert property(p) $display("@%0t DUT%h | p : PASSED!",$time,num); else $display("@%0t DUT%h | p : FAILED!",$time,num); endmodule // test【仿真结果】
示例中,$assertoff(1,test)表示所有例化自test的实例中的断言从6ns开始关闭,此时如果有断言正在执行将不会受到$assertoff(1,test)的影响,之后新的例化自test的实例中的断言将不再执行,直到后续$asserton重新开启断言检查。
【示例】
`timescale 1 ns / 1 ps module top_tb; logic clk; logic sig0,sig1,sig2; initial begin clk = 1'b0; forever #1 clk = ~clk; end // p1 stimulus initial begin sig0 = 1'b0;sig1 = 1'b0;sig2 = 1'b1; #2 sig0 = 1'b1; #2 sig0 = 1'b0;sig1 = 1'b1; #2 sig1 = 1'b0; $assertoff(0,u_dut0); $assertoff(1,u_dut1); $assertoff(1,top_tb); #2 sig2 = 1'b0; #2 sig2 = 1'b1; #4 sig0 = 1'b1; // new #2 sig0 = 1'b0;sig1 = 1'b1; #2 sig1 = 1'b0; #2 sig2 = 1'b0; #2 sig2 = 1'b1; $asserton(0,u_dut0); #4 sig0 = 1'b1; // new #2 sig0 = 1'b0;sig1 = 1'b1; #2 sig1 = 1'b0; #2 sig2 = 1'b0; #2 sig2 = 1'b1; #6 $stop; end // instanced dut test u_dut0(clk,sig0,sig1,sig2,2'b00); test u_dut1(clk,sig0,sig1,sig2,2'b01); test u_dut2(clk,sig0,sig1,sig2,2'b10); // sequence sequence s; $rose(sig1) ##2 $fell(sig2); endsequence // s // property property p; @(posedge clk) $rose(sig0) |-> ##1 s; endproperty // p a : assert property(p) $display("@%0t | p : PASSED!",$time); else $display("@%0t | p : FAILED!",$time); endmodule // top_tb module test(clk,sig0,sig1,sig2,num); input clk,sig0,sig1,sig2,num; logic [1:0] num; sequence s; $rose(sig1) ##2 $fell(sig2); endsequence // s // property property p; @(posedge clk) $rose(sig0) |-> ##1 s; endproperty // p a : assert property(p) $display("@%0t DUT%h | p : PASSED!",$time,num); else $display("@%0t DUT%h | p : FAILED!",$time,num); endmodule // test【仿真结果】
示例中,$assertoff(0,u_dut0);/$assertoff(1,u_dut1);/$assertoff(1,top_tb);分别将:u_dut0及其以下所有层次断言关闭;u_dut1模块内的所有断言关闭;top_tb模块内的所有断言关闭,但是不包含其下所有层次。因为u_dut2未受到影响,所以其断言检查一直有效;$asserton(0,u_dut0)重新开启了u_dut0的断言检查,所以开启后仅u_dut0的断言重新使能,而之前关闭的u_dut1和top_tb断言检查并未重新启动。所以在具体设计时,一定要分清楚需要关闭的断言的层次要求,以免关闭需要的检查。