# 指令系统

## **CPU指令的执行流程**

几乎所有的冯•诺伊曼型计算机的CPU，其工作都可以分为5个阶段：取指令、译码、执行、访存取数和结果写回

### 取指令阶段

取指令（Instruction Fetch，IF）阶段是将一条指令从主存中取到指令寄存器的过程。

程序计数器PC中的数值，用来指示当前指令在主存中的位置。当一条指令被取出后，PC中的数值将根据指令字长度而自动递增：若为单字长指令，则(PC)+1；若为双字长指令，则(PC)+2，依此类推。

### 指令译码阶段

取出指令后，计算机立即进入指令译码（Instruction Decode，ID）阶段。

在指令译码阶段，指令译码器按照预定的指令格式，对取回的指令进行拆分和解释，识别区分出不同的指令类别以及各种获取操作数的方法。

在组合逻辑控制的计算机中，指令译码器对不同的指令操作码产生不同的控制电位，以形成不同的微操作序列；在微程序控制的计算机中，指令译码器用指令操作码来找到执行该指令的微程序的入口，并从此入口开始执行。

### 执行指令阶段

在取指令和指令译码阶段之后，接着进入执行指令（Execute，EX）阶段。

此阶段的任务是完成指令所规定的各种操作，具体实现指令的功能。为此，CPU的不同部分被连接起来，以执行所需的操作。

### 访存取数阶段

根据指令需要，有可能要访问主存，读取操作数，这样就进入了访存取数（Memory，MEM）阶段。

此阶段的任务是：根据指令地址码，得到操作数在主存中的地址，并从主存中读取该操作数用于运算。

### 结果写回阶段

作为最后一个阶段，结果写回（Write Back，WB）阶段把执行指令阶段的运行结果数据“写回”到某种存储形式。

结果数据经常被写到CPU的内部寄存器中，以便被后续的指令快速地存取；

在有些情况下，结果数据也可被写入相对较慢、但较廉价且容量较大的主存。许多指令还会改变程序状态字寄存器中标志位的状态，这些标志位标识着不同的操作结果，可被用来影响程序的动作。

在指令执行完毕、结果数据写回之后，若无意外事件（如结果溢出等）发生，计算机就接着从程序计数器PC中取得下一条指令地址，开始新一轮的循环，下一个指令周期将顺序取出下一条指令。

许多新型CPU可以同时取出、译码和执行多条指令，体现出并行处理的特性。

## 机器指令

* 机器指令：机器语言的语句称为机器指令。
* 指令系统：全部机器指令的集合称为机器的指令系统。机器的指令系统集中反映了机器的功能

机器指令一般包括操作码和地址码两部分，如图：

![机器指令一般格式](https://img-blog.csdnimg.cn/img_convert/3ce0f7505de9799422ab6057b457fb79.png)

### 1. 操作码

* 作用：指明该指令所要执行的操作，可能还要指出操作数的类型、寻址方式等
* 长度：操作码的长度可能是固定的，也可能是可变的
  1. 长度固定：用于指令字长较长的情况，如IBM370
  2. 长度可变：操作码分散在指令字的不同字段中

> 为什么要使用扩展操作码技术？

在指令字长确定的情况下，使用扩展操作码技术可以有效扩大指令数。这一点之后的讲解中会体现出来

> 扩展操作码技术有哪些？

扩展操作码技术有两种：

1. 保留某一位作为扩展标志进行扩展
2. 保留码点作为扩展标志进行扩展

这里介绍第二种。

> 保留码点作为扩展标志进行扩展

如图，假设一条指令包含了1个操作码和3个地址码，指令字长为16位，操作码占4位。如图：

![4位操作码指令例子](https://img-blog.csdnimg.cn/img_convert/3413c251a18de8d2bbd69ec391358b39.png)

其所能产生的指令如下：

![4位操作码指令条数](https://img-blog.csdnimg.cn/img_convert/f9edd8a3d491eaf74bf11751a4e3d0ff.png)

需要注意：

1. 三地址指令：地址码有三个A1、A2、A3
2. 4位操作码能够生成的指令原本应该是16条，但这里仅使用了15条。原因就在于：保留了操作码1111作为扩展标志，假如OP使用的是1111，就代表占用了地址码 A1进行扩展操作码，操作码就成为8位，如下图所示：

![8位操作码扩展](https://img-blog.csdnimg.cn/img_convert/fec4a00367afede4639421c0067e5575.png)

* 这里同样保留了操作码1111 1111作为扩展标志，代表该指令系统仍能进行扩展。最终的扩展如下：

![4位操作码最终扩展](https://img-blog.csdnimg.cn/img_convert/aa07b9c1bf74e55cc441defb341ac8fc.png)

4位操作码指令原本仅能表示16条指令，但使用了扩展操作码技术后，能够表示61条指令。

### 2. 地址码

* 作用：指出操作数、下一条指令等的地址
* 对于一条指令而言，它可能有多个地址码，也可能没有地址码。其中：
  1. 包含0个地址字段的称为：零地址指令
  2. 包含1个地址字段的称为：一地址指令
  3. 包含2个地址字段的称为：二地址指令
  4. …

接下来介绍不同指令中地址码的作用

> 四地址指令如图

![四地址指令](https://img-blog.csdnimg.cn/img_convert/5b7b7ef185d6e980a63f44db7a661855.png)

四次访存：

1. 取指令（上一条指令的 A4）
2. 取第一操作数
3. 取第二操作数
4. 存结果

若使用PC代替 A4，就成了三地址指令。每执行一条指令，PC+1（指令计数器）

**三地址指令**

![三地址指令](https://img-blog.csdnimg.cn/img_convert/10be421d20df337b0869c376836977fd.png)

若用 A1或A2代替 A3，就成为了二地址指令

**二地址指令**

![二地址指令](https://img-blog.csdnimg.cn/img_convert/496e4bcf4cccae6b94a1e30f08aed837.png)

若使用ACC（累加器）替代 A1或A2，将结果保存在ACC中，就成了一地址指令。

**一地址指令**

![一地址指令](https://img-blog.csdnimg.cn/img_convert/051021e01f5cc31f1b26b7659c0faa70.png)

* 取指令（PC）
* 取 A1中的操作数

### 3. 指令字长

指令字长取决于：

1. 操作码的长度
2. 操作数地址的长度
3. 操作数的地址个数

* 早期计算机，指令字长固定：指令字长=机器字长=存储字长
* 现代计算机，指令字长可变：一般为字节的整数倍。其中高频指令一般被设置为短操作码指令/短字节指令

> 小结
>
> * 当用一些硬件资源代替指令字中的地址码字段后
>   1. 可扩大指令的寻址范围
>   2. 可缩短指令字长
>   3. 可减少访存次数
> * 当指令的地址字段为寄存器时
>   1. 可缩短指令字长
>   2. 指令执行阶段不访存

## 寻址方式

### 1. 指令寻址

指令寻址有两种方式：

1. 顺序寻址：PC指令计数器实现，每条指令执行后，PC+1，得到下一条指令地址
2. 跳跃寻址：由转移指令指出下一条指令的地址

![指令寻址](https://img-blog.csdnimg.cn/img_convert/09821525379e9565d42e89b2bee3b1f7.png)

> 需要注意：PC+1中的1是一个指令的字长

### 2. 数据寻址

从数据寻址的角度看，指令的一般格式如下：

![数据寻址指令一般格式](https://img-blog.csdnimg.cn/img_convert/3fa36a8ef9bdc4a9a2d4aa4834c6151d.png)

* 寻址特征：数据寻址共有10种不同的寻址方式，寻址特征字段通过不同的符号表明该指令操作数的寻址方式
* 形式地址Ａ：就是数据在指令字中的地址，实际上它不是操作数的真实地址（对某些寻址方式而言）
* 有效地址：操作数的真实地址

> 为了分析的简便，以下设定分析采用的模型机满足：指令字长 = 存储字长 = 机器字长
>
> * EA 代表操作数的真实地址
> * 均以单地址指令为例

**1. 立即寻址**

特征：形式地址A就是操作数。即指令中直接携带操作数，不需要访存取操作数。如图：

![立即寻址](https://img-blog.csdnimg.cn/img_convert/6a8c4f76fadea145fb70859f7e309799.png)

* \#是立即寻址的特征
* 立即寻址的特点：
  1. 指令执行阶段不访存（因为不需要取操作数）
  2. A 的位数限制了立即数的范围

**2. 直接寻址**

特征： EA=A，有效地址由形式地址直接给出。即形式地址A保存的就是操作数的真实地址。如图：

特点：

1. 执行阶段访问一次存储器（取操作数）
2. A 的位数决定了该指令操作数的寻址范围（做题时可根据直接寻址范围逆推A的位数）
3. 操作数的地址不易修改（必须修改A）

**3. 隐含寻址**

特征：操作数地址隐含在操作码中。比如之前一地址指令的例子，对于一地址的加法指令，另一个操作数隐含在ACC中。隐含寻址如图：

![隐含寻址](https://img-blog.csdnimg.cn/img_convert/fa409feeb41bd11058e63f75576ff816.png)

* 指令字中少了一个地址字段，可缩短指令字长。
* 需要注意：隐含的操作数地址，实际上该操作数是通过另一条存取指令放至ACC中的

**4. 间接寻址**

特征： EA=（A），有效地址由形式地址间接提供。

> * 一次间接寻址：形式地址保存一个存储单元的地址，该存储单元保存的才是操作数的真实地址
> * N次间接寻址：形式地址保存存储单元 A1地址， A1保存 A2的地址…最后的 An保存的才是操作数的真实地址

![间接寻址](https://img-blog.csdnimg.cn/img_convert/e16e4fd1fbfd49dc3f30c9112d47fe2f.png)

* 指令执行阶段访存次数：
  1. 一次寻址：2次
  2. N次寻址： N+1 次
* 可扩大寻址范围
* 便于编制程序，可以通过修改间接存储单元中的真实地址实现修改操作数

**5. 寄存器寻址**

特征： EA=Ri，有效地址即为寄存器编号。

![寄存器寻址](https://img-blog.csdnimg.cn/img_convert/ba0e4a799086d2a027bbb5556703398f.png)

* 执行阶段不访存，只访问寄存器，执行速度快
* 寄存器个数有限，可缩短指令字长
* Ri的位数决定存储器的个数。（逆推存储器位数）

**6. 寄存器间接寻址**

特征： EA=(Ri)，形式地址A保存寄存器地址 Ri，寄存器保存操作数真实地址。

![寄存器间接寻址](https://img-blog.csdnimg.cn/img_convert/269f2d35220f18e55f1713d7304497ef.png)
