为何Verilog的fork-join中#10后加分号会引发行为差异?
为什么Verilog的fork-join里,延迟语句后的分号会改变执行行为?
问题的核心在于Verilog的分号是语句结束符,加上分号会把原本绑定在一起的「延迟+执行逻辑」拆成两个独立的并行分支,完全改变了执行时序。
两种代码的本质差异
第一种代码(#10后无分号)
module waveform_fork_join(); reg A,B,C,D,E,F,en; initial fork en = 1'b0; A = 1'b1; B = 1'b0; C = 1'b0; D = 1'b0; E = 1'b1; F = 1'b1; #10 begin A = 1'b0; B = 1'b1; C = 1'b1; end #20 begin A = 1'b1; B = 1'b0; D = 1'b1; E = 1'b0; end #30 begin B = 1'b1; E = 1'b1; F = 1'b0; end #40 begin en = 1'b1; B = 1'b0; D = 1'b0; F = 1'b1; end #50 begin B = 1'b1; end #60 begin B = 1'b0; D = 1'b1; end #70 B = 1; #80 $finish; join endmodule
这里的#10 begin...end是一个完整的并行分支:意思是「先等10个时间单位,再执行begin块里的赋值」。同理,#20 begin...end、#30 begin...end等都是独立的延迟执行分支,各自在对应时间点触发变量更新。
输出表现:变量会按10、20、30等时间点依次切换状态,比如A在10时刻变0、20时刻变回1,完全符合预期的波形时序。
第二种代码(#10后有分号)
module waveform_fork_join1(); reg A,B,C,D,E,F,en; initial fork en = 1'b0; A = 1'b1; B = 1'b0; C = 1'b0; D = 1'b0; E = 1'b1; F = 1'b1; #10; begin A = 1'b0; B = 1'b1; C = 1'b1; end #20; begin A = 1'b1; B = 1'b0; D = 1'b1; E = 1'b0; end #30; begin B = 1'b1; E = 1'b1; F = 1'b0; end #40; begin en = 1'b1; B = 1'b0; D = 1'b0; F = 1'b1; end #50; begin B = 1'b1; end #60; begin B = 1'b0; D = 1'b1; end #70; B = 1; #80 $finish; join endmodule
这里的#10;变成了一条独立的并行分支:它只做一件事——等待10个时间单位,之后就结束,完全不执行任何赋值。而后面的begin...end是另一条完全独立的并行分支,这条分支没有任何延迟,会在0时刻(和第一个赋值分支同时)执行里面的所有赋值!
同理,#20;、#30;等都是只做延迟的空分支,它们后面的begin块全都是0时刻执行的分支。这就导致所有begin块的赋值会在0时刻一次性执行,直接覆盖了第一个分支的初始值。
输出表现:0时刻所有变量就被begin块的赋值覆盖,之后仅在70时刻B被赋值为1,其余时间点无变量更新,直到80时刻执行$finish。
总结
在fork-join中,每一条以分号结尾的语句(或语句块)都是一个并行执行的线程:
- 没加分号:
#N begin...end是一个线程,等待N时间后执行块内逻辑 - 加了分号:
#N;是一个线程(仅做延迟,无操作),begin...end是另一个线程(立刻执行块内逻辑)
内容的提问来源于stack exchange,提问作者lehar
相关产品推荐
相关产品推荐

