锁存器(latch)和触发器(flip-flop)有什么区别?
更新时间:2026-09-21。问题驱动短答页。基础见 锁存器与触发器,RTL 陷阱见 锁存器陷阱,可综合性见 什么是综合。
一句话回答
锁存器是「电平敏感」:使能电平有效期间输出跟着输入走(透明、直通),电平一关才把值锁住;触发器是「边沿敏感」:只在时钟上升沿(或下降沿)那一瞬间采样输入,其余时间输入怎么变都不理。现代同步设计一律以触发器为时序单元,latch 只在少数刻意场景出现。
核心对照
| 维度 | 锁存器 latch | 触发器 flip-flop |
|---|---|---|
| 敏感方式 | 电平(enable 高/低有效时透明) | 时钟边沿 |
| 透明期 | 使能有效时 Q=D,输入实时穿透 | 不存在,仅沿处采样 |
| 何时改变 | 整个有效电平区间都可能变 | 一个周期只变一次 |
| 本质 | 一对交叉耦合反相器/与非门 | 主从两级 latch 拼成 |
| 面积 | 略小 | 略大 |
| STA 建模 | 透明、需 time borrowing,复杂 | 沿到沿,模型简单清晰 |
| DFT 扫描 | 不友好 | 天然可串扫描链 |
为什么 RTL 要避免意外 latch
同步设计里所有状态在时钟沿更新,STA 能按「寄存器到寄存器」干净地算时序。latch 在电平期间透明,数据何时进入不确定,会打乱沿到沿分析,还可能把组合毛刺直接放过去。
更常见的坑是综合器替你推断出本来不想要的 latch:组合逻辑块里某个输出在某些分支没有被赋值,综合器认为「那它就得保持原值」,只能给你配一个锁存器:
verilog
// 组合逻辑却漏了 default / 分支不全 → 推断出 latch
always @(*) begin
if (sel) y = a;
// sel==0 时 y 没赋值 → y 必须保持 → 综合出 latch
end
// 正确:给默认值,保证任何分支 y 都被驱动
always @(*) begin
y = b; // 默认值
if (sel) y = a;
endif没有else、case不全且没有default、敏感列表用错,是三大 latch 来源。- 时序逻辑
always @(posedge clk)里不写else是正常保持,那是时钟使能、不是 latch,别误伤。
什么时候才故意用 latch
- 高速/高性能数据通路用 latch 做 time borrowing(时间借用),借前半/后半周期平衡两级之间的裕量。
- 标准单元内部、脉冲锁存、门控时钟单元(ICG 里就含低有效锁存器防毛刺,见 门控时钟)。
- 这些都是有意为之并配套专门时序约束,新手不要在业务 RTL 里手搭。
总结
latch 电平敏感、使能有效时透明直通,flip-flop 边沿敏感、只在时钟沿采样;同步设计选用触发器是因为其时序沿确定、STA 简单、DFT 友好,而面积略小的 latch 会带来透明期和 time borrowing 的分析负担;组合 always @(*) 中 if/case 分支不全、输出未在所有路径赋值会被综合出意外 latch,正确做法是先给默认值再覆盖,时序块里不写 else 则只是正常的时钟使能保持。