【问题标题】:What is the difference between begin end and fork join with respect to non-blocking statements?对于非阻塞语句,begin end 和 fork join 有什么区别?
【发布时间】:2020-09-23 09:07:14
【问题描述】:

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

例子:

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一个接一个地执行语句。

有人能解释清楚吗?

【问题讨论】:

  • 了解可综合代码和不可综合代码的区别。如果您打算真正构建一些东西,请编写可综合的代码。

标签: verilog system-verilog fork-join vlsi


【解决方案1】:

在上面的非阻塞语句示例中,我们使用了 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

把它想象成一个在每个时间步执行的流程图。 (timestep 是一个特定的仿真时间 - 12345ns 或其他。)begin-end 块中的代码行在 ACTIVE 区域中执行(即早),但是,您的非阻塞分配的左侧直到 NBA 地区才会更新,即稍后。

【讨论】:

  • 这是对问题中所述假设错误的非常有用的更正。但是,它实际上并没有解决这个问题。这个答案被标记了(可能是因为这个)我把它标记回零,因为纠正假设是有用的。
【解决方案2】:

您对非阻塞分配的描述不正确。程序块中的所有语句(always、initial、final)总是顺序执行,包括具有非阻塞赋值的语句。多个语句包含在开始/结束对中。

阻塞赋值和非阻塞赋值的区别在于值被赋值给左侧变量。非阻塞赋值导致延迟赋值。它也是按顺序完成的,但在延迟调度区域中。这是一个模拟工件。

fork/join 对导致内部的所有语句并行执行。它们属于测试台,不可合成。通常它们用于在模拟中并行运行多个测试台任务

【讨论】:

    【解决方案3】:

    Serge 是正确的。您可以将 fork .. join 视为将每个表达式拆分为自己的操作块。因此,如果您重新编码示例:

    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;
    

    在这种情况下,它的行为恰好就好像它在 begin .. end 对中一样。

    正如其他人所指出的,综合工具通常会拒绝 fork .. join 构造,因为虽然您在这里没有使用它们,但 fork join 提供了为高效测试台编码而设计的附加功能。例如,代码执行在连接处停止,直到每个分叉块都完成执行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-28
      • 2012-01-15
      • 1970-01-01
      • 2014-06-24
      • 2013-09-06
      相关资源
      最近更新 更多