2026-09-23 更新于 2026-10-01

计算机组成笔记

关于计算机组成原理的笔记。持续更新

写在前面:本笔记侧重于概念和底层的理解。建议先夯实了基础再做题,事半功倍

当前进度:程序执行概览、整数表示与运算电路。 先认识一条指令的执行过程,再解释数怎样编码、加法怎样实现;寄存器与时钟的细节留待后续。

阅读路线:程序执行 → 数的表示 → 运算电路。

教材模块 本文位置
计算机系统概述、指令执行入门 第一章
整数表示与补码运算 第二章
加法器、ALU 与溢出检测 第三章
数据通路与状态保存入门 第一章第三部分;第三章第五部分

第一章:程序是怎样执行的

第一部分:计算机里的各部件怎样分工?

1. 计算机到底在干什么?

假设一家工厂接到订单,要把两批原料加工成一件产品。它需要有地方放原料、有机器加工、有运输通道,还要有人安排先后顺序。

计算机也是这样。先抓住三件事:存储数据、加工数据、搬运数据。

比如一行代码:

1
c = a + b;

在一个简化的机器模型里,相当于从存储位置取出 a 和 b,交给运算部件相加,再把结果保存起来。它涉及一连串实际的数据传送和状态变化,不能只用抽象的“算一下”来理解。

2. 五大功能部件各自负责什么?

  • 运算器:工厂里的加工机器。 对数据做算术运算和逻辑运算。ALU(算术逻辑单元)是其中的重要部件,负责加法、与、或等操作。
  • 控制器:安排生产的调度员。 根据指令决定现在该读哪个数据、做什么操作、把结果送到哪里。
  • 存储器:仓库。 保存程序和数据,供执行时读取,也接收需要保存的结果。
  • 输入设备:进料口。 把外部信息送入计算机,例如通过键盘输入内容。
  • 输出设备:出料口。 把处理结果交给外部,例如显示到屏幕上。

⚠️ 易混点:控制器不等于运算器。 调度员安排“把这两份数据相加”,真正做加法的是运算电路。

CPU 通常包含运算器、控制器和寄存器等部件。不能把 CPU 理解成只有一个计算器,也不能把整台计算机都叫作 CPU。

3. 寄存器、内存、硬盘有什么区别?—— 手边工作台与仓库

如果每加工一步都要跑去远处仓库拿东西,工人再快也没用。所以工位旁边需要小工作台,常用材料先放在手边。

  • 寄存器: CPU 内部的小型存储部件,像工位上的工作格,放当前操作数、地址或状态。
  • 主存(内存): 程序运行时的重要存储空间,像车间仓库,容量比手边工作格大。
  • 辅存(如 SSD): 用于长期保存文件和程序,像大仓库。程序和数据通常需要经过加载等过程,才能被 CPU 使用。

Cache 可以理解成 CPU 与主存之间的近处备料区,用来缓解速度差距。这里先分清角色,不展开其内部规则。

核心矛盾:速度、容量和成本很难同时做到理想。 存储层次就是围绕这个矛盾作出的安排。


第二部分:程序怎样变成机器指令?

1. 存储程序:把“加工步骤”也放进仓库

假设每加工一件产品,都要有人站旁边喊:“先拿 a,再拿 b,然后相加。”这就谈不上自动化。

解决办法是把操作步骤写成工单,让机器自己按工单执行。

存储程序思想:把程序的指令预先存入存储器,机器运行时自动取出并执行。 在经典冯·诺依曼模型中,指令和数据都以二进制形式存储。

⚠️ 同样是比特,不代表含义相同。 一张纸可以是加工说明,也可以是数量记录;机器取它来作指令还是作数据,要看执行上下文。

2. 机器指令是什么?—— 一张具体的加工工单

下面这条教学用汇编指令:

1
ADD R3, R1, R2

表示:

1
R3 ← R1 + R2

可以把它翻译成工厂语言:“取工作格 R1 和 R2 中的材料,做加法,把结果放进 R3。”

  • 做什么: 加法。
  • 输入在哪里: R1、R2。
  • 结果放哪里: R3。

机器里保存的不是字符 ADD,而是对应的二进制编码。操作类型、寄存器编号等信息都要按规则编码。

ISA(指令集体系结构)就像机器对外公布的操作手册: 支持哪些操作、有哪些可用寄存器、执行应产生什么效果。具体 CPU 再用硬件实现这些约定。

3. 高级语言、汇编和机器指令是什么关系?

可以把高级语言想成“我要完成什么”的生产要求,汇编更接近逐条机器工单,机器编码则是硬件能够识别的格式。

例如前面的加法,在简化模型中可以写成:

1
2
3
4
LOAD  R1, [a]
LOAD R2, [b]
ADD R3, R1, R2
STORE [c], R3

底层过程:搬进来 → 计算 → 保存回去。 这只是教学示意,实际编译器可能利用寄存器中已有的数据,生成不同指令。


第三部分:跟着一条指令走完执行过程

1. PC 和 IR 为什么要分开?—— 工单位置与当前工单

工厂自动执行工单,需要同时知道两件事:去哪里拿下一张,以及现在手里拿的是哪一张。

  • PC(程序计数器): 保存取指所需的地址,像记录工单位置的指针。
  • IR(指令寄存器): 保存取出的当前指令,像工位上正在处理的工单夹。

⚠️ PC 不是“已经执行了几条指令”的计数器,也不是源代码行号。 它保存的是指令地址。

下面约定一个简单模型:按字节编址,每条指令占 4 字节,当前 PC 为 1008,该地址处是一条 ADD。这里只用于说明过程,不代表所有指令集都采用固定的 4 字节指令。

2. 取指:先把工单拿到手

CPU 根据 PC 中的地址取出指令,放入 IR。在本例的顺序执行过程中,PC 可以更新为 1012,为下一次取指作准备。

1
2
PC 给出 1008 → 取出指令 → IR 保存当前 ADD
PC 更新为 1012

为什么当前操作没做完,PC 就能先往后移? 像工人已经把工单夹在面前,就可以先把取单指针移到下一张,当前工作不会因此丢失。具体更新时机由硬件设计决定。

3. 译码:控制器把工单变成具体动作

看到“把 R1 和 R2 相加”,控制器需要安排:

  • 选择 R1、R2 作为输入。
  • 让 ALU 执行加法。
  • 选择 ALU 的结果作为写回数据。
  • 允许 R3 接收结果。

控制信号就像车间里的开关和调度指令。 它决定哪些通路接通、哪个部件执行什么操作。数据通路负责搬运和处理,控制器负责协调它们。

4. 执行与写回:加工完,还得放到指定位置

假设 R1 保存 5,R2 保存 7。为了看清运算,只画低 8 位:

1
2
3
4
  00000101
+ 00000111
----------
00001100

ALU 得到 12,再把结果写进 R3。

类比: 产品刚从加工机器出来,还不等于已经入库。必须送进指定工作格,下一步才能从那里取到它。

⚠️ ADD 写回 R3,不会自动写回内存中的 c。 示例里还需要 STORE,才能把 R3 中的结果存到 c 对应的位置。

5. 不同工单会走不同路线

指令 工厂类比 主要作用
LOAD 从仓库领料到工作格 内存 → 寄存器
ADD 把工作格中的材料送去加工 寄存器 → ALU → 寄存器
STORE 把结果送回仓库 寄存器 → 内存
JUMP 改变接下来要领的工单位置 改变后续取指地址

JUMP 为什么能改变执行顺序?因为它改变了后续取指的位置。条件分支、循环等控制流,就与比较和跳转密切相关。

注意:ADD 不需要读取数据内存,不代表它不需要取指。 取加工工单和取加工原料,是两个不同动作。

本章自测

假设当前 PC 为 400,每条指令占 4 字节,机器刚取出一条 ADD。

  1. 在上述顺序执行模型中,PC 接下来指向哪里?当前 ADD 又保存在哪里?
  2. 控制器和 ALU 的工作有什么区别?用调度员与加工机器解释。
  3. 为什么 ADD 得到结果之后,还可能需要一条 STORE?

第二章:计算机怎样表示和运算整数

上一章把数据交给 ALU 就能得到结果。先不拆电路,先弄清同一串比特怎样代表不同的数,以及运算规则从哪里来。

第一部分:二进制怎样表示数值?

1. 为什么一串 0 和 1 能表示数?

十进制里的 345,并不是把 3、4、5 简单摆在一起,而是:

1
3 个百 + 4 个十 + 5 个一

二进制使用同样的位权思想,只是每一位只能填 0 或 1,相邻位置的权重相差两倍。

把 4 位二进制想成四个格子,从左到右分别能放一张面值 8、4、2、1 的卡片。填 1 表示放入,填 0 表示不放。

例如 1011:

$$ 1\times 8+0\times 4+1\times 2+1\times 1=11 $$

核心理解:同一个 1 放在不同位置,贡献的数值不同。 不要只记“逢二进一”,还要知道每一位的权重。

2. 位数有限,能表示的范围也有限

四个格子,每格两种状态,一共有 $2^4=16$ 种组合。全部用于表示非负整数,就可以表示 0~15。

一般 n 位无符号整数的范围是:

$$ 0\le x\le 2^n-1 $$

类比: 只有两位的十进制计数器最多显示 99,无法直接显示 100;4 位二进制也没有无限的位置可以继续写。


第二部分:怎样给二进制数加上正负?

1. 最直观的方案:留一位表示符号

如果还要表示欠款,就不能只记录“有多少钱”,还得记录是拥有还是欠着。

原码的办法很直观:最高位表示符号,0 为正、1 为负,其余位表示绝对值。用 4 位举例:

1
2
0101:+5
1101:-5

类比: 两张金额都是 5 元的单据,一张贴“收入”,另一张贴“支出”。金额部分相同,标签不同。

2. 直观不等于适合直接运算

现在要算 $5+(-5)$。按常识应该是零,但如果把上面的整串编码直接送进普通二进制加法器:

1
2
3
4
  0101
+ 1101
------
1 0010

只留低 4 位,得到 0010,也就是 2,结果错了。

问题在哪里? 加法器按位权处理整串比特,并不知道最高位被人另外贴上了“负号”的含义。就像会计把“支出标签的编号”也当金额加进账里,当然对不上。

原码可以表示负数,但做有符号运算时,需要额外处理符号、大小关系等情况。于是就有了新的需求:能不能设计一种编码,让负数也能更直接地使用加法硬件?


第三部分:补码为什么能统一加减法?

1. 先看钟表:往回走,也能换成向前走

在 12 小时的钟面上,从 3 点往回走 5 格,会到 10 点;从 3 点向前走 7 格,也会到 10 点。因为 7 和 -5 相差整整一圈。

固定宽度的二进制加法也有类似的“绕圈”现象。4 位只能保存 16 种状态,所以可以把它想成标了 0~15 的钟面:

1
2
1111 + 0001 = 1 0000
只保留低 4 位 → 0000

底层原理:保留 n 位加法结果,就是保留模 $2^n$ 的结果。 超出位宽的进位可以单独记录,但不会自动成为这 n 位的一部分。

2. 负数怎样对应到钟面上的位置?

在模 16 的意义下,往回走 1 格和向前走 15 格等效:

$$ -1\equiv15\pmod{16} $$

同样,往回走 5 格等于向前走 11 格:

$$ -5\equiv11\pmod{16} $$

于是可以用 1111 表示 -1,用 1011 表示 -5。4 位补码把 16 种状态解释成:

编码 补码含义 可以怎样理解
0000~0111 0~7 非负数
1000 -8 从零反向走 8 格
1011 -5 从零反向走 5 格
1110 -2 从零反向走 2 格
1111 -1 从零反向走 1 格

⚠️ 同一串比特,解释规则不同,数值就不同。 1110 按无符号数解释是 14,按 4 位补码解释是 -2。不是比特自己发生了变化。

3. “取反加一”为什么成立?

4 位正数 5 是 0101。逐位取反,相当于用 1111 减去它,也就是 $15-5$;再加 1,就得到 $16-5$:

1
0101 → 取反得到 1010 → 加 1 得到 1011

这正是 -5 在模 16 中对应的编码。

所以“取反加一”有它的来由:先得到差一圈的补数,再补上那一个 1。 记住模运算的原因,比孤立地背步骤更容易理解。

4. 用同一个加法器完成减法

重新计算 $5+(-5)$:

1
2
3
4
  0101    (+5)
+ 1011 (-5)
------
1 0000

低 4 位是 0000,结果为零。

再计算 $7-3$,把它改成 $7+(-3)$:

1
2
3
4
  0111    (+7)
+ 1101 (-3)
------
1 0100

低 4 位是 0100,结果为 4。

类比: 机器只擅长把钟表往前拨,我们就把“倒拨几格”换成“向前拨剩下的格数”。这样,加正数和加负数都能利用同一套加法电路。

5. 为什么 4 位补码只能表示 -8~7?

16 种编码分配给有符号整数后,0000~0111 表示 0~7,1000~1111 表示 -8~-1。零只占一个编码,因此负数一边比正数一边多一个。

一般 n 位补码的范围是:

$$ -2^{n-1}\le x\le 2^{n-1}-1 $$

⚠️ 补码没有让位数变多。 它让编码适合运算,但不能突破有限位宽的容量限制。

6. 进位和溢出不是一回事

刚才算 $5+(-5)$ 时,最高位之外有进位,但低 4 位的结果零是正确的。

再看 $7+1$:

1
0111 + 0001 = 1000

没有多出第五位,但 1000 按补码解释成 -8。两个正数相加却得到负数,这是因为真正的结果 8 已经超出 4 位补码的上限。

  • 进位: 从某一位向更高位传出的位。
  • 有符号溢出: 数学结果超出了当前有符号编码能表示的范围。

类比: 钟表能绕回去,不代表账本里“欠的钱”和“有的钱”也能随便绕。硬件留下了一个合法编码,不等于它还能表达你想要的数学结果。


本章自测

  1. 1011 按 4 位无符号整数、4 位原码、4 位补码解释,分别是多少?为什么 -5 的四位补码是 1011?
  2. 为什么补码可以把减法转成加法?
  3. 为什么最高位有进位,不一定表示有符号溢出?

先解释编码规则,再用具体数值检查结果。


第三章:从逻辑门到 ALU

已经知道比特怎样表示数,接着把加法器拆开,从逻辑门逐步搭到 ALU,最后回到第一章的 ADD 指令。

第一部分:逻辑门怎样实现一位加法?

前面一直说“把两个数交给加法器”,但工厂里不能只有一块写着“我会加法”的牌子。现在要把这台加工机器拆开,看它究竟靠什么工作。

1. 逻辑门:只按固定规则办事的小开关

数字电路用不同的电平范围表示 0 和 1。逻辑门由晶体管等器件组成;在数字逻辑这一层,可以先把晶体管理解成受电信号控制的开关,再研究开关组合后的输入、输出关系。

类比: 车间门口有几个只认固定规则的检查员。它们不会读整张订单,只判断眼前的条件是否满足:

  • AND(与): 两个条件都满足才放行,相当于“有工牌,并且有通行许可”。
  • OR(或): 至少一个条件满足就放行,相当于“走人工验证或电子验证,任意一种通过即可”。两个都满足也通过。
  • XOR(异或): 两个输入不同时输出 1,相当于两盏灯中“恰好亮一盏”才算通过。
  • NOT(非): 把结果翻转,0 变 1,1 变 0。
A B AND:$A\land B$ OR:$A\lor B$ XOR:$A\oplus B$
0 0 0 0 0
0 1 0 1 1
1 0 0 1 1
1 1 1 1 0

⚠️ 或与异或的区别,就在两个输入都是 1 时:OR 输出 1,XOR 输出 0。 后面做加法,正好会用到这个区别。

2. 一位加法要给出两个答案

小学列竖式时,个位算出 12,要在个位写 2,再向十位进 1。二进制也是一样,只是满 2 就进位。

因此 $1+1$ 的二进制结果是 10:本位写 0,向高位进 1。 一个一位加法部件需要两个输出:

  • Sum(S): 留在本位的结果。
  • Carry(C): 送给高一位的进位。

把两个一位输入的情况全部列出来:

A B 二进制和 S:本位结果 C:进位
0 0 0 0 0
0 1 1 1 0
1 0 1 1 0
1 1 10 0 1

观察本位结果这一列:输入不同时是 1,相同时是 0,正好就是 XOR。再看进位:只有两个输入都是 1 时才产生,正好就是 AND。

$$ S=A\oplus B,\qquad C=A\land B $$

这就得到了半加器(Half Adder):同一对 A、B 同时送入异或门和与门,分别得到 S 和 C。

核心原理:不需要电路“理解数学”。只要输入、输出规则与一位加法完全一致,电路就实现了这一位的加法。

3. 为什么只叫“半”加器?

假设算到十位时,个位已经向上进了 1。十位的工人不能只加两张原始单据,还要接收低位递过来的那张进位单。

半加器只有 A、B 两个输入,无法直接处理第三个输入。对于多位加法,还需要一个能同时处理 A、B 和低位进位 的部件。


第二部分:全加器怎样串起多位运算?

1. 全加器:把低位递来的进位也算进去

**全加器(Full Adder,FA)**有三个输入、两个输出:

  • 输入:A、B、$C_{in}$(低位传来的进位)。
  • 输出:S(本位结果)、$C_{out}$(传向高位的进位)。

类比: 每个工位收到两张本位单据,再接收前一个工位送来的进位单。凑够两个“1”,就向下一站换出一个进位,剩下的留在本位。

A B $C_{in}$ S $C_{out}$
0 0 0 0 0
0 0 1 1 0
0 1 0 1 0
0 1 1 0 1
1 0 0 1 0
1 0 1 0 1
1 1 0 0 1
1 1 1 1 1

本位结果的规律是:三个输入里有奇数个 1,S 就是 1。因此:

$$ S=A\oplus B\oplus C_{in} $$

进位的规律是:三个输入中至少两个是 1,就要进位。因此:

$$ C_{out}=(A\land B)\lor(A\land C_{in})\lor(B\land C_{in}) $$

⚠️ 有些教材写成 $C_{out}=AB+AC_{in}+BC_{in}$,这里的乘表示与,加号表示或,不是普通算术加法。 三个输入全为 1 时,进位输出仍然只有一个比特 1。

2. 两个半加器加一个或门,就能组成全加器

不用从头发明一台机器,把刚做好的半加器组合起来即可:

  1. 第一个半加器: 计算 A、B,得到临时和 T、进位 P。
  2. 第二个半加器: 计算 T、$C_{in}$,得到最终的 S、另一条进位 Q。
  3. 或门: 只要 P、Q 中有一个产生进位,就输出 $C_{out}=P\lor Q$。
1
2
3
4
5
6
7
A、B ──→ 半加器 1 ──→ T ──┐
│ ├──→ 半加器 2 ──→ S
P Cin ──┘ │
│ Q
└────────→ OR ←─────────┘
│
Cout

类比: 第一张工作台先处理两份原料,第二张再把前一站送来的补料加进去;两处产生的进位统一交给高位。复杂部件就是这样由简单部件拼起来的。

3. 四个全加器怎样处理一个四位数?

每一位安排一个全加器,把低位的 $C_{out}$ 接到高一位的 $C_{in}$。普通加法没有外部进位时,最低位的初始进位 $C_0=0$。

四位串行进位加法器:从 FA0 到 FA3 依次传递进位,计算无符号数 0101 加 0111,得到 1100

图中从左到右是低位到高位,蓝色横线传递进位,黑色竖线分别表示操作数输入和本位结果输出。最后读数要按高位到低位排列,即 S3、S2、S1、S0。

这叫串行进位加法器,也叫涟波进位加法器(Ripple Carry Adder)。就像接力:本位产生的进位,成为下一位的一个输入。

⚠️ “串行”说的是进位的依赖关系。 不是 CPU 每过一个时钟才算下一位,也不是所有输入必须排队才能进入电路。各位输入可以同时到达,但某些高位结果要等进位传播后才能稳定。

4. 逐位算一遍 5 + 7

这里先按 4 位无符号整数解释:$5=0101$、$7=0111$,从最低位 bit 0 开始。

位次 A B 输入进位 本位计算 S 输出进位
bit 0 1 1 0 $1+1+0=2$ 0 1
bit 1 0 1 1 $0+1+1=2$ 0 1
bit 2 1 1 1 $1+1+1=3$ 1 1
bit 3 0 0 1 $0+0+1=1$ 1 0

按高位到低位把 S 拼起来,得到 1100,即无符号整数 12,最高位输出进位为 0。

⚠️ 如果改按 4 位补码解释,结论就不同。 5、7 都能表示,但结果 12 超出 -8~7 的范围,1100 会被解释成 -4,说明发生了有符号溢出。电路输出的比特没变,数值解释和是否越界的判断变了。

5. 位数多了,为什么会慢?

把四个工位增加到几十个,最坏情况下进位要一路传过去。例如 1111 + 0001,最低位产生的进位会不断影响高位。

逻辑门有传播延迟,导线传递信号也不是瞬间完成。进位依赖链越长,最坏情况下等待结果稳定的时间就越长。 这种延迟会影响电路能采用多短的时钟周期。

先行进位等更快的设计,就是设法减少逐级等待。这里先知道串行进位的瓶颈,不能据此认为所有真实 CPU 的加法器都简单串着几十个全加器。


第三部分:同一套电路怎样完成加减法?

1. 补码怎样变成实际电路?

前面知道减法可以转成加负数。在固定 n 位、保留低 n 位结果的意义下:

$$ A-B\equiv A+\overline{B}+1\pmod{2^n} $$

横线表示对 B 的 n 个比特逐位取反。现在已经有加法器,只要解决两件事:需要减法时把 B 取反,并且额外加 1。

类比: 工厂已经有一台加法机器,不必为了减法再建一条完全独立的生产线;先在进料口转换原料,再让同一台机器加工。

2. XOR:受控制的翻转开关

异或有两条特别有用的性质:

$$ B_i\oplus0=B_i,\qquad B_i\oplus1=\overline{B_i} $$

可以把它想成一个“翻面开关”:控制位为 0,卡片原样通过;控制位为 1,每张卡片的 0、1 全部翻转。

设置控制信号 SUB,规定 0 做加法、1 做减法。把 SUB 同时接到 B 每一位对应的异或门,得到:

$$ B'_i=B_i\oplus SUB,\qquad i=0,1,\ldots,n-1 $$

再把最低位全加器的输入进位设为 $C_0=SUB$,整台机器计算的就是 $A+B'+C_0$。

SUB 各位异或后的 B′ 最低位输入进位 实际运算
0 B 0 $A+B$
1 B 的逐位取反 1 $A+\overline{B}+1$,即减法的低 n 位结果

⚠️ SUB 要广播到 B 的每一位,不是只翻转最低位。额外的 1 则只送到最低位的输入进位端,不是给每一位都加 1。 其余各位接收前一级实际产生的进位。

3. 完整跑一次 5 - 3

设 A 为 0101,B 为 0011,SUB 为 1:

1
2
3
4
5
6
7
8
9
B       = 0011
B′ = 1100 (每一位与 SUB=1 异或)
C0 = 1

0101
+ 1100
+ 0001
------
1 0010

保留低 4 位得到 0010,即 2。如果忘记让 C0 等于 1,就只做了取反,没有完成补码取负,结果会差 1。

这正是补码在硬件上的价值:加法和减法可以共用加法电路,用少量控制逻辑切换。


第四部分:电路怎样判断进位和溢出?

1. 同一组比特,两本不同的账

考虑四位加法:

1
1111 + 0001 = 1 0000
  • 按无符号数解释: $15+1=16$,超出四位的 0~15 范围。最高位进位为 1,低四位不能独立表示完整结果。
  • 按补码解释: $-1+1=0$,低四位 0000 正确,没有有符号溢出。

类比: 同一张编码单据交给两种记账规则,会得到不同的金额含义。加法电路计算比特,是否超范围必须结合位宽和数值解释判断。

2. 补码加法的判断:同号相加,结果变号

四位补码的范围是 -8~7。如果算 $7+3$:

1
0111 + 0011 = 1010

两个正数加出了被解释为 -6 的编码,发生溢出。同样,两个负数相加,结果若变成非负数,也发生溢出。例如 $-8+(-1)$ 的低四位会变成 0111,即 7。

补码加法的规则:两个操作数同号,结果的符号却与它们不同,就发生有符号溢出;异号相加不会发生有符号加法溢出。 这里讨论的是加法,不能把同一句判断不加区分地套到减法上。

3. 电路怎样检查溢出?

对 n 位加法,记 $C_{n-1}$ 为进入最高符号位的进位,$C_n$ 为符号位送出的进位。两者不同时,发生补码溢出:

$$ V=C_{n-1}\oplus C_n $$

又是一个 XOR。 这次它比较的是符号位两侧的进位,而不是两个操作数。看前面的四位 $5+7$:进入 bit 3 的 $C_3=1$,输出的 $C_4=0$,因此 V 为 1,和数值范围判断一致。

四位加法 低四位结果 最高位进位 $C_4$ 补码溢出 V
1111 + 0001 0000 1 0
0111 + 0011 1010 0 1
0101 + 0111 1100 0 1

结论要分开说:最高位进位反映无符号加法是否超范围,有符号溢出反映补码结果是否超范围。 不能只盯着一个 Carry,就判断所有整数运算是否正确。


第五部分:ALU 怎样参与指令执行?

1. 加减法器不是完整的 ALU

CPU 除了加减法,还需要与、或、异或等操作。可以先构造一个简单的 ALU:把输入送给加减法模块和若干逻辑运算模块,再从这些模块的输出中选择一个作为结果。

类比: 同一批材料可以送到不同加工工位。调度员说“这次要加法结果”,出料口就接通加法工位;说“这次做按位与”,就接通与运算工位。

负责选择的部件叫 MUX(Multiplexer,多路选择器):根据选择信号,从多个输入中选一个输出。它本身不负责把两个数相加。

1
2
3
4
5
A、B ──→ 加减法模块 ──┐
├→ AND 模块 ─────┤
├→ OR 模块 ──────┼──→ MUX ──→ Result
└→ XOR 模块 ─────┘ ↑
结果选择信号

在这个教学模型里,控制器既要决定加减法模块的 SUB,又要决定 MUX 选择哪个模块。例如:

需要的操作 加减法模块的 SUB MUX 选择
ADD 0 加减法模块
SUB 1 加减法模块
AND 对该结果无影响 AND 模块
OR 对该结果无影响 OR 模块
XOR 对该结果无影响 XOR 模块

⚠️ ALUControl 的具体编码由设计决定。 不是所有处理器都用某组固定的 00、01 编码,也不是每种 ALU 都让所有模块一直同时工作。比较、移位等功能的组织方式也可能不同。

2. 回到 ADD:控制器到底控制了什么?

执行 ADD R3, R1, R2 时,现在可以把原先一句“ALU 做加法”拆开:

  1. 寄存器堆提供 R1、R2 的值。
  2. 控制器让加减法模块处于加法模式,即 SUB 为 0。
  3. 加法电路根据各位输入和进位产生结果。
  4. MUX 选择加法结果,写回通路在规定时刻把它保存到 R3。

对于能容纳 12 的位宽,例如 8 位,5 和 7 相加得到 00001100。至此,从指令到逻辑门的联系就具体了:操作码决定控制信号,控制信号选择数据通路,逻辑电路产生结果,寄存器保存结果。

3. 组合逻辑与时序逻辑:加工机器不等于仓库

刚才的半加器、全加器、MUX,以及这里的简单 ALU 数据运算部分,都属于组合逻辑:经过传播延迟、输出稳定后,结果由当前输入决定,不保存上次运算的状态。

类比: 计算器的加工部分负责“当前这批原料能算出什么”,它不是负责保存旧结果的账本。输入一变,输出也会随之变化,而不是自动把前一次答案留下来。

寄存器则必须能够保存之前写入的值,在允许更新时才接收新值。这需要时序逻辑,其行为与已有状态有关。PC、IR 也需要这种存储能力。

类型 可以怎样理解 本节例子
组合逻辑 按当前输入加工,不记旧账 半加器、全加器、MUX
时序逻辑 保存状态,再按条件更新 寄存器、PC、IR

⚠️ “没有记忆”不等于“没有延迟”;“能保存状态”也不等于“断电不丢失”。 寄存器通常需要供电维持状态。至于触发器和时钟怎样实现受控更新,下一部分再继续拆。


本章自测

  1. 半加器为什么需要 S 和 C 两个输出?它还缺哪个输入,才需要扩展成全加器?
  2. 全加器输入 A、B、Cin 都为 1 时,S 和 Cout 分别是什么?能否用两个半加器推一遍?
  3. 画四个全加器计算 0101 + 0111,标出每一级的进位。为什么按无符号数解释得到 12,按四位补码解释却发生溢出?
  4. 设 A 为 0101、B 为 0011。SUB 为 0 和 1 时,B′、C0、低四位结果分别是什么?哪一种情况发生补码溢出?
  5. 减法时为什么必须翻转 B 的每一位,又为什么只把额外的 1 接到最低位?
  6. MUX 会做加法吗?如果加法器已经算出结果,为什么还需要寄存器和写回控制?
  7. 为什么 1111 + 0001 有最高位进位却没有补码溢出,而 0111 + 0010 没有最高位进位却发生了补码溢出?

答题时分别说清电路怎样连、编码怎样解释、结果有没有超出范围,不要把三个层面混在一起。


更新于 2026-10-02。按程序执行、数的表示、运算电路组织已学内容。