Latch的含义
D锁存器:控制信号C = 0时,输出信号被锁存;C = 1时,输出随输入信号而改变,就像通过了缓冲器。
危害:
1)输入信号如果多次变化,容易产生毛刺;
2)在大部分 FPGA 的资源中,可能需要比触发器更多的资源去实现 Latch 结构;
3)锁存器的出现使得静态时序分析变得更加复杂。
应用:门控时钟(clock gating)的控制
组合电路中出现Latch
根本原因:在 if 语句、case 语句、问号表达式中,信号出现了“存储”功能,但是没有时钟驱动,就会产生Latch
- if -else结构不完整,缺少 else
系统默认 else 的分支下寄存器 q 的值保持不变,即具有存储数据的功能,所以寄存器 q 会被综合成 latch 结构。
reg q ;
always @(*)
if (en) q = data ;
- if-else条件语句中有多条赋值语句时,每个分支条件下赋值语句的不完整
本质同上。
output reg q1 ,q2 ;
always @(*) begin
if (en) q1 = data1 ;
else q2 = data2 ;
end
- case 选项列表不全且没有加 default 关键字,或有多个赋值语句不完整
本质同上。
always @(*) begin
case(sel)
2'b00: q = data1 ;
2'b01: q = data2 ;
endcase
end
- 信号对自己赋值,或者赋值的判断条件中有自己
assign d = (sel2 && d) ? 1'b0 : 1'b1 ; //d -> latch
assign c= c;
- 敏感信号列表不完整
该触发的时候没有触发,那么相关寄存器还是会保存之前的输出结果,因而会生成锁存器。
组合电路中避免Latch
- 避免123类 latch 的方法主要有 2 种,一种是补全 if-else ,case结构,或者对信号赋初值。
// 补全条件分支结构
always @(*) begin
if (en) q = data ;
else q = 1'b0 ;
end
//赋初值
always @(*) begin
q = 1'b0 ;
if (en) q = data ; //如果en有效,改写q的值,否则q会保持为0
end
其中补充完整 case 选项列表时,可以罗列所有的选项结果,也可以用 default 关键字来代替其他选项结果。
always @(*) begin
case(sel)
2'b00: q = data1 ;
2'b01: q = data2 ;
default: q = 1'b0 ;
endcase
end
always @(*) begin
case(sel)
2'b00: q = data1 ;
2'b01: q = data2 ;
2'b10, 2'b11 :
q = 1'b0 ;
endcase
end
- 不要将赋值信号放在赋值源头,或条件判断中
- 用 always@(*)