我想编写并发断言,它是在从UVM测试平台在DUT上执行一些寄存器写入后开始的。
class test extends uvm_test;
bit flag;
task run_phase(uvm_phase phase);
//call register write task , data is chosen in a random fashion
write(addr,data);
flag = 1; // flag gives the time when the register is written.
// after this task the assertions must start depending on data.
endtask
endclass
module top();
//instantiate dut, interface and other stuff
property p1(logic a,logic [4:0] b,logic flag,logic c);
disable iff(!reset || b[i] == 1 || !flag)
/*
default register value is 0, enable assertion only if 0 is written into it.
(0 is for enabling certain feature in DUT and by-default it is enabled.
1 is for disabling that feature. Assertion must never be enabled if b[i] contains 1)
*/
@(posedge clk)
a == 0 |-> $stable(c);
endproperty
assert property p1(dut_top.path_to_dut_signal,uvm_test_top.data,uvm_test_top.flag,dut_top.path_to_dut_other_signal); // gives compile error
// basically I need here dut's signal and the data written to register
// call run_test and set config_db for interface here
initial
begin
// ... run_test
end
这会产生交叉模块引用编译错误,因为 uvm_test_top 是在运行时创建的,我想断言输入是在编译时设置的。
所以,我找到了一些解决方法,为此。
在全局空间中声明一些temp和flag变量,如下所示:
bit flag; // in global space
logic [4:0] temp;
class test extends uvm_test;
task run_phase(uvm_phase phase);
//call register write task
write(addr,data);
temp=data, flag=1;
// after this task the assertions must start depending on temp.
endtask
endclass
/** In top, **/
property p1(logic a,logic [4:0] b,logic flag,logic c);
disable iff(!reset || b[i] == 0 || flag ==0)
@(posedge clk)
a == 0 |-> $stable(c);
endproperty
assert property p1(dut_top.path_to_dut_signal,temp,flag,dut_top.path_to_dut_other_signal);
// solves the error
这里使用了两个全局空间变量;哪个,最好避免。
无论哪种方式,我都可以将这些变量置于顶部,并在测试中通过$ root访问它们。但是,我不喜欢使用$ root来实现可重用性和包问题(如果我的名字发生了变化,或者写了断言的seprate模块,那么测试就会出错)。
我想知道还有其他更好的方法来实现这个目标吗?这样我就可以延迟执行断言了。即使我将它延迟1个时间戳,我也会评估uvm_test_top(听起来很疯狂!! !!)。
另外,我不想使用接口信号,因为DUT是协议不可知的,它可以支持基于`ifdefs的不同接口。 (实际上这也是另一种解决方法!)
非常感谢任何帮助。
答案 0 :(得分:4)
我能想到的最便携的事情就是在你的SVA接口/模块/检查器中声明一个事件,它发出有趣的寄存器写入时的信号:
interface sva_checker(...);
event register_written;
property my_prop;
register_written |-> ...
endproperty
endinterface
这样,您只能在发生寄存器写入后触发您的属性。您也不需要根据协议信号确定何时发生寄存器写入,因为您将依赖于来自测试平台的信息。
现在有趣的部分是从你的UVM测试平台触发这个事件。首先,您需要将此接口传递给UVM测试平台。如果这是您拥有的唯一界面,那么它非常简单。您只需执行配置数据库集和相应的get:
// in top or wherever you instantiate your SVA checker
uvm_config_db #(virtual sva_checker)::set(...);
// in your UVM TB
uvm_config_db #(virtual sva_checker)::get(..., sva_checker);
现在,在您的代码中,您可以在知道写入寄存器后触发事件:
task run_phase(uvm_phase phase);
//call register write task , data is chosen in a random fashion
write(addr,data);
-> sva_checker.register_written;
// after this task the assertions must start depending on data.
endtask
这样您就不会使用任何分层路径,并且您不会遇到可重用性问题。
P.S。我考虑将UVM寄存器包用于寄存器。通过这种方式,您可以在寄存器写入后自动触发此事件,而无需手动调用。