2

我已阅读“Verilog 综合中的非阻塞分配,致命的编码风格!” 通过克利福德卡明斯。他说以下代码(第 12 页,简化版)是教科书中经常使用的触发器的正确​​实现,即使不是任何人都应该使用的那种。该文件获得了最佳论文奖,因此我认为该声明是正确的。

module ff (q, d, clk)
  output q;
  input d, clk;
  reg q;

  always @(posedge clk)
    q = d;
endmodule

我想知道如果两个或多个这些触发器串联连接,为什么它会继续正常工作。说

module two_ffs (q, d, clk)
  input d, clk;
  output q;

  wire tmp;

  ff firstff (tmp, d, clk);
  ff secondff (q, tmp, clk);
endmodule

在我看来,tmp 的值可能在被 secondff 使用之前被更新,从而导致一个触发器而不是两个触发器。有人可以告诉我标准的哪一部分说不能发生吗?非常感谢。

[并不是说我会考虑编写这样的代码,我只是想了解阻塞/非阻塞行为,即使在糟糕的编码风格使含义不明显的情况下]

后来补充:

我现在认为这篇论文不太可能是正确的。1364-2201 Verilog 标准的第 5 节“调度语义”解释了会发生什么。特别是,第 68 页的第 5.6.6 节“端口连接”说单向端口就像连续分配一样。反过来,连续分配只是对所有内容都敏感的始终块。所以底线是,在我下面的示例中,ff 的两个实例化等效于具有多个 always 子句的模块,每个人都会同意它被破坏了。

在 Clive Cummings 回答问题后添加:

我感谢 CC 指出,从标准第 5 节中取出的上述陈述仅涉及更新事件的时间,并不意味着某些连续赋值和始终块之间的字面等效性。尽管如此,我认为他们解释了为什么一些模拟器(例如 Icarus Verilog)会在“触发器”中产生不同的模拟结果,其中包含阻塞和非阻塞分配。[在一个更大的例子中,我得到了 2 个带有阻塞分配的明显 ffs,而正确的 5 个带有非阻塞分配。] 其他模拟器(例如具有默认选项的 Modelsim 或 Cver)似乎产生相同的结果,无论哪种形式使用赋值。

4

2 回答 2

7

全部 -

一些更正和更新。2001 Verilog 标准的第 5.6.6 节没有说“单向端口就像连续赋值一样”,它说“端口通过隐式连续赋值语句连接进程”。我将在下面指出一个区别。

其次,“连续分配只是对所有事物都敏感的始终块”是不正确的。连续分配将值驱动到可由其他源驱动的网络上,具有 Verilog 标准中所述的预定义分辨率功能。始终阻止变量的更改值和最后的程序更改获胜(无解决方案)。

关于我对 1-always 块触发器的描述,我在论文中的描述不是 100% 准确的(但通常是准确的)。理论上,2 实例化触发器模型确实存在竞争条件,尽管这种情况很少见。这种竞争很少见,因为当您对声明为输出的变量进行始终块赋值时,Verilog 编译器会自动抛出“隐式连续赋值语句”(IEEE-1364-2001,第 5.6.6 节,第 1 段)将程序变量转换为网络驱动分配(您永远不会看到这种情况发生!)这种转换通常足以在端口上引入等效的非阻塞分配延迟,因此模拟工作。我过去曾尝试过编译器优化开关,它有效地删除了触发器之间的模块端口,并观察到了不需要的竞争条件,所以从技术上讲,我对一个好的 1-always,blocking-assign 触发器的描述不是 100 % 正确的; 因此,您仍然应该使用本文中描述的非阻塞分配。

同一模块中的 2-always 阻塞赋值示例具有明确的竞争条件。正如所写的那样,它可能会起作用,因为大多数编译器自顶向下执行代码,但如果你颠倒 always 块的顺序,你可能会看到一场比赛。

问候 - Cliff Cummings - Verilog 和 SystemVerilog 大师

于 2012-06-27T17:53:46.727 回答
0

阅读论文的1.3 版,第 9 节示例 13。它下面的文本解释说,如果模块只包含一个 always 块是可以的。我目前的理解是,这不是单独模块之间的问题。让您的示例发挥作用。但是,如果一个模块包含多个 always 块,则执行顺序未定义,将导致本文第 2 节中讨论的竞争条件

下面的示例与问题中的 2 flop 示例几乎相同,只是它位于 1 个模块中,因此执行顺序未定义,这可能不起作用。

module ff (q, d, clk)
  output reg q;
  input d, clk;
  reg d_delay ;

  always @(posedge clk)
    d_delay = d;

  always @(posedge clk)
    q = d_delay;

endmodule
于 2012-06-26T19:18:33.327 回答