在 systemverilog 中正确使用“禁用分叉”
Posted
技术标签:
【中文标题】在 systemverilog 中正确使用“禁用分叉”【英文标题】:proper use of "disable fork" in systemverilog 【发布时间】:2012-12-26 13:59:42 【问题描述】:我有类似下面的伪代码:
for (lets say 10 iterations)
begin
// Do some configuration changes
fork
begin
///apply input to design
end
begin
while (1)
/// at particular point update expected status / values
end
begin
while (1)
/// read status and verify with expected values
end
join_any
end
来自代码:只有输入的应用程序才能中断分叉,因为其他 2 个线程正在 while (1) 下工作 我想在 for 的每次迭代之间禁用所有线程,即一旦应用输入流 - 禁用所有生成的线程,直到下一次迭代开始(使用新配置)
所以我将上面的代码修改为
....
join_any
disable_fork
end
但是,这似乎也禁用了 for 循环/或类似的东西,我不明白,但效果是测试挂起。 谁能解释一下原因和解决方法?
【问题讨论】:
这可能会变成一个无用的问题:在禁用不会导致更多事务的分叉后,我没有释放信号量。我目前正在调试,稍后会更新 你想完成什么?你确定你需要一个并行块吗? 谢谢@Adam12 是的,这些块需要并行,我需要验证功能的方式。我正在尝试验证在更新特定寄存器时读取是否提供有效数据。是的,问题是因为我没有发布信号量。我已经解决了它并且它现在可以正常工作了 【参考方案1】:"disable fork" 不仅会杀死由您的 fork...join_any 启动的进程,还会杀死作为执行 disable-fork 的同一进程的后代的任何其他进程。如果您在该进程生命周期的早期启动了任何其他进程(例如,使用 fork...join_none),那么这些其他进程也将被终止。
您可以通过使您的 fork...join_any 及其后来的 disable-fork 在其自己的新子进程中运行来相当容易地防止这种情况发生。这限制了您的 disable-fork 的影响,因此它只能影响您关心的新启动的进程,并保证没有其他不需要的影响。
通过将整个混乱包含在“fork begin...end join”中来做到这一点,如下所示:
fork begin // isolate the following code as a single child process
fork // launch the processes you wish to manage
apply_input();
update_status();
verify_status();
join_any // kill off the *_status threads when apply_input terminates
disable fork;
end join // end of child process isolation
这是 fork...join_any 和 fork...join_none 的一个众所周知的问题。最近在 Verification Guild 论坛上对此进行了讨论,并在 Sutherland 和 Mills 的书“Verilog 和 SystemVerilog Gotchas”的第 79 和第 80 节中进行了描述。
将“fork begin”和“end join”放在单行上是不寻常的,但我喜欢它作为一种非常明显的方式,即我正在同步地分叉一个子进程。通常这将是无用的事情,但在这种情况下,这是必不可少的。
这个成语很常见,也很容易出错,你可能更喜欢将它封装在一对宏中(我不喜欢这样,但是...):
`define BEGIN_FIRST_OF fork begin fork
`define END_FIRST_OF join_any disable fork; end join
现在你可以写...
`BEGIN_FIRST_OF
apply_input();
update_status();
verify_status();
`END_FIRST_OF
其中名称“...FIRST_OF”旨在反映与执行相同操作的 Specman (e) 语言结构的相似性。
【讨论】:
谢谢,这更有意义。到目前为止,我的测试中只有一个分支,所以我的方法是有效的,但我正在将它们更改为您建议的,以便将它们与未来的更改隔离开来。我同意你的看法,至少在我习惯正确的方法之前我不会使用定义【参考方案2】:您应该考虑在 SystemVerilog 中使用 processes 而不是 disable
process process1;
process process2;
fork
begin
process1 = process::self();
# do something in process 1
end
begin
process2 = process::self();
# do something in process 2
end
join_any
#1;
if (process1 != null && process1.status != process::FINISHED)
process1.kill();
if (process2 != null && process2.status != process::FINISHED)
process2.kill();
它应该比禁用更安全。
【讨论】:
即使这样也会有竞争条件,因为 process1 甚至可以在 process2 创建之前完成。 @VineethVS,不确定你的意思。空检查不包括吗? @Diegomanas 不,空检查是为了确保被调用的进程不为空。如果进程 1 完成时甚至没有创建进程 2,会发生什么情况。 我可能在这里遗漏了一些东西。但是,如果您的进程甚至没有创建,那么保存进程处理程序 (process1/2) 的变量将不会被初始化,因为它是在进程本身内部完成的。因此,空处理程序【参考方案3】:禁用分叉应该可以正常工作。这是一个小例子。
module top;
initial
begin
$display(" BEFORE fork time = %0t ",$time );
for(int i = 0 ; i < 3 ; i++)
begin
fork
automatic int j = i;
begin
$display(" Action thread started time = %0t j: %0d",$time,j);
#(10*j);
$display(" Action thread ended time = %0t j: %0d",$time,j);
end
begin
$display(" Entered timeout_15 = %0t j: %0d",$time,j);
#15;
$display(" Ended timeout_15 = %0t j: %0d",$time,j);
end
join_any
disable fork; // it kills all processes
$display("---------------------------------------------------");
end
#100; // This is to make sure if there any threads ..
$display(" time = %0d Outside the main fork ",$time );
$display(" time = %0d After wait fork ",$time );
end
endmodule
输出::
BEFORE fork time = 0
Action thread started time = 0 j: 0
Entered timeout_15 = 0 j: 0
Action thread ended time = 0 j: 0
---------------------------------------------------
Action thread started time = 0 j: 1
Entered timeout_15 = 0 j: 1
Action thread ended time = 10 j: 1
---------------------------------------------------
Action thread started time = 10 j: 2
Entered timeout_15 = 10 j: 2
Ended timeout_15 = 25 j: 2
---------------------------------------------------
time = 125 Outside the main fork
time = 125 After wait fork
【讨论】:
因为这里的fork被封装到了begin/end块中以上是关于在 systemverilog 中正确使用“禁用分叉”的主要内容,如果未能解决你的问题,请参考以下文章
systemverilog 的解决方法没有 `if 编译器指令
如何定义 coverpoint system verilog