5 、指令系统
一、指令的基本结构🧀
一条机器指令通常由两类字段组成:
- 操作码:说明要执行什么操作,如加法、访存或转移。
- 地址码:说明操作数在哪里、结果写到哪里,或者直接给出操作数。
1、指令字长🧀
| 类型 | 特点 | 典型代表 |
|---|---|---|
| 定长指令 | 每条指令长度相同,取指和译码简单,适合流水线 | MIPS、基础 RISC-V 指令 |
| 变长指令 | 不同指令占用的字节数不同,编码密度高,但译码复杂 | x86 |
顺序执行时,PC 增加的是当前指令所占的字节数。若一条指令分别占 1、2、4 字节,且起始地址为 0x1,下一条指令地址分别为 0x2、0x3、0x5。
2、扩展操作码🧀
操作码长度固定时,能够表示的操作数量固定。扩展操作码让地址数较少的指令借用空出的地址字段表示更多操作。
前缀约束
短操作码不能是更长操作码的前缀,否则译码器无法确定应当在哪里结束读取操作码。扩展操作码的设计本质上需要满足类似前缀编码的唯一可译码要求。
二、寻址方式🧀
形式地址是指令地址字段中给出的值,有效地址 EA 是经过寻址计算后得到的实际操作数地址。设形式地址为 \(D\),寄存器内容为 \((R)\)。
| 寻址方式 | 操作数或有效地址 | 特点 |
|---|---|---|
| 立即寻址 | 操作数 \(=D\) | 操作数直接编码在指令中,速度快,但数值范围有限 |
| 直接寻址 | \(EA=D\) | 一次访存即可取得操作数,寻址范围受地址字段长度限制 |
| 间接寻址 | \(EA=(D)\) | 先从内存取得有效地址,寻址范围大但访存次数多 |
| 寄存器寻址 | 操作数 \(=(R)\) | 操作数位于寄存器中,速度快 |
| 寄存器间接寻址 | \(EA=(R)\) | 寄存器保存操作数地址,便于处理指针 |
| 相对寻址 | \(EA=(PC)+\operatorname{signext}(D)\) | 常用于分支和位置无关代码 |
| 变址寻址 | \(EA=(IX)+D\) | 常用于数组,变址寄存器随元素位置变化 |
| 基址寻址 | \(EA=(BR)+D\) | 常用于程序重定位和分段,基址在一段计算期间通常保持稳定 |
| 堆栈寻址 | 操作数由栈顶指针隐含指出 | 地址字段可省略,适合函数调用和表达式求值 |
相对寻址、变址寻址和基址寻址都可以看作偏移寻址。三者的加法形式相似,区别在于寄存器的语义和主要用途。
容易记反
立即寻址的操作数在指令内部,不是“全部在主存中”。指令本身虽然存放在主存,但执行时无需再根据地址字段访问一次主存来取得该操作数。
三、指令类型🧀
常见机器指令可以分为:
- 数据传送:寄存器、主存和 I/O 设备之间传送数据,如
MOV、LOAD、STORE。 - 算术运算:加、减、乘、除及增量运算。
- 逻辑运算:与、或、异或、取反和位测试。
- 移位运算:逻辑移位、算术移位和循环移位。
- 程序控制:条件转移、无条件转移、循环控制、子程序调用和返回。
- 输入输出:显式 I/O 指令,或者通过存储器映射 I/O 完成访问。
对于补码定点数:
在固定位宽下,最高位产生的进位被丢弃;是否发生溢出要根据标志位判断。
1、常用状态标志🧀
| 标志位 | 含义 | 何时为 1 |
|---|---|---|
ZF | Zero Flag | 运算结果为 0 |
SF | Sign Flag | 运算结果最高位为 1 |
CF | Carry Flag | 无符号加法产生进位;采用借位语义的体系中,减法发生借位 |
OF | Overflow Flag | 有符号结果超出当前位宽的表示范围 |
有符号溢出的快速判断:
- 加法:两个同号数相加,结果与操作数异号。
- 减法:两个异号数相减,结果符号与被减数异常相反。
CF 的减法语义在不同指令集之间可能不同:有的体系把它定义为“发生借位”,有的保存“不借位”的进位输出。做题时应以题目或 ISA 的定义为准。
区分 CF 与 OF
设 32 位减法指令执行:
按无符号数理解,被减数大于减数,没有借位;若题目规定 CF=1 表示借位,则 \(CF=0\)。
按补码有符号数理解:
结果未超出 32 位有符号整数范围,因此 \(OF=0\)。
四、RISC 与 CISC🧀
| 对比 | RISC | CISC |
|---|---|---|
| 指令长度 | 通常固定或格式规整 | 常使用变长指令 |
| 指令格式 | 较少 | 较多 |
| 寻址方式 | 较少 | 较丰富 |
| 访存方式 | 常采用 Load/Store 结构 | 许多指令可以直接操作内存 |
| 寄存器 | 通常较多 | 传统设计中相对较少 |
| 控制方式 | 常用硬布线控制 | 传统上较常使用微程序控制 |
| 流水线 | 规则指令便于流水化 | 译码与执行时间更复杂 |
RISC 并不意味着“每条指令都只用一个周期”,现代处理器中的访存、乘除法、缓存缺失和分支预测失败仍可能需要多个周期。
RISC-V 的具体指令格式已经在“RISC-V 汇编语言”章节中说明,这里不再重复。
五、指令格式计算例题🧀
某计算机字长为 16 位,主存地址空间为 \(128\,\text{KB}\),按字编址,采用以下单字长指令:
Ms/Rs:源操作数的寻址方式与寄存器编号。Md/Rd:目的操作数的寻址方式与寄存器编号。
M | 寻址方式 | 含义 |
|---|---|---|
000 | 寄存器直接 | 操作数 \(=(R_n)\) |
001 | 寄存器间接 | 操作数 \(=M[(R_n)]\) |
010 | 寄存器间接、自增 | 先访问 \(M[(R_n)]\),再令 \(R_n\leftarrow R_n+1\) |
011 | 相对寻址 | 目标地址 \(=(PC)+(R_n)\) |
1、位数分析🧀
- 操作码 4 位,最多表示 \(2^4=16\) 条指令。
- 寄存器编号 3 位,最多表示 \(2^3=8\) 个寄存器。
- 主存按 16 位字编址,\(128\,\text{KB}/2\,\text{B}=64K=2^{16}\) 个字,因此
MAR至少 16 位。 - 一个存储字为 16 位,因此
MDR至少 16 位。
2、机器码分析🧀
已知 add 操作码为 0010B,求 add (R4), (R5)+ 的机器码:
拼接后得到:
若 \(R4=1234_H\)、\(R5=5678_H\)、\(M[1234_H]=5678_H\)、\(M[5678_H]=1234_H\),则:
目的操作数使用自增寻址,因此执行后: