如何防止SVA的新线程
How to prevent new threads of SVA
假设我的设计中有一个按钮。当按钮被按下三次时,我想在接下来的两个时钟之间增加计数器,我想用 SVA 检查这个行为。
我写了这个:
`timescale 1ns / 1ps
module tb();
parameter NUMBER_OF_PRESSES = 10;
parameter CLK_SEMI_PERIOD = 5;
bit clk;
always #CLK_SEMI_PERIOD clk = ~clk;
bit button_n;
bit reset_n;
logic [7:0] counter;
property p;
logic[7:0] val;
disable iff(!reset_n) @(posedge clk) (($fell(button_n)[=3]),val=counter) |=> ##[0:2] (counter== val+1);
endproperty
assert property(p);
initial begin
automatic bit key_d;
automatic byte key_lat;
automatic byte key_press_count;
reset_n = 1;
button_n = 1;
counter = 0;
fork
begin
repeat(NUMBER_OF_PRESSES) begin
repeat(5)begin
@(negedge clk);
end
button_n = 0;
key_lat = $urandom_range(1,4);
repeat(key_lat) begin
@(negedge clk);
end
button_n = 1;
end
end
begin
forever begin
@(posedge clk);
if(!button_n && key_d) begin
key_press_count++;
end
if(key_press_count == 3) begin
counter++;
key_press_count = 0;
end
key_d = button_n;
end
end
join_any
end
endmodule
这在第一次按下三下时效果很好,但之后它总是会抛出断言错误,因为它在每次按下按钮时都会启动新的断言线程。所以,我需要防止测试平台这样做。当重复已经开始时,我不需要开始新线程。
我该怎么做?
我不确定我完全理解你的问题。先说说我的理解,以及我认为你的问题出在哪里。如果我弄错了,请道歉。
您打算在 button_n ("presses") 上检测负数,并且在第三个上,您增加 "counter".
这里的问题是您声明的 objective(实际上与 SVA 匹配)和您的设计做了不同的事情。
您的 SVA 将在每三次否定后检查计数器是否具有预期值 1-3 个周期。这适用于按下 0、1 和 2。但它也必须适用于按下 1、2 和 3。然后按下 2、3 和 4 等。我怀疑断言在按下 2 时通过,然后在按下 3 时失败。即你检查在第三次之后每次按下你的计数器。
另一方面,您的设计有所不同。它计数 3 个否定,递增计数器,然后从头开始计数。
我建议不要在断言中使用局部变量,除非您确定它是您需要的——我认为这里不是这种情况。您可以在 key_press_count == 3 上设置 SVA 触发器(假设您适当地定义了 key_press_count 而不是自动变量)。
如果您坚持使用本地 SVA 变量,您可以稍微修改触发条件以包含计数器。例如一些类似的东西(虽然可能有点错误,还没有测试过):
(counter == 0 || $changed(counter)) ##1 ($fell(button_n)[=3], val = counter)
IMO,这是个坏主意,支持 RTL 是更好的方式来记录您的意图,并准确检查您所追求的行为。
希望对您有所帮助
假设我的设计中有一个按钮。当按钮被按下三次时,我想在接下来的两个时钟之间增加计数器,我想用 SVA 检查这个行为。 我写了这个:
`timescale 1ns / 1ps
module tb();
parameter NUMBER_OF_PRESSES = 10;
parameter CLK_SEMI_PERIOD = 5;
bit clk;
always #CLK_SEMI_PERIOD clk = ~clk;
bit button_n;
bit reset_n;
logic [7:0] counter;
property p;
logic[7:0] val;
disable iff(!reset_n) @(posedge clk) (($fell(button_n)[=3]),val=counter) |=> ##[0:2] (counter== val+1);
endproperty
assert property(p);
initial begin
automatic bit key_d;
automatic byte key_lat;
automatic byte key_press_count;
reset_n = 1;
button_n = 1;
counter = 0;
fork
begin
repeat(NUMBER_OF_PRESSES) begin
repeat(5)begin
@(negedge clk);
end
button_n = 0;
key_lat = $urandom_range(1,4);
repeat(key_lat) begin
@(negedge clk);
end
button_n = 1;
end
end
begin
forever begin
@(posedge clk);
if(!button_n && key_d) begin
key_press_count++;
end
if(key_press_count == 3) begin
counter++;
key_press_count = 0;
end
key_d = button_n;
end
end
join_any
end
endmodule
这在第一次按下三下时效果很好,但之后它总是会抛出断言错误,因为它在每次按下按钮时都会启动新的断言线程。所以,我需要防止测试平台这样做。当重复已经开始时,我不需要开始新线程。
我该怎么做?
我不确定我完全理解你的问题。先说说我的理解,以及我认为你的问题出在哪里。如果我弄错了,请道歉。
您打算在 button_n ("presses") 上检测负数,并且在第三个上,您增加 "counter".
这里的问题是您声明的 objective(实际上与 SVA 匹配)和您的设计做了不同的事情。
您的 SVA 将在每三次否定后检查计数器是否具有预期值 1-3 个周期。这适用于按下 0、1 和 2。但它也必须适用于按下 1、2 和 3。然后按下 2、3 和 4 等。我怀疑断言在按下 2 时通过,然后在按下 3 时失败。即你检查在第三次之后每次按下你的计数器。
另一方面,您的设计有所不同。它计数 3 个否定,递增计数器,然后从头开始计数。
我建议不要在断言中使用局部变量,除非您确定它是您需要的——我认为这里不是这种情况。您可以在 key_press_count == 3 上设置 SVA 触发器(假设您适当地定义了 key_press_count 而不是自动变量)。
如果您坚持使用本地 SVA 变量,您可以稍微修改触发条件以包含计数器。例如一些类似的东西(虽然可能有点错误,还没有测试过): (counter == 0 || $changed(counter)) ##1 ($fell(button_n)[=3], val = counter)
IMO,这是个坏主意,支持 RTL 是更好的方式来记录您的意图,并准确检查您所追求的行为。
希望对您有所帮助