SVA中的$rose和$fell
SVA中内嵌了边沿检测的函数,用户可以通过这些函数检查信号在采样时钟的前后的高低变化情况。常用的边沿检测函数有$rose和$fell。
1 $rose
在仿真中$rose并不是单纯的判断信号的跳边沿,而是判断时钟采样信号前后是否存在0->1/x->1/z->1的变化。其格式如下:
$rose(expression);
需要注意这里的$rose不是上升沿!
【示例】
`timescale 1 ns / 1 ps module top_tb; logic clk; logic [2:0] sig0; logic sig1; initial begin clk = 1'b0; forever #1 clk = ~clk; end initial begin sig0 = 3'b000; sig1 = 1'b0; #2 sig0 = 3'b001; #2 sig1 = 1'b1; sig0 = 3'b000; #2 sig1 = 1'b0;#2 sig0 = 3'b100; #2 sig1 = 1'b1;#2 sig1 = 1'b0; #4 $stop; end // property p property p; @(posedge clk) $rose(sig0) |-> ##1 sig1; endproperty // p // assertion a : assert property(p) $display("@%0t | p : PASSED!",$time); else $display("@%0t | p : FAILED!",$time); endmodule // top_tb【仿真结果】
示例中3ns时,sig[0]被采样到高电平,先序算子在此刻成功,注意先序算子并没有在2ns时触发。这是因为在该采样时钟之前的上一个采样时钟沿采样到的sig0[0]为低电平,3ns时当前采样时钟采样到sig[0]为高电平,$rose感知到sig[0]在前后2个采样时钟周期存在低高变化,即该函数此时返回为真,所以在仿真中$rose并不是单纯的判断信号的跳变沿,而是判断连续两个时钟采样周期信号是否存在0->1/x->1/z->1。同时,需要注意,$rose仅对表达式最低位的跳变变化敏感,对于非最低位信号的变化并不敏感。
2 $fell
在仿真中$fell并不是单纯的判断信号的跳边沿,而是判断时钟采样信号前后是否存在1->/x->0/z->0的变化。其格式如下:
$fell(expression);
需要注意这里的$fell不是下降沿!
【示例】
`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'b1;sig1 = 1'b0; #2 sig0 = 1'b0;#2 sig1 = 1'b1; sig0 = 1'b1;#2 sig1 = 1'b0; #4 $stop; end // property p_fell property p; @(posedge clk) $fell(sig0) |-> ##1 sig1; endproperty // p a : assert property(p) $display("@%0t | p : PASSED!",$time); else $display("@%0t | p : FAILED!",$time); endmodule // top_tb【仿真结果】
示例中3ns时,sig0被采样到低电平,先序算子在此刻成功,注意先序算子并没有在2ns时触发。这是因为在该采样时钟之前的上一个采样时钟沿采样到的sig0为高电平,3ns时当前采样时钟采样到sig0为低电平,$fell感知到sig0在前后2个采样时钟周期存在高低变化,该函数此时返回为真。
$rose和$fell并不像posedge和negedge那样判断信号的跳边沿,$rose和$fell是基于相邻两个采样周期,判断信号在两个连续的采样周期被采样的值的变化情况。
3 $stable
当表达式在连续两个采样时钟周期保持不变时返回真。其格式如下:
$stable(expression);
【示例】
`timescale 1 ns / 1 ps module top_tb; bit clk; bit sig0,sig1; // default value : 0 initial begin clk = 1'b0; forever #1 clk = ~clk; end initial begin sig0 = 1'b0; sig1 = 1'b0; #2 sig0 = 1'b1;#4 sig1 = 1'b1; #4 sig0 = 1'b0;#2 sig1 = 1'b0; $stop; end // property p_stable property p; @(posedge clk) $stable(sig0) |-> ##1 sig1; endproperty // p a : assert property(p) $display("@%0t | p : PASSED!",$time); else $display("@%0t | p : FAILED!",$time); endmodule
【仿真结果】
1ns时,因为sig0类型为bit,其默认值为0,在1ns时$stable认为sig0当前值与前一周期值一样也是0,所以1ns时$stable为真,但是在3ns时sig1为0,所以此时属性断言失败。在5ns时,因为sig0在前一周期(3ns)处的值和5ns处的值都为高,且一个时钟周期后sig1为高,所以此时属性断言成功,后续时刻点操作类似,不再赘述。这里需要注意$stable检测时信号的类型,示例中如果sig0为logic类型,那么仿真结果是不一样的,因为logic类型的变量的默认值为不定态,这样sig0在0时刻和1时刻的值就是不一样的,此时$stable就会返回假。
4 $past
$past主要用于检查当前表达式前一个时钟周期(如果不指定number_of_ticks,默认指向前一个时钟周期)值是否为真,如果为真则$past返回为真。其格式如下:
$past(expression[,number_of_ticks]);
其中number_of_ticks可以指定检查当前时刻之前number_of_ticks个周期的采样值。
【示例】
`timescale 1 ns / 1 ps module top_tb; bit clk; bit sig0,sig1; // default value : 0 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; #4 sig0 = 1'b1;#2 sig1 = 1'b1; #4 $stop; end property p; @(posedge clk) $past(sig0) |-> ##1 sig1; endproperty // p a : assert property(p) $display("@%0t | p : PASSED!",$time); else $display("@%0t | p : FAILED!",$time); endmodule // top_tb【仿真结果】
在5ns时,$past(sig0)指的时在3ns时刻时钟采样sig0的值,3ns时sig0的值为1,所以此时$past(sig0)返回真。后续时刻$past(sig0)计算方式与此相同,不再赘述。
5 $changed
格式:
$changed(expression);
当表达式发生变化(不管是高低变化还是低高变化)时返回真,返回值类型为布尔类型。
【示例】
`timescale 1 ns / 1 ps module top_tb; bit clk; bit sig0,sig1; // default value : 0 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; #2 sig0 = 1'b1; #2 sig1 = 1'b0;#4 $stop; end property p; @(posedge clk) $changed(sig0) |-> ##1 sig1; endproperty // p a : assert property(p) $display("@%0t | p : PASSED!",$time); else $display("@%0t | p : FAILED!",$time); endmodule【仿真结果】
示例中,在3ns时,sig0被采样到为高电平,在1ns时即前一个采样周期sig0被采样到为低电平,所以在3ns时$changed感知到sig0在连续2个时钟周期存在电平值变化,此时$changed(sig0)返回真。5ns时,sig0被采样到为低电平,而此采样点前一周期的3ns处sig0被采样到为高电平,所以此时$changed(sig0)检测到sig0在连续两个时钟周期存在边沿变化,该函数返回真,后续$changed(sig0)变化类似,不再赘述。