触发器和锁存器推断困境

evi*_*cal 2 hardware verilog digital-logic digital-design flip-flop

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

always_ff @ (posedge clk, negedge rst) 
begin
  if (!rst)
    a <= '0;
end
Run Code Online (Sandbox Code Playgroud)

总是块对信号边缘敏感这一事实不应该足以推断出触发器吗?在这种情况下,当触发复位的下降沿时,a 变为 0,否则保持以前的值。

这个问题来自这个 stackoverflow 问题中选择的最佳答案:
System Verilog always_latch vs.always_ff

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

我将在这里分享我迄今为止所发现的内容。之所以合成锁存器而不是触发器,是因为赋值的右侧是一个常数。在这种情况下,锁存器和触发器的行为是等效的,因为无论它是在信号边沿(触发器)捕获输入值,还是在启用输入锁存(锁存器)作为输入时捕获输入值,都无关紧要。没有改变。因此综合工具选择占用资源较少的元件,即锁存器。

另一方面,如果在赋值的右侧有一个变量,则综合必须推断出触发器,因为输入是在边沿(触发器)上采样还是在输入锁存期间采样很重要启用(锁存),意味着两个逻辑元素不相等。

这是一个例子。前两个always块将合成一个锁存器(在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
Run Code Online (Sandbox Code Playgroud)

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

在此输入图像描述

块 3. (tb_y) 的行为类似于异步触发器,块 4. (tb_z) 的行为类似于锁存器。但综合工具在这两种情况下都会推断出锁存器。

如果有人可以阐明这一点或评论代码或波形,我们将不胜感激。

Mat*_*lor 5

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

考虑一下这段代码的行为方式:最初的值awill 是'x。当rst被断言为低电平时a将变为'0。a然后将永远保留'0。因此, 的状态a不仅取决于输入的当前状态,还取决于过去的状态。因此,我们有顺序逻辑,而不是组合逻辑。触发器在时钟沿改变状态;a才不是。事实上,always 块对信号边沿敏感是无关紧要的。这仅意味着内部代码在该信号边缘( 的正边缘)上执行clk。但当这种情况发生时,什么也没有发生,所以这段代码的行为就像一个锁存器。