触发器和闩锁推断两难

时间:2016-06-01 14:22:03

标签: verilog hardware digital-logic flip-flop digital-design

有人可以向我解释为什么会推断出锁存器而不是触发器吗?

always_ff @ (posedge clk, negedge rst) 
begin
  if (!rst)
    a <= '0;
end

始终阻塞对信号边缘敏感的事实不足以推断出触发器。在这种情况下,当触发复位的下降沿时,获得0,否则它保持原值。

此问题来自此stackoverflow问题中选定的最佳答案:
System Verilog always_latch vs. always_ff

=============================================== ============================

我将在此分享我到目前为止所发现的内容。它合成锁存器而不是触发器的原因是因为在赋值的右侧是CONSTANT。 在这种情况下,锁存器和触发器的行为是等效的,因为它是否捕获信号边沿(触发器)上的输入值或启用输入锁存(锁存器)无关紧要因为输入没有改变。因此,综合工具选择占用较少资源的元素,即锁存器。

另一方面,如果在赋值的右侧有一个VARIABLE,则合成必须推断触发器,因为输入是否在边缘上采样是很重要的(翻转 - 翻转)或在输入锁存期间启用(锁存),意味着两个逻辑元素不等同

这是一个例子。前两个始终块将合成一个锁存器(在Quartus 14中),这是正常的,因为它们是等价的,因为它是常量。但是,3.和4. always块也将被合成为一个锁存器,这不是预期的行为,这些块不等同! 3.块将发出警告,而4.将不会发出警告。

 module ff_latch(
   input logic clk,
   input logic nrst,
   input logic a,
   output logic t, x, y, z
 );

    always_ff @(posedge clk, negedge nrst) 
       begin
          if (!nrst)
           t <= 0;
       end

    always_latch
       begin
          if (!nrst)
           x <= 0;
       end

    always_ff @(posedge clk, negedge nrst) 
       begin
          if (!nrst)
           y <= a;
       end

    always_latch
       begin
          if (!nrst)
           z <= a;
       end

endmodule: ff_latch

对我来说这种行为是不正确的,因为我特意说我想要一个触发器(带边缘触发)。这甚至不是编码模糊,总是第3和第4块明显不同,从上面的模拟中可以看出:

enter image description here

块3.(tb_y)表现得像异步触发器和块4.(tb_z)表现得像 latch 但是合成工具在两种情况下都会推断出锁存

如果有人可以对此进行阐述或评论代码或波形,我们将不胜感激。

2 个答案:

答案 0 :(得分:4)

合成器将推断锁存器,因为此代码的行为类似于锁存器。它的行为不像触发器。它就这么简单。

考虑一下此代码的行为:最初a的值为'x。如果rst声明为低,则a将变为'0a将永远保留在'0。因此,a的状态不仅取决于输入的当前状态,还取决于过去的状态。因此,我们有顺序逻辑,而不是组合逻辑。触发器在时钟边沿改变状态; a没有。始终块对信号边缘敏感的事实是无关紧要的。这只意味着内部代码在该信号边缘上执行 - clk的上升沿。但是当发生这种情况时,没有任何事情发生,所以这段代码就像一个锁存器。

答案 1 :(得分:1)

因为你还没有明确指出时钟发生了什么。就好像a完全不依赖于clk或它的构成。您的所有说明都是a0时设置为rst=0。此外,它(隐含地)说a在所有其他情况下保持其先前的值。这可以通过锁存器实现。

请注意,仅仅因为你拥有clk的@posed,并不意味着该块中的每个变量都将被合成为一个翻牌。当在clk的posedge处激活块时,您还需要对a进行非阻塞分配。请参阅here

如果你坚持使用翻牌来实现相同的功能,你可以试试这个:

always_ff @ (posedge clk or negedge rst) 
begin
  if (!rst)
    a <= '0;
  else 
    a <= a;  //Here, we are specifying what happens @posedge of clk
end