最近做笔试题遇到了好多这种题型,不太会,写篇文章讨论一下。
module test;
initial begin
for(int j=0;j<3;j++)begin
fork
$write("%d\n",j);
join_none
end
$display("\tend\n");
end
endmodule
运行结果
未添加#0的情况下,fork...join_none中启动的线程在主线程代码执行完后运行。
先执行了打印语句$display("\tend\n"),for循环中,循环了三次,启动了三个$write线程,执行完打印语句后,开始同时运行,静态变量j只分配一次内存,三次$write都更新这个内存,所以三次的结果都是j=3。为得到预期的结果,将特定变量加上automatic属性
module test;
initial begin
for(int j=0;j<3;j++)begin
automatic int k=j;
fork
$write("%d",k);
join_none
end
$display("\tend\n");
end
endmodule
运行结果为
声明为automatic的变量,变量存在动态存储区,每次对任务或函数的调用都会分配动态存储区域来存储变量,任务或函数执行完,自动释放其动态存储区。
或者可以使用wait fork达到预期效果
wait fork调用会引起调用进程阻塞直到所有子进程结束。一般用来确保所有子进程的执行都已经结束。
module test;
initial begin
for(int j=0;j<3;j++)begin
fork
$write("%d\n",j);
join_none
wait fork;
end
$display("\tend\n");
end
endmodule
执行结果为
或者使用#0来达到预期效果
解释这张图:
Preponed Region
- 采样数据,为断言做准备
Active Region
- 阻塞赋值
- 计算非阻塞赋值的右侧表达式,更新相应的事件到NBA Region(非阻塞赋值区)。
- 连续赋值
- 调用$display系统函数
- primitive计算
Inactive Region
- #0延迟下的阻塞赋值
NBA Region
- 更新非阻塞赋值的左侧表达式
Observed Region
- 使用Preponed Region采样到的值来计算断言
Reactive Region
- 所有定义在program内的阻塞赋值
- 所有定义在program内的非阻塞赋值计算,并将相应的更新时间调度至Re-NBA Region。
- 所有program内的连续赋值
- 执行系统函数$exit及隐式的$exit命令
Reactive Region与Active Region内执行事件是类似的,不过加了program的限定。
Re-Inactive Region
- program中#0延迟的进程
Re-NBA Region
- 执行Reactive Region调度多来的非阻塞赋值左侧更新
Postponed Region
- 调用$monitor和$strobe系统函数
- 收集利用strobe采样的功能覆盖率
module test;
initial begin
for(int j=0;j<3;j++)begin
fork
$write("%d\n",j);
join_none
#0 $display("\tend\n");
end
end
endmodule
将#0放在for循环内部,在执行主线程时会被#0阻塞住,所以会出现上面这种执行结果。
当fork...join_none的进程被堵塞住,或者使用automatic另起线程进行赋值都可以得到预期的结果。
.......