一、前言
本文主要简单讲解Latch的概念、产生的原因、危害以及如何避免其产生。目的是帮初学者在设计数字电路时更加规范,避免因Latch导致的不可预测问题。
二、Latch是什么
Latch其实就是锁存器,是一种在异步电路中,对输入信号电平敏感的单元,用来存储信息。它的特点是当锁存信号无效时,输出信号会随输入信号变化,这时锁存器就像是一个缓冲器。当锁存信号有效时,输入信号被锁存,输出信号保持不变,输入信号的变化不再影响输出。因此Latch也被称为透明锁存器,因为当锁存信号无效时,输出对输入是“透明”的。
三、Latch的危害
需要注意的是,Latch的问题只会出现在组合逻辑中,在同步电路中应尽量避免产生Latch,但并不表示Latch是完全没有用的,Latch在异步电路中是非常有用的。
在同步电路中Latch会产生不好的效果,容易受到毛刺的影响,导致输出不稳定;不能进行异步复位,上电后初始状态不确定;会使静态时序分析变得复杂,增加设计难度和验证的难度;占用过多的FPGA资源,引入额外的时序问题,不利于提高系统的工作频率。
四、几种产生Latch的情况
同步电路设计中,以下几种情况会产生Latch,需要避免。
情况一:组合逻辑中if语句没有else
`timescale 1ns/1ns
module latch_one
(
input wire in1 , //输入信号in1
input wire in2 , //输入信号in2
input wire in3 , //输入信号in3
output reg [7:0] out //输出信号out
);
//out:根据3个输入信号选择输出对应的8bit out 信号
always@(*)
if({in1, in2, in3} == 3'b000)
out = 8'b0000_0001;
else if({in1, in2, in3} == 3'b001)
out = 8'b0000_0010;
else if({in1, in2, in3} == 3'b010)
out = 8'b0000_0100;
else if({in1, in2, in3} == 3'b011)
out = 8'b0000_1000;
else if({in1, in2, in3} == 3'b100)
out = 8'b0001_0000;
else if({in1, in2, in3} == 3'b101)
out = 8'b0010_0000;
else if({in1, in2, in3} == 3'b110)
out = 8'b0100_0000;
else if({in1, in2, in3} == 3'b111)
out = 8'b1000_0000;
// else 把最后一个if的else注释,观察综合后结果
// out = 8'b0000_0001;
endmodule
图1 RTL视图(一)
根据上边的代码综合出来的RTL视图如图1所示,我们可以看到红色框中的Latch锁存器。
情况二:组合逻辑中case的条件不能够完全列举且不写default
`timescale 1ns / 1ps
module latch_two
(
input wire in1 , //输入信号in1
input wire in2 , //输入信号in2
input wire in3 , //输入信号in2
output reg [7:0] out //输出信号out
);
//out:根据 3 个输入信号选择输出对应的 8bit out 信号
always@(*)
case({in1, in2, in3})
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;
//把最后一种情况和 default 都注释掉,使 case 的条件不能够完全列举
// 3'b111 : out = 8'b1000_0000;
// default: out = 8'b1000_0001;
endcase
endmodule
图2 RTL视图(二)
根据上边的代码综合出来的RTL视图如图2所示,我们可以看到红色框中的Latch锁存器。
情况三:组合逻辑中输出变量赋值给自己(一)
`timescale 1ns / 1ps
module latch_three(
input wire in1 , //输入信号 in1
input wire in2 , //输入信号 in2
input wire in3 , //输入信号 in3
output reg [7:0] out //输出信号 out
);
//out:根据 3 个输入信号选择输出对应的 8bit out 信号
always@(*)
if({in1, in2, in3} == 3'b000)
out = 8'b0000_0001;
else if({in1, in2, in3} == 3'b001)
out = 8'b0000_0010;
else if({in1, in2, in3} == 3'b010)
out = 8'b0000_0100;
else if({in1, in2, in3} == 3'b011)
out = 8'b0000_1000;
else if({in1, in2, in3} == 3'b100)
out = 8'b0001_0000;
else if({in1, in2, in3} == 3'b101)
out = 8'b0010_0000;
else if({in1, in2, in3} == 3'b110)
out = 8'b0100_0000;
else if({in1, in2, in3} == 3'b111)
out = 8'b1000_0000;
else
out = out; //在else中将输出变量赋值给自己
endmodule
图3 RTL视图(三)
根据上边的代码综合出来的RTL视图如图3所示,我们可以看到红色框中的Latch锁存器。
情况四:组合逻辑中输出变量赋值给自己(二)
`timescale 1ns / 1ps
module latch_three(
input wire in1 , ///输入信号 in1
input wire in2 , ///输入信号 in2
input wire in3 , ///输入信号 in3
output reg [7:0] out //输出信号 out
);
//out:根据 3 个输入信号选择输出对应的 8bit out 信号
always@(*)
case({in1, in2, in3})
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 = out; //输出变量赋值给自己
default: out = 8'b0000_0001;
endcase
endmodule
图4 RTL视图(四)
根据上边的代码综合出来的RTL视图如图4所示,我们可以看到红色框中的Latch锁存器。
五、总结
在组合逻辑中一定要避免输出信号处于不定的状态,一定要让输出无论在任何条件下都有一个已知的状态,就可以避免Latch的产生。