二轮强化笔记
笔记结构
按章节顺序整理:一、数据的表示与运算(第 2 章)→ 二、存储系统(第 3 章)→ 三、中央处理器(第 5 章)。后续章节按学习进度依次往后补充,新内容不要堆到末尾。
课程勘误:BOK强化勘误
零、计算机系统概述



# 预处理
gcc -E hello.c -o hello.i
# 编译(生成汇编代码 hello.s)
gcc -S hello.i -o hello.s
# 汇编(生成目标文件 hello.o)
gcc -c hello.s -o hello.o
# 链接
gcc hello.o -o hello
# 执行
./hello关于程序员 可见寄存器 和 不可见寄存器 的 总结;
程序在计算机中运行的 过程;
指令集体系结构(ISA)
定位:ISA 是软件与硬件的接口(分界面),即机器语言程序员能看到的计算机抽象属性。上层软件只依赖 ISA,不关心硬件如何实现。
ISA 规定的内容(列举题常考):
| 规定对象 | 内容 |
|---|---|
| 指令系统 | 指令格式(操作码 / 地址码)、指令类型、寻址方式 |
| 寄存器组 | 程序员可见寄存器(通用寄存器、PC、PSW) |
| 存储组织 | 编址单位、寻址空间、数据存放方式(大端 / 小端) |
| 特权与异常 | 特权指令的划分、中断 / 异常处理机制 |
| I/O 结构 | I/O 端口编址及与 CPU 的数据传送方式 |
ISA ≠ 具体实现
ISA 只定义「能做什么」(规范),数据通路、硬布线 / 微程序、流水线这些「怎么实现」属于微体系结构,对软件透明。
同一 ISA 可有多种实现:x86(CISC)各代 CPU 指令集兼容,内部微结构却完全不同。
与其他笔记的关联
- 可见 / 不可见寄存器(本笔记第三章):分界正是 ISA 划定的,MAR、MDR、IR 属实现层,不可见。
- 特权指令 / 用户态内核态(OS 第一章):特权级是 CPU 硬件提供的机制,OS 只是使用者;系统调用的 trap(访管)指令在用户态执行、陷入内核态。
- RISC / CISC(4. 指令系统):两种 ISA 设计哲学——定长 / 变长指令、Load-Store / 多寻址模式;对应本笔记 2009 真题的硬布线 / 微程序之别。
一、数据的表示与运算
本章框架
四种编码(原 / 反 / 补 / 移)→ 移位与符号扩展 → 定点数加减、ALU 电路、标志位、溢出判别 → 浮点数与 IEEE 754 → C 语言类型转换 → 真题。
主线一句话:计算机里所有带符号数都是补码;IEEE 754 浮点数则是尾数原码、阶码移码。
机器数与真值
真值是真正想表达的那个数,机器数是它在机器里的二进制存储形式。同一个真值用不同编码(原 / 反 / 补 / 移)写出的机器数不同;反过来,同一个机器数按不同编码翻译,真值也可能不同。
编码的对象
原码、反码、补码、移码只适用于带符号数。无符号数直接转二进制即可,没有符号位,也没有原反补移的概念。看到无符号数,立刻抛开这四种编码的思维。
四种编码
原码
符号位 不参与运算:0 直接翻译成正号,1 翻译成负号,数值部分单独转二进制。
- 求原码:真值数值部分转二进制,符号写成 0 / 1。
- 原码求真值:最高位直接翻译成 ±,后面数值位转十进制。
表示范围( 位机器字长):
零有两种表示
,。
因为原码的符号位只表示正负、不属于数值部分,符号位和数值位相互独立,所以 和 能各写出一种编码。
反码
正数: 反码 = 原码;
负数: 反码 = 原码符号位不变、数值位全部取反。
反码只是原码 → 补码的媒介(取反后再加 1 就是补码),计组里几乎不单独考。唯一外延:计算机网络 UDP 校验和用到二进制反码加法。
补码(核心)
补码的地位
计算机里所有带符号数都以补码形式存储和运算。只要看到一个带符号数的机器数(如 ),求真值一律按补码翻译。无符号数则直接二进制转十进制,与补码无关。
补码求真值(CSAPP 法,最快):最高位权值 带负号,其余位权值带正号,求和。
真值 → 补码机器数怎么写
好凑权值时直接凑:,对应位写 1 → 。
不好凑时先写原码再转:如 ,先写 的原码,再「符号位不变、数值位取反末位加 1」得补码。
原则:视真值随机应变,哪种快用哪种。
表示范围( 位):
为什么补码比原码多表示一个数
两者最大值相同,但补码最小值能到 ,原码只能到 。
关键:编码 在原码里被拿去表示 (符号位不参与运算),而补码符号位参与运算, 的真值就是 。
所以原码永远表示不出 ,补码可以——这是大题在最小值处常挖的坑。
正数:原码 = 补码;只有负数两者才有差别。
移码
定义:在真值基础上整体加一个偏置值,把表示范围平移到全为正。常用于浮点数阶码。
注: 所谓 移码公式 无非就是 通过 真值转二进制 或是 二进制转真值
- 移码范围:,全部大于 0,可当无符号数看待。
- 移码真值范围:与补码一致,。
移码求真值,两种方法:
-
定义式:把移码当无符号数转成十进制,再减偏置值。(4 位)
-
转补码:移码符号位翻转即得补码,再按补码求真值。。
「移码当无符号数」的真正含义
无符号数翻译出来的是移码本身的十进制值,不是真值!还要再减偏置值才是真值。很多同学漏掉这一步。
编码相互转换
| 转换 | 规则 |
|---|---|
| 原码 ↔ 补码 | 正数相同;负数符号位不变,数值位取反再加 1 |
| 补码 ↔ 移码 | 符号位翻转(不论正负) |
| 原码 ↔ 反码 | 正数相同;负数符号位不变,数值位取反 |
| 反码 → 补码 | 末位加 1 |
范围速记
原码 ,补码 ,无符号 。
补码比原码多一个 ,移码把补码整体平移成全正。
真题

根据编码特征,将表示范围相加 看是否等于 对应位数可表示个数(排除)
移位运算
先打破一个错误观念
移位由硬件完成,所有位都跟着移动,不存在「符号位保持不变」的移位。
算术移位针对有符号数(补码),逻辑移位针对无符号数;只有右移才区分这两种,左移规则统一。
本质:左移 = ,右移 = 。题目问移位后真值,可直接拿移位前真值乘除 2。
| 方向 | 规则 | 溢出 |
|---|---|---|
| 左移 | 高位丢弃,低位补 0 | 可能溢出,判据:移位前后符号位是否改变 |
| 逻辑右移 | 高位补 0(无符号数) | 不溢出 |
| 算术右移 | 高位补符号位(补码) | 不溢出(符号位永不变) |
两点提醒
移位法则面向补码和无符号数。若真考了别的码移位,最保险是先转补码移完再转回;或用真值乘除 2 后再转回该码。
敏感度:看到 ()立刻反应为右移 5 位,看到 反应为左移 5 位,不要把真值写成小数。
符号扩展
| 类型 | 对象 | 规则 |
|---|---|---|
| 零扩展 | 无符号数 | 整数在**高位(左)补 0;小数在低位(右)**补 0 |
| 符号扩展 | 带符号数 | 高位补符号位 |
补码化简技巧(超好用)
补码高位连续的 1 可视为符号扩展,求真值时只保留一个符号位 + 有效数值位,其余 1 全删。
。
配合「最高位权值带负号」法,补码转真值会非常快。
真题

short 先符号扩展 到 32 位,再赋值给 unsigned int , 最后用无符号数解释
这里 隐藏的坑 是 short int 转 unsigned int 时做的是 符号扩展,导致 无符号数 计算数值大小时少算了前面的 1
定点数加减法与运算电路
对象都是补码。加法直接算;最高位多进出的那一位直接丢弃,不能用它判断溢出(溢出有专门方法判别)
减法转加法:
的法则:y 的补码(含符号位)取反,末位加 1
真题

ALU 电路如何实现减法
核心控制信号 (subtraction 缩写):
| 多路选择器 | 低位进位 | 实际运算 | |
|---|---|---|---|
| 0(加法) | 选通 | 0 | |
| 1(减法) | 选通 | 1 |
即:取反部件把 取反, 时多路选择器选通 ,同时 作为低位进位送入加法器,合起来正好实现「取反加 1」。加法器本身只会做加法,减法靠这套电路转换而来。

标志位(存于 PSW / FR)
| 标志 | 全称 | 适用 | 含义与算法 |
|---|---|---|---|
| SF | Sign Flag | 带符号 | 结果符号,( 为输出结果) |
| OF | Overflow Flag | 带符号 | 溢出,(最高位进位 ⊕ 次高位进位) |
| CF | Carry Flag | 无符号 | 进位 / 借位, |
| ZF | Zero Flag | 都有效 | 结果为 0 时置 1 |
OF 验证
(4 位补码):,但 4 位补码最大只能表示 ,必溢出。
算进位:最高位进位 ,次高位进位 ,,确实溢出。
无符号数表示范围
位无符号数:(如 4 位为 )。CF 判的就是它有没有超出这个范围。
溢出判别
带符号
前提
最高位进位直接丢弃,不能用「高位有没有进位」判断溢出。下面四种方法才行。
方法一 · 看符号:只有这两类才可能溢出(减法可化归为加法):
方法二 · 进位异或:
方法三 · 逻辑表达式( 为操作数符号, 为结果符号, 溢出):
推导:
「同时发生」用与(乘)、「两种之一」用或(加),再对含 0 的项取反使溢出时结果为 1
方法四 · 双符号位(模 4 补码,了解即可):设两个符号位,高位代表真正符号。
| 符号位 | 含义 |
|---|---|
| 00 | 正数,无溢出 |
| 11 | 负数,无溢出 |
| 01 | 正溢出 |
| 10 | 负溢出 |
复习提醒
双符号位只为直观判溢出,不会和移位、符号扩展等混考。不要自己把不相干的知识点硬凑成难题,真题从不这么出。
无符号
进/借位
移位
真题
如何判断左移是否溢出,实际上只要看 移出符号位和当前符号位 是否相同
- 相同:溢出
- 不同:没溢出
由此还能讨论 右移出现的 问题: 如果移出的是 1,说明数值发生精度缺失
浮点数基础
格式(类比科学计数法):
符号、 尾数、 基数(一般为 2)、 阶码。阶码 调整小数点位置
浮点数的符号其实就是尾数的符号
浮点 ≠ 小数
浮点数也包括整数。「浮 / 定」指运算中小数点位置是否浮动:定点数小数点固定,浮点数靠阶码浮动。
规格化(一般浮点数,非 IEEE 754)
意义:让非零浮点数在尾数最高数位上保持一个有效值,从而扩大可表示范围。
| 尾数编码 | 正数规格化 | 负数规格化 |
|---|---|---|
| 原码(常考) | (表示 ) | |
| 补码 |
为什么原码负数是 1.1、补码负数是 1.0
原码符号位不参与运算,最高位的 1 只是负号不是数值,所以 真值是 ,别误读成数字 。
补码符号位参与运算, 真值绝对值()比 ()更大,能表示的范围更广。
左规 / 右规:
- 左规:尾数左移一位、阶码减 1,直到最高数位为有效值。可能要进行多次(如 需左移 3 位)。
- 右规:尾数右移一位、阶码加 1,当有效位跑到小数点前时进行。一般只需一次。
IEEE 754(重中之重)
学 754 前先清空
754 的规格化、隐藏位、偏置值都和「一般浮点数」不同,把前面的左规右规原则先放一边。754 固定:尾数用原码,阶码用移码。
格式
| 类型 | 符号 S | 阶码 E | 尾数 M | 总位数 | |
|---|---|---|---|---|---|
| float | 1 | 8 | 23 | 32 | |
| double | 1 | 11 | 52 | 64 |
规则设置
-
偏置值特殊:754 的移码偏置值在 基础上 再减 1。float:;double:。
-
隐藏位:尾数虽存 23 / 52 位,但规格化要求小数点前恒为 1,这 1 位 不存入机器数。所以实际尾数精度 float 为 24 位、double 为 53 位。
-
求真值时:先把符号位翻译成 ±,再在小数点前 补上隐藏的 1。
真值公式
特殊值(阶码全 0 / 全 1 被保留)

普通规格化数的阶码(按无符号数翻译的移码值):float 为 ,double 为 (0 和全 1 留作特殊用途)。
编码数量不变,变的是编码的范围(上移了),即 精度损失
非规格化数(冷门易考)
只要阶码全 0、尾数任意,真值不再用上面的公式,而采用 非规格化公式:
float:;double:。
注意小数点前是 0 不是 1,指数固定为 / 。这个公式要单独记。
为什么把尾数的隐藏位 1 取消了?
如果说 阶码、尾数 全零 拿来表示 0 并且 规划数的公式是:
那么 就不能被表示了,同理使用 非规格化公式 也无法得到 最小正值
浮点数运算细节
舍入(对阶 / 规格化右移时可能移出有效位)
| 策略 | 做法 |
|---|---|
| 0 舍 1 入(最常用) | 被移出位的最高数位为 0 则舍去,为 1 则尾数末位加 1 |
| 向 | 取右边最近可表示数 |
| 向 | 取左边最近可表示数 |
| 向 0 | 直接丢弃移出位 |
连锁反应
舍入若使末位加 1,可能再次触发右规。考试有时不说明舍入策略却偷偷进位,遇到对不上时往「末位加 1」方向想。
溢出判断
-
尾数溢出不一定真溢出,可通过规格化调整;调整中若导致阶码溢出,才是真正溢出。
-
判浮点数溢出,看的是阶码。
-
上溢:报错;下溢:当作 0 处理,机器不报错。
C 语言强制类型转换
| 转换 | 溢出 | 精度 | 说明 |
|---|---|---|---|
| int → float | 不溢出 | 可能损失 | float 范围更大但尾数仅 24 位 < int 的 32 位 |
| int → double | 不溢出 | 无损失 | double 尾数 53 位 > 32 位 |
| float → double | 不溢出 | 无损失 | 范围、精度都更大 |
| double → float | 可能溢出 | 可能损失 | 范围变小、尾数变少 |
| float / double → int | 可能溢出 | 丢小数 | 小数向零截断;超 int 范围则溢出 |
一句话记忆
小范围转大范围安全;大范围转小范围(double→float、浮点→int)既可能溢出又可能丢精度。int→float 个数相同(都 种)但范围不同,故不溢出却可能舍入。
真题精选
2010 · 补码乘法溢出
8 位补码寄存器,化简求真值:
8 位补码范围 。 乘选项中任何一个负数,结果(正数)必超过 127,凡含 的乘法必溢出。答案 B。
2021 · 无符号 vs 带符号比大小
三个 16 位机器数 ,,。
- 无符号:高位 1 越多越大。 高 4 位全 1, 最高位为 0 最小; 比 更晚出现 0,故 。
- 带符号(补码): 符号位 0 为正,最大;化简求真值 ,,故 。
答案 D。
活用
求真值时先用符号扩展化简高位连续的 1;不好凑权值就转原码再求(如 转原码得 比硬凑快)。方法要随机应变。
2022 · 标志位逻辑表达式
ALU 输入 、输出 均为 16 位,已知 ,FR 即 PSW。
- (符号就是结果最高位)。
- 题目只给了符号位、没给次高位进位,所以 不能用 ,要改用逻辑表达式:
出题特点
408 大题常把学过的知识点藏得很深。看到 别只想到进位异或那一种,要联想到逻辑表达式——前提是把知识架构盘熟,看到条件就能反应出考点。
2011 · 真值 → IEEE 754(float)
把 转成 float 机器数:
-
转二进制:,,故
-
规格化:(小数点左移 3 位 = 尾数右移 3 位 = 阶码加 3)
-
对位:;; 后补 0 至 23 位(隐藏的 1 不存)
-
拼机器数:,每 4 位转 16 进制得
答案 A。
通用流程
遇到这类题:
先把「机器数格式(1 / 8 / 23)」和「真值格式 」两个架子写出来,
把真值整理成对应形状,逐位代入 即可。切记小数点前的 1 不存入机器数。
二、存储系统
主存
地址引脚数

真题
MAR 位数 是理论主存地址空间最大地址引脚,实际芯片多大与其无关
RAM 只有 32MB,剩下的空间是 ROM ,MAR 对应的是 ROM 还是 RAM
字位扩展

字扩展实现原理
字扩展的实现是基于cpu地址总线有多余引脚 因此 可以通过译码器选片
复用的原先 低位地址线,不是将多余引脚直接当作地址线连接扩展片 对应 高位顺序存储器 低位地址 做块内地址,高位地址 做片选地址
同 位扩展 —— 低位交叉存储器 进行区分


真题
注意本题的最大地址位是13位()
位扩展后的两片芯片 可以直接看成一个 拼好的大芯片
因为位扩展是数据线并联、地址线共用,两片同时被选中、同时工作,对外表现就是一个字长更宽的单一芯片。
所以做字扩展分组的时候,直接把每组的两片当成一个2Kx8的整体来算地址范围就行,不需要再考虑组内两片的区分。

重点在 对 RAM 芯片分别进行了什么扩展
把 RAM的 15 组误认为 15片 先做位扩展时,每组需要 2 片 4K × 4 位芯片,因此总片数必须再乘2.
忽略 ROM与 RAM的扩展方式不同 ROM 的位宽已满足要求,只做字扩展;RAM 的位宽不足,必须先位扩展至 8 位,再字扩展。
低位交叉编址
- 存储单元大小:8 位(1 字节),是编址单位。
- 存储字长:存储体一次读写的位数(如 32 位)。
低位交叉编址把连续字节分布到不同存储体(用地址低位选体),总线一次可并行读写多个存储体,从而提高带宽。
数据传输流程:
-
存储体将 32 位输出到内部数据总线。
-
内存控制器通过字节选择信号,只把所需的 1 字节放到系统总线。
-
多个存储体轮流放置,系统总线上每次只有 1 字节,形成连续流。
关键点
存储体输出的 32 位放在内部总线,不是直接上系统总线;系统总线可能只有 8 位,每次传 1 字节。靠流水线每个时钟周期传 1 字节,提高带宽。
2017 年第 6 题(交叉编址)
题目:某计算机主存按字节编址,由 4 个 64M×8 位的 DRAM 芯片采用交叉编址方式构成,并与宽度为 32 位的存储器总线相连,主存每次最多读写 32 位数据。若 double 型变量 x 的主存地址为 ,则读取 x 需要的存储周期数是()。
A. 1 B. 2 C. 3 D. 4
分析:
- 4 个芯片低位交叉编址,连续字节分布于不同存储体(低 2 位选体)。
- 总线宽 32 位(4 字节),一次可并行读取 4 个不同存储体的字节。
- double 占 8 字节,地址 低 2 位为 2,连续 8 字节低 2 位依次为 。
- 前 4 字节()一批、后 4 字节()一批,共需 2 个存储周期。
答案:B
易错点
非对齐地址容易误判为 3 次。实际上低位交叉编址下,只要连续字节覆盖所有存储体即可并行读取。
存取周期与存取时间
- 存取时间:完成一次读 / 写操作所需的时间。
- 存取周期:连续两次启动同一存储体进行访问的最小时间间隔。
- 关系:存取周期 = 存取时间 + 恢复时间,所以存取周期 > 存取时间。
2013 年真题
关键算式:
其中 为总线(传输)周期, 为存取周期, 为 8 个总线周期。
易错:存取周期包含恢复时间,必须保证 ,才能保证两次启动同一体的时间间隔不小于其存取周期。虽然过了存取时间就能传数据,但等满一个存取周期再传,模型更简单。
突发传送
本质:一次地址传输后,连续传输多个数据单元,无需为每个数据单元单独发出地址和握手信号。
核心特质:
| 特性 | 说明 |
|---|---|
| 地址只发一次 | 主设备在突发传输开始时只发送一次起始地址,后续数据按地址自动递增读取 |
| 连续传输 | 多个数据单元(字节/字)在一个总线事务中连续传输,中间不释放总线 |
| 无需握手 | 每个数据单元不需要独立的请求/应答握手,大幅减少协议开销 |
工作流程:

优势:
- 总线利用率高:地址阶段只占一次,后续全是数据传输,减少空闲等待
- 延迟低:省去每个数据单元的地址发送和握手时间
- 适合 Cache 行填充:Cache 一次从主存装入一整行(如 32 字节),正好用突发传输
典型应用场景:
- Cache 与主存之间的一次行交换(最常见)
- DMA 连续数据块传输
- PCIe 总线事务
与低位交叉存储器的关系
突发传送和低位交叉编址是两个不同层面的概念,但它们经常配合使用:
- 突发传送是总线传输协议层面的概念:一次地址发多个数据
- 低位交叉是存储体组织层面的概念:连续地址分散到不同存储体
真题中,低位交叉存储器用流水线方式轮流启动各存储体,数据在总线上的传输就是突发方式——先发一个起始地址,然后连续送出多个存储体的数据,无需每个存储体都重新发地址。
BOK 解题技巧:

多体存储器识别与判断
题目中识别多体存储器的关键信号:
| 题目表述 | 对应考点 | 判断动作 |
|---|---|---|
| ” 个 位的芯片交叉编址” | 低位交叉编址 | 立刻反应:低 位选体,可并行启动 |
| ”存储器总线宽度为 位” | 一次传输的数据量 | 算 字节,即一轮最多同时读几个体 |
| ”按字节编址” + 个存储体 | 体号 = 地址低 位 | 算连续地址跨多少个体,判断是否需要多轮 |
| ”存取周期为 ,总线周期为 “ | 流水线启动时间 | 第一轮 ,后续每隔 启动新一轮 |
| ”连续读取 个存储单元” | 算出所需存储周期数 | 看 个地址是否跨轮(跨轮则需 的倍数) |
高位 vs 低位交叉编址识别:
| 编址方式 | 题目特征 | 能否并行 |
|---|---|---|
| 高位交叉 | 地址高位选体、低位为体内偏移;多用”连续编址”、“顺序编址”表述 | 不能 |
| 低位交叉 | 地址低位选体、高位为体内偏移;多用”交叉编址”、“多体交叉”表述 | 能 |
判断步骤(做题时按顺序过):
- 读题,找”交叉编址”/“多体”/” 个芯片”等关键词
- 确定是高位还是低位交叉(低位交叉才考并行)
- 算 得到体号位数,确定地址中哪几位是体号
- 用给定地址的低 位作为起始体号
- 连续 个地址覆盖多个体:每 个为一轮,看需要几轮
- 每轮耗时 = 一个存取周期(实际上第一轮 ,后续每轮 )
轮数判断速算
假设 个体,起始体号为 ,连续读取 个单元:
第一轮能读 个(从当前体到末尾体),剩余 个需要 轮。
总轮数 = 。
Cache
平均访问时间
- :命中率
- :Cache 访问时间
- :主存访问时间
推导:
原始形式:
展开得:
关键理解
必花,缺失时额外花 。 是缺失率不是命中率;缺失代价是 ,不是 。考试常问「命中率提升到多少时平均访问时间降到某值」,列方程求解即可。
典型例题
若 ,,要求平均访问时间 ,求最小命中率 。
命中率至少 90%。
cache 位数计算
块内地址位数:
注意编址编的是 存储单元 的地址,而非存储字节。
LRU 替换算法位数:。
命中率:
数组访问次数的坑
对下面这类程序:
数组访问次数 = 数组大小 × 2(一读一写)。


这里的 总容量位数 包含了 标记阵列 和 数据阵列 两个部分的位数
少算了一个 有效位
cache 行因为上电初始化 产生 垃圾数据
因此需要一个 有效位 搭配,表示是否是从主存中装入的数据
局部性原理
- 时间局部性:一个数据项被访问后,不久的将来很可能再次被访问。例:循环中多次读写同一变量(
sum += a[i]中的sum)。 - 空间局部性:一个数据项被访问后,地址相邻的数据项很可能很快被访问。例:顺序访问数组元素。
易错点
数组声明
int a[24][64];只是分配空间,不是访问元素。初始化循环中每个元素只被访问一次,只有空间局部性,没有时间局部性。
虚拟存储与 TLB
虚拟存储
- 每个进程都认为自己占据了整个虚拟空间。
- 同一进程不同虚页间连续的虚拟地址,指向的物理地址 不连续。
- 虚拟存储的核心是 离散分配主存空间。
- 用户能见到的地址都是虚拟地址;物理地址是要被保护的。
TLB 查找逻辑
查找流程:
-
先比较 tag 位。
-
再查看有效位。
-
有效位 = 0 时,去页表中查找。
易错点
TLB 中有表项、tag 比对通过,但有效位 = 0 时,应去页表查找,而不是直接判缺页异常。
概念速查
| 概念 | 说明 |
|---|---|
| 虚拟地址 | 用户程序使用的地址 |
| 物理地址 | 实际内存地址 |
| 有效位 | 标识 TLB / Cache 行是否有效 |
| 缺页异常 | 虚拟页面不在物理内存中 |
三、中央处理器(数据通路与控制器)
本章框架
CPU = 数据通路(执行部件)+ 控制器(控制部件)。数据通路中数据流经 ALU、寄存器、多路选择器等;控制器解码指令、生成控制信号、驱动数据通路。
主线:控制器接收机器指令 → 译码 → 每个时钟周期发出微命令 → 驱动数据通路完成微操作 → 更新 PC 取下一条指令。

数据流过的都算数据通路
CPU 组成
CPU 从功能上分为运算器和控制器,但更完善的分类将其分为数据通路和控制器两部分:
| 分类 | 包含部件 | 角色 |
|---|---|---|
| 数据通路 | ALU、寄存器组、多路选择器、内总线 | 指令的执行部件 |
| 控制器 | 指令译码器、时序控制单元、控制信号发生器 | 指令的控制部件 |
数据通路
元件分类
| 类型 | 特点 | 典型元件 |
|---|---|---|
| 组合逻辑元件 | 输出仅取决于当前输入,无状态存储,信号单向传输 | ALU、译码器、多路选择器、三态门 |
| 时序逻辑元件 | 输出与历史输入有关,具备状态存储,须在时钟节拍下工作 | 各类寄存器(PC、IR、MAR、MDR、通用寄存器等) |
时钟线 vs 数据线
时钟线控制何时锁存,数据线(总线)传输什么数据,两者不要混。时钟触发边沿到来时,锁存器把输入端电平状态存下来。
组合逻辑元件
| 元件 | 功能 | 控制信号 |
|---|---|---|
| ALU | 算术逻辑运算 | ALUop(选择运算类型) |
| 译码器 | n 位输入 → 种输出,每次只有一个被使能 | — |
| 多路选择器 | 多输入选一输出 | Select |
| 三态门 | 控制信号线通断 | EN(1 导通,0 高阻态断开) |
寄存器分类(8086)
| 类别 | 寄存器 | 说明 |
|---|---|---|
| 通用寄存器 | AX/BX/CX/DX | 运算、地址、计数、I/O |
| 段寄存器 | CS/DS/ES/SS | 指向各段起始地址 |
| 变址寄存器 | SI/DI | 数组/字符串操作 |
| 指针寄存器 | SP/BP/IP | 栈指针、基址、指令指针 |
| 标志寄存器 | FLAGS | 条件标志(OF/CF/SF/ZF)+ 控制标志(IF/TF/DF) |
| 不可见寄存器 | MAR/MDR/IR | 汇编程序员不可直接控制 |
可见 vs 不可见
汇编程序员可见:通用寄存器、段寄存器、FLAGS、IP。
不可见:MAR、MDR、IR——不能通过指令直接操作。
暂存器 T 的作用
ALU 需两个操作数,但内部数据总线同一时刻只传一个。流程:先取第一个操作数存入 T → 再取第二个 → 两者一起送入 ALU 运算。
控制器
主要功能与工作原理
| 功能 | 说明 |
|---|---|
| 指令解码 | 取出指令后译码,确定操作类型和操作数 |
| 生成控制信号 | 根据译码结果生成控制信号驱动各部件 |
| 时序控制 | 按时间顺序发出控制信号,确保逻辑正确 |
工作流程:取指令 → 分析指令(译码)→ 执行指令(发控制信号)→ 转向下条指令(更新 PC)
译码阶段确定的是什么
译码阶段确定的是形式地址(A),不是有效地址(EA)。
EA 需要在 执行阶段 用 成(间接寻址、基址寻址等需要计算 EA)。
组成
| 组件 | 功能 |
|---|---|
| 指令控制器 | 从 CS:IP 获取指令地址,取指放入 IR,修改 IP 指向下一条 |
| 时序控制器 | 产生时序信号,控制指令执行节奏 |
| 控制信号发生器 | 接收译码结果,每时钟周期产生控制信号 |
时序系统
-
指令周期:一条指令从取出到执行完成的全部时间。
-
CPU 周期:指令执行中的一个阶段(取指、执行等),通常等于一次访存时间。
-
时钟周期:最基本节拍,由晶体振荡器决定。
机器周期 = 取指周期的条件
当指令字长 = 存储字长时,机器周期 = 取指周期。
控制信号类型
| 类型 | 示例 | 说明 |
|---|---|---|
| 内存读写 | MemR / MemW | 控制内存或 I/O 读写 |
| 寄存器选择 | Rin / Rout | 选择特定寄存器读写 |
| ALU 操作码 | ALUop = Add | 选择 ALU 运算类型 |
寄存器传送语言(RTL)
常见符号
| 符号 | 含义 |
|---|---|
R1, R2, ... | 通用寄存器 |
PC | 程序计数器 |
IR | 指令寄存器 |
MAR | 内存地址寄存器 |
MDR | 内存数据寄存器 |
M[x] | 内存中地址为 x 的数据单元 |
← | 数据从右到左传送 |
,(逗号) | 并行操作(同一时钟周期) |
if | 条件执行 |
语法结构
赋值(← 右源左目标):
R1 ← R2 + R3 ; R2 + R3 送入 R1
并行操作(逗号分隔,同一时钟周期):
PC ← PC + 4, MAR ← PC
顺序操作(多行,每行一个时钟周期):
MAR ← PC
MDR ← M(MAR)
IR ← MDR
存储器访问:
; 读存储器
MAR ← PC
MDR ← M(MAR)
; 写存储器
MAR ← R1, MDR ← R2
M(MAR) ← MDR
RTL 源寄存器的 () 写法
有的 RTL 中源寄存器用
()包围:R2 ← (R1),与R2 ← R1含义相同。以题目给定条件为准。
指令的控制信号
以 ADD R0, (R1) 为例(R1 间接寻址,取内存数据与 R0 相加,结果存 R0)。
取指和译码阶段(所有指令相同)
| 时钟 | RTL | 控制信号 |
|---|---|---|
| C1 | MAR ← PC | PCout, MARin |
| C2 | MDR ← M(MAR) | MemR, MDRin |
| C3 | IR ← MDR | MDRout, IRin |
| C4 | PC ← PC + 1 | PCin(增量器) |
取指阶段对所有指令相同
取指只是”从 PC 地址读指令送入 IR 并更新 PC”,与指令类型无关,控制信号统一。
执行、访存和写回阶段(因指令而异)
| 时钟 | RTL | 控制信号 |
|---|---|---|
| C5 | MAR ← R1 | R1out, MARin |
| C6 | MDR ← M(MAR) | MemR, MDRin |
| C7 | T1 ← R0 | R0out, T1in |
| C8 | T2 ← MDR + T1 | MDRout, Add, T2in |
| C9 | R0 ← T2 | T2out, R0in |
控制器种类
根据控制信号生成方式的不同,控制器分为硬布线控制器和微程序控制器。
| 对比项 | 硬布线控制器 | 微程序控制器 |
|---|---|---|
| 实现方式 | 逻辑门电路硬件布线 | CM 中存储微指令 |
| 速度 | 快 | 慢(需访 CM) |
| 灵活性 | 差(改逻辑需改硬件) | 好(改微指令即可) |
| 设计难度 | 复杂 | 相对简单 |
| 本质 | 有限状态机(FSM) | 用”程序”控制”程序” |
| 适用场景 | RISC | CISC |
硬布线控制器
-
输入:指令译码信号 + 时序信号 + 状态反馈(标志位)
-
核心:组合逻辑门网络(固定布线)
-
输出:微操作控制信号
-
特点:高速但固定,修改需改物理电路
微程序控制器
核心思想:每条机器指令 → 分解为微操作序列 → 对应一段微程序(多条微指令)。
结构:
| 组件 | 功能 |
|---|---|
| IR | 存放当前机器指令 |
| 起始和转移地址形成部件 | 根据操作码生成微程序起始地址,计算下一条微指令地址 |
| µPC(微程序计数器) | 存放当前微指令地址 |
| CM(控制存储器) | 存储所有微指令序列 |
| µIR(微指令寄存器) | 存放当前执行的微指令 |
微程序控制器受哪些寄存器支持
题目问”微程序控制器受哪些寄存器 support 或辅助”→ 答 IR 和 PSW。
IR 提供操作码确定微程序入口;PSW 提供状态标志决定转移方向。
微指令结构:微命令字段(控制各部件微操作) + 下地址字段(指示下一条微指令地址)。
工作流程:
-
机器指令操作码译码 → 微程序起始地址
-
µPC 从 CM 取微指令送入 µIR
-
µIR 微命令字段直接控制 CPU 各部件
-
根据下地址字段计算下一条微指令地址 → 送回 µPC
-
重复直到完成该机器指令所有微操作
微指令编码方式
| 方式 | 原理 | 特点 |
|---|---|---|
| 直接编码(水平) | 每一位直接对应一个微命令,无需译码 | 高并行、高速、微指令长 |
| 字段直接编码(垂直) | 互斥微命令分组编码,经译码器激活 | 微指令短、并行受限、稍慢 |
| 混合编码 | 部分直接 + 部分字段编码 | 兼顾并行度与长度 |
互斥 vs 相容
互斥微命令:同一时刻只能激活一个 → 放同一字段内编码。
相容微命令:可同时激活 → 放不同字段或用直接编码。
指令、微指令、微命令的层次
-
指令:程序员可见的最小功能单位
-
微指令:CM 中的一个字,对应一个时钟周期的一组微命令
-
微命令:最基本的、不可再分的硬件操作
一句话记忆
一条指令对应一段微程序,微程序包含多条微指令,每条微指令发出一组微命令,微命令直接控制硬件。
练习精选
练习 · 写出 SUB 指令的 RTL 和控制信号
给定指令 SUB R1, (R2)(R2 间接寻址,取内存数据与 R1 相减,结果存 R1),写出取指和执行阶段的 RTL 及控制信号。
参考答案
取指阶段与所有指令相同(C1–C4),执行阶段如下:
时钟 RTL 控制信号 C5 MAR ← R2 R2out, MARin C6 MDR ← M(MAR) MemR, MDRin C7 T1 ← R1 R1out, T1in C8 T2 ← T1 − MDR MDRout, Sub, T2in C9 R1 ← T2 T2out, R1in
对照要点
与
ADD R0, (R1)相比,操作数寄存器从 R0/R1 换成 R1/R2,运算从 Add 换成 Sub,其余结构完全一致。考试中遇到任何OP Rd, (Rs)格式的指令,都能套这套模板。
练习 · 控制器辨析
下列关于硬布线控制器和微程序控制器的说法,正确的是()。
A. 硬布线控制器的速度比微程序控制器慢
B. 微程序控制器的控制逻辑存储在 CM 中,修改方便
C. 硬布线控制器的修改只需更新微指令
D. 微程序控制器更适合 RISC 架构
答案:B
关键区别
硬布线 = 硬件电路固定 → 快但难改;微程序 = 存储器存微指令 → 慢但灵活。RISC 指令简单、追求速度,偏向硬布线;CISC 指令复杂、需要灵活性,偏向微程序。
练习 · 微指令编码位数计算
某微指令的微命令字段需控制 5 个互斥微命令和 3 个独立微命令。采用字段直接编码方式,互斥微命令分一组编码,独立微命令各占一位,该微指令的微命令字段至少需要多少位?
分析:
-
5 个互斥微命令分一组,需 位(加 1 是因为要留一个编码表示”无操作”)
-
3 个独立微命令各占 1 位,共 3 位
答案:6 位
易错点
互斥微命令分组编码时,必须预留一个编码值表示”该组无微命令被激活”(通常用全 0)。5 个互斥微命令需要 种编码(5 个命令 + 1 个无操作 + 2 个空余),所以是 3 位而非 位——虽然结果相同,但思路要正确。
2016 · 单周期处理器
题目:单周期处理器中所有指令的指令周期为一个时钟周期。下列关于单周期处理器的叙述中,错误的是( )。
A. 可以采用单总线结构数据通路
B. 处理器时钟频率较低
C. 在指令执行过程中控制信号不变
D. 每条指令的 CPI 为 1
答案:A
核心考点:单周期处理器的核心约束不是”结构简单”,而是”所有必要操作必须在一个时钟周期内完成”。
C:单周期处理器中一条指令只经历一个时钟周期,该周期内控制信号保持稳定,不像多周期处理器分时变化。
单总线 vs 单周期
单总线结构一次只能传送一路数据,而单周期处理器要求同一条指令的取指、译码、执行、访存、写回都在一个周期内完成。
以加法指令 为例,两个源操作数必须在同一周期内送入 ALU,但单总线无法同时传送两个操作数,只能分步完成,与单周期”一个周期完成一条指令”矛盾。
易错点
不要把”单周期”理解成”结构简单,什么数据通路都能用”。单总线最大的限制是并发能力差——凡是题目涉及同一周期内多个数据传送需求时,都要警惕单总线是否会成为瓶颈。
中断与异常(内中断 vs 外中断)
核心对比:
| 特性 | 外部中断(Interrupt) | 内部异常(Exception) |
|---|---|---|
| 来源 | CPU 外部(I/O 设备、时钟等) | CPU 内部(指令执行引发) |
| 与当前指令的关系 | 无关 | 直接相关 |
| 同步/异步 | 异步(不可预知时间) | 同步(执行某指令必发生) |
| 响应时机 | 当前指令执行完毕后 | 指令执行过程中 |
| 可屏蔽性 | 部分可屏蔽 | 不可屏蔽 |
响应时机是高频考点
外部中断:CPU 在每条指令执行结束后检查中断请求信号(INTR),有则响应。
内部异常:CPU 在执行指令的过程中发现异常(如除零、非法操作码、缺页),立即响应。
记忆方法:异常是”自己人犯错”,边干活边发现;中断是”外人敲门”,干完手上的活再开门。
异常三类及其返回断点:
| 类型 | 含义 | 返回断点 | 例子 |
|---|---|---|---|
| 故障(Fault) | 可修复的错误 | 返回当前指令重新执行 | 缺页异常 |
| 陷阱(Trap) | 有意安排的异常 | 返回下一条指令 | 系统调用、断点调试 |
| 终止(Abort) | 不可恢复的致命错误 | 无法返回,终止程序 | 硬件校验错 |
易错点
“内部异常处理后返回到发生异常的指令继续执行”是错误的。只有 Fault 才返回当前指令,Trap 返回下一条指令,Abort 不能返回。不能把 Fault 的返回方式当成所有异常的共性。
2015 · 内部异常
题目:内部异常(内中断)可分为故障(fault)、陷阱(trap)和终止(abort)三类。下列有关内部异常的叙述中,错误的是( )。
A. 内部异常的产生与当前执行指令相关
B. 内部异常的检测由 CPU 内部逻辑实现
C. 内部异常的响应发生在指令执行过程中
D. 内部异常处理后返回到发生异常的指令继续执行
答案:D
关键理解:
三类异常返回不同
Fault 返回当前指令(修正后重执行),Trap 返回下一条指令,Abort 不返回。D 把所有异常都当成 Fault 处理了,过于绝对。
A 正确:内部异常由当前指令执行引发(除零、非法操作码、缺页等),与外部中断的根本区别之一。
B 正确:异常检测由 CPU 内部控制逻辑、运算逻辑等硬件完成,不是外设发起的。
C 正确:内部异常在指令执行过程中被发现并响应。对比:外部中断是当前指令执行完毕后才检查。
D 错误:见上表。
中断时通用寄存器的保存
硬件自动保存的部分(很少):
以 x86 为例,硬件只自动保存:
- EFLAGS / RFLAGS(状态寄存器)
- CS + EIP / RIP(返回地址)
- 如果涉及特权级切换,还会保存 SS + ESP / RSP
通用寄存器(rax, rbx, rcx 等)硬件不管。
通用寄存器由软件保存:
操作系统在中断处理程序入口手动压栈到内核栈:
; Linux x86-64 中断入口
interrupt_entry:
push rax
push rbx
push rcx
push rdx
push rsi
push rdi
push rbp
push r8 ~ r15
call do_irq ; 执行中断处理
pop r15 ~ r8 ; 返回前恢复
pop rbp
pop rdi
...
pop rax
iretq ; 硬件自动恢复 EFLAGS + CS + RIP内核栈布局:
内核栈(从高到低):
┌─────────────┐
│ SS │ ← 硬件自动压(特权级切换时)
│ RSP │ ← 硬件自动压
│ RFLAGS │ ← 硬件自动压
│ CS │ ← 硬件自动压
│ RIP │ ← 硬件自动压
├─────────────┤
│ RAX │ ← 软件(OS)手动压
│ RBX │
│ ... │
└─────────────┘
一句话总结
硬件只保存返回地址和状态寄存器,通用寄存器由操作系统在中断处理程序开头手动压栈到内核栈,返回前再弹出恢复。这也是中断处理有一定开销的原因之一。
2009 · RISC vs CISC
题目:下列关于 RISC 的叙述中,错误的是( )。
A. RISC 普遍采用微程序控制器
B. RISC 大多数指令在一个时钟周期内完成
C. RISC 的内部通用寄存器数量相对 CISC 多
D. RISC 的指令数、寻址方式和指令格式种类相对 CISC 少
答案:A
核心对比:
| 特性 | RISC | CISC |
|---|---|---|
| 指令条数 | 少 | 多 |
| 寻址方式 | 少 | 多 |
| 指令格式 | 规整、定长 | 不规整、变长 |
| 通用寄存器 | 多 | 少 |
| 控制器 | 硬布线(速度快) | 微程序(灵活) |
| 指令周期 | 多数 单周期 | 多数 多周期 |
| 流水线 | 容易实现 | 较难实现 |
记忆口诀
RISC = 精简 + 快速:指令少、格式规整 → 硬布线控制 → 单周期 → 流水线
CISC = 复杂 + 灵活:指令多、格式不规整 → 微程序控制 → 多周期 → 流水线难
关键理解:
为什么 RISC 用硬布线?
RISC 指令少、格式规整,控制逻辑简单,硬布线可以直接用组合逻辑产生控制信号,速度最快。CISC 指令复杂多变,用硬布线设计难度太大,微程序用”存储逻辑”代替”组合逻辑”,虽然慢但灵活。
A 错误:RISC 普遍采用硬布线控制器,微程序控制更常见于 CISC。
B 正确:RISC 追求简单规整,大多数指令可单周期完成。
C 正确:RISC 只有 Load/Store 指令访存,其余在寄存器间操作,需要大量通用寄存器减少访存。
D 正确:精简指令集的本意就是减少指令数、寻址方式和指令格式。
考点速查
高频考点
- 手写给定指令的 RTL 和各阶段控制信号
- 硬布线 vs 微程序控制器的区别与选择
- 微指令编码方式辨析(互斥 / 相容判断、位数计算)
- 寄存器可见性分类(MAR / MDR / IR 不可见)
- 时序系统三级包含关系(指令周期 ⊃ 机器周期 ⊃ 时钟周期)
- 微程序控制器受 IR 和 PSW 支持
- 译码阶段确定形式地址,EA 在执行阶段用 ALU 计算
