文章目录
一、总线断言函数
$onehot(BUS)
:BUS中有且仅有1bit是高,其他是低$onehot0(BUS)
:BUS中有不超过1bit是高,也允许全0;$isunknown(BUS)
:BUS中存在高阻态或未知态;$coutones(BUS) == n
:BUS中有且仅有n bits 是高,其他是低$past(signal,cycle_num,1)
:returun of cycle past value of signal
二、assert和assume
分类 | 形式化验证 | 示例 |
---|---|---|
assert | 测试sig1和sig2可能的值,sig1:2’b00,2’b01,2’b10,2’b11sig2:1’b0,1’b1 | assert((sig1 == 2’b10)&&(sig2 ==1’b1)) |
assume | 测试sig1和sig2可能的值,sig1:2’b10sig2:1’b1 | assume((sig1 == 2’b10)&&(sig2 ==1’b1)) |
三、rose和fell
- 在仿真中 r o s e 并 不 是 单 纯 的 判 断 信 号 的 跳 边 沿 , 而 是 判 断 时 钟 采 样 信 号 前 后 是 否 存 在 0 − > 1 / x − > 1 / z − > 1 的 变 化 。 其 格 式 如 下 : ‘ rose并不是单纯的判断信号的跳边沿,而是判断时钟采样信号前后是否存在0->1/x->1/z->1的变化。其格式如下:` rose并不是单纯的判断信号的跳边沿,而是判断时钟采样信号前后是否存在0−>1/x−>1/z−>1的变化。其格式如下:‘rose(expression);`
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
- 在#2时刻sig0是0,则先序算子
$rose(sig0)
没有触发,所以后续算子没法进行; - 在#3时刻sig0是1,则先序算子成立,然后判断在一个时钟周期内sig1上升了,函数返回为真;
- 在仿真中 r o s e 并 不 是 单 纯 的 判 断 信 号 的 跳 变 沿 , 而 是 判 断 连 续 两 个 时 钟 采 样 周 期 信 号 是 否 存 在 0 − > 1 / x − > 1 / z − > 1 。 同 时 , 需 要 注 意 , rose并不是单纯的判断信号的跳变沿,而是判断连续两个时钟采样周期信号是否存在0->1/x->1/z->1。同时,需要注意, rose并不是单纯的判断信号的跳变沿,而是判断连续两个时钟采样周期信号是否存在0−>1/x−>1/z−>1。同时,需要注意,rose仅对表达式最低位的跳变变化敏感,对于非最低位信号的变化并不敏感。
f
e
l
l
判
断
时
钟
采
样
信
号
前
后
是
否
存
在
1
−
>
/
x
−
>
0
/
z
−
>
0
的
变
化
。
其
格
式
如
下
:
fell 判断时钟采样信号前后是否存在1->/x->0/z->0的变化。其格式如下:
fell判断时钟采样信号前后是否存在1−>/x−>0/z−>0的变化。其格式如下:fell(expression);需要注意这里的$fell不是下降沿!
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
- 在2ns时,在该采样时钟之前的上一个采样时钟沿采样到的sig0为高电平,所以先序算子没有成立;
- 在3ns时,sig0由1变为0所以先序算子成立成立,在一个时钟之后将sig1拉高
三、stable和past
$stable中的表达式在连续两个时钟周期保持不变,返回为真
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;#4 sig1 = 1'b1;
#4 sig0 = 1'b0;#2 sig1 = 1'b0;
#4 $stop;
end
// property p_fell
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 // top_tb
- 连续两个时钟周期都保持稳定先序算子成立,后续的如果也成立就成立
- 在15ns处,后续的没有成立则算没有成立
$past:用于检查表达式前一个时钟周期值是否为真,如果为真就返回真。可以进行指定前几个时钟
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 sig0 = 1'b1; sig1 = 1'b0;
#4 sig0 = 1'b1;#2 sig1 = 1'b1;
#4 $stop;
end
// property p_fell
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时为1,返回真,过了一个时钟在7ns处会看到sig1为0,返回假
- 上面的5、7都是说明在那个时刻实现的先序算子。
四、changed
$changed(expression)
表达式发生变化时,返回真;
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;
#2 sig0 = 1'b1;#2 sig1 = 1'b0;
#4 $stop;
end
// property p_changed
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 // top_tb
- 3ns时采样到sig0高电平,然后与1ns的采样的低电平比较,所以changed返回为真,同样在5ns也是返回为真
五、重复操作
如果在协议中可能会出现需要检查某个信号保持一种状态多少个采样周期,例如@(posedge clk) $rose(sig0) |-> ##1 sig1 ##1 sig1 ##1 sig1##1 sig1;
,这就比较繁琐,所以SVA由重复的运算符
重复运算符 | 说明 | 格式 |
---|---|---|
连续重复 | 表达式或者序列在指定数量的采样周期内连续的匹配,表达式或者序列的每次匹配之间都有一个采样周期的延迟。 | expr or sequence_name[*n] expr or sequence_name[*m:n] |
跟随重复 | 表达式匹配达到指定的次数,而且每次匹配不一定在连续的采样周期上,被检验的重复表达式的最后一个匹配应该发生在整个序列匹配结束之前 | expr[->n] |
非连续重复 | 与跟随重复类似,除了它并不要求信号的最后一次匹配发生在整个序列匹配前的那个采样周期 | expr[=n] |
5.1 [*n]和[*m:n]
使用时表达式或者序列每次匹配一个采样周期,表达式或者序列连续重复匹配n次,或者是n~m次;
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 sig0 = 1'b0;sig1 = 1'b1;
#10 sig1 = 1'b0;#4 $stop;
end
// property p
property p;
@(posedge clk) $rose(sig0) |-> ##1 sig1[*5];
endproperty // p
// assertion
a : assert property(p) $display("@%0t | p : PASSED!",$time);
else $display("@%0t | p : FAILED!",$time);
endmodule // top_tb
- 1ns时开始观察sig0,然后在3ns处rose成立,之后隔一个时钟周期5ns处开始看sig1是否保持5个时钟周期;
5.2 [->m]和[->m:n]
[->m]使用时表示表达式重复连续匹配出现m次,但是整个重复表达式的最后一次匹配必须发生在其后续表达式匹配前的一个采样周期
5.3 [=m]和[=m:n]
[->m]要求整个重复表达式的最后一次匹配必须发生在其后续表达式匹配的前一个相邻采样周期,而[=m]并没有要求整个重复表达式的最后一次匹配必须发生在一定的条件下