CPU 与指令系统

指令格式、数据通路与控制信号题的固定动作:字段翻成寄存器传送、清点位宽、读结构图、逐拍写信号。

这一支有两种固定形态:

知识框架概要

从一句 C 语句到一串控制信号,中间只有几层固定的翻译。把这几层背成骨架,任何一问都能定位到其中一环。

一、C 语句 → 指令序列只有这几种译法

读代码清单之前先认语法:Intel 格式是 目的, 源dword ptr 一类前缀交代操作数长度,见 操作数长度后缀内存寻址格式

C 结构编译出来的指令模式
赋值、读写局部变量mov,一端是寄存器、另一端是 [ebp − d]数据传送
一维数组 a[i]三条:下标左移 log₂(元素大小) → 加基址 → load/lw 取数变址寻址
二维数组 a[i][j](x86)一条 mov [基址寄存器 + 变址×比例 + 首地址], 源内存寻址格式
x * 2ᵏx / 2ᵏ左移 / 算术右移 k 位移位
if … else …cmp + 反条件跳转到 else,then 段末尾 jmp 跳过 else选择结构语句
while / do-while循环体末尾一条条件跳转构成回边while 语句do-while 语句
for初值 mov +(可能先 jmp 到条件判断)+ 体尾自增 + 条件跳转回边for 语句
条件本身一律 cmp 做减法置标志,再由跳转指令读标志比较条件跳转
函数定义与返回push ebp 是函数第一条、ret 是最后一条,返回值放 eax函数定义和调用
函数调用与传参实参 push 入栈 → call(相对寻址),被调用方从 [ebp + 8] 起取参数子程序调用栈操作

配套的三条口径每年都要用:

  1. 变量住哪:局部变量在 [ebp − d]、参数在 [ebp + 8] 起,栈帧布局见 函数调用时内存结构;也可能全部分配在寄存器里,此时整段代码没有栈帧(2014#442024#44)。
  2. 移位位数和比例因子等于元素大小int 移 2 位、short 移 1 位,2024#44 第 3 问就是把 int 换成 short 改这一位。
  3. 机器码里的多字节字段按端序排,见 大小端;结构体成员和数组元素的地址还受 数据对齐 约束。

指令长度是否等长顺带就是 CISC / RISC 的判据(2017#44),见 不同位数指令

二、指令格式

  1. 指令 = 操作码 ‖ 寻址方式 ‖ 地址码 —— 操作码位数定指令条数上限,见 指令格式
  2. 寻址方式决定「地址码里的数是操作数、是地址、还是相对偏移」,见 寻址方式
  3. 翻译结果永远是一行 读谁 → 算什么 → 写回谁,见 寄存器传送语言

三、执行这一行靠固定的几个部件

  1. 取指部件:PC(下一条地址)、IR(当前指令)
  2. 访存接口:MAR(地址,宽度 = 地址线)、MDR(数据,宽度 = 数据线)
  3. 运算部件:ALU 及其暂存器 —— 单总线结构下一个输入必经暂存器、输出必经结果寄存器
  4. 数据仓库:通用寄存器组 GPRs
  5. 指挥者:CUOp(IR) 逐拍发控制信号

结构见 数据通路

四、指令周期是一条固定的时间轴

取指 → 译码 → 取操作数 → 执行 → 写回 →(有请求则)响应中断

每一拍上只有两类信号:让谁上总线(Xout)让谁被写入(Xin),加上 MemR / MemW / ALUop / 多路选择器的选择端,见 指令的控制信号。五个阶段里,取指、译码、写回的写法是死的,只有取操作数和执行随指令变

阶段RTL 模板有效控制信号
取指MAR ← (PC)
MDR ← M(MAR),PC ← (PC)+1
IR ← (MDR)
PCout, MARin
MemR, MDRinE, PC+1
MDRout, IRin
译码指令译码无,由译码器完成
取操作数只由寻址方式决定,见下表
执行A ← (Rx)(单总线才需要单独占一拍)
AC ← (A) op (Ry)
Rxout, Ain
Ryout, ALUop, ACin
写回寄存器Rz ← (AC)ACout, Rzin
写回主存MDR ← (AC)
M(MAR) ← (MDR)
ACout, MDRin
MDRoutE, MemW

2009#44 的题干直接给出了上表前三行,要求照这个格式续写执行阶段——格式跟着题干抄,不要自创

取操作数这一段只有四种写法:

寻址方式RTL访存次数
立即数操作数就在 IR 里,不必取0
寄存器直接A ← (Ri)0
寄存器间接 (Ri)MAR ← (Ri)MDR ← M(MAR)1
基址 / 变址(带位移)先用 ALU 算有效地址 AC ← (Ri) + 位移,再 MAR ← (AC)MDR ← M(MAR)1
存储器间接上面两拍做两遍:先取出地址,再取出操作数2

三点写法上的约定,比记信号名更要紧:

  1. 暂存器和结果寄存器的名字随题目图变2009#44AAC2015#43T,教材里常写成 YZ。照图上的名字写,见 暂存器
  2. MDR 有两组进出信号:连内总线的是 MDRin / MDRout,连数据总线(DB)那一侧的是 MDRinE / MDRoutE。读主存写 MDRinE、写主存写 MDRoutE,方向弄反是这类题的常见失分点。
  3. 多选器型数据通路不写 Xin / Xout:改成对每个 MUX 回答「这一拍它选哪一路」再写 0/1/2,2026#44 就是逐个信号问这个。

语法与符号见 寄存器传送语言,寻址方式见 寻址方式

五、把这条时间轴切成五段并重叠,就是流水线

IF → ID → EX → MEM → WB,重叠后只多出三类冒险:结构、数据、控制,见 流水线冒险

解题注意点

两种形态各走一路:给了指令格式和数据通路的,按前四条的次序走;给了 C 源码和机器级代码清单的,直接跳到「代码清单题的固定五问」。

先把字段翻成一句寄存器传送

不要先动二进制。先把每个字段翻成自然语言,再压成一行:

读谁 → 算什么 → 写回谁

语法见 寄存器传送语言。这一步先把操作数方向和数据去向定下来,位串是最后一步的事。

数一遍位宽

要求的量由什么决定
指令条数上限操作码位数
通用寄存器个数寄存器编号字段的位数
MAR 位数地址线宽度,不是字长
MDR 位数数据线宽度
主存单元宽度编址单位,按字节编址就是 8 位
多路选择器的控制信号位数⌈log₂(输入路数)⌉

2021#432026#43 就在 MAR / MDR 和「按字节编址推不出寄存器宽度」上设坑。相关指标见 指令格式计算机性能指标

读结构图

  1. 先给 PC、IR、MAR、MDR、ALU、GPRs、暂存器逐个标出输入来自哪、输出去哪
  2. 判断是单总线,还是多路选择器加专用通路;
  3. 单总线:一拍只允许一个部件把数据放上总线,所以 ALU 的一个输入必须先进暂存器,输出也要先落到结果寄存器(两者的名字随题目图变)。2015#432022#43 直接问「为什么要设置暂存器」;
  4. 多选器型:每个 MUX 对应一个控制信号,先回答「这一拍它该选哪一路」,再写 0/1。2024#432026#44 是这类。

结构见 数据通路

节拍与控制信号

阶段表和信号写法在知识框架第四条里,落笔时按三条走:

  1. 一拍写一行,先写功能再写信号。功能用 写成一句寄存器传送,信号从这句话里读出来:数据流入某部件就写 Xin,流出就写 Xout,不要凭记忆背信号名。
  2. 不冲突的动作合并到同一拍。单总线上一拍只允许一个部件把数据放上总线,除此之外互不干扰的两个动作可以写进一行、用逗号隔开——2009#44 的另一种答案就靠 MDR ← M(MAR), A ← (R0) 少用一拍。
  3. 周期数不能套经验值。「取指 3 拍」这种数字不能直接用,一次访存本身可能占多个周期2022#43 给的条件是「从发出主存读命令到数据送到 MDR 共需 5 个时钟周期」,取指阶段因此至少 7 个周期。

代码清单题的固定五问

给了 C 源码和机器级代码清单的那五年(2014、2017、2019、2023、2024),小问基本只在这五类里循环。四条式子先写在草稿上:

下条指令地址 = 本条指令地址 + 本条机器码字节数
代码段长度   = 末条指令地址 − 首条指令地址 + 1
转移目标地址 = 下条指令地址 + 偏移量
偏移量       = 目标地址 − 下条指令地址
  1. 求下条地址或函数长度:数机器码字节数。2017#44push ebp 数到 ret 得 60H = 96B。
  2. 判寻址方式:跳转和 call 一律 相对寻址0(R4) 是寄存器间接(基址寻址);[ebp − 8] 是用基址寻址访问栈帧;[ecx + edx×4 + 位移] 是基址 + 比例变址 + 位移;指令里写死的常数是立即数寻址。
  3. 求目标地址或偏移量:基准永远是下一条指令2023#44jmp 是 00401079H + 2 + 09H = 00401084H;2019#45call 偏移是 00401000H − 0040102AH = FFFFFFD6H。偏移单位不是字节时还要乘一条指令的长度,2014#44 的公式因此是 (PC) + 4 + OFFSET × 4。
  4. 判端序:把偏移量或位移量字段的字节序和它该表示的数值对照,低字节先出现就是小端——D6 FF FF FF ↔ FFFFFFD6H(2019#45)、00 20 42 00 ↔ 00422000H(2023#44)。反过来,题目给定小端时用它把内存字节拼成机器数(2024#44)。
  5. 反推寄存器与变量的对应:谁被「乘元素大小」就是下标变量,谁被当基址相加就是数组首地址,谁在自己身上累加就是 sum。2024#44 第 1 问就是这一步;2023#44 由「一行 64 个 int」反推出 ecx = i × 256。

问到「这段代码取指会不会缺页」「a[i] 在哪一页」就接到 存储系统 那条地址翻译链上,去掉低 log₂(页大小) 位取页号即可。

时间指标与流水线

问的是公式陷阱
CPU 执行时间指令数 × CPI × 时钟周期时钟周期和主频不要弄反
MIPS主频 ÷ (CPI × 10⁶)
流水线总周期数阶段数 + (指令数 − 1) + 停顿拍数数据冒险的停顿和分支的固定阻塞要单独加

按序发射按序完成意味着后一条指令的取指会被前一条的译码连带堵住2012#442014#44 都要求指出阻塞位置和原因,见 流水线冒险

历年题索引

上面这些要点用熟就已经能应付大部分小问,下面这张表只用来查「某一年额外拐了什么弯」。

真题主线这一年特别问了什么
2009#44单总线数据通路仿照给出的节拍表列出执行阶段的控制信号
2010#43指令格式 + 机器码转移目标范围、执行后哪些寄存器和存储单元变化
2012#44移位指令 + 五段流水线指出两处阻塞原因并画流水线图
2013#44条件转移 + 标志寄存器无符号数「≤」转移要用哪几个标志位
2014#44分支指令 + 相对寻址求 OFFSET 并推出目标地址公式
2015#43单总线 CPU 结构图暂存器 T 的作用、补全数据通路连线
2015#44机器码 + 控制信号填执行过程中 ①~⑧ 的控制信号
2017#44机器级代码 + CISC/RISC算 cmp 执行后的 CF、能否用移位实现乘 2
2019#45函数调用 + call 相对寻址算 call 的偏移量并判断端序
2020#43无乘法指令的机器三种实现方式下执行时间的长短比较
2021#43R/I/J 型指令格式立即数的扩展方式、无条件转移的格式
2022#43数据通路 + 标志位写 SF 与 OF 的逻辑表达式、取指最少几个周期
2023#44机器级代码 + 寻址方式两条跳转指令的目标地址计算、大小端
2024#43控制信号 + ALU 标志slli 与 lw 的 Ext 和 ALUctr 各取什么值
2025#44补码除法器数据通路除法异常的两种情形与异常响应中 CPU 的动作
2026#43指令格式 + 表达式补全实现 y = 16x − 5 的四条指令编码
2026#44数据通路 + 扩展器EXTOP 至少几位、左移指令周期的控制信号

易错清单

  • 转移目标地址漏掉 PC 自增和偏移缩放。形如 (PC) + 2 + 2 × OFFSET,两项都不能省,见 相对寻址
  • 偏移量没有先符号扩展。一律先扩展到地址宽度再参与运算。
  • 字节序方向写反D6 FF FF FF 表示的是 FFFFFFD6H,写成 D6FFFFFFH 会连带错掉「端序」和「机器数」两问(2019#452024#44)。
  • 把加法器的进位直接当成 CF。减法和 cmp 的借位标志是进位输出取反,2017#44 由 C = 0 得 CF = 1。
  • 以为移位能通吃「乘 2」。整型可以,浮点不行——float 的机器数含阶码和隐含的最高有效位(2017#44)。
  • 单总线一拍写了两个源上总线。这是数据通路题最常见的整段失分。
  • 溢出被当成自动转异常。要靠运算指令后面的陷阱指令才会转到异常处理程序。
  • 开 / 关中断当成普通指令。它们是特权指令,用户态不可用,2021#45 专门问这一点。

异常响应由硬件完成的动作是固定的四句:关中断、保存断点(PC 与 PSW)、切到内核态、按向量转异常处理程序。见 异常

上一页:存储系统;下一页:I/O 计算