使用阻塞分配来推断Verilog中的触发器

时间:2012-06-25 23:19:35

标签: verilog system-verilog

我读过“Verilog综合中的非阻塞分配,杀死的编码样式!”作者:Clifford Cummings。他说下面的代码(第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部分中的上述陈述仅涉及更新事件的时间安排,并不意味着文字等同于一些连续的任务和总是块。然而,我认为他们解释了为什么一些模拟器(例如Icarus Verilog)会在“触发器”中产生具有阻塞和非阻塞分配的不同模拟结果。 [在一个更大的例子中,我得到2个具有阻塞分配的明显ffs,正确的5个具有非阻塞分配。]其他模拟器(例如具有默认选项或Cver的Modelsim)似乎产生相同的结果,无论哪种形式使用了分配。

2 个答案:

答案 0 :(得分:6)

全部 -

一些更正和更新。 2001版Verilog标准的第5.6.6节没有说“单向端口就像连续分配”,它说“端口通过隐式连续赋值语句连接进程”。我将在下面注意到有所不同。

其次,“连续分配只是对所有事物始终保持敏感,”事实并非如此。将连续分配 驱动 值分配到网络上,这些网络可由具有预定义分辨率功能的其他来源驱动,如Verilog标准中所述。始终阻止 更改 变量值以及最后的程序更改获胜(无解决方案)。

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

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

问候 - Cliff Cummings - Verilog& SystemVerilog Guru

答案 1 :(得分:0)

阅读论文的Version 1.3,第9节示例13.其下的文字说明如果模块只包含一个始终块,则可以。我目前的理解是,它不是单独模块之间的问题。允许您的示例工作。但是,如果一个模块包含多个always块,那么执行顺序是不确定的,并且会导致paper的第2部分中讨论的竞争条件。

下面的示例几乎与问题中的2个翻牌示例相同,除了它在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