指令系统
考点定位
- 大纲章节:指令格式(定长/扩展操作码)、指令的寻址方式、数据的对齐与大端小端存放、CISC 与 RISC 的基本概念、高级语言程序与机器级代码之间的对应(x86/MIPS 精神)
- 常见题型:扩展操作码设计(高频计算)、寻址方式 EA 计算与访存次数(选择高频)、大小端判断(选择)、汇编与栈帧(选择/小计算)
- 考查频率:高(每年 4-8 分,扩展操作码与寻址方式几乎轮流出题;新大纲加入的"高级语言与机器码"近年在选择题反复出现)
- 前置知识:补码与定点数(相对寻址位移量、栈帧地址计算)见数据的表示和运算;存储器编址与 MAR/MDR 见存储器层次结构
- 工程师读者注意:你写过汇编、读过反汇编,但考试考教材口径的访存次数计数与扩展操作码的编码空间计算——计数规则与工程直觉略有出入,按本节口径作答
一、指令格式
1.1 指令的两要素
- 操作码:指明做什么(加、转移、访存……),其位数决定指令条数上限( 位 OP 最多 条)。
- 地址码:指明操作数/结果/下一条指令的来源,可以是主存地址、寄存器编号或立即数。
- 指令字长 = 操作码位数 + 各地址码位数,可以等于、大于或小于机器字长(见计算机系统概述三字长对比)。
1.2 按地址码个数分类(访存次数是考点)
以下计数口径(唐教材口径):取指令本身 1 次访存(PC 顺序提供下条指令地址,不含在"执行"计数内另算),执行阶段另行统计取操作数与存结果。选择题常问"执行一条 XX 地址指令共访存几次",按"取指 + 取操作数 + 存结果"合计。
规律:地址码越少,指令越短、通用寄存器依赖越高;隐含约定(ACC、堆栈、PC)替代了显式地址。二地址 R 型(寄存器-寄存器)执行阶段 0 次访存——RISC 的基础。
1.3 定长操作码 vs 扩展操作码
- 定长操作码:OP 固定 位,最多 条指令,译码快,但浪费编码空间(短指令的地址码空间被 OP 占死)。
- 扩展操作码(变长操作码):短指令 OP 短、留出部分编码作"扩展标志"引出长 OP。高频计算考点,见 1.4。
1.4 扩展操作码设计(高频计算,完整步骤 + 验证)
设计四步(背下来,考试直接套):
- 定框架:指令字长、每个地址字段位数 → 各级 OP 可用位数 = 字长 − 地址字段总位数。
- 从最短 OP 开始分配:本级留出全 1 编码(或若干高位前缀)作扩展标志,其余编码分配给本级指令。
- 逐级扩展:下一级 OP = 上一级扩展标志 + 新增位,同样再留新标志。
- 验证编码空间:。这一步能查出多算/漏算。
标准例题(模拟题):指令字长 16 位,每个地址字段 4 位,要求:三地址 15 条、二地址 15 条、一地址 15 条,零地址最多多少条?
第一级(三地址,OP 4 位):编码 0000~1110 共 15 条,留 1111 作扩展标志。
第二级(二地址,OP 8 位,形如 1111 xxxx):xxxx 取 0000~1110 共 15 条,留 1111 1111。
第三级(一地址,OP 12 位,形如 1111 1111 xxxx):15 条,留 1111 1111 1111。
第四级(零地址,OP 16 位,形如 1111 1111 1111 yyyy):yyyy 任意 4 位 → 条。
验证: ✓。
反向题套路:"已知字长 16 位、地址 4 位,三地址 12 条、二地址 60 条、一地址 60 条,零地址最多多少条?"
- 三地址用 12 个前缀(0000~1011),剩 4 个前缀可扩展。
- 二地址编码空间 = ,用 60 条,剩 4 个编码可扩展。
- 一地址空间 = ,用 60 条,剩 4 个编码。
- 零地址最多 = 条。
- 验证: ✓。
关键心法:每放弃一个编码,换来的是 个下一级编码;"留 1 换 16"这笔账要会算。
二、指令的寻址方式
2.1 指令寻址(找下一条指令)
- 顺序寻址:(PC) + "1"(一条指令字长)→ PC。注意这个"1"是一条指令的长度,不是字节 1;定长指令且按字编址时 +1,变长指令按实际字节数加。
- 跳跃寻址:执行转移类指令时,下条地址来自指令的地址字段(直接/间接/相对寻得),PC 被改写。
2.2 数据寻址(找操作数)——九种方式与 EA 计算式
约定:A 为指令中的地址码字段,(X) 表示 X 单元的内容,EA 为操作数的有效地址。
计数口径提醒:表中是取一个操作数的访存次数;一条指令总访存 = 取指 1 次 + 各操作数取数 + 存结果(若有)。
相对寻址计算例:转移指令本身地址为 2000(字地址),指令字长 1 个字,位移量 A = −3(补码),则目标 EA = (PC) + A = (2000 + 1) + (−3) = 1998。最大坑:(PC) 是"本条指令地址 + 指令字长"(即下一条指令地址),不是本条指令地址。
基址 vs 变址的快速判别(选择题高频):"由操作系统管理、程序执行中内容不变" → 基址;"面向用户、执行中由用户/程序修改" → 变址。数组处理 a[i]:把数组首地址放 A、i 放 IX,一条指令在循环中不变——这是变址最典型应用。
堆栈 SP 修改口径:408 常用"入栈先减后存(先 (SP)−1 → SP,再存入),出栈先取后加"(栈向低地址生长,x86 口径)。若题目采用其他口径(自底向上生长)会明确说明,作答以题目图为准。
2.3 综合取数手推(大题模板)
设主存与寄存器状态:(R1)=0x200,(PC)=0x100(已指向下条),(0x200)=0x800,(0x800)=0x15,(BR)=0x600,(IX)=5,指令中 A = 0x200。各寻址方式的 EA 与取值:
(按寻址方式逐级展开取数为动态内容,待动画化。)
三、数据的对齐与大端、小端存放
3.1 边界对齐
设存储字长 32 位、按字节编址、一次访存取一个存储字:
- 边界对齐:大小为 字节的数据,其地址必须是 的倍数(字地址低 2 位为 00、半字低 1 位为 0)。任何数据一次访存取出。
- 不对齐存放:一个字可能跨两个存储字 → 需要 2 次访存并拼接,硬件代价大。
408 口径:按边界对齐是空间换时间(可能浪费尾部字节)。选择题问"某半字数据存放在地址 0x1002,是否对齐"——半字要求偶地址,0x1002 对齐 ✓;若在 0x1003 则不对齐。
3.2 大端与小端
多字节数据的字节序(设 32 位数 0x12345678 存于首地址 0x400,按字节编址):
- 大端:高位字节在低地址,符合书写/阅读顺序;网络字节序、部分 RISC。
- 小端:低位字节在低地址;x86、多数 ARM 默认配置。
- 判别代码(高频选择题素材):
四、CISC 与 RISC(对比表必背)
必背结论:RISC 不一定兼容 CISC;RISC 的"取指、译码、执行"规整性是流水线(后续章节)的基础;CISC 对特殊任务(如字符串处理)单条指令能力强。选择题常拿"RISC 完全不采用微程序控制""RISC 指令一定比 CISC 少就一定快"这类绝对化表述设错。
五、高级语言与机器级代码(新大纲,x86/MIPS 精神)
5.1 从 C 语句到机器指令
C 语句 → 编译器 → 汇编 → 汇编器 → 机器码。工程师对这条链路熟,考试只考两类:读小段汇编反推 C 语义、栈帧变化。x86(32 位,Intel 语法)对照示例:
5.2 AT&T 与 Intel 汇编格式差异(选择考点)
判别技巧:看到 %、$、(%ebp) 就是 AT&T;看到方括号就是 Intel。
5.3 常见指令对栈帧的影响(必背行为表)
设 32 位 x86,栈向低地址生长,push = SP 先减 4 再存,pop = 先取再加 4:
要点:①call/ret 各隐含一次栈访存且改 PC,jmp 只改 PC 不访存;②参数与局部变量的访问通过 ebp 相对寻址([ebp+8] 参数、[ebp−4] 局部变量),正是 2.2 节基址/相对寻址的工程实例;③栈帧推演题画图跟踪 SP/EBP 两个箭头即可。
(call/ret 栈帧建立与销毁为动态内容,待动画化:SP/EBP 双指针随指令移动。)
5.4 MIPS 精神(简要)
MIPS 是 408 教材 RISC 范例:32 位定长指令、32 个通用寄存器($zero 恒 0、$sp 栈指针、$ra 返回地址)、只有 lw/sw 访存、jal 跳转并链接(返回地址存 $ra)、jr $ra 返回、无 push/pop 硬件指令(栈操作用 addi $sp,$sp,-4 + sw 手工完成)。与 x86 对照着记:x86 栈指令硬件化,MIPS 全软件管理——这一对比本身就能出选择题。
例题
例题 1(模拟题) 某机指令字长 16 位,每个地址字段 4 位。若采用扩展操作码:三地址指令 15 条、二地址指令 15 条、一地址指令 15 条,则零地址指令最多( )条。
解:由 1.4 节标准推导,零地址 = 条(验证 )。答 16。
例题 2(模拟题) 变址寻址方式中,操作数 EA =( )。 A. A B. (A) C. (IX) + A D. (PC) + A
解:C。变址 EA = (IX) + A;D 是相对寻址;B 是间接寻址;A 是直接寻址。错因提醒:基址与变址形式相同(基址是 (BR)+A),题目靠"寄存器名"区分,看清 IX 还是 BR。
例题 3(模拟题) 转移指令占 2 个字节、存放在主存字节地址 1000 处(按字节编址),相对寻址位移量为 12(补码),求转移目标地址。
解:(PC) = 1000 + 2 = 1002(下一条指令地址),EA = 1002 + 12 = 1014。错因提醒:用 1000 而非 1002 作基数是最常见错误——PC 在取指后已加上本条指令长度。
例题 4(模拟题) 一次间接寻址的取数指令,从取指令到取得操作数共访存( )次。
解:取指 1 次 + 按 A 取 EA 1 次 + 按 EA 取操作数 1 次 = 3 次。若问"执行阶段"则为 2 次。审清"共"还是"执行阶段"。
例题 5(模拟题) x86 机器执行 call f 后栈顶内容是( )。
A. f 的首条指令地址 B. 返回地址(call 的下一条指令地址) C. EBP 旧值 D. 参数
解:B。call 压入的是返回地址;f 自己的序言才压 EBP。错因提醒:目标地址经 PC 跳转、不进栈。
例题 6(模拟题) 判断:AT&T 语法 movl 8(%ebp), %eax 与 Intel 语法 mov eax, [ebp+8] 语义相同。
解:正确。二者都把 [ebp+8] 处的 32 位数送 eax。要点:AT&T 源在前,8(%ebp) 即 Intel 的 [ebp+8]。
常见坑
- 相对寻址的 (PC) 是下一条指令地址(本条地址 + 指令字长),位移量用补码可正可负。
- 基址寄存器面向系统(BR 执行中不变,A 变),变址寄存器面向用户(IX 变,A 不变)——两者 EA 形式一样,别混。
- 立即寻址没有 EA;问"EA = ?"的选项里立即寻址常被写成 EA = A(错误口径,A 是操作数不是地址)。
- 一次间址取操作数 2 次访存,N 重间址 N+1 次;别忘取指本身 1 次是否计入要审题。
- 扩展操作码验证公式 必做,多算一级或漏留扩展标志当场暴露。
- 扩展操作码各级指令数上限:上级每留 1 个编码,下级多 条;"每级都取满 15"只是习惯,不是规定。
- 小端是低字节在低地址;union 判别输出 1 → 小端。
- 不对齐的 32 位数据最多需 2 次访存(跨两个存储字),不是 4 次。
- RISC 也有访存指令(Load/Store),"RISC 完全不能访存"是错误表述;不能访存的是运算类指令。
call访存且改 PC,jmp只改 PC 不访存——问"哪条指令改变了栈"时 jmp 不算。- MIPS 无 push/pop,返回地址存
$ra寄存器(不自动压栈,需软件保存)。
自测
- 指令字长 32 位,每个地址字段 6 位。不扩展时三地址指令最多多少条?若三地址指令留出 8 个编码作扩展标志,二地址指令最多多少条?
- 寄存器间接寻址取一个操作数访存几次?与间接寻址(一次间址)差在哪?
- 某机器按字节编址,
call指令长 4 字节、位于 0x0800,CPU 执行它压栈的返回地址是多少? - 32 位存储字、按字节编址,地址 0x1001 处存放一个 16 位半字,是否边界对齐?
- 写出 AT&T 语法中"把立即数 10 送 eax"与"取 [eax+4*ebx+8] 处 32 位数送 ecx"的指令。
自测答案与简析
- 三地址 OP = 32 − 18 = 14 位,最多 条。留 8 个编码作扩展标志后,二地址 OP = 20 位(14 位前缀 + 6 位新增),最多 条。心法:上级每放弃 1 个编码,下级换得 个。
- 1 次(按寄存器内容访主存)。间接寻址要 2 次:先访主存取 EA,再访主存取数;寄存器间接把"取 EA"放进寄存器,省一次主存访问。
- 0x0804(下一条指令地址 = 0x0800 + 4)。
- 不对齐:16 位半字要求偶地址,0x1001 是奇地址,取出需 2 次访存。
movl $10, %eax;movl 8(%eax,%ebx,4), %ecx。要点:AT&T 立即数$、寄存器%、内存disp(base,index,scale)。