我在 fork-join 中设置了“disable fork”,它嵌入了 forever begin 中。 因此,我期望每次线程中的任何一个完成后都会创建和终止新进程。但它只运行一次。
我有下面的代码只执行一次。
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
在上面的任务中,一旦 ack_arrival 完成,“disable fork”会杀死整个任务而不是进程,这样任务就不会检测到任何其他“req”更改。 有人可以解释为什么会这样吗?
disable fork
禁用当前线程的children。您的声明在没有子进程的分叉进程中。所以 join
不会发生,直到您的过期超时发生在 5µs。但是,你在 138ns 之前调用 $finish
,然后才有可能发生。如果您将到期延迟更改为5ns,您将看到发生了什么。
你应该在之后立即使用
fork/join_any
和 disable fork
。
// `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
有缺陷的解决方案
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
这是测试平台的链接EDA playgroup