锁存器与触发器:记忆是怎么来的
更新时间:2026-09-10。本文是「芯片设计 · 入门层」数字逻辑基础第六篇。与 组合逻辑与时序逻辑 强相关——那篇讲 RTL 侧的隐式锁存器坑,本篇讲门级原理。
本文要回答的问题
- 没有时钟,两个门怎么"记住"一个比特?SR 锁存器如何置位/复位/保持,非法态是什么?
- D 锁存器的"透明—锁存"是什么意思?为什么叫电平敏感?
- D 触发器为什么是边沿触发?主从两级锁存器如何合成一个沿?
- 建立时间、保持时间到底在约束什么?违反会怎样(亚稳态)?
- T/JK 触发器是什么,为什么现代 RTL 几乎只用 D 触发器?
一、反馈即记忆:交叉耦合的双稳态
到目前为止的组合逻辑,输出完全由当前输入决定,输入一撤输出就变——没有记忆。把两个反相器首尾交叉耦合(甲的输出接乙的输入,乙的输出再接回甲的输入),就出现了一个环:
┌──────┐ ┌──────┐
Q ──→│ INV1 │── Q̄ ──→│ INV2 │──┐
↑ └──────┘ └──────┘ │
└───────────────────────────────┘这个环有两个稳定状态:Q=0(则 Q̄=1,反过来又维持 Q=0)或 Q=1(Q̄=0)。一旦进入某一态,即使没有外部输入,它也会一直保持——这就是 1 比特记忆的本质:反馈造成的双稳态。但这个环没法方便地"写入",于是需要能置位/复位的锁存器。
二、SR 锁存器
把交叉耦合的两个门换成两个或非门(或两个与非门),并各留一个外部输入,就得到 SR 锁存器。以或非门版为例(S=Set 置 1,R=Reset 置 0,高有效):
| S | R | 次态 Q | 含义 |
|---|---|---|---|
| 0 | 0 | 保持 Q | 无操作,靠反馈维持 |
| 1 | 0 | 1 | 置位 |
| 0 | 1 | 0 | 复位 |
| 1 | 1 | 非法 | Q=Q̄=0,违反互补;撤去后态不确定 |
S=R=1 时两个输出都被强拉成 0(不再互补),且两输入若同时撤回到 00,最终落到 0 还是 1 取决于门延迟的赛跑,结果不可预测——这就是"非法态/未定义态",使用时必须避免。与非门版则是低有效(S̄ R̄ = 01 置位等),逻辑对偶。SR 锁存器已具备"保持 / 置 1 / 清 0"三功能,但没有时钟控制、且有非法输入。
三、D 锁存器:电平敏感的"透明窗口"
给锁存器加一个使能(时钟电平)端,并把 S/R 约束成永远互补(S=D、R=D̄,从根上杜绝非法态),就得到 D 锁存器(D latch):
- 使能 EN(或 CLK)= 高电平期间:锁存器"开门",输出
Q直接跟随输入 D(Q = D),称为透明(transparent); - EN 由高变低(关门)后:D 被"冻结"在关门瞬间的值上,靠交叉耦合保持,此后 D 再怎么变 Q 都不理。
因为它对电平敏感(高电平这段时间内都在接收),所以叫电平触发/电平敏感。要特别注意:透明窗口内 D 上若有毛刺会直接传到 Q,且它没有明确唯一的采样时刻。Verilog 里它对应 always @(clk or d) if (clk) q <= d;(敏感于电平,不含 posedge)。
四、主从两级锁存器 → 边沿 D 触发器
把两个 D 锁存器一主一从串起来,用反相的时钟控制,就合成了只在时钟跳变瞬间采样的 D 触发器(D flip-flop, DFF):
- **主锁存器(master)**在 CLK=低时透明、跟随 D,CLK 变高时关门锁存;
- **从锁存器(slave)**在 CLK=高时透明,把主锁存器刚锁存的值送到输出 Q。
合起来看:CLK 上升沿到来前主锁存器跟踪 D、从锁存器关着(输出不变);上升沿那一刻主锁存器关门(锁住沿前的 D)、从锁存器开门把它送出;高电平期间主锁存器已关、D 的后续变化进不来。于是输出 Q 只在时钟上升沿那一瞬间更新为 D 的值,其余时间纹丝不动——这就是边沿触发。标准单元里的 DFF 内部多是这种主从(或类似真单相时钟)结构,但对 RTL 设计者它就是一个沿触发黑盒:
always @(posedge clk) // 注意是 posedge(边沿),不是电平
q <= d; // 仅在上升沿把 d 存入 q为什么同步设计只用边沿触发器、不用锁存器? 因为全芯片共用一个时钟沿,所有触发器在同一瞬间采样、在两次沿之间让组合逻辑稳定,时序关系清晰、可用 STA 穷举验证(见 时钟与复位、STA 入门)。latch 的透明窗口会"借用时间"、行为电平相关,分析复杂且易透传毛刺,所以 组合逻辑里意外综合出 latch 被当作缺陷(有意用 latch 的低功耗/高速设计属进阶话题)。
五、建立时间、保持时间与寄存器传输模型
真实触发器不是理想的,内部主锁存器关门、反馈建立都需要时间。为保证能正确采到 D,输入端 D 必须相对于时钟沿满足两个时序窗:
- 建立时间 t_setup:时钟沿之前,D 必须已稳定的最短时间;
- 保持时间 t_hold:时钟沿之后,D 还必须继续保持稳定的最短时间。
←t_setup→│←t_hold→
D 必须稳定 ────────│──────── 稳定
↑ clk 上升沿(采样点)时钟沿之后,Q 还要经过**时钟到输出延迟 t_co(clk-to-Q)**才更新。寄存器到寄存器路径的时间预算由此而来(这是 STA 的核心公式,本篇先建立直觉):
T周期 ≥ t_co + 组合逻辑延迟 + t_setup − 时钟偏斜- 不满足建立时间(数据来得太晚)→ 这条路径跑不到目标频率,报 setup 违例,通常降频或缩短组合逻辑解决。
- 不满足保持时间(新数据来得太早、沿后很快就变)→ 可能冲进同一沿、采错,hold 违例与频率无关、必须修。
六、亚稳态:在错误的时刻采样
如果 D 在 t_setup/t_hold 窗口内恰好在变化(触发器在"模棱两可"的瞬间采样),内部交叉耦合节点可能停在既非 0 也非 1 的亚稳态(metastability)中间电平,并经过一段随机长短的"决断时间"后才随机收敛到 0 或 1。它不违反物理,只是输出何时合法不可预测。单时钟同步系统里满足 STA 就不会发生;它主要出现在异步信号/跨时钟域输入(如按键、另一个时钟域的信号)。标准对策是两级同步器(串两个触发器,给亚稳态一个周期去收敛),其失效概率用 MTBF 量化——深入分析见进阶 建立保持时间与亚稳态 与 CDC 基础。
七、T/JK 触发器与现代实践
教科书还有 T 触发器(T=1 则每拍翻转,是计数器的核心)和 JK 触发器(用 J/K 组合实现保持/置位/复位/翻转,消除了 SR 的非法态)。但它们都能用 D 触发器加少量组合逻辑得到(如 T 触发器即 q_next = q ⊕ T),现代标准单元库和 RTL 几乎只提供/只使用 D 触发器,因为它行为最简单、最利于时序分析和自动综合。需要翻转、计数时写 q <= q + 1 或 q <= q ^ t,综合器自动用 DFF 实现(见下一篇 寄存器/计数器/移位寄存器)。
八、SR 锁存器的门级走查与去抖应用
把 SR 锁存器用两个交叉耦合的与非门画出来(低有效版,输入记为 S̄、R̄)更容易看出"反馈怎么把值锁住":门 G1 的输出是 Q,一个输入接 R̄,另一个输入接 G2 的输出 Q̄;门 G2 反过来。稳态时若 Q=1、Q̄=0,则 G2 因有一个输入为 0 而持续把 Q 维持为 1,G1 又对称地维持 Q̄=0,形成自洽的环。拉低 S̄ 一下,G1 翻转,Q̄ 变 1,进而让 G2 输出 Q=0;即使 S̄ 随后恢复,新状态也被彼此的反馈维持住——写入靠一个短暂脉冲,保持靠反馈,不需要一直按着输入,这正是"记忆"与组合逻辑最本质的区别。
SR 锁存器在真实设计里虽不直接用于数据通路,却有两个常见身影:
- 开关去抖(debounce):机械按键按下/松开瞬间触点会在几毫秒内抖动十几次,直接送时钟或中断会被当成多次按动。用一个 SR 锁存器(配合互补触点或一小段定时)把第一次有效跳变锁住,就能输出一个干净的电平;现代设计更多用"两级同步器 + 定时计数"在数字域完成,原理仍是用记忆滤掉抖动。
- 异步请求捕获:早期异步握手用 SR 锁存器捕获脉冲式请求(置位)、在应答后清除(复位),它对"只关心事件有没有发生、不关心发生在哪个沿"的场景很自然;现代同步设计则把这种请求先两级同步再进状态机(见 CDC 基础)。
记住 SR 锁存器的非法态本质是"同时要求 Q 和 Q̄ 都被强拉",以及更隐蔽的"两输入同时撤去后靠延迟赛跑定结果"——这个"延迟赛跑决定最终态"的思想,在亚稳态和异步电路里会以更危险的形式再次出现。
九、建立/保持时间的电路来源与寄存器参数
为什么一个理想上"沿触发"的器件会要求数据在沿之前就稳定?因为主从结构里,主锁存器是在时钟上升沿前后那一小段时间内关上门的:D 必须在关门动作完成前通过传输门进到内部节点并建立起电平(这对应 t_setup),关门后还需要一小段时间让输入侧真正断开,期间 D 不能变(对应 t_hold)。这两个数不是人为规定,而是内部开关切换、节点充放电的物理时间。工艺库(.lib)为每个触发器记录一组时序参数,STA 报告里最常打交道的是:
| 参数 | 含义 | 违反后果 |
|---|---|---|
setup / t_su | 沿前数据需稳定的时间 | setup slack 为负:最高频率上不去 |
hold / t_h | 沿后数据需保持的时间 | hold 违例:任何频率都错,必须改电路 |
clk→Q(t_co) | 沿到输出有效的延迟 | 占用下游路径预算 |
min_pulse_width | 时钟高/低电平最小宽度 | 时钟太短内部来不及翻转 |
recovery/removal | 异步复位撤销相对于沿的建立/保持 | 释放不当导致部分触发器没复位 |
ck→q min | 最快输出时间 | 用于 hold:新数据可能冲得太快 |
一个常见困惑:保持时间为什么和频率无关、且必须在任何频率下都满足? 因为 hold 约束的是"同一个沿":发射端在这个沿输出新值,捕获端在同一个沿采旧值,若新值经最短路径在捕获端保持窗内就冲到 D 端,就会把该沿该采的旧值顶掉。降频拉长的是两沿之间的时间,救不了同一沿内的快慢关系,所以 hold 违例只能靠加缓冲/调偏修,是流片前必须清零的硬错误(深入见 建立保持与亚稳态)。
十、触发器的使能/复位/置位控制端
真实 DFF 不止 D 和 clk,工艺库里的触发器通常带一串控制端,RTL 里对应固定写法:
// 带异步复位、时钟使能的 DFF(映射为带 CE/复位的单元)
always @(posedge clk or negedge rst_n) begin
if (!rst_n) q <= 1'b0; // 异步复位:在敏感列表里,不等沿
else if (en) q <= d; // 时钟使能:en=0 时保持
end
// 同步复位版:复位只在沿上生效,敏感列表只有 clk
always @(posedge clk) begin
if (rst) q <= 1'b0;
else if (en) q <= d;
end- 时钟使能 CE:物理上就是 D 端前一个"二选一"(en=1 选 D、en=0 选旧 Q),库里做成专用 CE 管脚比用组合逻辑拼更省电;不使能时不接收新数据,是时钟门控之外最常用的省电手段(见 低功耗设计直觉)。
- 同步复位 vs 异步复位:同步复位干净、抗复位毛刺,但必须有时钟才生效(时钟没起来复位不了);异步复位立刻生效、不依赖时钟,但释放时刻若落在沿附近会惹亚稳态,规范做法是"异步断言、同步释放"(见 复位设计)。
- 置位 preset/clear:需要上电为 1 的单元用异步置位;能少用就少用,混用大量 set/reset 会让复位树和扫描链复杂化。
十一、一个时钟周期里发生了什么
把建立保持、clk→Q、组合逻辑串起来,沿触发系统的一个周期就像一次精确接力:
沿 n 组合云 F 在两沿间求值(可能带毛刺) 沿 n+1
│ R1 的 Q 经 clk→Q 开始变化 │
▼ ▼
┌───────────┐ ┌───────────┐
│ R1(发射) │────────────── D2=F(Q1) ──────────────────▶│ R2(捕获) │
└───────────┘ └───────────┘
|←t_co→←──── t_logic + t_route ────→← t_setup →|
|←──────────── 必须 ≤ T 周期(再扣掉 skew)────→|这就是寄存器到寄存器(reg-to-reg)路径的 setup 恒等式:T + t_skew ≥ t_co + t_logic + t_route + t_setup。四件事吃掉周期预算:吐数据的 t_co、组合云的 t_logic、导线的 t_route、捕获端要提前备料的 t_setup。时序优化的全部手段——拆流水线、换快加法器、retiming、换 LVT 单元、加大驱动降线延迟——本质都是在压缩这条不等式右边某一项。把这张图刻进脑子,后面 时序为什么不满足、STA 报告解读 里的 launch/capture、slack 正负就都有了物理画面。
十二、常见误用与排查清单
- 把数据当时钟:用组合信号边沿触发逻辑 → 改时钟使能/同步脉冲(见 计数器分频纪律)。
- 同一寄存器多处赋值:在多个 always 块或复位外多处写
q<=→ 集中到一个沿块、用条件区分。 - 给非寄存器复位:给组合信号、乘法结果写异步复位无意义也综合不出 → 只复位真正的状态。
- 时钟未稳就放复位:上电 PLL 未锁定就工作 → 等 lock 信号并经复位同步器释放(见 时钟树与复位网络)。
- 依赖
initial初态:FPGA 可加载初值,ASIC 不行 → 所有需要已知初值的状态必须显式复位。 - 异步信号直接进沿:不做同步 → 两级同步器/握手/异步 FIFO(见 CDC 基础)。
十三、亚稳态再定量:MTBF、决断时间与同步器级数
本篇第六节给了亚稳态的定性描述,这里补上工程上真正用来做决策的量化关系。触发器采样到变化中的信号后,不一定永远停在中间电平,它会以指数规律从亚稳态向某个合法态收敛;经过时间 t 仍未收敛的概率近似 P(t) = T0 · exp(−t/τ),其中 τ 是工艺决定的亚稳收敛时间常数,T0 是采样窗口宽度。系统看到亚稳输出的平均无故障时间:
MTBF = exp(t_r/τ) / (f_clk · f_data · T0)
t_r 是给第一级同步触发器的"决断时间"——在两级同步器里基本等于一个时钟周期(减去第二级的建立时间)。这个公式解释了三件经验事实:①加一级同步器,MTBF 是指数级改善而不是线性:从直接使用异步信号到两级同步,t_r 从几乎为零变成一整个周期,MTBF 常从微秒级跳到几十年甚至上万年;②时钟越快,留给决断的时间越短,越需要更多级,高速 SerDes/快时钟域常用三级甚至四级;③输入翻转越频繁(f_data 高)撞上窗口的机会越多,但仍由指数项主导。工程上不是"两级永远够",而是按目标 MTBF(常要求大于系统寿命、失效率低于其他失效源)代入库参数算一遍,工艺越先进、电压越低,τ 往往越差,低压设计里同步器是需要专门挑"高增益、低 τ"单元的(库里通常有专门的同步器单元标记,禁止工具在它们之间插优化逻辑)。
十四、锁存器的正面用途:什么时候故意用 latch
本篇主线是"同步设计避免 latch",但任何经验丰富的工程师都该知道它合法的三个舞台,免得在别人的电路里见到时误判为错误。
第一是时间借用(time borrowing)。锁存器高电平期间透明,数据可以在窗口内任何时刻到达并"穿过"它,而不像触发器必须赶在沿前 t_setup 到齐。用交替电平的两级锁存器替代触发器做流水线(latch-based pipeline),慢路径可以向相邻周期"借"时间,只要整体平均值满足周期即可,常用于把已经榨干的 CPU 主频再提高一些;代价是时序分析变成非沿对沿的模型,工具和设计方法学都更复杂。
第二是低电平有效窗口里的无毛刺保持,ICG 内部那半个锁存器就是最典型的例子(见 竞争与冒险):它不是拿来存数据,而是用来"在危险时段冻结使能"。存储器编译器生成的 SRAM 也大量使用锁存器做地址/写数据的脉冲捕获。
第三是面积与功耗极端敏感处:锁存器比主从触发器少一半左右的时钟负载和面积,在海量寄存器的设计(如大阵列、寄存器堆)里有时有意用锁存器组配合两相时钟。这三条的共同点是:设计者清楚自己在用电平敏感器件,并配套了时钟方案和分析方法——这与"always 块漏写分支意外长出 latch、没人意识到"有天壤之别。代码规范层面,SystemVerilog 的 always_latch 关键字就是给"有意使用"准备的显式标记,lint 规则会放过它、严管其他形式的推断锁存器。
十五、从本篇出发的学习地图
数字时序的所有进阶话题,几乎都能挂在"记忆元件 + 时间窗"这两个概念上,这里给出后续阅读的依赖顺序,供自学时不迷路。
第一步先消化时钟与复位基础设施:时钟树怎么长出来、偏斜(skew)和抖动(jitter)有什么区别、PLL/MMCM 怎么造频率、复位网络怎么分布(见 时钟与复位、时钟树与复位网络)。没有这层背景,时序报告里的 launch/capture 时钟、uncertainty、latency 都只是数字。第二步进静态时序分析:把本篇的 reg-to-reg 不等式推广到全部路径类型(输入/输出、恢复/移除、多周期、伪路径),学会读 slack 报告(STA 入门);这一步做完,"建立违例降频、保持违例改电路"就从口诀变成可操作的流程。第三步处理异步世界:亚稳态的定量分析、同步器家族、握手与异步 FIFO(建立保持与亚稳态、CDC 基础、复位设计),这些是多时钟域 SoC 的日常。第四步才是进阶结构:latch 时间借用、真单相时钟、门控时钟与低功耗、retiming 与多阈值优化。
一个检验标准:如果给你一张含两个触发器、一段组合逻辑、标注了 t_co/t_logic/t_setup/时钟偏斜的图,你能判断最小时钟周期、说明降频能否解决每种违例、并指出异步输入该加什么——那本篇的目标就达到了。剩下的全部内容都是这张图在不同场景下的展开。
十六、自测要点
合上材料,若能流畅回答下面六个问题,本篇就算真正掌握:①只用两个与非门说明 SR 锁存器如何保持、置位、复位,并指出非法输入为何"非法";②画出 D 锁存器透明/锁存两个阶段,解释 D 上的毛刺为什么在透明期会传到 Q;③用主从两级锁存器解释 D 触发器为何只在上升沿采样,指出主、从各自何时透明;④写出寄存器路径周期预算公式,说明 setup 违例和 hold 违例分别怎么修、为什么降频修不了 hold;⑤解释亚稳态的收敛过程、两级同步器为什么有效以及它为什么不是"绝对可靠";⑥说明现代 RTL 为什么只用 D 触发器,T/JK 怎么用 D 型等价实现。能把第④、⑤两问讲出物理过程而不是背结论,后面的 STA 与 CDC 学习会轻松很多——它们不过是把这张"沿、窗口、延迟"的图应用到更复杂的时钟结构上。
与现有篇目的衔接
- RTL 侧对照:组合逻辑与时序逻辑(隐式 latch 坑、
<=用法) - 时钟/复位:时钟与复位、时钟树与复位网络
- 下一篇:寄存器、计数器与移位寄存器
- 深入:进阶 建立保持时间与亚稳态、CDC 基础、静态时序分析入门
总结
一句话总结:记忆来自反馈——两个交叉耦合反相器构成有 0/1 两个稳定态的环就能存 1 比特;SR 锁存器加了置位/复位/保持能力但有 S=R=1 非法态,D 锁存器把输入约束成互补、在使能高电平期间"透明"跟随 D、关门后冻结,属于电平敏感器件;用反相时钟驱动的主、从两级 D 锁存器串接,便合成只在时钟上升沿瞬间采样的边沿 D 触发器,这正是同步设计统一采用 DFF、而在组合逻辑里杜绝意外 latch 的原因;为可靠采样,D 必须满足沿前建立时间和沿后保持时间,输出经 clk-to-Q 延迟才更新(寄存器路径周期预算 T≥t_co+组合延迟+t_setup−skew),若恰在时序窗内变化则可能进入随机收敛的亚稳态,靠跨时钟域两级同步器应对;T/JK 触发器都能用 DFF 加组合逻辑等价实现,故现代 RTL 与标准单元几乎只用 D 触发器——这套"边沿采样 + 建立保持"模型是时钟、复位、STA、CDC 全部话题的物理底座。