英文:
Use of disable fork inside forever loop of fork-join
问题
在上述任务中,一旦ack_arrival完成,"disable fork"会终止整个任务,而不是仅终止进程,因此任务不会检测到任何其他"req"更改。有人可以解释为什么会这样吗?
不好意思,我已经翻译了内容并提供了翻译的代码,不会回答关于要翻译内容的问题。
英文:
I am having "disable fork" inside a fork-join which embeds inside forever begin.
So I am expecting every time new process would be created & killed once either of the thread gets finished. But it runs only once .
I am having the below code which is executing only once.
module tb();
`timescale 1ns/1ns
bit clk;
always #2 clk =~ clk;
task automatic req_ack(ref bit req, ref bit ack, input string name);
forever begin
$display("waiting for req");
@(req);
$display("Req changed at %t for %0d", $time, req);
fork
begin
#5us;
$display("ACK expired");
disable fork;
end
begin
wait(ack == req); //This will succeed
$display("Ack received for %s at %t", name, $time);
disable fork;
end
join
end
endtask
bit tx_req, tx_ack;
initial begin
repeat(5) @(posedge clk);
tx_req = 1;
repeat(5) @(posedge clk);
tx_ack = 1;
$display("ack from tb at %t", $time);
repeat(5) @(posedge clk);
tx_req = 0;
repeat(5) @(posedge clk);
tx_ack = 0;
repeat(15) @(posedge clk);
$finish;
end
initial begin
req_ack(tx_req, tx_ack, "TX");
end
endmodule
In the above task, once ack_arrival gets finished, " disable fork" kills the whole task instead of the process such that task doesn't detect any other "req" change.
Can someone please explain why does it so ?
答案1
得分: 4
`disable fork`禁用当前线程的_children_。你的语句在forked进程中,该进程没有子进程。所以`join`直到你的过期超时在**5µs**发生之前都不会发生。但是,在此之前的138ns,你调用了`$finish`,它根本不会有机会发生。如果你将过期延迟更改为**5ns**,你将看到发生了什么。
你应该立即在`fork/join_any`之后使用`disable fork`。
```Verilog
// `timescale 需要放在模块外部
`timescale 1ns/1ns
module tb();
bit clk;
always #2 clk =~ clk;
task automatic req_ack(ref bit req, ref bit ack, input string name);
bit local_req, local_ack;
fork
// 用于在fork/join_any中访问引用参数的解决方法
forever @req local_req = req;
forever @ack local_ack = ack;
forever begin
$display("waiting for req");
@(req);
$display("Req changed at %t for %0d", $time, req);
fork
begin
#5us;
$display("ACK expired");
end
begin
wait(local_ack == local_req); //这将成功
$display("Ack received for %s at %t", name, $time);
end
join_any
disable fork;
end
join
endtask
bit tx_req, tx_ack;
initial begin
repeat(5) @(posedge clk);
tx_req <= 1; // 使用NBA以避免tb竞态条件
repeat(5) @(posedge clk);
tx_ack <= 1;
$display("ack from tb at %t", $time);
repeat(5) @(posedge clk);
tx_req <= 0;
repeat(5) @(posedge clk);
tx_ack <= 0;
repeat(15) @(posedge clk);
$finish;
end
initial begin
req_ack(tx_req, tx_ack, "TX");
end
endmodule
英文:
disable fork
disables the children of the current thread. Your statement is inside the forked process which has no children. So the join
cannot happen until your expiration timeout occurs at 5µs. But, you call $finish
at 138ns before that ever has a chance of happening. If you change your expiration delay to 5ns, you will see what is happening.
You should use fork/join_any
with a disable fork
immediately afterwards.
// `timescale needs to go outside module
`timescale 1ns/1ns
module tb();
bit clk;
always #2 clk =~ clk;
task automatic req_ack(ref bit req, ref bit ack, input string name);
bit local_req, local_ack;
fork
// workaround for accessing ref arguments in fork/join_any
forever @req local_req = req;
forever @ack local_ack = ack;
forever begin
$display("waiting for req");
@(req);
$display("Req changed at %t for %0d", $time, req);
fork
begin
#5us;
$display("ACK expired");
end
begin
wait(local_ack == local_req); //This will succeed
$display("Ack received for %s at %t", name, $time);
end
join_any
disable fork;
end
join
endtask
bit tx_req, tx_ack;
initial begin
repeat(5) @(posedge clk);
tx_req <= 1; // use NBA to avoid tb races
repeat(5) @(posedge clk);
tx_ack <= 1;
$display("ack from tb at %t", $time);
repeat(5) @(posedge clk);
tx_req <= 0;
repeat(5) @(posedge clk);
tx_ack <= 0;
repeat(15) @(posedge clk);
$finish;
end
initial begin
req_ack(tx_req, tx_ack, "TX");
end
endmodule
答案2
得分: -2
一个有缺陷的解决方案
自动化测试程序;
bit tx_req = 0;
任务 自动 req_ack(引用 bit req);
while(1) begin
@(req);
叉口: STOP_THIS
开始 : 超时
int delay = $urandom_range(1,3);
重复(delay) #1;
$display("timeout thread run");
禁用 STOP_THIS;
end
开始 : ack_arrival
int delay = $urandom_range(1,3);
重复(delay) #1;
$display("ack_arrival thread run");
禁用 STOP_THIS;
end
合并
end
endtask : req_ack
initial begin
req_ack(tx_req);
end
initial begin
for(int i=0; i<10; i++) begin
tx_req = i%2;
#10;
end
end
endprogram
英文:
A flawed solution
program automatic test;
bit tx_req = 0;
task automatic req_ack(ref bit req);
while(1) begin
@(req);
fork: STOP_THIS
begin : timeout
int delay = $urandom_range(1,3);
repeat(delay) #1;
$display("timeout thread run");
disable STOP_THIS;
end
begin : ack_arrival
int delay = $urandom_range(1,3);
repeat(delay) #1;
$display("ack_arrival thread run");
disable STOP_THIS;
end
join
end
endtask : req_ack
initial begin
req_ack(tx_req);
end
initial begin
for(int i=0; i<10; i++) begin
tx_req = i%2;
#10;
end
end
endprogram
Here is the link of testbench EDA playgroup
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论