【问题标题】:Flip-flop and latch inferring dilemma触发器和锁存器推断困境
【发布时间】:2016-06-01 14:22:03
【问题描述】:

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

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

always 块对信号边沿敏感这一事实是否足以推断出触发器。在这种情况下,当触发复位的下降沿时,a 为 0,否则保持原来的值。

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

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

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

另一方面,如果在分配的右侧有一个 VARIABLE,则综合将不得不推断一个触发器,因为输入是否在边缘采样(触发器flop)或在启用输入锁存期间(latch),这意味着两个逻辑元件不等价

这是一个例子。前两个 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

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

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

如果有人能对此有所了解或评论代码或波形,将不胜感激。

【问题讨论】:

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


    【解决方案1】:

    合成器会推断出一个锁存器,因为这段代码表现得像一个锁存器。它的行为不像触发器。就这么简单。

    想想这段代码的行为:最初a 的值将是'x。当rst 被断言为低电平时,a 将变为'0。然后a 将永远留在'0。因此a 的状态不仅取决于输入的当前状态,还取决于过去的状态。因此,我们有顺序逻辑,而不是组合逻辑。触发器在时钟沿改变状态; a 没有。 always 块对信号边沿敏感的事实无关紧要。这只是意味着里面的代码是在那个信号边沿上执行的——clk 的上升沿。但是当这种情况发生时,什么都不会发生,所以这段代码的行为就像一个闩锁。

    【讨论】:

    • 好的,但在我看来,它也可以像人字拖一样工作。在负复位时清除触发器,否则在 clk 的上升沿保持先前的值。这相当于: [link] (imgur.com/htuPVsC) 此外,硬件不能有状态 x。它可以是 0、1 或 Z,因此在两种情况下(锁存器或触发器)它都会在上电时确定某个任意值(0 或 1)。在我看来,代码的行为可以像两者一样,但综合工具会选择占用较少资源的那个。
    • @evilpascal 选择占用资源较少的电路对于合成器来说几乎是生计。
    【解决方案2】:

    因为你还没有具体说明时钟摆位时会发生什么。就好像a 根本不依赖于clk 或其姿态。您的所有描述都是在rst=0 时将a 设置为0。此外,它(含蓄地)说a 在所有其他情况下都保持其先前的值。这可以通过锁存器来实现。

    请注意,仅仅因为您拥有@posedge 或clk 并不意味着该块中的每个变量都将被合成为触发器。当块在 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
    

    【讨论】:

    • 但是我帖子中的第一个代码应该表现得像一个带有异步复位而不是锁存器的触发器,因为它应该只在复位的下降沿采样,而不是在复位时一直采样取消断言。请在编辑后的问题中查看我的分析。
    • 触发器可以做而锁存器不能做的事情是在 clk 的边缘采样信号。复位将输出值强制为恒定值。这可以通过锁存器来实现,综合工具更喜欢锁存器,因为它的面积较小。您示例中的y 信号就像一个触发器,因为现在nrst 就像一个时钟信号并在其边沿对输入值进行采样。这不能由单个锁存器完成。请注意,尽管您指定了@negedge rst,但由于输出被分配给一个常数,它不需要对 rst 边缘敏感。一个对 rst 级别敏感的模块就足够了。
    • 当常量位于赋值的右侧时,锁存器和触发器的行为是等效的。这不是问题。你提到了y 信号,这就是事情变得奇怪的地方,因为yz 都被合成为锁存器,我认为这不可能是真的。由于赋值右侧有一个变量(信号),最后两个 always 块(yz)的功能不能等效(参见我附加的分析和波形)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-07
    • 1970-01-01
    • 2012-07-01
    • 1970-01-01
    • 2012-02-23
    • 1970-01-01
    相关资源
    最近更新 更多