Instruction System Basics
指令是计算机执行某种操作的命令,是计算机运行的最小功能单位。一台机器能够识别并执行的全部机器指令构成它的指令系统,也称为指令集ISA。
指令系统处在软件和硬件之间:高级语言程序最终必须被翻译成机器指令;硬件则按指令中的字段完成取数、运算、访存、转移和控制等动作。不同体系结构的机器指令格式和指令含义不同,因此一台机器通常只能直接执行自己指令系统中的指令。
指令格式
一条机器指令是一组有意义的二进制代码,通常由操作码字段和地址码字段组成。
- 操作码(Operation Code,
OP):指出指令要做什么操作,例如加法、传送、转移、停机。 - 地址码:指出操作对象在哪里,可能表示操作数地址、结果地址、寄存器编号、立即数或下一条指令地址。
地址码的数量并不固定。根据显式地址码个数,指令可以分为零地址、一地址、二地址、三地址和四地址指令。
| 类型 | 常见格式 | 典型含义 | 执行阶段访存次数 |
|---|---|---|---|
| 零地址指令 | OP |
不需要操作数;或在堆栈机中隐含使用栈顶、次栈顶 | 通常为 0 |
| 一地址指令 | OP A1 |
OP(A1) -> A1,或 (ACC) OP (A1) -> ACC |
常见为 1-2 次 |
| 二地址指令 | OP A1 A2 |
(A1) OP (A2) -> A1 |
常见为 3 次 |
| 三地址指令 | OP A1 A2 A3 |
(A1) OP (A2) -> A3 |
常见为 3 次 |
| 四地址指令 | OP A1 A2 A3 A4 |
(A1) OP (A2) -> A3,且 A4 给出下址 |
常见为 3 次 |
上表的访存次数只统计执行阶段访问操作数和写回结果的次数,不统计取指本身。若某个操作数在寄存器中,或结果写入寄存器,访存次数会减少。
指令字长
指令字长是一条机器指令包含的二进制位数,也就是 OP 字段、地址码字段以及其他辅助字段合起来的总位数。
例如某条指令格式为:
1 | OP(6) + A1(10) |
则这类指令的指令字长为:
$$
6+10=16\text{ 位}
$$
- 定长指令字结构:所有指令长度相同,取指和译码较简单。
- 变长指令字结构:不同指令长度可以不同,编码更灵活,但取指和译码更复杂。
如果指令字长等于存储字长,则一次访存通常能取出一条指令;如果指令字长大于存储字长,则一条指令可能需要多次访存才能取完。
- 指令字长:一条机器指令有多少位,回答“这条指令编码有多长”。
- 机器字长:CPU 一次能直接处理的数据位数,常与通用寄存器位数、ALU 位数相关。
- 存储字长:主存一个存储单元可保存的二进制位数,或一次存储读写的数据宽度。
- 主存地址位数:地址编码有多少位,决定最多能区分多少个可寻址单元。
它们之间可能相等,也可能不相等。比如某机器的机器字长为 32 位,指令字长也可能是 16 位、32 位或变长;主存按字节编址时,一个地址只指向 8 位的字节,但 CPU 仍然可以一次处理 32 位数据。
求指令格式、操作码扩展、地址码分配时,关注的是指令字长;求 ALU、通用寄存器、整数运算范围时,关注的是机器字长;求一次访存能取多少位、指令要取几次时,才需要看存储字长或编址单位。
操作码可以采用定长,也可以采用可变长。
| 类型 | 含义 | 优点 | 代价 |
|---|---|---|---|
| 定长操作码 | 所有指令的 OP 字段位数相同 |
译码简单,硬件实现方便 | 指令种类受固定 OP 位数限制 |
| 可变长操作码 | 不同指令的 OP 字段位数可以不同 |
在固定指令字长内容纳更多指令种类 | 译码规则更复杂 |
若操作码有 $n$ 位,且全部采用定长操作码,则最多可表示 $2^n$ 条不同指令。
扩展操作码
扩展操作码是一种常见的定长指令字结构可变长操作码设计:地址码少的指令,可以把原本不再需要的地址码字段继续用作操作码字段。
例如指令字长为 16 位,每个地址码为 4 位。若先把前 4 位作为基本操作码:
- 三地址指令格式:
OP(4) + A1(4) + A2(4) + A3(4); - 二地址指令格式:
OP(8) + A1(4) + A2(4); - 一地址指令格式:
OP(12) + A1(4); - 零地址指令格式:
OP(16)。
扩展操作码必须满足两个规则:
- 短操作码不能是长操作码的前缀。否则取到短码时,硬件无法判断它是一条短操作码指令,还是某条长操作码指令的开头。
- 任何两条指令的操作码不能重复。否则相同编码会对应两个不同操作,译码无法唯一确定。
扩展操作码指令设计
扩展操作码指令的设计要看码空间怎么被逐层占用。
以 16 位指令字、4 位地址码为例:
| 指令类型 | 操作码位数 | 每保留 1 个上层短码可扩展出的本层编码数 |
|---|---|---|
| 三地址 | 4 |
- |
| 二地址 | 8 |
$2^4=16$ |
| 一地址 | 12 |
$2^4=16$ |
| 零地址 | 16 |
$2^4=16$ |
若有 m 条三地址指令:
- 三地址层共有 $2^4=16$ 个基本短码。
- 用掉
m个三地址短码后,还剩 $16-m$ 个短码可继续向下扩展。 - 每个剩余短码可接上
4位,扩展出 $2^4$ 个二地址操作码。
所以二地址指令最多为:
$$
(16-m)\times 2^4
$$
如果还给定了二地址指令数量,就继续扣除二地址层已占用的编码,再把剩余二地址编码向下一层扩展。
指令字长 16 位,每个地址码 4 位。若已定义 15 条三地址指令,则只剩 1 个四位短码可扩展,所以最多能定义:
- 二地址指令:$1\times 2^4=16$ 条;
- 若二地址指令只用
15条,则还能留下1个八位操作码继续扩展; - 一地址指令最多:$1\times 2^4=16$ 条;
- 若一地址指令只用
15条,则还能留下1个十二位操作码继续扩展; - 零地址指令最多:$1\times 2^4=16$ 条。
设每个地址码长度为 a,每向下一层扩展一次,就多出 $2^a$ 个更长操作码。因此:
若要容纳 $N_0$ 条零地址指令,至少要在一地址层预留 $\lceil N_0/2^a\rceil$ 个操作码入口。
若还要容纳 $N_1$ 条一地址指令,则一地址层总共需要
$$
N_1+\left\lceil\frac{N_0}{2^a}\right\rceil
$$个操作码位置。
再把这些需求折算到二地址层:二地址层需要
$$
N_2+\left\lceil\frac{N_1+\left\lceil N_0/2^a\right\rceil}{2^a}\right\rceil
$$个操作码位置。
继续向上折算到最高地址数那一层。最高层需要多少个操作码位置,就决定最高层操作码至少要多少位。
字长必须是计算机的编制单元位数的整数倍
计算机按字节编址,地址码长度为 6 位,只有两种指令格式。要求支持 29 条三地址指令和 107 条二地址指令,求指令字长至少多少位。
这里只有三地址和二地址指令。二地址层需要 107 个操作码,折算到三地址层,需要预留:
$$
\left\lceil\frac{107}{2^6}\right\rceil=2
$$
个三地址层操作码入口。
三地址层还要直接容纳 29 条三地址指令,所以三地址层总共需要:
$$
29+2=31
$$
个操作码位置。
因为 $\lceil \log 31 \rceil = 5$,所以三地址层操作码至少要 5 位。三地址指令还需要 3 个地址码,每个 6 位,因此指令字长至少为:
$$
5+3\times6=23
$$
[!question] 因此最少指令字长为
23位。对吗????
[!important] 错误!
由于计算机按字节编址,指令字长必须得是8的整数倍!
所以正确答案:24
指令也可以按功能分类。
| 类型 | 作用 | 例子 |
|---|---|---|
| 数据传送指令 | 在寄存器、主存、I/O 端口之间传送数据 | LOAD、STORE、MOV |
| 算术逻辑指令 | 完成加减乘除、与或非、比较等操作 | ADD、SUB、AND、CMP |
| 移位指令 | 对操作数进行逻辑移位、算术移位或循环移位 | SHL、SAR |
| 转移指令 | 改变程序执行顺序 | 无条件转移、条件转移、调用、返回、陷阱 |
| 输入输出指令 | 在 CPU 和外设接口之间传送数据或状态 | 端口输入、端口输出 |
| CPU 控制指令 | 改变 CPU 或系统运行状态 | 开中断、关中断、设置程序状态字 |
CPU 控制指令通常影响整个系统的运行状态,因此属于特权指令。
CPU 区分两种运行状态:
- 用户态:运行普通应用程序,只能执行非特权指令。
- 内核态:运行操作系统内核程序,可以执行特权指令。
CPU 当前处于哪种状态,通常由程序状态字寄存器(PSW)中的状态位表示。用户态程序若试图执行特权指令,会触发异常处理,CPU 转入内核态,由操作系统接管并决定如何处理。
陷阱(Trap)也会改变程序执行流。它常用于从当前程序转入预设的系统处理程序,例如系统调用、调试断点或异常处理入口。
指令系统还可以从设计风格上分为 CISC 和 RISC。