我们知道阻塞语句和非阻塞语句之间的区别是:阻塞语句按顺序执行(下一个语句的执行被阻塞,直到当前语句完成(,并用于在组合电路中执行。
示例:
always@(*) begin
c = A & B;
D = C/A;
end
这里所有的语句都按顺序执行(阻塞语句(
而非阻塞语句是并行执行的(下一个语句的执行不被阻塞(,用于在顺序电路中执行。
示例:以移位寄存器为例
always@posedge(clk) begin
A<=B;
B<=C;
C<=D;
end
这里所有的语句都是并行执行的,因为它是非阻塞的,并且我们使用了posedge clk
现在,如果您看到begin end
和fork join
之间的区别,那么区别是:在begin end
中,语句是按列出的顺序(即按顺序(执行的,而在fork join
中,语句则是并行执行的。
我的问题是,在上面的非阻塞语句示例中,我们使用了begin end
,但这些语句是并行执行的,而不是按顺序执行的,但如果你看到begin end
和fork join
之间的区别,就会发现begin end
会一个接一个地执行这些语句。
有人能解释清楚吗?
在上面的非阻塞语句示例中,我们使用了begin-end但是这些语句是并行执行的,而不是顺序执行的
这不是真的。在上面的非阻塞语句示例中,我们使用了begin
-end
和,这些语句按顺序执行。然而,尽管如此,处决的顺序并不重要。微妙但重要的区别。
当执行包含非阻塞赋值的代码行时,它会立即执行,但赋值的左侧(目标(不会立即获得其新值。因此,同一begin
-end
块中的任何其他语句,如果使用非阻塞赋值读取分配给的变量,都将使用该变量的旧值。因此,在begin
-end
块内使用非阻塞分配的语句的顺序通常无关紧要。你的例子就是这样。
那么,非阻塞分配的左手边什么时候更新?
System Verilog有9个所谓的调度器区域:
from prev time step
|
PREPONED
|
ACTIVE
|
INACTIVE
|
NBA
|
OBSERVED
|
RE-ACTIVE
|
RE-INACTIVE
|
RE-NBA
|
POSTPONED
|
V to next time step
Verilog有4:
from prev time step
|
ACTIVE
|
INACTIVE
|
NBA
|
POSTPONED
|
V to next time step
将其视为在每个时间步长执行的流程图。(时间步长是一个特定的模拟时间-1234ns或其他时间。(begin
-end
块中的代码行在ACTIVE区域中执行(即早期(,但是,直到NBA区域才更新非块分配的左手边,即稍后。
您对非阻塞分配的描述不正确。过程块中的所有语句(始终、初始、最终(始终按顺序执行,包括具有非块赋值的语句。多个语句包含在开始/结束对中。
分块和非分块赋值之间的区别在于将值分配给左侧变量的时间。非阻塞分配导致分配延迟。它也是按顺序进行的,但在延迟的调度区域中。这是一个模拟工件。
fork/join对导致内部的所有语句并行执行。它们属于试验台,不可合成。通常,它们用于在模拟中并行运行多个测试台任务。
Serge是正确的。你可以想到叉子。。将每个表达式拆分为自己的动作块。所以,如果你重新编码你的eample:
always@posedge(clk) begin
A<=B;
B<=C;
C<=D;
end
作为
always@posedge(clk) fork
A<=B;
B<=C;
C<=D;
join
模拟器会将以上内容解释为:
always@posedge(clk) A<=B;
always@posedge(clk) B<=C;
always@posedge(clk) C<=D;
在这种情况下,它的行为恰好与一开始一模一样。。端对。
正如其他人所指出的,合成工具通常会拒绝叉子。。join构造,尽管您在这里没有使用它们,但fork-join提供了为高效的测试台编码而设计的附加功能。例如,代码执行在连接处停止,直到每个分叉块都完成了执行。