08-避免Latch的产生

发布时间 2023-05-23 20:52:25作者: Icer_Newer

1.Latch简介

Latch就是锁存器,是一种在异步电路系统中,对输入信号电平敏感的单元,用来存储信息
锁存器在数据未锁存时,输出端的信号随输入信号变化,就像信号通过一个缓冲器,一旦锁存信号有效,数据就会被锁存,输入信号不起作用,因此,锁存器也被称为透明锁存器,指的是不锁存时输出对于输入是透明的

2. 异步电路与同步电路

异步电路:异步电路主要是组合逻辑,用于产生FIFO或者RAM的读写控制信号脉冲,但是它同时也用在时序电路中,此时它没有统一的时钟,状态变化的时刻是不稳定的,通常输入信号只在电路处于稳定状态时才发生变化
同步电路:同步电路是由时序电路(寄存器和各种触发器)和组合逻辑电路构成的电路,其所有操作都是在严格的时钟控制下完成的,这些时序电路共享一个时钟CLK,而所有的状态变化都是在时钟上升沿(或者下降沿)完成的
异步电路中广泛使用的是Latch,在异步电路中可以使用Latch替代寄存器,但是在同步电路中,Latch对于电路会出现不好的结果

  • 对于毛刺敏感
  • 不能异步复位,上电之后处于不定态
  • 占用更多的逻辑资源
  • 额外延迟
  • 复杂的静态时序分析

3.几种产生Latch的情况及避免

  • 组合逻辑中if-else语句,缺少else语句
  • 组合逻辑中case条件分支语句条件未完全列举,且缺少default语句(在使用case语句的时候要么完全列举所有情况,要么加default)
  • 组合逻辑中输出变量赋值给了自己

4.验证Latch

使用之前写过的3-8译码器进行验证Latch
.qpf结尾的文件就是之前创建的quartus项目文件,双击可以打开quartus项目

4.1 正确的代码

module decoder(
  input wire in_1,
  input wire in_2,
  input wire in_3,
  
  output reg [7:0] out
);

  always@(*) begin
    if({in_1,in_2,in_3} == 3'b000)
      out <= 8'b0000_0001;
    else if ({in_1,in_2,in_3} == 3'b001)
      out <= 8'b0000_0010;
    else if ({in_1,in_2,in_3} == 3'b010)
      out <= 8'b0000_0100;
    else if ({in_1,in_2,in_3} == 3'b011)
      out <= 8'b0000_1000;
    else if ({in_1,in_2,in_3} == 3'b100)
      out <= 8'b0001_0000;
    else if ({in_1,in_2,in_3} == 3'b101)
      out <= 8'b0010_0000;
    else if ({in_1,in_2,in_3} == 3'b110)
      out <= 8'b0100_0000;
    else if ({in_1,in_2,in_3} == 3'b111)
      out <= 8'b1000_0000;
    else 
      out <= 8'b0000_0001;
  end

endmodule

4.2 if-else 产生latch

module decoder(
  input wire in_1,
  input wire in_2,
  input wire in_3,
  
  output reg [7:0] out
);

  always@(*) begin
    if({in_1,in_2,in_3} == 3'b000)
      out <= 8'b0000_0001;
    else if ({in_1,in_2,in_3} == 3'b001)
      out <= 8'b0000_0010;
    else if ({in_1,in_2,in_3} == 3'b010)
      out <= 8'b0000_0100;
    else if ({in_1,in_2,in_3} == 3'b011)
      out <= 8'b0000_1000;
    else if ({in_1,in_2,in_3} == 3'b100)
      out <= 8'b0001_0000;
    else if ({in_1,in_2,in_3} == 3'b101)
      out <= 8'b0010_0000;
    else if ({in_1,in_2,in_3} == 3'b110)
      out <= 8'b0100_0000;
    else if ({in_1,in_2,in_3} == 3'b111)
      out <= 8'b1000_0000;
    // else 
    //  out <= 8'b0000_0001;
  end

endmodule

4.3 case语句产生latch情况

```plaintext
module decoder
(
  input wire in_1,
  input wire in_2,
  input wire in_3,
  output reg [8:0] out
);
 
  // 使用case语句
  // 使用if-else语句
  always@(*)
  begin
    case({in_1,in_2,in_3})
      3'b000 : out = 8'b0000_0001;
      3'b001 : out = 8'b0000_0010;
      3'b010 : out = 8'b0000_0100;
      3'b011 : out = 8'b0000_1000;
      3'b100 : out = 8'b0001_0000;
      3'b101 : out = 8'b0010_0000;
      3'b110 : out = 8'b0100_0000;  
      // 3'b111 : out = 8'b1000_0000;
      // default : out = 8'b0000_0001;
    endcase
  end
endmodule

正常代码综合

错误代码综合

4.4 将变量赋值给自己

module decoder
(
  input wire in_1,
  input wire in_2,
  input wire in_3,
  output reg [8:0] out
);
 
  // 使用case语句
  // 使用if-else语句
  always@(*)
  begin
    case({in_1,in_2,in_3})
      3'b000 : out = 8'b0000_0001;
      3'b001 : out = 8'b0000_0010;
      3'b010 : out = 8'b0000_0100;
      3'b011 : out = 8'b0000_1000;
      3'b100 : out = 8'b0001_0000;
      3'b101 : out = 8'b0010_0000;
      3'b110 : out = 8'b0100_0000;  
      3'b111 : out = 8'b1000_0000;
      default : out = out;    // 将输出变量赋值给自己,也会产生latch
    endcase
  end
endmodule
  • 代码每次修改之后都要进行重新编译