时序逻辑电路 — 让电路记住事情:锁存器、触发器与状态机¶
这一章讲什么: 第 6 章的电路是「健忘的」——输入撤走,输出立刻消失。 本章用一条反馈线让电路拥有「状态」:锁存器记住一位,触发器让这一位 踩着时钟的节拍更新,状态机(状态图 + 转换表)把「记住 + 按规则更新」 变成可设计的工程流程。读完你会理解:CPU 的寄存器、程序计数器、 乃至现代处理器的分支预测器,全是这一章的零件。
1. 顶层全景:记忆的五级台阶¶
① 反馈:两个或非门交叉相连 → SR 锁存器(会记住,但什么时候记不可控)
② 门控:加 Enable → 门控锁存器(能选「什么时候记」)
③ 专用:D 和 ¬D 分别接 S、R → D 锁存器(记什么不再有二义性)
④ 节拍:两个 D 锁存器主/次串联 + 时钟反相 → D 触发器(每时钟周期只变一次)
⑤ 设计:状态图/转换表 + 触发器选型 + 卡诺图化简 → 任意时序电路
(例:两位计数器;例:分支预测器)
图说:①~④在解决「怎么记」,⑤在解决「记了怎么用」——台阶⑤才是工程。
本章开篇先立概念支柱。系统状态:对系统的完整描述——「知道了 t₀ 时刻的状态 和 t₀~t₁ 时间的输入,就能唯一确定 t₁ 时刻的状态和输出」;怎么进入这个状态不重要, 重要的是状态本身就包含了决定未来所需的全部信息1。有限状态机(FSM): 只能处于有限个状态之一的计算模型,外部输入驱动它在状态间转移(可能伴随输出)。 时序逻辑电路可以实现有限状态机;按输出依赖分两种——摩尔型(输出只看当前状态, SR 锁存器即此型)和米利型(输出还看导致转移的输入)2。
这两个名词值得当场记牢,因为出门就会撞见:任何一本体系结构或编译原理的进阶书 都用它们分类控制器;区别也很实际——摩尔型的输出稳定一整拍(它不看输入), 米利型的输出可能随输入毛刺抖动(它直接喂组合逻辑)。本章两个设计例子 都是摩尔型:预测输出直接等于状态位,连输出电路都省了。
「时序逻辑电路的时间历史可以由电路的当前状态来概括」46——这句话是全章的 许可证:既然状态含一切,那么设计时序电路 = 设计「状态 + 转移规则」, 剩下的只是用触发器和门把表翻译出来。第 5、6 章教你翻译语言(布尔代数、门), 本章教你写规格(状态图表)——规格层是这一章的真正增量。
2. 主线例子的第 ① 步:SR 锁存器——反馈造记忆¶
两个或非门,输出各接到另一个的输入(图 7-1),就是最基本的锁存器3。 跟着信号走一遍,记忆就是这么诞生的:
S = 0, R = 0(保持):无论当前是 Set(Q=1)还是 Reset(Q=0),
两个门的互相反馈让输出原封不动——输入撤了,状态还在。这就是记忆。
S = 1, R = 0(Set):上方或非门输出 ¬(1∨?) = 0 → ¬Q 变 0,
反馈到下方门:¬(0∨0) = 1 → Q = 1。此后 S 回到 0,反馈维持 Q = 1。
S = 0, R = 1(Reset):镜像,下方门先动,Q 被拉回 0。
S = 1, R = 1(禁止!):两个输出都被压成 0 → Q = ¬Q,违反布尔代数。
「设计电路时必须避免这种输入组合。」
把「保持」那两行展开演算一次,看清反馈的角色——这是全章最值得在纸上 复算的一段47:
假设当前处于 Set(Q = 1, ¬Q = 0),撤掉输入(S、R 回到 0):
上方或非门:¬Q = ¬(0 ∨ 0) = 1 ← 它的输入是 R 和「下方的输出 Q」
等等,换个说法更不容易绕晕:两个门,上门输出 ¬Q,下门输出 Q。
上门:¬Q = ¬(S ∨ Q) —— 输入是 S 和下门的输出 Q
下门:Q = ¬(R ∨ ¬Q) —— 输入是 R 和上门的输出 ¬Q
代入 Set 状态(Q = 1, ¬Q = 0)且 S = R = 0:
上门:¬(0 ∨ 1) = 0 ✓(¬Q 保持 0)
下门:¬(0 ∨ 0) = 1 ✓(Q 保持 1)
没有任何外部输入在维持,两个输出互相「撑着」对方——这就是反馈的记忆。
再试 Reset 状态(Q = 0, ¬Q = 1):
上门:¬(0 ∨ 0) = 1 ✓ 下门:¬(0 ∨ 1) = 0 ✓
同样自洽。两种自洽的稳态,就是「存了 0」和「存了 1」。
这个「互相撑着」的结构有个物理代价:两个门的输出是靠对方「顶住」的, 所以上电瞬间它可能落在哪个稳态是不确定的——这正是 4.2 节 PR/CLR 异步输入存在的理由:先给电路一个确定的起点,再让它跑16。
把行为画成状态图(气泡 = 状态,状态下方是输出,箭头上的标签 = 导致转移的 输入组合):两个状态(Set / Reset),四条边。注意它的输出只取决于所处状态, 不取决于输入——所以它是摩尔型状态机4。同样的信息也能写成状态转换表 (S、R、当前 Q → 下一 Q;被禁止的行填 X),原书提醒:状态图是有向图, 「图论工具在设计过程中占有一席之地」5。
或非门版的状态转换表(表 7-1)值得逐行看一眼,它是后面所有转换表的祖先29:
S R | 当前 Q | 下一 Q
------+--------+--------
0 0 | 0 | 0 ← 保持:00 不动状态
0 0 | 1 | 1 ← 保持
0 1 | 0 | 0 ← R=1 复位(本来就在 Reset)
0 1 | 1 | 0 ← R=1 复位(从 Set 拉到 Reset)
1 0 | 0 | 1 ← S=1 置位
1 0 | 1 | 1 ← S=1 置位(本来就在 Set)
1 1 | 0 | X ← 禁止:Q = ¬Q 违反布尔代数
1 1 | 1 | X ← 禁止
图说:S、R「通常为 0」从而保持状态;瞬间只动一个:只拉高 S → Set(输出 1),
只拉高 R → Reset(输出 0)。X 不是「未知」,是「不允许设计出现」。
一个容易踩的坑原书专门点名:用与非门也能造 SR 锁存器,但因与非是或非的 逻辑补,输入要换成 ¬S、¬R——「当只有两个选择时,差一错误(off-by-one error) 会造成截然相反的行为」6。NAND 版锁存器物理上更快(与非门快于或非门), 但保持状态需要两个输入都为 1、禁止组合变成了 ¬S = ¬R = 0——高有效还是 低有效,图纸之外心里要一直挂着账。
把 NAND 版的四种输入也走一遍(表 7-2 是它们的状态转换表)39:
¬S ¬R = 1 1:保持。两个与非门都至少有一个输入是 1,交叉反馈维持现态。
¬S ¬R = 0 1:Set。¬S = 0 把上方与非门输出钉成 1(Q = 1),
反馈使下方门 ¬(1∧1) = 0(¬Q = 0),进入 Set。
¬S ¬R = 1 0:Reset,镜像。
¬S ¬R = 0 0:禁止!两个输出都被迫为 1 → Q = ¬Q,逻辑上不可能。
图说:和 NOR 版逐行为对偶(0↔1、AND↔OR 互换)——第 4 章的对偶原理,
在锁存器上又兑现了一次。
「与非门是或非门的逻辑补,因此我们使用 ¬S 和 ¬R 作为输入」40—— 这句话值得拆开来体会:不是「重新设计了一个锁存器」,而是按对偶原理 机械翻译了旧的。时序电路的设计里,对偶不是数学趣味,是省一半图纸的功夫。
3. 门控与 D 锁存器:让「记」变得可控¶
3.1 门控 SR 锁存器¶
问题:锁存器输入一有变,状态就变。计算机里成千上万个器件各变各的, 「每个设备改变状态以及将其输出传送至下一个设备都需要时间,精确的时序 取决于元件细微的制造差异。结果未必可靠。」7 第一道控制:加 Enable—— 两个额外的与非门把 Enable 和 S、R 分别 AND 后喂给锁存器。 Enable = 0 时锁存器输入恒为「保持」组合,状态冻结;Enable = 1 时 S、R 才起作用8。
行为对照表(表 7-3)的读法34:
Enable | S R | 当前 Q | 下一 Q
-------+------+--------+--------
0 | - - | 0 | 0 ← Enable=0:输入无所谓(「-」),状态冻结
0 | - - | 1 | 1
1 | 0 0 | 0 | 0 ← Enable=1:退化成普通 SR
1 | 0 0 | 1 | 1
1 | 0 1 | 任意 | 0 ← 复位
1 | 1 0 | 任意 | 1 ← 置位
1 | 1 1 | 任意 | X ← 仍是禁区
图说:Enable=0 的那两行是全表的「免战牌」——只要没挂牌,外头怎么闹都不改状态。
「只有当 Enable = 1 且 S 和 R 的值相反时,锁存器的状态才会改变」—— 原书马上用这个观察做下一步:既然只有「S、R 相反」这两行有用, 何必留两个输入?
3.2 D 锁存器:消灭二义性¶
门控 SR 还有个瑕疵:Enable = 1 时 S = R = 1 仍是禁区。把输入改成单根的 D(data),内部用一根非门同时生成 D 和 ¬D 分别接 S、R—— 「要存的位」只有一个,且永远不可能同时为 19。D 锁存器: Enable = 1 时,Q 跟着 D 变;Enable = 0 时,Q 保持。 这就是「可存储一位的电路」,第 2 章的「位」第一次有了实体。
真值表(表 7-4)短得可爱,四行有效,全是「D 是什么,下一 Q 就是什么」35:
Enable | D | 当前 Q | 下一 Q
-------+---+--------+--------
0 | - | 0 | 0 ← 冻结
0 | - | 1 | 1
1 | 0 | 0 | 0
1 | 0 | 1 | 0 ← Q 清零
1 | 1 | 0 | 1 ← Q 置一
1 | 1 | 1 | 1
图说:Enable=1 的两对行完全一样——当前 Q 被无视了,这就是「写入」的语义:
旧值作废,新值是 D。SR 锁存器的四种输入,被压缩成「一个数据 + 一个使能」。
「现在,我们得到了一个能够使用 D 输入存储一位数据的电路,并可以使用 Enable 输入与其他操作同步。然而,D 锁存器存在一些问题」——问题正是 3.3 节的主角。
3.3 锁存器的适用边界(作者的重要判断)¶
D 锁存器在「该长时间保持一种状态」的场合很好——原书给的例子是 I/O 端口: 键盘按键的时刻由用户决定,程序无法预知;键被按下时字符编码先在 输入端口锁存,程序什么时候来读都行10。但 CPU 和主存内部不行:
D 锁存器启用期间,输出仍会被输入影响。
若锁存器的输出是另一个设备的输入:第二个设备在主锁存器稳定前读到的是乱值,
主锁存器稳定后它又必须赶紧读——因为主锁存器随时可能再变。
靠「禁用/启用第二个设备」来错开?可以,但「协调启用和禁用之间的来回切换
不是件容易的事」[^11]。
图说:单锁存器的病根——输出在整个「透明期」里都不保证稳定。
把「来回切换」方案展开一句,你就知道它为什么难:输入要经过稳定时间 (电子元件达到新电压电平所需的时间)才可靠;输出传到下一级又有传播延迟; 所以第二级必须等「第一级稳定 + 传播延迟」之后才能启用——「一旦我们的 D 锁存器稳定下来,就将其禁用。传播延迟之后,就可以启用 D 锁存器所连接的设备」。 这个「等—开—关—再等」的交替方案,理论上自洽,工程上是要对每一对相连的 器件分别算账的噩梦——原书的结论是干脆换结构,不是优化这个方案30。
解法是下一节的触发器:把「接受输入」和「提供输出」在时间上分家。
4. 触发器:踩着时钟的记忆¶
4.1 时钟¶
时钟是 0 和 1 之间交替的方波,「用于启用/禁用需要同步的设备的输入」12。 画出来就是一条方形的波浪:
电压
1 ──┐ ┌───┐ ┌───
│ │ │ │
0 └───┘ └───┘
↑ ↑ ↑ ↑
正沿 负沿 正沿 负沿
图说:每一级(高电平、低电平)持续的时间通常相等;
电路不关心电平本身,关心的是「沿」——电平翻转的那一瞬间。
两个设计规则:电路靠时钟沿(正向 0→1 或负向 1→0)触发动作; 时钟频率必须足够慢——慢到所有器件能在下一个同向时钟沿之前完成操作12。 (这句「必须足够慢」是全书性能主线的种子:第 20 章的 CPU 频率之战、 第 5 章的 RC 延迟,都是它的展开。为什么用「沿」而不是「电平」? 电平有一段持续时间,期间什么都可能发生(回想 D 锁存器的透明期); 沿是一个瞬间,瞬间没有「期间」——把更新钉在一个瞬间,才把成千上万器件的 动作钉成了整齐的一排。)
4.2 D 触发器:主/次两级,半拍间隔¶
结构:两个 D 锁存器串联(主级、次级),时钟信号经一个非门后接主级的 Enable,原样接次级的 Enable——两级永远处于相反模式13。
主线例子的第 ② 步:一个时钟周期内走两遍。
CK = 0 期间:
主级 Enable = 1 → 写模式:D 的任何变化都会写进主级;
次级 Enable = 0 → 读模式:输出 Q 冻结为上一个周期的值,完全可靠。
⇒ 此刻主级在「采样」,次级在「展示」——输入怎么晃都碰不到输出。
CK 跳到 1 的瞬间(正沿):
主级 Enable = 0 → 刚采到的值被锁进主级;
次级 Enable = 1 → 主级的值经短暂稳定后成为新输出 Q。
⇒ 输出在正沿处更新为新采样值;一个周期内只此一次。
图说:输入采样和输出更新错开半个周期,这就是「隔离输出与输入变化」的全部秘密;
因此这种触发器叫「正沿触发」。去掉那个非门,就是负沿触发。
这就是本章的核心工程成果:D 触发器的输出在每个时钟周期只能改变一次14。 成千上万个触发器挂在同一根时钟上,全体同步地「采样—展示」,数字电路的 可靠性问题就此解决。(术语约定:原书用「锁存器」指不看时序的存储位, 「触发器」指这种半周存储半周输出的器件15。)
对比锁存器与触发器的一张速查表(本章术语坑的避雷图):
| 锁存器(latch) | 触发器(flip-flop) | |
|---|---|---|
| 透明期 | Enable 有效期间,输出随输入变 | 无透明期:输出只在时钟沿更新 |
| 电平/边沿 | 电平敏感 | 边沿敏感(正沿/负沿) |
| 同步代价 | 连用时要逐对算稳定时间和传播延迟 | 一根时钟全员同步,每周期至多变一次 |
| 适用 | I/O 端口等外部驱动、长保持场合 | CPU、主存等高速协同场合 |
| 结构 | 一级 | 主/次两级(概念模型) |
注意最后一行是概念模型——「有更高效的电路可用于实现边沿触发的 D 触发器」, 主/次结构是给你理解用的,不是工厂用的;但理解一旦建立,符号级设计 (图 7-10 的方框 + CK 三角/小圆圈)就够用了16。
还有两个工程细节:
- 异步输入:预置(PR)和清零(CLR)可以不看时钟直接置位——「当 PR 输入 为 1 时,Q 变为 1,无论其他输入(甚至包括 CLK)是什么」;上电初始化靠它们16; 「异步」的意思是它们不踩在时钟节拍上,什么时候来什么时候生效;
- 图纸符号与 VLSI:时钟输入端的小圆圈 = 负沿触发;触发器编号 Q1、Q2…… 画大图时从不展开内部17。原书在此给了读者一个尺度感: VLSI(超大规模集成电路)在单个半导体微芯片上包含「数十亿亿个晶体管门电路」—— 「这些触发器既经济又高效,因此被广泛应用于超大规模集成电路(VLSI)电路中」。 触发器是这门巨型工业的「标准砖块」,就像字节之于软件。
4.3 T 触发器:一位的「取反开关」¶
需求原型:CAPS LOCK 键——按一下翻转一次状态。状态转换表(表 7-5)只有四行: T = 0 保持,T = 1 翻转36:
T | 当前 Q | 下一 Q
---+--------+--------
0 | 0 | 0 ← 保持
0 | 1 | 1
1 | 0 | 1 ← 翻转
1 | 1 | 0
问题变成:用什么 D 值让 D 触发器做出同样的转换?
补一列「需要的 D」,答案直接现形(表 7-6):
保持 → D = 当前 Q;翻转 → D = ¬当前 Q。
合并:D = (¬T ∧ Q) ∨ (T ∧ ¬Q) = T ⊕ Q
把 Q 反馈回来和 T 做 XOR 再接回 D 输入的 D 触发器,就是 T 触发器 (图 7-12)18。T = 0 保持,T = 1 每拍翻转。注意这里的设计手法—— 「想要一个新的触发器,先写出它的转换表,再反推出 D 触发器的输入」—— 和 JK 的设计(下节)是同一个套路,也是六步设计法的迷你版。
4.4 JK 触发器:四种功能的全集¶
SR 的保持/置位/复位,加上 T 的切换——JK 触发器用两个输入 J、K 做全四种: JK = 00 保持、01 复位、10 置位、11 切换(SR 的禁区被改造成了最有用的功能)。 表 7-7 把这四种操作写成转换表37:
操作 J K | 当前 Q | 下一 Q
-------+----+--------+--------
保持 0 0 | 0 | 0
保持 0 0 | 1 | 1
复位 0 1 | 0 | 0
复位 0 1 | 1 | 0
置位 1 0 | 0 | 1
置位 1 0 | 1 | 1
切换 1 1 | 0 | 1
切换 1 1 | 1 | 0
图说:前 6 行和 SR 锁存器(Enable=1 时)一模一样;最后两行是 SR 的禁区,
在 JK 里成了「求反」。一张表说清为什么 JK 叫「通用触发器」。
电路做法:给 SR 触发器的每个输入与非门再各加一个信号,反馈接法取 J 侧 = ¬Q、K 侧 = Q——J = K = 1 时,电路自动把自己的现态取反后喂回输入, 完成切换19。切换功能为什么靠反馈就能实现?把 J = K = 1 代入:输入与非门 的三个输入是 1、1、¬Q(或 Q)——Q = 0 时 ¬Q = 1,¬S 那一路被拉成「置位」, Q 被推到 1;Q 变 1 之后 ¬Q 变 0,两路输入全松,触发器保持——一个时钟沿, 恰好翻一次38。原书还用表 7-9 把这四种操作逐行回验了一遍,确认反馈没弄坏 其他三种功能。
成本上,JK 比 SR/T 略复杂(「大约相当于给 D 触发器添加一个 XOR 门」), 换来的是设计灵活性:「只有一种设计具有制造成本优势」的说法不存在, JK 的四种功能让它在设计中提供更大的灵活性,进而有助于节省成本20。 这也是本章两个设计例子都选 JK 的原因。
5. 设计时序逻辑电路:六步流程¶
原书给的设计法是本章的方法论落点,和软件工程的迭代观接得很顺: 「从设计开始,分析,改进,使其更快、更便宜等」21:
(1) 文字描述 → 状态转换表 + 状态图(技术规格)
(2) 状态二进制编码(N 个状态需要 log₂N 位;选哪种编码影响后面的组合逻辑难度)
(3) 选触发器类型(通常由手头组件决定;JK 是好起点)
(4) 转换表里加列:造成每个状态转换所需的触发器输入
(5) 卡诺图/代数化简每个触发器输入
(6) 画图
(4)(5)(3) 可能要反复几轮——选触发器、定输入、化简是个小循环。
这套流程的灵魂在步骤 (1) 和 (4) 之间:规格用「人话的状态」写, 实现用「触发器的输入」写,中间靠一张翻译表(步骤 4)连接。 你只要会把「下一状态」翻译成「该置位/复位/保持/切换」,任何状态机 都只剩卡诺图的体力活。这也是为什么作者反复强调卡诺图——到了时序设计, 组合逻辑的部分(步骤 5)完全沿用第 4 章的手艺,一点新东西都不加。
5.1 主线例子的第 ③ 步:两位计数器¶
需求:Enable = 1 时按 0, 1, 2, 3, 0… 每个时钟周期递增;Enable = 0 时保持22。
步骤 1~2(状态与编码):四个状态,两位编码 n₁n₀,状态值 = 输出值 ( Moore 型:输出即状态)。转换表:Enable=0 时「下一个 = 当前」; Enable=1 时 0→1→2→3→0(3 之后绕回 0——译码环的老朋友又出现了)。 编码版转换表(表 7-11)长这样31:
Enable | 当前 n1 n0 | 下一个 n1 n0
-------+-----------+-------------
0 | 0 0 | 0 0 ← 保持
0 | 0 1 | 0 1
0 | 1 0 | 1 0
0 | 1 1 | 1 1
1 | 0 0 | 0 1 ← 递增
1 | 0 1 | 1 0
1 | 1 0 | 1 1
1 | 1 1 | 0 0 ← 绕回 0
图说:左半(Enable=0)是恒等映射,右半(Enable=1)是「+1 模 4」。
整张表就是规格;后面的步骤只是把它翻译成门。
步骤 3~4(选 JK,列输入):两个 JK 触发器,一位一个。填表规则用 JK 的 四种功能翻译「当前位 → 下一位」:不变 = 保持(0X 或 X0,另一位无关填 X)、 0→1 = 置位(1X)、1→0 = 复位(X1)、变 = 切换(11)。表里会冒出大量 X (无关项)——「卡诺图是一种很好的方法,因为其图形化描述往往更容易将 无关条目的影响可视化」23。表 7-12 的填法举例32:
Enable=1, 当前 01 → 下一个 10:高位 0→1(置位:J1=1, K1=X),
低位 1→0(复位:J0=X, K0=1)
Enable=0, 当前 11 → 下一个 11:两位都保持(J1=X, K1=0; J0=X, K0=0)
Enable=1, 当前 11 → 下一个 00:两位都切换(J1=X, K1=1; J0=X, K0=1)
图说:每格填两个值(J 和 K),规则背一张四行小表就够:
不变→保持(0X/X0),0→1→置位(1X),1→0→复位(X1),翻转→切换(11)。
步骤 5(化简):四张卡诺图(每触发器 J、K 各一)圈完,结果干净得惊人:
J0 = K0 = E
J1 = K1 = E ∧ n0
图说:低位触发器每拍都翻转(像秒针);
高位触发器只在低位为 1 且 Enable 时翻转(像分针,每两拍走一格)——
一个两位计数器,就是「秒针驱动分针」的钟表结构。
步骤 2(编码)和步骤 3(选触发器)在本例各有一句作者的经验之谈,值得记下:
- 编码:「不管哪种编码都行,但有些编码会使得电路中的组合逻辑更简单」—— 计数器例子用了最自然的编码(状态值 = 二进制值),省掉了输出译码电路; 预测器例子里 s₁ = 预测位,又省一根输出线。编码是免费的午餐,点单要动脑;
- 触发器:「JK 触发器是一个不错的入手点,因为这种触发器提供了所有的功能」; 设计完成后想换回更简单的触发器?「通常情况下,任何潜在的成本或功耗的节省 都不足以证明改用另一种触发器是合理的」——先求全,再求省;省要省得有数。
步骤 6(时序验证):图 7-19 的时序图里能看到两条延迟:时钟沿之后, 输入先变(Qi.JK),输出在「时钟周期的下半周期」才跟着变(nᵢ)—— 「每个输出值实际发生变化之前的短暂延迟代表了电子器件完全稳定到新值所需的 时间」24。第 5 章的 RC、第 20 章的建立/保持时间,都在这里等着。
顺带一提步骤 6 的意义:它不只是「画图收尾」。时序图是你和物理世界对表的 唯一手段——纸面上自洽的状态机,到了硅片上可能因某个门的延迟略长而错拍; 能在时序图上指出「这一拍里谁必须等谁」,才算把设计从逻辑层落到了物理层。 原书在此只走了一小步(一段延迟说明),但指的方向是对的:逻辑对了之后, 还有一场时序的仗要打(第 20 章的 I/O 时序就是那场仗的正面战场)。
把时序图的意思用文字走一遍(以从 1 数到 2 的那一拍为例)41:
某时钟沿前:状态 n1n0 = 01,Q1.JK = E∧n0 = 1(高位待切换),Q0.JK = E = 1(低位待切换)
时钟正沿到来:
主级锁存这个输入 → 次级随后翻转 → n1n0 从 01 变成 10
沿后短暂延迟:两个输出在新值上稳定下来
新的输入值随之更新:Q1.JK = E∧n0 = 0(低位已是 0,高位不翻了),
Q0.JK = E = 1(低位下个沿还翻)
下一时钟正沿:n1n0 = 10 → 11……
图说:输入看「旧状态」算出来,沿来了状态才更新——更新后的状态是下一拍的输入。
这正是「状态机」三个字在波形图上的样子:状态是台阶,时钟沿是楼梯口。
5.2 第二个例子:分支预测器(软件读者的重头戏)¶
先补背景——流水线:现代 CPU 分阶段执行指令(取指、译码、执行……),
像装配线一样同时处理多条指令,以此提速25。麻烦在于条件分支:
程序执行到 if 时,下一条指令在两个地址之一;「在决策指令进入流水线
一定阶段之前,无法知道究竟要提取哪一条指令」。分支预测就是赌一把:
提前按猜测取指;猜错了「冲刷流水线并提取另一条指令,从头开始」26。
设计目标:预测器坚持当前预测,直到连续猜错两次才改口(2 位饱和计数器 的雏形)。四个状态27:
No(强不采纳):最近两次都没采纳 → 预测「不采纳」
No-error(弱不采纳):上次没采纳、最近一次被采纳了 → 仍预测「不采纳」(才错一次)
Yes-error(弱采纳):镜像
Yes(强采纳):最近两次都采纳 → 预测「采纳」
状态图(从 No 出发):
No --实际未采纳--> No(预测不变)
No --实际采纳--> No-error(预测仍「不采纳」——连错两次才改!)
No-error --实际采纳--> Yes(连错两次,改口,预测「采纳」)
Yes-error --实际未采纳--> No
……(其余弧线对称)
把状态图按分支走两遍——这是理解「饱和计数」语义的最短路径42:
场景 A:分支一直不采纳(预测一直对)
No --未采纳--> No --未采纳--> No …… 永远停在 No,输出 Don't take ✓
场景 B:某次分支被采纳了(预测错一次)
No --采纳--> No-error
No-error --未采纳--> No 一次错误就被原谅,回到 No
No-error --采纳--> Yes 连续两次错,改口,之后预测 Take
场景 C:改口之后又连续两次未采纳
Yes --未采纳--> Yes-error --未采纳--> No 又改回来
图说:「连错两次才改口」= 状态机在强/弱两档之间各设一道缓冲,
单次异常(比如循环结束那一次)不会掀翻预测——一次错误被原谅,两次才算数。
规格表(表 7-13)把状态图收成表格:「当前状态 + 预测 + 两种实际结果 各自导向的下一个状态和预测」43。注意表里有个贴心设计——预测列在 「下一个状态」旁边:预测是跟着状态走的输出(Moore 型),不是跟着输入走的。
步骤 2~4 照旧:编码 s₁s₀(s₁ 直接就是预测位——编码选得妙,输出线都省了), 转换表 + JK 输入表。编码表(表 7-14)本身就值得看一眼,因为它示范了 「编码选择可以顺手把输出电路省掉」33:
状态 s1 s0 预测
-------- ----- ----------
No 0 0 Don't take
No-error 0 1 Don't take
Yes-error 1 0 Take
Yes 1 1 Take
图说:s1 恰好等于预测位:预测输出不用任何门,直接从高位触发器的 Q 引出。
「哪种编码都行,但有些编码会让组合逻辑更简单」——设计步骤(2)的价值实例。
转换表(表 7-15)只有 8 行,把 Actual 和状态合起来枚举完45:
Actual | 当前 s1 s0 | 下一个 s1 s0
-------+-----------+-------------
0 | 0 0 | 0 0 ← No,未采纳:留在 No
0 | 0 1 | 0 0 ← No-error,未采纳:原谅,回 No
0 | 1 0 | 0 0 ← Yes-error,未采纳:再错一次,掉到 No
0 | 1 1 | 1 0 ← Yes,未采纳:降级到 Yes-error
1 | 0 0 | 0 1 ← No,采纳:记一笔,升 No-error
1 | 0 1 | 1 1 ← No-error,采纳:连错两次,跳到 Yes
1 | 1 0 | 1 1 ← Yes-error,采纳:原谅,回 Yes
1 | 1 1 | 1 1 ← Yes,采纳:保持
图说:读法只有一个——低位 s0 记「最近一次的方向」,高位 s1 记「当前的预测」;
Actual 和 s0 一致就原谅(回强状态),不一致就记错(往弱状态挪一格)。
步骤 5 的化简结果:
读一眼这四个式子的行为,比状态图更直观:Actual = 1(这次采纳了)时, 低位触发器被置位;若已经处于 No-error(低位已是 1),高位也被置位—— 跳到 Yes。「连续错两次」被翻译成「低位先记一笔,高位看低位脸色」, 账本是两个触发器,不是任何神秘算法。
原书的收尾两句值得原样记住:「这个例子展示了最简单的分支预测方法。 还有更复杂的预测方法」;以及那条功耗提醒——预测硬件耗电,电池设备上 要掂量28。
把这个电路在你脑内装机完毕:
输入 Actual(这次分支实际采纳了吗?)→ 两个与门 + 一个非门
→ 两个 JK 触发器的 J/K 输入 → 触发器状态 s1s0 → 输出 = s1(预测)
每个分支指令在 CPU 里配一份这样的状态(真实 CPU 是成千上万分之一的表项),
每次执行完把 Actual 喂进去,下次执行前把 s1 读出来当下注方向。
赌对了:流水线没断过;赌错了:冲刷,重来,状态机记一笔账。
判断(我们的,不是书里的): 这个例子是全书给软件读者的最好礼物—— 它把「分支预测」这个听上去很玄的 CPU 特性,降解成了一张 8 行的转换表和 三个门。你写的
if跑得快不快,部分取决于这么一小坨电路今天猜没猜对。 「预测 = 一个有状态的小机器 + 一条反馈线」,这个图像比任何教科书定义都好记。 如果错,会错在: 真实的商用预测器(如 Intel 的 TAGE)用的是几十位历史、 成百上千项的表,不是 4 状态机;但「状态 + 转移规则」的骨架与本例相同—— 复杂的是规模,不是原理。判据是:任何一个预测器都能画出状态图。
5.3 7.4 小结:四种存储位的家谱¶
原书小结给了一张极简家谱,对照查一遍自己带走没有44:
| 器件 | 一句话 | 关键输入 |
|---|---|---|
| SR 锁存器 | 状态取决于 S/R(置位或复位) | S、R(可带 Enable) |
| D 触发器 | 存 1 位;主/次隔离输入输出,与时钟同步 | D、CK(可带 PR/CLR) |
| T 触发器 | 启用时每拍在 0/1 间切换 | T、CK |
| JK 触发器 | 保持/置位/复位/切换四功能全集,通用触发器 | J、K、CK |
两个设计例子(计数器、预测器)的共同骨架:文字规格 → 状态图/表 → 编码 → JK 输入表 → 卡诺图 → 电路。状态机不是某类特殊电路,是所有时序电路的 通用语法——CPU 的程序计数器是计数器,预测器是计数器加方向感, 寄存器文件是 D 触发器的阵列,内存(第 8 章)是锁存器的阵列。
6. 作者的判断与证据¶
判断一:「协调启用和禁用之间的来回切换不是件容易的事。」 7.1.4 节用一整页的篇幅讲「为什么单锁存器不够、交替启用有多难」, 然后才引出主/次结构——这是典型的「把问题逼到疼再给药」的讲法。 证据是那段论证本身就是问题陈述:传播延迟、稳定时间、禁用窗口, 每个名词都来自第 5 章的电子学。
判断二:JK 触发器的「灵活性省成本」论。 「只有一种设计具有制造成本优势」 被明确否定;JK 用稍高的器件复杂度换设计空间的扩大20。这和第 4 章 「最小解不唯一」、第 6 章「门数 ≠ 成本」连成一条完整的工程观: 局部最优不值得追求,设计空间值得。
判断三:预测器的功耗提醒是本书少有的「能耗意识」显式表达。 全书的硬件叙事大多围绕速度与成本,这里突然提醒「额外的硬件会消耗更多的 电力,这在由电池供电的设备中值得留意」——说明作者眼里,功耗是设计的 一等约束,不是脚注。
判断四:这一章的讲法是「从故障出发」的。 单锁存器不可靠 → 触发器; 时钟太慢不行 → 频率约束;S=R=1 是禁区 → JK 把禁区变成切换; 上电状态不定 → 异步预置清零。每一种器件都不是「发明的成品」, 而是「上一代的故障报告」。记住这个讲法,你自己读任何器件手册时 也能问出对的问题:它是为了治什么病被造出来的?
7. 边界与局限¶
- 没讲建立/保持时间、时钟偏移、亚稳态——触发器在真实时钟下的 失效模式(采样恰好在数据变化时会进入亚稳态)本章只字未提;第 20 章 也不展开,这是本书与「数字设计专业课」的明确分界;
- 主/次结构的 D 触发器不是工业实现——「有更高效的电路可用于实现 边沿触发的 D 触发器,但本讨论表明其也可以通过普通的逻辑门来构建」16; 工业触发器直接用时钟控制的传输门,但主/次图景是理解一切边沿触发的 最好心智模型;
- 米利型状态机只给了名字;设计例子两个都是摩尔型;
- 分支预测器的「连续错两次」只是最简策略;真实 CPU 用多位饱和计数器 加历史表,但骨架一致(补充,不在书里,来自通用知识);
- 动手实践分量重:计数器和预测器都值得在逻辑模拟器里跟着搭一遍, 「这就像一次手把手的动手实践」22——书里的两个完整例子本来就是 按「带你做一遍」写的;
- 触发器选型没有唯一解,本章的态度是「JK 起步、求全优先」。 步骤(3)里那句「任何潜在的成本或功耗的节省都不足以证明改用另一种触发器 是合理的」是经验之谈而非定理——它成立的前提是设计尚在小规模; 大规模 ASIC 里 D 触发器才是绝对主流(结构简单、时序分析容易), JK 更多留在教科书和 CPLD 里(补充,不在书里,来自通用知识)。 原书选 JK 教学是对的:四种功能让输入表的「无关项」最多,化简的演示效果最好。
8. 可带走的¶
全章主线例子,一行走完: SR 锁存器(反馈 = 记忆)→ 门控(Enable 选时机) → D 锁存器(D/¬D 消灭二义性)→ D 触发器(主/次两级错半拍,每周期输出 只变一次)→ 六步设计法 → 两位计数器(秒针带分针)→ 分支预测器 (4 状态 + 3 个门 = CPU 的「直觉」)。 这一章的主线是「把不可控的物理世界,驯化成踩着拍子的数字世界」: 反馈给了记忆,时钟给了节拍,主/次结构给了「节拍内互不干扰」, 六步流程给了从人话规格到电路的翻译器。
- 反馈 = 记忆:输出接回输入,电路就有了状态;状态的定义是 「知道状态 + 输入,就能确定未来」;
- SR 锁存器:S 置位、R 复位、S=R=1 禁止;状态图和转换表是它的两张脸;
- 高/低有效要一直记账:NAND 版锁存器输入极性整个反过来,off-by-one 致命;
- Enable(门控)解决「什么时候记」;D 输入解决「记什么」的唯一性;
- 锁存器适合慢速、外部驱动的场合(键盘);CPU 内部要靠触发器;
- 时钟 = 同步节拍;时钟必须慢到所有器件能完成操作;
- D 触发器 = 两个锁存器主/次串联,时钟反相错开:输入采样与输出更新 隔开半拍,输出每周期只变一次;
- 小圆圈 = 负沿触发;PR/CLR 是异步输入(不看时钟直接置位,上电靠它);
- T 触发器 = D 触发器 + 反馈 XOR(T ⊕ Q);JK 触发器四功能全集 (保持/置位/复位/切换),11 = 切换是 SR 禁区的合法化;
- 六步设计法:规格(状态图表)→ 编码(log₂N 位)→ 选触发器 → 填触发器输入 → 卡诺图化简 → 画图;中间三步是小循环;
- 计数器 = 低位翻转、高位「低位为 1 才翻转」——钟表结构;
- 分支预测器 = 状态机 + 反馈:「连续错两次才改口」是 4 个状态就能实现的 智能;预测错了冲刷流水线重头来;
- 设计时序电路先写状态图表(规格),再翻译触发器输入(实现)—— 翻译口诀只有一张四行表:不变→保持、0→1→置位、1→0→复位、翻转→切换;
- 编码是免费的午餐:让状态位直接兼任输出位,能省一整块输出译码电路;
- 摩尔型的输出稳一整拍,米利型的输出随输入动——选型先看这条;
- 每一种触发器都是「故障报告」:D 触发器治透明,D 锁存器治二义性, JK 治禁区,PR/CLR 治上电不定;
- 时序图是和物理世界对表的唯一手段——逻辑对了之后,还有一场时序的仗 (谁等谁、等多久)在第 20 章正面展开;
- 本章两个设计例子的总账:规格 → 电路,全程只用了第 4 章(卡诺图、布尔代数) 加本章(触发器、转换表)的工具——「组合逻辑 + 记忆 + 设计流程」三件套, 就是时序电路设计的全部家当;
- 遇到任何时序电路,先问三个问题:状态有几个(几位触发器)、 什么输入导致什么转移、输出绑在状态上还是输入上——三问答完, 电路图已经在你脑子里了;
- 摩尔型输出稳、米利型输出快——稳和快之间,就是状态机的整个设计空间;
- 「时序逻辑」这四个字翻译过来就是:有记忆的逻辑——而记忆 = 反馈 + 节拍;
- 分支预测器这个例子值得二刷:它是全书第一次让软件读者看到, 自己写的程序的性能,有一部分被一小坨触发器「预判」着;
- 学完后回到自己的代码看一眼:程序里的「状态」「事件」「状态迁移」, 和本章的状态机是同一张图的两份拷贝。
9. 原文地图¶
本章地图覆盖第 7 章全文(锁存器、触发器、六步设计法、两个设计实例、小结);
行号以转码文本(一行 = 一个自然段)为准,机器可用 book-verify --fix 校正漂移。
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| 系统状态定义 | 第7 章 时序逻辑电路 | text/13-ch07.txt:1(搜「92 时序逻辑电路」) |
| 有限状态机、摩尔/米利型 | 第7 章 时序逻辑电路 | text/13-ch07.txt:17(搜「有限状态机」) |
| SR 锁存器四种输入 | 第7 章 时序逻辑电路 | text/13-ch07.txt:44(搜「保持当前状态」) · text/13-ch07.txt:67(搜「不允许」) |
| 状态图与状态转换表 | 第7 章 时序逻辑电路 | text/13-ch07.txt:74(搜「状态图」) · text/13-ch07.txt:84(搜「状态转换表」) |
| 摩尔型判断(输出只看状态) | 第7 章 时序逻辑电路 | text/13-ch07.txt:79(搜「摩尔型」) |
| NAND 版锁存器与 off-by-one 警告 | 第7 章 时序逻辑电路 | text/13-ch07.txt:106(搜「速度快于」) · text/13-ch07.txt:148(搜「差一错误」) |
| 「结果未必可靠」引出 Enable | 第7 章 时序逻辑电路 | text/13-ch07.txt:171(搜「未必可靠」) |
| 门控 SR 锁存器 | 第7 章 时序逻辑电路 | text/13-ch07.txt:177(搜「门控」) |
| D 锁存器与键盘例子 | 第7 章 时序逻辑电路 | text/13-ch07.txt:209(搜「D 锁存器」) · text/13-ch07.txt:240(搜「键盘」) |
| 「协调切换不容易」 | 第7 章 时序逻辑电路 | text/13-ch07.txt:256(搜「不是件容易的事」) |
| 锁存器/触发器术语约定 | 第7 章 时序逻辑电路 | text/13-ch07.txt:266(搜「术语各不相同」) |
| 时钟信号与频率限制 | 第7 章 时序逻辑电路 | text/13-ch07.txt:272(搜「时钟」) · text/13-ch07.txt:280(搜「足够慢」) |
| D 触发器主/次结构与正沿触发 | 第7 章 时序逻辑电路 | text/13-ch07.txt:289(搜「主/次」) · text/13-ch07.txt:295(搜「正沿触发」) |
| 「输出每周期只能改变一次」 | 第7 章 时序逻辑电路 | text/13-ch07.txt:703(搜「只能改变一次」) |
| 异步预置/清零 | 第7 章 时序逻辑电路 | text/13-ch07.txt:314(搜「异步」) |
| 负沿触发的符号 | 第7 章 时序逻辑电路 | text/13-ch07.txt:325(搜「小圆圈」) |
| T 触发器(CAPS LOCK 与 XOR) | 第7 章 时序逻辑电路 | text/13-ch07.txt:332(搜「CAPS LOCK」) · text/13-ch07.txt:330(搜「7.2.3 T 触发」) |
| JK 触发器四功能与反馈设计 | 第7 章 时序逻辑电路 | text/13-ch07.txt:377(搜「4 种可能的操作」) · text/13-ch07.txt:409(搜「Ja = ¬Q」) |
| JK 的灵活性省成本 | 第7 章 时序逻辑电路 | text/13-ch07.txt:444(搜「节省成本」) |
| 六步设计法 | 第7 章 时序逻辑电路 | text/13-ch07.txt:447(搜「迭代的」) · text/13-ch07.txt:451(搜「状态转换表」) |
| 计数器:J0 = K0 = E 等 | 第7 章 时序逻辑电路 | text/13-ch07.txt:545(搜「J 0」) |
| 计数器时序与稳定延迟 | 第7 章 时序逻辑电路 | text/13-ch07.txt:570(搜「短暂延迟」) |
| 流水线与分支预测背景 | 第7 章 时序逻辑电路 | text/13-ch07.txt:582(搜「装配线」) · text/13-ch07.txt:589(搜「条件分支」) |
| 「连续两次错误才改口」 | 第7 章 时序逻辑电路 | text/13-ch07.txt:595(搜「连续犯两次错误」) |
| 预测器化简结果与功耗提醒 | 第7 章 时序逻辑电路 | text/13-ch07.txt:682(搜「Actual」) · text/13-ch07.txt:697(搜「电力」) |
| 「时间历史由当前状态概括」 | 第7 章 时序逻辑电路 | text/13-ch07.txt:11(搜「当前状态」) |
| 表 7-3 门控 SR 锁存器 | 第7 章 时序逻辑电路 | text/13-ch07.txt:189(搜「表 7-3」) |
| 表 7-4 D 锁存器真值表 | 第7 章 时序逻辑电路 | text/13-ch07.txt:217(搜「表 7-4」) |
| 表 7-5/7-6 T 触发器与 D 值 | 第7 章 时序逻辑电路 | text/13-ch07.txt:347(搜「表 7-5」) · text/13-ch07.txt:357(搜「表 7-6」) |
| 表 7-7 JK 触发器转换表 | 第7 章 时序逻辑电路 | text/13-ch07.txt:384(搜「表 7-7」) |
| 表 7-11/7-12 计数器两表 | 第7 章 时序逻辑电路 | text/13-ch07.txt:499(搜「表 7-11」) · text/13-ch07.txt:525(搜「表 7-12」) |
| 表 7-14/7-15/7-16 预测器三表 | 第7 章 时序逻辑电路 | text/13-ch07.txt:634(搜「表 7-14」) · text/13-ch07.txt:642(搜「表 7-15」) · text/13-ch07.txt:664(搜「表 7-16」) |
| 步骤(2)(3)的编码与触发器经验 | 第7 章 时序逻辑电路 | text/13-ch07.txt:454(搜「log2N」) · text/13-ch07.txt:513(搜「不错的入手点」) |
| 「成本或功耗的节省都不足以」换型 | 第7 章 时序逻辑电路 | text/13-ch07.txt:516(搜「都不足以证明」) |
| 锁存器/触发器的术语约定 | 第7 章 时序逻辑电路 | text/13-ch07.txt:266(搜「术语各不相同」) |
| 时序图与稳定延迟 | 第7 章 时序逻辑电路 | text/13-ch07.txt:170(搜「时序」) · text/13-ch07.txt:570(搜「短暂延迟」) |
| 上电不定与异步预置/清零 | 第7 章 时序逻辑电路 | text/13-ch07.txt:314(搜「异步」) |
| 「设计过程的迭代」 | 第7 章 时序逻辑电路 | text/13-ch07.txt:447(搜「迭代的」) |
-
出处:「第7 章 时序逻辑电路」第 1 段(
text/13-ch07.txt:1,搜「92 时序逻辑电路」)。原文:「系统状态是对系统的描述,知道了 t0 时刻的状态和 t0~t1 时间的输入,就能唯一地确定 t1 时刻的状态和 t0~t1 时间的输出。」 ↩ -
出处:「第7 章 时序逻辑电路」第 17 段(
text/13-ch07.txt:17,搜「有限状态机」)。原文:「系统状态的概念体现在有限状态机中,这是一种计算的数学模型,可以处于有限数量的状态中的任何一种」「如果时序逻辑电路的设计使其输出仅取决于其所处的状态,则称为摩尔型状态机。如果输出还依赖于导致状态发生转换的输入,则称为米利型有限状态机。」 ↩ -
出处:「第7 章 时序逻辑电路」第 44 段(
text/13-ch07.txt:44,搜「保持当前状态」)与第 52 段(text/13-ch07.txt:52,搜「交叉反馈」)。原文:「每个或非门的输出都被馈送到另一个或非门的输入」「正是这种反馈使得锁存器能够保持在一种状态」。 ↩ -
出处:「第7 章 时序逻辑电路」第 74 段(
text/13-ch07.txt:74,搜「状态图」)与第 79 段(text/13-ch07.txt:79,搜「摩尔型」)。原文:「带箭头的线条显示了状态之间可能的转换,并标有导致转换到下一个状态的输入」「因为输出只取决于状态,而非输入,所以锁存器属于摩尔型状态机。」 ↩ -
出处:「第7 章 时序逻辑电路」第 82 段(
text/13-ch07.txt:82,搜「有向图」)与第 84 段(text/13-ch07.txt:84,搜「状态转换表」)。原文:「状态图是一个有向图:状态是顶点,导致状态转换的输入是边。尽管这超出了本书的讨论范围,但图论工具在设计过程中占有一席之地。」 ↩ -
出处:「第7 章 时序逻辑电路」第 148 段(
text/13-ch07.txt:148,搜「差一错误」)。原文:「当只有两个选择时,差一错误(off-by-one error)会造成截然相反的行为。」 ↩ -
出处:「第7 章 时序逻辑电路」第 171 段(
text/13-ch07.txt:171,搜「未必可靠」)。原文:「每个设备改变状态以及将其输出传送至下一个设备都需要时间,精确的时序取决于元件细微的制造差异。结果未必可靠。我们需要一种同步活动的方法,以便有序地操作。」 ↩ -
出处:「第7 章 时序逻辑电路」第 177 段(
text/13-ch07.txt:177,搜「门控」)与第 181 段(text/13-ch07.txt:181,搜「保持为 1」)。原文:「只要 Enable = 0,两个控制与非门的输出都保持为 1。这会将¬S = 1 和¬R = 1 发送到……输入端,使状态保持不变。」 ↩ -
出处:「第7 章 时序逻辑电路」第 226 段(
text/13-ch07.txt:226,搜「D 输入」)与第 231 段(text/13-ch07.txt:231,搜「补值」)。原文:「数据输入 D 被馈送至 SR 锁存器的 S 端;其补值被送至 R 端。」 ↩ -
出处:「第7 章 时序逻辑电路」第 240 段(
text/13-ch07.txt:240,搜「键盘」)。原文:「一个正在运行的程序无法知道用户何时会按下键盘上的某个键。当键被按下时,程序可能还没有做好读取的准备,所以该字符的二进制编码应该在输入端口锁存。」 ↩ -
出处:「第7 章 时序逻辑电路」第 256 段(
text/13-ch07.txt:256,搜「不是件容易的事」)。原文:「协调启用和禁用之间的来回切换不是件容易的事。我们将在 7.2 节给出这个问题的解决方案。」 ↩ -
出处:「第7 章 时序逻辑电路」第 272 段(
text/13-ch07.txt:272,搜「时钟」)与第 280 段(text/13-ch07.txt:280,搜「足够慢」)。原文:「时钟是一种提供电子时钟信号的设备,通常是在 0 和 1 电平之间交替的方波」「时钟频率必须足够慢,使得所有电路元件在下一个时钟转换(在相同方向上)发生之前有时间完成它们的操作。」 ↩↩ -
出处:「第7 章 时序逻辑电路」第 289 段(
text/13-ch07.txt:289,搜「主/次」)与第 299 段(text/13-ch07.txt:299,搜「CK = 0」)。原文:「隔离输出与输入变化的一种方法是将一个 D 锁存器的输出与另一个 D 锁存器的输入以主/次配置(primary/secondary configuration)相连。」 ↩ -
出处:「第7 章 时序逻辑电路」第 295 段(
text/13-ch07.txt:295,搜「正沿触发」)与第 703 段(text/13-ch07.txt:703,搜「只能改变一次」)。原文:「因此,触发器在接受输入和提供输出之间提供半个时钟周期的时间间隔。由于输出在 0 到 1 转换时可用,这称为正沿触发。」「D 触发器的输出在每个时钟周期只能改变一次。」 ↩ -
出处:「第7 章 时序逻辑电路」第 266 段(
text/13-ch07.txt:266,搜「术语各不相同」)。原文:「我将使用术语“锁存器”来表示存储单个位的设备,不考虑时序因素,而使用“触发器”来表示在半个时钟周期内存储一位,然后在另外半个时钟周期内将其作为输出的设备。」 ↩ -
出处:「第7 章 时序逻辑电路」第 314 段(
text/13-ch07.txt:314,搜「异步」)与第 318 段(text/13-ch07.txt:318,搜「无论其他输入」)。原文:「这些已知值是独立于时钟过程的输入,因此被称为异步输入」「当 PR 输入为 1 时,Q 变为 1,¬Q 变为 0,无论其他输入(甚至包括 CLK)是什么。」 ↩↩↩↩ -
出处:「第7 章 时序逻辑电路」第 320 段(
text/13-ch07.txt:320,搜「更高效的电路」)与第 325 段(text/13-ch07.txt:325,搜「小圆圈」)。原文:「有更高效的电路可用于实现边沿触发的 D 触发器,但本讨论表明其也可以通过普通的逻辑门来构建」「图 7-10(b)中时钟输入端的小圆圈表示这个 D 触发器是由负向时钟转换触发的。」 ↩ -
出处:「第7 章 时序逻辑电路」第 332 段(
text/13-ch07.txt:332,搜「CAPS LOCK」)与第 330 段(text/13-ch07.txt:330,搜「7.2.3 T 触发」)。原文:「如果字母键处于小写模式,按下 CAPS LOCK 键会将其切换到大写模式」「D = (¬T ∧ Q) ∨ (T ∧ ¬Q) = T ∨_ Q」。 ↩ -
出处:「第7 章 时序逻辑电路」第 377 段(
text/13-ch07.txt:377,搜「4 种可能的操作」)与第 409 段(text/13-ch07.txt:409,搜「Ja = ¬Q」)。原文:「实现 4 种可能的操作(置位、复位、保持、切换)需要两个输入:J 和 K」「Ja = ¬Q 且 Ka = Q」。 ↩ -
出处:「第7 章 时序逻辑电路」第 440 段(
text/13-ch07.txt:440,搜「复杂性」)与第 444 段(text/13-ch07.txt:444,搜「节省成本」)。原文:「额外带来的复杂度大约相当于给 D 触发器添加一个 XOR 门而得到的 T 触发器」「JK 触发器通过提供 4 种功能,在设计中提供了更大的灵活性,进而有助于节省成本。」 ↩↩ -
出处:「第7 章 时序逻辑电路」第 447 段(
text/13-ch07.txt:447,搜「迭代的」)。原文:「任何领域的设计通常都是迭代的,这一点你无疑已经从你的编程经验中了解到了。从设计开始,分析,改进,使其更快、更便宜等。」 ↩ -
出处:「第7 章 时序逻辑电路」第 465 段(
text/13-ch07.txt:465,搜「手把手」)与第 467 段(text/13-ch07.txt:467,搜「序列」)。原文:「如果你手边有数字电路模拟器,或是所需的硬件,不妨跟着操作。这就像一次手把手的“动手实践”。」「当 Enable = 1 时,计数器按照序列 0, 1, 2, 3, 0, 1…,每个时钟周期递增一次。」 ↩↩ -
出处:「第7 章 时序逻辑电路」第 537 段(
text/13-ch07.txt:537,搜「无关」)。原文:「在这个表中,JK 触发器有相当多的“无关”条目。这表明我们可以做不少简化工作。此外还反映出卡诺图是一种很好的方法,因为其图形化描述往往更容易将“无关”条目的影响可视化。」 ↩ -
出处:「第7 章 时序逻辑电路」第 570 段(
text/13-ch07.txt:570,搜「短暂延迟」)。原文:「在时钟转换之后,每个输出值实际发生变化之前的短暂延迟代表了电子器件完全稳定到新值所需的时间。」 ↩ -
出处:「第7 章 时序逻辑电路」第 582 段(
text/13-ch07.txt:582,搜「装配线」)。原文:「除了非常便宜的微控制器,大多数现代 CPU 都是分阶段执行指令的。每个阶段都由专门执行该阶段操作的硬件组成。一条指令以装配线方式经过各个阶段。」 ↩ -
出处:「第7 章 时序逻辑电路」第 589 段(
text/13-ch07.txt:589,搜「条件分支」)至第 593 段(text/13-ch07.txt:593,搜「冲刷流水线」)。原文:「在决策指令(decision-making instruction)进入流水线一定阶段之前,无法知道究竟要提取哪一条指令」「如果预测有误,则 CPU 忽略对预测指令所做的工作,冲刷流水线并提取另一条指令。」 ↩ -
出处:「第7 章 时序逻辑电路」第 595 段(
text/13-ch07.txt:595,搜「连续犯两次错误」)与第 606 段(text/13-ch07.txt:606,搜「No-error」)。原文:「预测器继续预测相同的结果……直到连续犯两次错误」;状态图与表 7-13 给出四种状态。 ↩ -
出处:「第7 章 时序逻辑电路」第 695 段(
text/13-ch07.txt:695,搜「更复杂的预测方法」)与第 697 段(text/13-ch07.txt:697,搜「电力」)。原文:「这个例子展示了最简单的分支预测方法。还有更复杂的预测方法」「虽然能够提高一些算法的速度,但是分支预测所需的额外硬件会消耗更多的电力,这在由电池供电的设备中值得留意。」 ↩ -
出处:「第7 章 时序逻辑电路」第 84 段(
text/13-ch07.txt:84,搜「状态转换表」)。原书表 7-1 给出或非门 SR 锁存器的完整状态转换表,底部两行的 X 表示「不允许」的情况。 ↩ -
出处:「第7 章 时序逻辑电路」第 249 段(
text/13-ch07.txt:249,搜「传播延迟」)至第 256 段(text/13-ch07.txt:256,搜「不是件容易的事」)。原文:「在 D 锁存器的输入变得可靠之前,应该禁用第二个设备,同时要考虑传播延迟。一旦我们的 D 锁存器稳定下来,就将其禁用。传播延迟之后,就可以启用 D 锁存器所连接的设备。」「协调启用和禁用之间的来回切换不是件容易的事。我们将在 7.2 节给出这个问题的解决方案。」 ↩ -
出处:「第7 章 时序逻辑电路」第 499 段(
text/13-ch07.txt:499,搜「表 7-11」)。原书表 7-11 给出两位计数器的状态转换表(Enable × 当前 n1n0 → 下一个 n1n0)。 ↩ -
出处:「第7 章 时序逻辑电路」第 525 段(
text/13-ch07.txt:525,搜「表 7-12」)。原书表 7-12 给出使用 JK 触发器实现两位计数器所需的 J1、K1、J0、K0 输入,含大量 X 无关项。 ↩ -
出处:「第7 章 时序逻辑电路」第 626 段(
text/13-ch07.txt:626,搜「二进制编码」)与第 634 段(text/13-ch07.txt:634,搜「表 7-14」)。原文:「对于这个问题,我们将为状态选择二进制编码 s1s0」「预测对应 s1」;表 7-14 给出状态与 s1s0、预测的对应。 ↩ -
出处:「第7 章 时序逻辑电路」第 189 段(
text/13-ch07.txt:189,搜「表 7-3」)。原书表 7-3:Enable = 0 时「- 表示输入无关紧要」;「只有当 Enable = 1 且 S 和 R 的值相反时,锁存器的状态才会改变。」 ↩ -
出处:「第7 章 时序逻辑电路」第 211 段(
text/13-ch07.txt:211,搜「真值表」)与第 217 段(text/13-ch07.txt:217,搜「表 7-4」)。原文:「D 锁存器允许我们存储一位的值」;表 7-4 给出带 Enable 的 D 锁存器真值表。 ↩ -
出处:「第7 章 时序逻辑电路」第 347 段(
text/13-ch07.txt:347,搜「表 7-5」)。原书表 7-5 给出 T 触发器状态转换表;「D 的等式」推导见第 213 段(text/13-ch07.txt:213,搜「D =」)。 ↩ -
出处:「第7 章 时序逻辑电路」第 384 段(
text/13-ch07.txt:384,搜「表 7-7」)。原书表 7-7 给出 JK 触发器状态转换表,最左列标注操作(保持/复位/置位/切换)。 ↩ -
出处:「第7 章 时序逻辑电路」第 405 段(
text/13-ch07.txt:405,搜「写模式」)至第 409 段(text/13-ch07.txt:409,搜「Ja = ¬Q」)。原文:「当 CK = 0 时,图 7-14 中的主级 SR 锁存器处于写模式。当 J = K = 1 时,我们希望它能切换输出 Q」「Ja = ¬Q 且 Ka = Q」。 ↩ -
出处:「第7 章 时序逻辑电路」第 149 段(
text/13-ch07.txt:149,搜「表 7-2」)。原文:「表 7-2 是与非门 SR 锁存器的状态转换表」「将 0 同时置于两个输入端会导致一个问题:两个与非门的输出都会变为 1。也就是说,Q = ¬Q = 1,这在逻辑上是不可能的。」 ↩ -
出处:「第7 章 时序逻辑电路」第 107 段(
text/13-ch07.txt:107,搜「逻辑补」)。原文:「与非门的物理结构使其速度快于或非门……与非门是或非门的逻辑补,因此我们使用¬S 和¬R 作为输入。」 ↩ -
出处:「第7 章 时序逻辑电路」第 170 段(
text/13-ch07.txt:170,搜「时序」)与第 563 段(text/13-ch07.txt:563,搜「Qi.JK」)。原文:「图 7-19 展示了二进制计数器按照序列 3、0、1、2、3(11、00、01、10、11)进行计数时的时序」「Qi.JK 是第 i 个 JK 触发器的输入,ni 是其输出」。 ↩ -
出处:「第7 章 时序逻辑电路」第 606 段(
text/13-ch07.txt:606,搜「No-error」)与第 609 段(text/13-ch07.txt:609,搜「连续两次」)。原文:「如果分支被采用,则 Actual = Taken 的弧线表示电路进入 No-error 状态……但是必须连错两次才能改变我们的预测」「如果采用了分支,则电路连续两次预测错误,因此转为 Yes 状态并输出 Take。」 ↩ -
出处:「第7 章 时序逻辑电路」第 613 段(
text/13-ch07.txt:613,搜「表 7-13」)。原书表 7-13 给出分支预测器状态表:当前状态、预测、Actual = Not Taken / Taken 各自的下一个状态和预测。 ↩ -
出处:「7.4 小结」部分(
text/13-ch07.txt:700,搜「SR 锁存器」)。原书 7.4 小结列出:SR 锁存器、D 触发器、T 触发器、JK 触发器(「通用触发器」)。 ↩ -
出处:「第7 章 时序逻辑电路」第 642 段(
text/13-ch07.txt:642,搜「表 7-15」)。原书表 7-15 给出分支预测器的状态转换表(Actual × 当前 s1s0 → 下一个 s1s0)。 ↩ -
出处:「第7 章 时序逻辑电路」第 11 段(
text/13-ch07.txt:11,搜「当前状态」)。原文:「时序逻辑电路的时间历史可以由电路的当前状态来概括。」 ↩ -
出处:「第7 章 时序逻辑电路」第 52 段(
text/13-ch07.txt:52,搜「交叉反馈」)。原文:「因此,两个或非门之间的交叉反馈维持锁存器的当前状态。」(分步演算中的门输入表达式是我们按图 7-1 的结构补写的:上门输入为 S 与 Q,下门输入为 R 与 ¬Q。) ↩