跳转至

第4章 指令系统

2027 王道 · 专题阅读 · 保留代码与校订注 · 与版本锁一致

第4章 指令系统

既出选择题也结合其他章出综合题。核心是各种寻址方式的有效地址计算(尤其三种偏移寻址)、扩展操作码设计、CISC 与 RISC 对比。2022 年新增的机器级表示(读汇编代码)历年多次出现,难度大但有套路。

回源 · PDF 第 153 页 · b_153_3

【知识树】第4章骨架

  • 指令格式
  • 操作码 + 地址码;定长指令字 vs 变长指令字
  • 零/一/二/三地址指令及其访存次数
  • 定长操作码 vs 扩展操作码
  • 指令类型:数据传送 / 算逻运算 / 移位 / 顺序控制 / I/O / CPU 控制
  • 寻址方式
  • 指令寻址:顺序寻址(PC 自增)、跳跃寻址(绝对/相对)
  • 数据寻址十种:隐含 / 立即 / 直接 / 间接 / 寄存器 / 寄存器间接 / 相对 / 基址 / 变址 / 堆栈
  • 三种偏移寻址:相对、基址、变址
  • 机器级代码表示
  • x86 寄存器与常用指令
  • 选择结构、循环结构、过程调用的机器级表示
  • CISC 与 RISC
回源 · PDF 第 153 页 · b_153_0;PDF 第 153 页 · b_153_4

4.1 指令格式

ISA 规定了哪四方面内容? ★2考

  • 指令格式、寻址方式、操作类型,以及各操作所需操作数的个数、类型和寻址约束
  • 操作数的数据类型,以及按大端还是小端存放
  • 程序可访问的寄存器编号、数量和位数,存储空间大小及编址方式
  • 程序员可见的控制状态,如程序计数器、条件码的定义与行为

★ 考过 2022、2025

回源 · PDF 第 153 页 · b_153_9

指令字长由什么决定?定长和变长各有什么好处?

指令字长取决于操作码长度、地址码长度及地址码个数。 - 定长指令字结构:所有指令字长相等 → 取指和译码简单,有利于流水线实现 - 变长指令字结构:指令字长随功能而异

⚠️ 主存按字节编址时,指令字长通常是字节的整数倍。

回源 · PDF 第 154 页 · b_154_7

四种地址格式的指令各需要几次访存? ★1考

(设地址码均为主存地址) - 零地址:无操作数指令(空操作、停机、关中断)或堆栈运算指令 - 一地址: - 若为 OP(A₁)→A₁,需3 次访存(取指 1 + 取数 1 + 写回主存 1) - 若为 (ACC)OP(A₁)→ACC 且结果只留在 ACC,通常是2 次访存(取指 1 + 取主存操作数 1) - 二地址:(A₁)OP(A₂)→A₁,4 次访存(取指 1 + 取数 2 + 存结果 1) - 三地址:(A₁)OP(A₂)→A₃,4 次访存(同上)

⚠️ 上述数字依赖“地址码都是主存地址”及具体语义;寄存器操作数、无需写回或堆栈隐含操作数都会改变访存次数。

★ 考过 2015

回源 · PDF 第 154 页 · b_154_9

定长操作码最多支持多少条指令? ★1考

n 位操作码字段最多表示 2ⁿ 条指令。 好处是简化硬件设计、提高译码速度,32 位及更长字长的系统常用。

★ 考过 2015

回源 · PDF 第 155 页 · b_155_7

设计扩展操作码必须遵守哪两条规则? ★3考

  • 短操作码不能是长操作码的前缀(即短码不能与长码的前面部分相同)
  • 各指令的操作码一定不能重复

另外一条设计原则:使用频率高的指令分配短操作码,频率低的分配长操作码,以减少译码时间。

★ 考过 2017、2021、2022

💡 记忆法:"短码不当长码的头" —— 否则译码时会提前误判。

回源 · PDF 第 155 页 · b_155_10

扩展操作码的经典算例是什么样的?

16 位指令字,4 位基本操作码 + 3 个 4 位地址字段: - 三地址指令:用 0000~1110 共 15 条,留 1111 作扩展窗口 - 二地址指令:用 1111 0000~1111 1110 共 15 条,留 1111 1111 继续扩展 - 一地址指令:同理 15 条,留 1111 1111 1111 - 零地址指令:16 条

⚠️ 每层都要留一个码字作为下一层的扩展窗口,所以每层是 15 条而不是 16 条(最后一层例外)。

回源 · PDF 第 155 页 · b_155_9;PDF 第 155 页 · b_155_13

【做题模板】扩展操作码怎样用前缀树数槽位?

  1. 从最短操作码层画一棵前缀树,每个码字是一条路径。
  2. 已分配给短指令的叶结点必须封死,不能再向下扩展;否则短码会成为长码前缀。
  3. 每保留一个未用短码,就能在下一层展开出 \(2^k\) 个新槽位(\(k\) 为本次新增位数)。
  4. 逐层扣除已分配指令,最后一层无须再为下一层留窗口。
  5. 用 Kraft 条件或逐层槽位数做反查,确认没有重码或前缀冲突。

高频指令放短码只是优化原则;“总位数必须是 8 的倍数”仅在题设采用按字节取指/编码时成立,不是 ISA 通则。

回源 · PDF 第 155 页 · b_155_10;PDF 第 155 页 · b_155_13

调用指令和转移指令的根本区别? ★1考

调用指令会保存下一条指令的地址(返回地址),以便子程序结束后返回主程序;转移指令不返回。

另外:无条件转移任何情况下都跳;条件转移仅在条件满足时跳,转移条件通常是某个标志位或多个标志位的组合。

★ 考过 2019

回源 · PDF 第 156 页 · b_156_10

4.2 指令寻址

PC 自增的大小由什么决定? ★4考

由编址方式和指令字长共同决定。 现代计算机按字节编址时: - 指令字长 16 位(2 字节)→ (PC) + 2 - 指令字长 32 位(4 字节)→ (PC) + 4

★ 考过 2013、2014、2019、2023

回源 · PDF 第 161 页 · b_161_11

跳跃寻址的两种方式?

  • 绝对转移:地址码直接给出目标地址
  • 相对转移:地址码给出相对于当前 PC 值的偏移量

⚠️ 无论哪种,转移指令的执行结果都是修改 PC 的值。

回源 · PDF 第 161 页 · b_161_8;PDF 第 161 页 · b_161_14

形式地址的位数分别限制了什么? ★2考

看是哪种寻址方式: - 立即寻址 → 形式地址位数决定操作数的取值范围 - 直接寻址 → 决定可寻址的存储空间大小 - 寄存器寻址 → 决定通用寄存器的最大数量 - 寄存器间接寻址 → 由寄存器的位数决定可寻址空间大小

★ 考过 2020、2023

回源 · PDF 第 161 页 · b_161_18

4.3 数据寻址方式(本章计算核心)

八种显式数据寻址方式的有效地址和访存次数?(主表)

(访存次数不含取本条指令) | 寻址方式 | 有效地址 | 访存次数 | |---|---|---| | 立即寻址 | A 即是操作数 | 0 | | 直接寻址 | EA = A | 1 | | 一次间接寻址 | EA = (A) | 2 | | 寄存器寻址 | EA = Rᵢ | 0 | | 寄存器间接寻址 | EA = (Rᵢ) | 1 | | 相对寻址 | EA = (PC) + A | 1 | | 基址寻址 | EA = (BR) + A | 1 | | 变址寻址 | EA = (IX) + A | 1 |

💡 记忆法:"立即和寄存器不访存,一次间址访两次,其余都一次"。

⚠️ 本表只列 8 种显式给出地址/寄存器字段的方式。若按本章“十种数据寻址”口径,还要加: - 隐含寻址:操作数地址由操作码或专用寄存器隐含 - 堆栈寻址:操作数由 SP 指示的栈顶隐含

回源 · PDF 第 165 页 · b_165_9

立即寻址的优缺点? ★1考

形式地址字段直接存放操作数本身(立即数,通常用补码表示),用 # 标识。 - 优点:执行阶段无须访问存储器,速度最快 - 缺点:立即数大小受形式地址字段位数限制,寻址范围非常有限

★ 考过 2023

回源 · PDF 第 162 页 · b_162_11

直接寻址的寻址范围怎么算? ★2考

EA = A,形式地址就是操作数真实地址。若形式地址占 24 位,则寻址范围为 2²⁴ = 16M。 - 优点:实现简单,执行阶段只访存一次 - 缺点:寻址范围受形式地址位数限制,且地址固定难以动态修改

★ 考过 2010、2021

回源 · PDF 第 162 页 · b_162_16

间接寻址为什么能扩大寻址范围? ★1考

EA = (A) —— 形式地址指向一个主存单元,该单元里存的才是操作数的有效地址。

因为有效地址的位数由存储字长决定,通常大于形式地址 A 的位数,所以能扩大寻址范围,还支持地址动态生成(指针、转移表)。代价是一次间址要 2 次访存。

★ 考过 2016

回源 · PDF 第 163 页 · b_163_3

寄存器编号位数和寄存器数量什么关系? ★2考

寄存器编号位数 = log₂(寄存器数量)。 例:CPU 有 32 个通用寄存器 → 编号需 5 位。

寄存器寻址(EA = Rᵢ)的优点:执行阶段无须访存,速度快;地址码位数少,有助于缩短指令字长。

★ 考过 2022、2024

回源 · PDF 第 163 页 · b_163_10

寄存器间接寻址相比另两种有什么取舍? ★1考

EA = (Rᵢ) —— 寄存器里存的是操作数所在主存单元的地址。 - 相比间接寻址:执行阶段只需一次访存(间接寻址要两次),开销更小 - 相比寄存器寻址:多了一次主存访问 - 寻址范围不受形式地址位数限制

★ 考过 2010

回源 · PDF 第 163 页 · b_163_15

相对寻址怎么算?陷阱在哪? ★6考

EA = (PC) + A

⚠️ 最大的坑:这里的 PC 是取指完成后自动更新的值(指向下一条指令),不是当前指令地址!

经典算例:按字节编址、指令长 2B,转移指令位于 1000H,形式地址 A = 0005H → 取指后 PC = 1002H → 目标地址 = 1002H + 0005H = 1007H(不是 1005H)

优点:目标地址相对当前指令位置偏移,程序可在内存任意浮动,便于重定位和代码共享。

★ 考过 2009、2010、2013、2014、2019、2023 —— 本章最高频

三步法:① 先确定题设所用的取指后 PC;② 把位移 \(A\) 按规定做符号扩展;③ 若 ISA 规定位移以字/半字为单位,再先左移缩放后相加。

💡 记忆法:"先定 PC,再扩展,最后按单位缩放"。是否缩放、缩放几位由 ISA/题设决定。

回源 · PDF 第 163 页 · b_163_24

基址寻址的 EA 和特点? ★1考

EA = (BR) + A - 基址寄存器 BR 的内容由操作系统设定,程序执行期间保持不变(作基地址) - 形式地址 A 作偏移量,由用户程序指定、可变 - 优点:扩大寻址范围(BR 位数通常大于 A)、简化编程(用户不必关心程序在主存的具体位置),利于多道程序和浮动程序 - 缺点:形式地址 A 位数较短,限制了偏移量范围

★ 考过 2019

回源 · PDF 第 164 页 · b_164_7

变址寻址的 EA 和典型用途? ★5考

EA = (IX) + A - 变址寄存器 IX 面向用户,其内容(偏移量)可在程序执行中动态修改 - 形式地址 A(基地址)保持不变 - 典型用途:处理数组、编写循环程序

算例:数组 B 首地址 1000H 存在 A 中,元素占 4B,访问 B[3] → IX 置为 0CH(3×4=12)→ EA = 0CH + 1000H = 100CH

★ 考过 2013、2016、2017、2018、2024

回源 · PDF 第 164 页 · b_164_0

基址寻址和变址寻址的本质区别? ★3考

两者都是"寄存器内容 + 形式地址",但分工完全相反: - 基址寻址面向系统:BR 由操作系统设定、运行时不可变,A 是可变的偏移量;用于多道程序和存储分配 - 变址寻址面向用户:IX 由用户程序动态调整,A 是固定的基地址;用于灵活的数据访问

★ 考过 2017、2018、2024

💡 记忆法:"基址系统定、变址用户改" —— 谁在变就看名字:变址的"变"在寄存器上。

回源 · PDF 第 165 页 · b_165_0

哪三种寻址方式属于偏移寻址? ★1考

相对寻址、基址寻址、变址寻址。 共同特点是通过某个寄存器的值与形式地址相加来确定有效地址,区别只在于用的是哪个寄存器(PC / BR / IX)。

★ 考过 2011

回源 · PDF 第 165 页 · b_165_3

堆栈寻址的两种实现?

  • 硬堆栈:由高速寄存器构成,成本高、容量小
  • 软堆栈:从主存划出一段区域实现,更经济实用

栈顶地址由堆栈指针 SP 给出。采用堆栈结构的机器中,多数指令表面上表现为无操作数形式,因为操作数地址由 SP 隐含指定。

回源 · PDF 第 165 页 · b_165_5

4.4 x86 汇编基础

x86 有哪 8 个 32 位通用寄存器?各自的角色?

  • EAX 累加器、EBX 基地址寄存器、ECX 计数寄存器、EDX 数据寄存器
  • ESI / EDI 变址寄存器
  • EBP 堆栈基指针、ESP 堆栈顶指针

⚠️ 除 EBP 和 ESP 外,其余通用寄存器用途比较灵活。EAX~EDX 的低 16 位可作 AX~DX 用,AX 又可拆成 AH / AL 两个 8 位寄存器。

回源 · PDF 第 177 页 · b_177_5

mov 指令有什么硬性限制? ★1考

两个操作数不能同时为内存 —— mov 不能直接从内存复制到内存。若需内存间复制,必须先加载到寄存器,再从寄存器写入目标内存。

★ 考过 2012

回源 · PDF 第 178 页 · b_178_3

push 和 pop 对 ESP 做什么?

  • 在本书采用的 32 位 x86、32 位操作数示例中,push 先将 ESP 减 4,再写入;pop 先读出,再将 ESP 加 4

⚠️ 并非所有 x86 模式和操作数大小都固定变化 4B;实际对 SP/ESP/RSP 的改变量由模式和操作数大小决定。

💡 记忆法:"压栈先减后放,出栈先取后加",栈往低地址长。

回源 · PDF 第 178 页 · b_178_4;PDF 第 178 页 · b_178_8

4.5 x86 常用指令

mul 和 imul 的溢出判据不同在哪?

  • mul(无符号乘):仅单操作数格式,被乘数隐含在 eax,乘积放在 edx:eax。edx ≠ 0 表示结果超出 32 位 → 置 CF = 1、OF = 1
  • imul(有符号乘):支持双操作数和三操作数格式,结果溢出时同样置 CF = 1、OF = 1

⚠️ 判据口径:无符号乘法以 CF 判断溢出,有符号乘法以 OF 为准。

回源 · PDF 第 178 页 · b_178_19

idiv 的被除数在哪?商和余数放哪?

  • 指令只指定除数
  • 被除数 = edx:eax 组成的 64 位数(edx 高 32 位、eax 低 32 位)
  • 执行后:商存入 eax,余数存入 edx

div 与 idiv 格式完全一致,只是对操作数的解释不同(无符号/有符号)。

💡 记忆法:"除法进去 edx:eax,出来商在 eax、余在 edx"。

回源 · PDF 第 179 页 · b_179_1

两个常见的位运算技巧?

  • and eax, 0fH → 把 eax 的高 28 位置 0、低 4 位保留(提取低位)
  • xor edx, edx → 把 edx 清零(比 mov edx,0 更快,是编译器常用写法)
回源 · PDF 第 179 页 · b_179_6

cmp 和 test 的区别?

  • cmp:执行减法运算但不保存结果,仅设置标志位(相当于 sub)
  • test:执行按位与运算但不保存结果,仅更新标志位、特别是 ZF(相当于 and)

典型搭配: - cmp eax, ebx + jle done → 比较后条件跳转 - test eax, eax + jz xxx → 测试 eax 是否为零(自己和自己与,结果为 0 说明 eax 为 0)

★ 考过 2013

回源 · PDF 第 180 页 · b_180_8

call 和 ret 各做了什么? ★1考

  • call:将下一条指令的地址(返回地址)压入栈,然后转移到 label 处执行
  • ret:从栈顶弹出返回地址,并转移到该地址继续执行

这两条是函数调用机制的核心。x86 用 EIP(指令指针寄存器,相当于 PC)指示当前指令地址,EIP 不能直接访问,只能通过控制流指令修改。

★ 考过 2019

回源 · PDF 第 180 页 · b_180_15

AT&T 格式和 Intel 格式有哪六点区别?

统考用 Intel 格式,但要能读懂 AT&T: - 大小写:AT&T 必须小写,Intel 不敏感 - 操作数顺序:AT&T 是"源, 目的";Intel 是"目的, 源" ← 最容易搞反 - 前缀:AT&T 寄存器加 %、立即数加 $;Intel 都不加 - 内存寻址符号:AT&T 用圆括号 ();Intel 用方括号 [] - 复杂寻址:AT&T disp(base, index, scale);Intel [base + index*scale + disp] - 操作数长度:AT&T 在助记符后加后缀 b/w/l;Intel 用 byte ptr / word ptr / dword ptr

⚠️ x86 里 word(字)始终表示 16 位(因为 32/64 位都是从 16 位扩展来的)。

💡 记忆法:"AT&T 源在前,Intel 目的在前" —— Intel 像赋值语句 目的 = 源。

回源 · PDF 第 180 页 · b_180_20

mov 和 lea 的区别?

  • mov:复制源操作数的值到目的操作数;可以是立即数→寄存器、寄存器→寄存器或寄存器↔内存(但不能两个操作数同时为内存)
  • lea:把有效地址本身加载到寄存器,不访问内存

例:lea eax, [edx+eax*2+8] → R[edx] + R[eax]×2 + 8 → R[eax](只算地址不取数)。

回源 · PDF 第 181 页 · b_181_3

4.6 选择与循环的机器级表示

哪些指令会设置条件码?

  • 很多算术逻辑运算指令(如 add、sub、imul、or、and、shl、inc、dec、sal)会按各自规则更新部分条件码
  • cmp 和 test 专门用于设置条件码,执行运算但不保存结果

常用条件码:CF、ZF、SF、OF。

⚠️ x86 的 NOT 不影响任何标志位;不同逻辑/移位指令更新哪些标志也不完全相同,不能把“自动设置全部条件码”当通则。

回源 · PDF 第 181 页 · b_181_8

if-else 翻译成 goto 形式的固定套路?

t = test_expr;
if (!t) goto false;    // 条件为假跳到假分支
  then_statement
  goto done;           // 真分支执行完跳过假分支
false:
  else_statement
done:

⚠️ 关键点:编译后先判断"假"的情况并跳转,真分支紧跟在判断之后。

回源 · PDF 第 181 页 · b_181_12

指针比较为什么用 jbe 而不是 jle?

在本题给定的目标代码中,编译器用 jbe,说明机器级比较采用了无符号条件码。C 语言层面,两个指针只有在指向同一数组对象(或其尾后位置)时做关系比较才有标准定义;不能据此推出“任意 C 指针都按无符号整数比较”。

⚠️ 这是汇编阅读题的常见陷阱:看到 jbe/ja/jb 说明操作数按无符号解释,看到 jle/jg/jl 说明按有符号解释。

回源 · PDF 第 182 页 · b_182_0

三种循环编译后统一变成什么形式? ★4考

为了讲清控制流,可把 while、for 等价改写成带标签和条件跳转的 do-while/跳转形式;实际编译器可因优化级别、体系结构和分支布局生成多种等价控制流,并非“编译器眼里只有 do-while”。

  • do-while(后测试):循环体至少执行一次

    loop: body_statement
          t = test_expr;
          if (t) goto loop;
    

  • while(前测试):加一个前置判断

    t = test_expr;
    if (!t) goto done;   // 初始条件为假,一次都不执行
    loop: body_statement
          t = test_expr;
          if (t) goto loop;
    done:
    

  • for:先转成 while,init_expr 只执行一次,update_expr 放在循环体之后

★ 考过 2014、2017、2019、2023

💡 记忆法:"编译器眼里只有 do-while" —— while 就是前面加个判断跳过,for 就是 while 加初始化和更新。

回源 · PDF 第 182 页 · b_182_6

4.7 过程调用的机器级表示

过程调用的六个步骤?

设 P 调用 Q: - ① P 将入口参数放到 Q 能访问的位置 - ② P 执行 call:把返回地址(call 的下一条指令地址)压栈,转移到 Q - ③ Q 建立自己的栈帧,为局部变量分配空间,必要时保存寄存器 - ④ Q 执行主体代码 - ⑤ Q 把返回结果放到约定位置(EAX),释放局部变量空间,恢复保存的寄存器 - ⑥ Q 执行 ret:弹出返回地址,转移回 P

回源 · PDF 第 184 页 · b_184_5

哪些寄存器是调用者保存?哪些是被调用者保存?

  • 调用者保存寄存器:EAX、ECX、EDX
  • 若 P 希望调用后仍使用这些寄存器的值,P 必须在调用前自行保存(压栈),返回后恢复
  • 被调用者保存寄存器:EBX、ESI、EDI
  • 若 Q 需要使用它们,Q 必须在使用前保存到栈,返回前恢复

💡 记忆法:"AX/CX/DX 归调用者管,BX/SI/DI 归被调用者管" —— 前三个是"干活寄存器",随时可能被覆盖。

回源 · PDF 第 184 页 · b_184_7

EBP 和 ESP 在栈帧中各起什么作用?

  • EBP(基址指针):指向当前栈帧的基址(保存旧 EBP 的位置),在当前过程执行期间保持不变 → 便于用固定偏移访问参数和局部变量
  • ESP(栈指针):始终指向当前栈顶,随入栈出栈动态变化

⚠️ 栈从高地址向低地址增长。 参数位于 [ebp+8]、[ebp+12]…(正偏移),局部变量位于 [ebp-4]、[ebp-8]…(负偏移)。

💡 记忆法:"参数在上(正偏移),局部变量在下(负偏移),中间隔着旧 EBP 和返回地址"。

回源 · PDF 第 184 页 · b_184_4;PDF 第 184 页 · b_184_10

过程的机器级代码分哪三部分?

  • 准备阶段:push ebp(保存调用者的 EBP)+ mov ebp, esp(建立新栈帧)
  • 过程体:实际功能代码
  • 结束阶段:pop ebp(恢复调用者 EBP)+ ret(弹出返回地址跳回)
回源 · PDF 第 186 页 · b_186_3;PDF 第 186 页 · b_186_4

leave 指令等价于哪两条指令?

mov esp, ebp   # 栈指针指回保存旧 EBP 的位置(释放栈帧)
pop ebp        # 弹出旧 EBP,恢复调用者的基址指针

执行完后 ESP 正好指向返回地址,ret 就能取出它跳回去。

回源 · PDF 第 185 页 · b_185_9

栈帧大小的对齐要求是什么?

在本书给定的 ABI、编译选项和代码生成示例中,GCC 为满足调用点的 16B 栈对齐约定加入填充。

算例:caller 实际用了 4(旧 EBP)+ 12(三个局部变量)+ 8(两个参数)+ 4(返回地址)= 28 字节 → 但最终分配 32 字节,多出的 4 字节是对齐填充。

⚠️ 这不是“所有 GCC、所有架构、每个函数栈帧本身都必须是 16B 倍数”的全局语法规则;要按目标 ABI、模式和调用点要求分析。

回源 · PDF 第 185 页 · b_185_0

参数入栈的顺序是怎样的?

左参数位于较低地址,右参数位于较高地址。

例:调用 add(temp1, temp2) 时,先把 temp2(右)放 [esp+4],再把 temp1(左)放 [esp]。所以在被调用者里,[ebp+8] 是第一个参数、[ebp+12] 是第二个参数。

回源 · PDF 第 185 页 · b_185_0;PDF 第 185 页 · b_185_1

为什么汇编里看不到加法指令却完成了加法?

因为编译器用 lea 指令代替 add:lea eax, [edx+eax] 实际执行 R[edx] + R[eax] → R[eax]。

lea 本意是算有效地址,但它的地址计算本身就是加法和乘法,所以常被编译器借用来做算术运算(且不影响标志位)。

回源 · PDF 第 186 页 · b_186_0

4.8 CISC 与 RISC

CISC 的七个特点? ★1考

  • 指令系统庞大复杂,指令数量通常超过 200 条
  • 指令长度不固定,指令格式和寻址方式种类繁多
  • 多数指令均可直接访问内存
  • 各类指令的使用频率差异显著
  • 指令执行时间相差较大,大多数指令需多个时钟周期
  • 控制器多采用微程序控制
  • 难以通过优化编译生成高效目标代码

★ 考过 2017

回源 · PDF 第 196 页 · b_196_2

RISC 的七个特点? ★2考

  • 只选使用频率最高的简单指令,复杂功能由多条简单指令组合
  • 指令长度固定,指令格式和寻址方式种类少
  • 仅 LOAD/STORE 指令可访问内存,其余运算都在寄存器间进行
  • CPU 中配备大量通用寄存器
  • 指令规整、易于流水;经典教材模型常把理想流水吞吐率写成接近 1 CPI,不等于每条指令的实际延迟都只有一个周期
  • 以硬布线控制为主,极少或不用微程序控制
  • 高度依赖编译器优化

★ 考过 2009、2025

回源 · PDF 第 196 页 · b_196_8

80/20 规律说的是什么?

对传统 CISC 指令系统的统计表明:约 80% 的程序执行仅依赖于 20% 的简单指令,其余 80% 的复杂指令使用频率极低。

这个观察正是 RISC 诞生的直接依据 —— 只保留高频简单指令,复杂功能用组合实现。

回源 · PDF 第 196 页 · b_196_0

CISC 与 RISC 的十项对比表?

对比项 CISC RISC
指令数目 > 200 条 < 100 条
指令字长 不固定 定长
可访存指令 不加限制 只有 LOAD/STORE
指令执行时间 相差较大 规整、利于流水,理想吞吐可接近 1 CPI
指令使用频度 相差很大 都比较常用
通用寄存器 较少 多
目标代码 难以优化编译 编译后代码高效
控制方式 经典教材常见微程序控制 经典教材常见硬布线控制
指令流水线 均可实现;复杂译码增加难度 指令规整,通常更易深度流水
兼容性 通常向后兼容 通常无法与老机型兼容
回源 · PDF 第 197 页 · b_197_3;PDF 第 197 页 · b_197_4

RISC 相比 CISC 的四点优势?

  • 更高效利用芯片面积(本书历史模型):把更多面积用于寄存器/数据通路而非复杂控制;“50%/10%”是教材示例,不是现代处理器通用比例
  • 更高的运算速度:指令少、格式统一、寻址简单 + 大量通用寄存器 + 流水线
  • 更易设计与维护:设计周期短、出错概率低
  • 更利于编译优化:指令类型和寻址方式有限,编译器易选最优指令序列
回源 · PDF 第 197 页 · b_197_3;PDF 第 197 页 · b_197_4;PDF 第 197 页 · b_197_5

LOAD/STORE 型指令有什么特点?

  • 访存与计算分离:只有 LOAD(内存→寄存器)和 STORE(寄存器→内存)能访问主存,所有运算指令仅操作寄存器
  • 指令格式规整:寄存器编号位数远少于内存地址,可实现定长指令,简化译码
  • 利于流水线:统一的指令长度和访存边界,使各阶段易于并行
回源 · PDF 第 199 页 · b_199_11

寻址方式多或少各有什么影响?

  • 寻址方式丰富:程序更简洁高效、便于表达复杂访问模式;但增加译码逻辑复杂度、不利于流水线调度、增大控制单元面积
  • 寻址方式过少:简化硬件、提升执行速度;但限制程序表达能力,迫使用多条指令模拟复杂访问
回源 · PDF 第 199 页 · b_199_3

【易混点】第4章成对概念对照

易混对 分界线
二地址 vs 三地址指令 访存次数都是 4 次,别以为三地址更多
定长操作码 vs 扩展操作码 前者 n 位固定支持 2ⁿ 条;后者短码不能当长码前缀
转移指令 vs 调用指令 调用保存返回地址、要回来;转移不返回
直接寻址 vs 间接寻址 EA = A(1 次访存)vs EA = (A)(2 次访存)
寄存器寻址 vs 寄存器间接寻址 EA = Rᵢ(0 次访存)vs EA = (Rᵢ)(1 次访存)
基址寻址 vs 变址寻址 BR 由 OS 设定不可变、A 可变;IX 由用户动态改、A 固定
相对寻址里的 PC 是取指后自动更新的值(已指向下一条指令)
AT&T vs Intel 格式 源在前 vs 目的在前;%/$ vs 无前缀;() vs []
jbe/ja vs jle/jg 前者无符号比较(指针用),后者有符号比较
mov vs lea 取内容 vs 取地址(lea 常被借去做加法)
调用者保存 vs 被调用者保存 EAX/ECX/EDX vs EBX/ESI/EDI
CISC vs RISC 教材典型实现常见微程序 vs 硬布线;RISC 的规整格式更利于流水线,但两类都可采用流水线或不同控制实现
回源 · PDF 第 199 页 · b_199_5

【必背数字】第4章

  • 访存次数按“取指 + 主存型源操作数 + 主存写回”逐项数:典型 ACC 一地址且结果留在 ACC 时 2 次;若结果写回主存则 3 次
  • 定长操作码 n 位 → 最多 2ⁿ 条指令
  • 执行阶段取操作数次数:立即/寄存器 0、一次间址通常 2、直接/寄存器间接通常 1;均不含取指
  • 相对寻址 EA = (PC) + A,PC 已自增
  • 基址寻址 EA = (BR) + A;变址寻址 EA = (IX) + A
  • 寄存器编号位数 = log₂(寄存器数),32 个寄存器需 5 位
  • 本书 32 位 x86/cdecl 栈帧例:首个栈上传参常从 [ebp+8] 起、局部变量向负偏移;具体 ABI、优化和省略帧指针会改变布局
  • 栈对齐由 ABI/调用点约定决定;常见现代 ABI 要求 16B 对齐,但不是“GCC 永远如此”的语言规则
  • 32 位示例中 push/pop 常使 ESP 减/加 4B;真实步长等于操作数/栈槽宽度
  • “CISC 指令多、RISC 指令精简”和 80/20 是教材中的历史趋势/经验规律,不是以 100、200 条划出的现代 ISA 定义
回源 · PDF 第 165 页 · b_165_9;PDF 第 165 页 · b_165_10