我有类似于伪代码的东西:
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
从代码:只有输入的应用程序可以解除fork,因为其他2个线程在while(1)下工作 我希望在每次迭代之间禁用所有线程,即一旦应用了输入流 - 禁用所有生成的线程,直到下一次迭代开始(使用新配置)
所以我将上面的代码修改为
....
join_any
disable_fork
end
然而,这似乎也禁用了循环以及类似的东西,我不明白,但效果是测试被挂起。 有人能解释一下原因和解决方案吗?
答案 0 :(得分:20)
“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 and 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)语言构造的相似性。
答案 1 :(得分:1)
您应该考虑在SystemVerilog中使用进程而不是禁用
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
if (process1 != null && process1.status != process::FINISHED)
process1.kill();
if (process2 != null && process2.status != process::FINISHED)
process2.kill();
它应该比禁用更安全。
答案 2 :(得分:0)
禁用fork应该可以正常工作。这是一个小例子。
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