Verilog 在if条件下,当else语句缺失时,推断出的闩锁是什么,以及如何创建闩锁。有人能简单解释一下吗?

Verilog 在if条件下,当else语句缺失时,推断出的闩锁是什么,以及如何创建闩锁。有人能简单解释一下吗?,verilog,Verilog,我试图找出推断出的锁存器以及内部需要它的原因,但我找不到任何足够详细的资源。当组合逻辑的输出具有未定义的状态时,会推断出锁存器,即它必须保持其先前的值 组合逻辑没有任何保持状态的触发器,因此输出应始终由输入定义 一个简单的例子可能是: always @* begin if (a == 1'b1) begin b = x|y|z; end end 当a==1'b0时,b是什么b未被重写,因此它将保留其值。一个没有国家概念的东西怎么能保持它的价值呢。您必须通过推断闩锁来引入状态。

我试图找出推断出的锁存器以及内部需要它的原因,但我找不到任何足够详细的资源。

当组合逻辑的输出具有未定义的状态时,会推断出锁存器,即它必须保持其先前的值

组合逻辑没有任何保持状态的触发器,因此输出应始终由输入定义

一个简单的例子可能是:

always @* begin
  if (a == 1'b1) begin
    b =  x|y|z;
  end
end
a==1'b0
时,
b
是什么<代码>b未被重写,因此它将保留其值。一个没有国家概念的东西怎么能保持它的价值呢。您必须通过推断闩锁来引入状态。这通常是一件非常糟糕的事情


您可以暗示锁存并小心计时等,但推断出的锁存通常来自错误代码。

在组合块内推断出锁存,其中网络未分配给已知值。将网络分配给自身仍将推断闩锁。还可以通过灵敏度列表和反馈回路中的缺失信号推断锁存

在Verilog/SystemVerilog中推断预期闩锁的正确方法是:

/* Verilog */       ////    /* SystemVerilog */
always @*           ////    always_latch
begin               ////    begin
  if (en) q = d;    ////      if (en) q = d;
end                 ////    end
意外推断闩锁的方式:
  • 灵敏度列表缺少信号(这就是为什么应使用
    @*
    ):

  • 缺失条件:

    always @*
    begin
      case(in[1:0])
       2'b00:  out = 1'b0;
       2'b01:  out = 1'b1;
       2'b10:  out = 1'b1;
       // inferred latch "out" :: missing condition 2'b11/default
     endcase
    end
    always @*
    begin
      next0 = flop0;
      next1 = flop1;
      // inferred latch "next2" :: missing initial condition
      next3 = flop3;
      case(a[2:0])
       3'b001:             next0 = in;
       3'b010:  if(b)      next1 = in;
       3'b100:  if(c)      next2 = in;
       default: if(!b&&!c) next3 = in;
     endcase   
    end
    
  • 反馈回路:

    assign out = en ? in : out; // inferred latch "out" :: feedback to mux
    assign a = en ? z : c;
    // ... any amount of code between ...
    assign z = en ? a : y; // inferred latch "a" :: feedback chain
    
    • 反馈回路可以遍历层次结构和设计
如何降低意外锁定的风险:
  • 使预期的插销简单且易于识别:
    • 用尽可能少的组合逻辑将预期的锁存器放在它们自己的始终块中;理想情况下,将锁存器的组合逻辑放在其单独的always块中。尽可能明确并确定预期的闩锁。使用注释、标签,并在可能的情况下使用SystemVerilog
      always\u-latch
  • 所有组合逻辑块都需要使用
    始终@*
    或SystemVerilog的
    始终梳定义
  • 确保在组合逻辑块中分配的所有变量都具有初始或默认分配。
    • case
      语句应具有
      默认条件
    • if
      语句应具有相应的
      else
    • 当组合逻辑块分配多个变量时,在块的开头(在任何
      案例
      案例
      之前)给每个变量一个初始值
  • 知道输入来自何处,输出将流向何处。
    • 组合逻辑的输入应为触发器组合逻辑的输出应为触发器
  • 进行代码审查,使用linting工具和逻辑等价性检查工具。
    • 代码审阅要求审阅者知道闩锁可以隐藏在哪里
    • 使用SystemVerilog的
      always_comb
      可以通过linting和逻辑等价性检查工具帮助识别推断的锁存

最坏的情况是,将所有逻辑放在同步块中。所有推断的锁存器都将成为推断的触发器。这通常是一个坏主意,因为它会不必要地增加门计数,创建更多路由,并影响定时。

闩锁仅使用组合always块生成。顺序逻辑永远不会生成锁存器


有关详细信息,请阅读

也许您可以包含指向您已经查看过的位置的链接,这样人们就不会建议您已经尝试过的内容。我认为应该添加
always\u latch
,作为在SystemVerilog@Morgan,你的建议已添加到我的答案中
assign out = en ? in : out; // inferred latch "out" :: feedback to mux
assign a = en ? z : c;
// ... any amount of code between ...
assign z = en ? a : y; // inferred latch "a" :: feedback chain