【问题标题】:Using blocking assignments to infer flip-flops in Verilog在 Verilog 中使用阻塞分配来推断触发器
【发布时间】:2012-06-27 06:21:54
【问题描述】:

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

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 节中摘录的陈述仅指更新事件的时间,并不意味着 e.g.一些连续的分配和总是阻塞。尽管如此,我认为他们解释了为什么某些模拟器(例如 Icarus Verilog)会在“触发器”中产生不同的模拟结果,其中包含阻塞和非阻塞分配。 [在一个更大的例子中,我得到了 2 个带有阻塞分配的明显 ffs,而正确的 5 个带有非阻塞分配。] 其他模拟器(例如具有默认选项的 Modelsim 或 Cver)似乎产生相同的结果,无论哪种形式使用赋值。

【问题讨论】:

  • 你确定这是一个正确实现的例子吗?对我来说,这看起来像是一个错误设计的教科书示例。我认为你的理解是正确的。
  • 我实际上在 this paper 的任何地方都看不到第一部分。我认为您可能误读了它,或者您能指出您从哪里获得该代码示例吗?我在第 12 页上没有看到它(我的版本可能与你不同)。
  • Tim:很抱歉没有提供链接(现在添加)。我指的是文档的 rev 1.3,而您找到的是 rev 1.2。再次抱歉。这两份文件都在第 9 节中。 “示例 13 显示了出现在大多数 Verilog 测试书中的触发器模型”。然后它的标题是“简单有缺陷......但它有效!”。
  • 好的,我知道了。嗯,我想不出他为什么会这么说。无论如何:“我们鼓励读者在发现潜在错误或希望提出改进建议时向 Cliff Cummings(已编辑)发送电子邮件。” 也许您可以询问作者 :)
  • 如果您可以访问大学图书馆,您可能需要考虑获得 IEEE 1364.1 Verilog 寄存器传输级综合标准

标签: verilog system-verilog


【解决方案1】:

阅读Version 1.3 的论文,第 9 节示例 13。它下面的文本解释说,如果模块只包含一个 always 块是可以的。我目前的理解是,这不是单独模块之间的问题。让您的示例发挥作用。但是,如果一个模块包含多个 always 块,则执行顺序未定义,并会导致 paper 第 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

【讨论】:

  • 我还认为模块之间的调度有点特殊。但标准说不是。请参阅顶部新添加的评论。非常感谢您的回复。
【解决方案2】:

全部 -

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

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

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

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

问候 - 克里夫卡明斯 - Verilog & SystemVerilog 大师

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-20
    • 2011-06-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多