作者:FPGA入门到精通
在FPGA开发中,避免Latch的产生是一项重要的设计原则,这也是FPGA初学者容易出现的一个错误。
本文将详细探讨Latch的概念、产生原因、潜在危害以及如何避免Latch的产生。
一、Latch是什么?
Latch就是锁存器,是一种对输入信号电平敏感的存储单元电路,可以在特定输入信号作用下改变状态,并在没有新的输入信号时保持当前状态。
Latch与锁存器的区别,锁存器是时钟边沿触发的存储器,输出状态只在时钟边沿变化,与时钟信号同步工作,因此在抑制噪声和异步信号方面更加稳定。
二、Latch的危害有哪些?
Latch在组合逻辑中会产生严重的危害,所以FPGA设计规范中都要求避免Latch的产生,以确保设计的可靠性和稳定性。
这些危害主要有:
1、毛刺(Glitch)问题
Latch可能导致输出信号产生瞬态的、不稳定的值,这些毛刺可能会传播到电路的其他部分,引起不可预测的行为。
2、时序分析困难
Latch的存在使得时序分析变得更加复杂,因为它们的行为不依赖于时钟信号,这使得确定准确的时序约束变得困难。
3、设计可维护性差
Latch的存在使得设计难以理解和维护,因为它们的非同步特性可能导致难以追踪的问题。
三、Latch的产生的几种情况
Latch在FPGA设计中的产生通常与代码逻辑有关系,在组合逻辑中容易出现,下面给出产生Latch的几种情况以及解决办法。
1、不完整的条件语句
在Verilog或VHDL中,如果 if 语句没有完全覆盖所有可能的条件,或者case语句没有使用 default 分支,就可能导致Latch的产生。
(1)不完整的if语句(没有else)
产生Latch的代码:
reg q;
always @(*) begin
if (en) q = data_in; // 如果en为0,q没有被赋值,产生Latch
end
避免Latch的代码:
reg q;
always @(*) begin
if (en) q = data_in;
else q = 0; // 明确为q赋值,避免Latch
end
(2)不完整的case语句(没有Default)
产生Latch的代码:
reg q;
always @(*) begin
case (sel)
2'b00: q = data0;
2'b01: q = data1;
endcase // 没有default分支,sel为2'b10或2'b11时产生Latch
end
避免Latch的代码:
reg q;
always @(*) begin
case (sel)
2'b00: q = data0;
2'b01: q = data1;
default: q = 0; // 添加default分支,避免Latch
endcase
2、信号自我赋值
在组合逻辑中,如果一个信号的赋值依赖于其自身的当前值,这也可能导致Latch行为。
产生Latch的代码:
reg [1:0] q;
always @(*) begin
case (sel)
2'b00: q = q; // q赋值给自身,产生Latch
2'b01: q = 2'd1;
default: q = 1'b0;
endcase
end
避免Latch的代码:
reg [1:0] q;
always @(*) begin
case (sel)
2'b00: q = 2'd2;
2'b01: q = 2'd1;
default: q = 1'b0;
endcase
end
四、总结
Latch的危害很严重,我们在写代码的过程中需要极力避免的。
其实处理起来也很简单,那就是在写组合逻辑代码(如assign语句或always(*)语句块)时,一定要把if语句和case语句写全,要包含else和default,且不能出现信号直接赋值自己的情况。