我们先来看一段代码:
timescale 1ns/1ps;
task jobs();
fork
begin
#10;
$display("delay 10ns");
end
begin
#20;
$display("delay 20ns");
end
join_any
disable_fork
endtask
这个简单的 fork join_any 会在 打印 “delay 10ns” 这句话之后结束整个 fork join_any 逻辑。这个例子简单,我们接着往下看:
timescale 1ns/1ps;
task job_delay_200ns();
#200ns;
$display("job_delay_200ns end");
endtask
task jobs_test();
fork
job_delay_200ns();
join_none
jobs();
endtask
根据fork join_none的语法,我们知道 job_delay_200ns() 和 jobs(),会同时执行,当打印 “delay 10ns” 这句话之后,按我们的理解,应该再延迟190ns,就应该打印“job_delay_200ns end” 这句话,但实际上会打印这句话吗?大家可以去跑一个简单的case,测试一下,实际上经过测试,永远都不会打印“job_delay_200ns end”,这是为什么呢?
这块就涉及到disable fork的作用范围了, disable fork的作用范围是当前线程的子线程,以及子线程的子线程,子子孙孙全被终结。
从这个jobs_test 的task能看出来,在整个task内,fork join_none 和 jobs() 在一个线程内,这样就相当于 处于job_delay_200ns 这个task 处于 jobs内 disable fork的子线程的位置上,因此也会受到disable fork的影响。
这里有一个很简单的办法,来避免这种误杀,请看代码:
timescale 1ns/1ps;
task jobs();
fork : guard_fork
begin
fork
begin
#10;
$display("delay 10ns");
end
begin
#20;
$display("delay 20ns");
end
join_any
disable fork
end
join : guard_fork
endtask
这样处理的结果类似于把 jobs 内部分disable fork在降一级,相当于 和 job_delay_200ns()内的 fork join_none 平级了,因此也消除了disable fork对其的影响。
还有一种方法,是给dsiable fork起名字,比如说 disable : xxxxx_fork,这样指定也是可以的,如果你讲这个fork 封装在了task内,并且会调用多次这个task时,你会发现 disable 一旦生效,所有task内的线程都结束了,也不是最好的解决办法。最好的办法还是采用第一种,给带disable 的fork套上套子,让他限定在fork join 内权力不要外溢。