Appearance
指令字段与机器码:切开位串、数出字段宽、加出下一条地址(专题总纲)
Intro
这一类题有两副长相。一副是给你一张字段定义表,标着 [15,12] OP、[11,9] Ms、[8,6] Rs;另一副是甩给你一段 x86 反汇编,每行写着虚拟地址、机器码字节和汇编助记符,让你在里面找答案。
看着像两类题,其实手上做的是同一件事。因为一条指令在机器里只有两样东西:
一串被字段切开的位,和一个占若干字节的地址。
小问基本都在这两样之间来回换算——少数几问是别的章节挂上来的,最后一节会点出来。两副长相的区别只在于字段的位置和长度是谁告诉你的:给字段表的那五道,题面直接画了位区图;给反汇编的那几道,你得自己从「两行虚拟地址差了多少」和「这一行机器码写了几个字节」里量出来。下文把这件事简称为量尺子。量出尺子之后,两组题就是同一道题。
字段只有三个属性,所以题只能问三种事
| 字段的属性 | 手上的动作 | 题面长什么样 |
|---|---|---|
| 它有宽度 | 数: | 最多多少条指令、多少个通用寄存器、偏移量范围多大 |
| 它有位置 | 切:按位区切开读编号,或把编号填回去 | 写出机器码、给出机器码问功能、判断某寻址方式 |
| 它有含义 | 加:编号指向的偏移量参与地址运算 | 转移目标地址、访存有效地址、下一条指令地址 |
数、切、加——九道真题的大部分小问落在这三个动作里。但不是全部:有相当一部分分值是别的章节挂在指令格式这副骨架上的,本文最后一节会列清楚哪些是外挂、该翻哪一章。以 2024-43 为例,13 分里有 9 分(标志位、控制信号)并不属于这三个动作。
数: 里的「宽」取哪一段,是第一个坑
2010 年那道题的操作数字段占 6 位,但它是 寻址方式 3 位 + 寄存器编号 3 位 拼起来的。问「最多多少个通用寄存器」,取的是寄存器编号那 3 位:
不是
切:正着填和反着读,是同一张表
正向是「汇编 → 机器码」:把每个助记符换成编号,按位区拼起来。反向是「机器码 → 功能」:先展开成二进制,再按位区截断。
反向那一步有个额外用处——判一条机器码到底是哪条指令。2024 年那道给出 A040 A103H,问为什么它一定是 lw:把低 7 位取出来是 0000011,只有 lw 的操作码是这个值;add 与 slli 要求高 7 位是 0000000,而这里是 1010000,对不上。排除法用的仍然是同一张字段表。
加:基准永远是「下一条指令的地址」
相对寻址算目标地址,基准是取完这条指令之后 PC 指向的位置。拿当前这条指令的地址去加,是这一步最常见的丢分处。三道真题三种写法,说的是同一件事:
- 2013 年:题面直接写成
——那个 +2就是跳过本条指令; - 2023 年:
jmp在00401079H、机器码EB 09两字节,目标 =; - 2019 年:
call在00401025H、机器码五字节,偏移量 = 目标 − 下一条 =。
没给字段表的那四道,尺子藏在两个地方
反汇编那一组里有三道(2017-44、2019-45、2023-44)没有字段定义表,但题面把尺子交给你了:
- 每行的机器码有几个字节 → 这条指令占几字节 → 下一条的地址;
- 多字节字段在内存里的排列顺序 → 大端还是小端。
(第四道 2024-44 是个例外:它给的是四条类 RISC-V 汇编,既没有虚拟地址也没有机器码字节,不用量尺子,直接把每条指令翻成 C 语义反推寄存器的角色。)
2019 年那道把两件事串成一问:call 的机器码是 E8 D6 FF FF FF,后四字节是偏移量。按上面算出偏移量真值是 D6 FF FF FF——最低有效字节 D6 落在最低地址,所以这台机器是小端。
判大小端不需要额外知识,把算出来的数和题面印的字节顺序对一下就行。
必错点
MAR 和 MDR 的位数有两种算法,看题面给了什么。 题面给了系统总线宽度,就跟总线走;没给,才用地址空间反推。
| 2021 年(给了总线) | 2010 年(没给总线) | |
|---|---|---|
| MAR | 20 位 = 地址线宽度 | 16 位 = |
| MDR | 8 位 = 数据线宽度 | 16 位 = 字长 |
2021 年那道的 MDR 是 8 位,哪怕字长是 16 位——代价是取一条 16 位指令要访存两次。别看见字长就往 MDR 上填。
自增量跟着编址单位走。 2010 年那道按字编址,(Rn)+ 执行后 Rn 加 1;同样的助记符放在按字节编址、字长 4 字节的机器上就是加 4。
补码偏移量两头不对称,而且「能跳过多少条」还要看从哪儿数起。 8 位补码的范围是
shamt 这类字段的宽度要从「能取几个值」倒推。 2024 年那道问「为什么 shamt 占 5 位」:字长 32 位,有意义的移位量是 0~31 共 32 个值,所以需要
一道题的答卷长什么样
以 2010 年那道的第 (3) 问为例——把 add (R4), (R5)+ 翻成机器码并追踪执行。字段表是题面给的:[15,12] OP、[11,9] Ms、[8,6] Rs、[5,3] Md、[2,0] Rd。
第一步,按位区把编号码回去。 一行一段,别在脑子里拼:
OP = 0010 (add)
Ms = 001 (寄存器间接,源)
Rs = 100 (R4)
Md = 010 (寄存器间接、自增,目的)
Rd = 101 (R5)
→ 0010 0011 0001 0101B = 2315H第二步,逐层拆间址。 寄存器间接是两层:寄存器里装的是地址,地址里装的才是操作数。写成两行不会绕晕:
源: (R4) = 1234H → M[1234H] = 5678H ← 源操作数
目: (R5) = 5678H → M[5678H] = 1234H ← 目的操作数
和: 5678H + 1234H = 68ACH第三步,写清楚谁被改了。 这一步最容易丢分——结果写回的是目的操作数所在的主存单元,不是寄存器:
| 位置 | 改变前 | 改变后 |
|---|---|---|
| 主存 5678H | 1234H | 68ACH |
| R5 | 5678H | 5679H |
R4 不变(源只被读);主存 1234H 也不变(它只是被当作地址读了一次)。(R5)+ 的自增是指令的后效,写回之后才发生,两件事都要写上。
真题的两种形态
第一组 · 题面给指令格式表(2010-43、2013-44、2021-43、2024-43、2026-43)——给一张或几张字段定义表,多数会先问规模(多少条指令、多少寄存器、各寄存器多少位),再问机器码的正反翻译,最后挂一问执行追踪。(2013 年那道是这一组里的另类:它不问规模也不问机器码翻译,问的是编址单位、跳转条数、检测位怎么设、以及数据通路部件。)近几年的题面越来越像真实 ISA:2021 年那道是类 MIPS 的 R/I/J 三型,2024 年那道直接用了 RISC-V 的 add/slli/lw。
第二组 · 题面给反汇编(2017-44、2019-45、2023-44、2024-44)——给一段带虚拟地址的机器级代码,问指令地址、跳转目标、寻址方式、字节序,以及这段汇编对应的源程序在做什么。
两组的交界处有一类问法值得单独记:从汇编反推每个寄存器装的是什么角色。2024 年那道给出四条指令 slli/add/lw/add,靠「乘 4 = int 步长」「加基址 = 取地址」这样的语义线索,就能定出哪个寄存器是数组首地址、哪个是下标、哪个是累加和。
这类题是拼盘题的宿主
指令格式是骨架,其他章节的知识常常挂上来。认出哪一问是外挂,就知道该翻哪一章:
- 溢出与标志位(2024-43 问
add之后的OF/CF、2019-45 问imul何时OF=1与 13! 为什么算错、2017-44 问cmp之后的CF)——数据表示与运算; - 控制信号取值(2024-43 问
Ext、ALUctr、ALUBsrc)——数据通路; - 数据通路部件填空(2013-44 第 (4) 问)——数据通路;
- 缺页判定与页号计算(2023-44 问取指会不会缺页、2024-44 问
a[i]所在页号与数组跨几页)——虚拟存储器; - 读懂程序在做什么(2019-45 问递归调用几次、哪条一定跳转)——机器级程序表示。
骨架部分的分照样要拿。 这些外挂问通常独立给分,指令格式那几问答对就是稳的。
交卷前扫一眼
数:
的「宽」取哪一段 · 切:一行一段码回去 · 加:基准是下一条指令的地址 · MAR/MDR 先看题面给没给总线宽度
配套内容
考纲要求、但这 9 道真题没有正面考过的(专题的巩固栏里配了题):
- 逐级扩展操作码——真题考过操作码空间怎么分配(2021 年那道把
000000留给 R 型、剩下 63 个编码给 I/J 型),但没考过三地址用剩的编码借给二地址、二地址用剩的再借给一地址这种变长操作码 - 定长编码与变长编码的平均指令长度——真题只让判 CISC 还是 RISC,没让算过变长能省下多少存储空间
- 各种寻址方式各要访存几次的横向对比——真题问过的寻址方式有寄存器直接、寄存器间接、自增、相对、变址、以及立即(2023 年那道判过源操作数是立即寻址),但从没让把它们的访存次数摆在一起比过;直接寻址、间接寻址、堆栈寻址也没正面出现过
- 移位代替乘除在带符号数上的校正——2017 年那道只问了浮点数不能用
shl,没问带符号整数算术右移的取整偏差怎么补
逐题精讲(建设中)——真题作答与 AI 判分入口见站内大题专题。