由两个或非门或者两个与非门组成,电路结构、图形符号和特性表如下所示。
此时,输出状态(次态)与输入状态、锁存器初态都有关。
当CLK=0时(无效),输出状态(次态)保持不变;只有当CLK=1时(有效),输出状态才随输入、初态的不同而改变,且与SR锁存器的特性一样。
当门控锁存器的控制信号有效时,锁存器就变成了一个组合电路,若此时输入信号发生多次变化,输出状态也可能发生多次变化,这一现象称为锁存器的空翻。此时,时序逻辑电路的模型就等效为两个各组合电路互为反馈的反馈系统,因此,系统有可能会因为瞬态特性不稳定而产生振荡现象,抗干扰能力差。
在CLK的有效电平期间,输出状态始终随输入状态变化,输出与输入状态保持相同,所以这个电路又叫“透明的D型锁存器”。
由两个D型锁存器组成,次态仅取决时钟有效边沿到达时输入的逻辑状态,且值保持不变到下次触发到达时(保持n个时钟周期)。
电路抗干扰能力强,工作可靠性更高。
寄存器能够存寄一组二值代码,即由N个触发器组成。
锁存器(Latch)具有如下特点:
(1)对毛刺敏感(使能信号有效电平时,输出状态可能随输入多次变化,产生空翻,对下一级电路很危险),不能异步复位,因此在上电后处于不确定的状态。
(2)锁存器会使静态时序分析变得非常复杂,不具备可重用性。(首先,锁存器没有时钟参与信号传递,无法做STA;其次,综合工具会将latch优化掉,造成前后仿真结果不一致)
(3)在FPGA中基本的单元是由查找表和触发器组成的,若生成锁存器反而需要更多的资源。根据锁存器的特点可以看出,在电路设计中,要对锁存器特别谨慎,如果设计经过综合后产生出和设计意图不一致的锁存器,则将导致设计错误,包括仿真和综合。因此,在设计中需要避免产生意想不到的锁存器。如果组合逻辑的语句完全不使用 always 语句块,就可以保证综合器不会综合出锁存器。
(4)但如果锁存器和触发器两者都由与非门搭建的话,锁存器耗用的逻辑资源要比D触发器少(D触发器需要12个MOS管,锁存器只需6个MOS管),锁存器的集成度更高,所以在的ASIC设计中会用到锁存器。但锁存器对毛刺敏感,无异步复位端,不能让芯片在上电时处在确定的状态;另外,锁存器会使静态时序分析变得很复杂,不利于设计的可重用。所以,在ASIC设计中,除了CPU这高速电路,或者RAM这种对面积很敏感的电路,一般不提倡用锁存器。
锁存器(Latch)的出现及解决办法
在基于always的组合逻辑描述语句中容易综合出锁存器的地方:
(1)在赋值表达式右边参与赋值的信号未在always@(敏感电平列表)中列出完整,生成透明锁存器;
(2)if语句的使用中缺少else语句(前提不是始终时钟触发);
(3)case语句没有给出全部情况。
举例说明:
(1)时序电路中if...else不完整不会生出latch,而组合逻辑就会产生latch:
左上的电路是时序逻辑,生成触发器,而触发器是有使能端(enable)的,使能端无效时就可以保存数据,无需锁存器。右上的电路是组合逻辑,在enable为低电平时,输出q要保持不变,而组合逻辑没有存储元件,只能生成锁存器来保持数据。所以在时序逻辑中,不完整的 if…else… 结构并不会生成锁存器,而组合逻辑中不完整的 if…else… 结构就会生成锁存器。为了避免我们设计的组合逻辑中出现不想要的锁存器,在使用 if…else… 结构时一定要写完整。
module ex1(
// input clk,
input enable,data,
output reg q
);
always @(*)
// always @(posedge clk) // 方法1:将锁存器改为带使能的触发器
begin
// q = 0; // 方法2:给输出变量赋初始值
if(enable)
q = data;
// else // 方法3:补全if...else语句
// q = 0;
end
endmodule
解决方法:
①将锁存器改为带使能的触发器(变为时序电路);
②给输出变量赋初始值;
③补全if...else语句。
感悟:
①在always模块内被赋值的每一个信号都必须定义成reg型,但不一定就会生成寄存器。
②组合逻辑一般使用assign语句。
③当组合逻辑使用always模块时,@(*)或敏感信号列表需写完整,都属于电平触发。另外,if...else以及case情况(必要时加上default)需写完整,或者输出状态赋初始值。
④时序逻辑中“always @(posedge clk)”属于同步时钟,而“always @(posedge clk,negedge rst)”属于同步时钟,异步复位。
⑤“=”阻塞赋值表示组合逻辑,“<=”非阻塞赋值表示时序逻辑。
另外,可以参考FPGA 中的latch 锁存器。