关于非阻塞语句,begin-end和fork-join之间有什么区别



我们知道阻塞语句和非阻塞语句之间的区别是:阻塞语句按顺序执行(下一个语句的执行被阻塞,直到当前语句完成(,并用于在组合电路中执行。

示例:

always@(*) begin
c = A & B;
D = C/A;
end

这里所有的语句都按顺序执行(阻塞语句(

而非阻塞语句是并行执行的(下一个语句的执行不被阻塞(,用于在顺序电路中执行。

示例:以移位寄存器为例

always@posedge(clk) begin
A<=B;
B<=C;
C<=D;
end

这里所有的语句都是并行执行的,因为它是非阻塞的,并且我们使用了posedge clk

现在,如果您看到begin endfork join之间的区别,那么区别是:在begin end中,语句是按列出的顺序(即按顺序(执行的,而在fork join中,语句则是并行执行的。

我的问题是,在上面的非阻塞语句示例中,我们使用了begin end,但这些语句是并行执行的,而不是按顺序执行的,但如果你看到begin endfork 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提供了为高效的测试台编码而设计的附加功能。例如,代码执行在连接处停止,直到每个分叉块都完成了执行。

最新更新