8086汇编——寄存器

一个典型的 CPU 是由运算器、控制器、寄存器等器件组成,这些器件靠内部总线相连。
它们在 CPU 中扮演着各自的角色:

  • 运算器进行信息处理;
  • 寄存器进行信息存储;
  • 控制器控制各种器件进行工作;
  • 内部总线连接各部件,在它们之间进行数据传输。

对于一个汇编程序员来说,寄存器是我们需要关心的部件,是我们可以用指令进行读写的部件。我们可以通过改变各种寄存器中的内容来实现对 CPU 的控制。

不同的 CPU 寄存器的个数、结构是不同的。8086 CPU 有 14 个寄存器,每个寄存器有一个名称:AX, BX, CX, DX, SI, DI, SP, BP, IP, CS, SS, DS, ES, PSW。

通用寄存器

8086 CPU 的所有寄存器都是 16 位的,可以存放两个字节。AX, BX, CX, DX 这 4 个寄存器通常用来存放一般性数据,被称为通用寄存器。下图展示了数据在 16 位寄存器中的存放情况:

8086 CPU 的上一代 CPU 中的寄存器是 8 位的,为了保证兼容性,使原来基于上代 CPU 编写的程序稍加修改就可以运行在 8086 CPU 之上, 8086 CPU 的 AX, BX, CX, DX 这 4 个寄存器都可以分为两个独立使用的 8 位寄存器来用:

  • AX 可分为 AH 和 AL;
  • BX 可分为 BH 和 BL;
  • CX 可分为 CH 和 CL;
  • DX 可分为 DH 和 DL;

AX 的低 8 位 (0~7) 构成了 AL 寄存器,高 8 位 (8~15) 构成了 AH 寄存器。AH 和 AL 寄存器是可以独立使用的 8 位寄存器。下图展示了 16 位寄存器以及它所分成的两个 8 位寄存器的数据存储情况:

段寄存器

我们知道 CPU 在访问内存时要由相关部件提供内存单元的段地址和偏移地址,送入地址加法器合成物理地址。段地址在 8086 CPU 的段寄存器中存放。8086 CPU 有 4 个段寄存器:CS, DS, SS, ES。当 8086 CPU 要访问内存时由这 4 个段寄存器提供内存单元的段地址。

CS 和 IP 寄存器

CS 和 IP 是 8086 CPU 中两个最关键的寄存器,它们指示了 CPU 当前要读取指令的地址。CS 为代码段寄存器,IP 为指令指针寄存器,从名称就可以看出它们跟 CPU 执行指令相关。

在 8086 计算机中任意时刻,设 CS 中的内容为 M,IP 中的内容为 N, 8086 CPU 将从内存 M*16+N 单元开始,读取一条指令并执行。下图展示了 8086 CPU 读取、执行指令的过程:

  1. 在初始状态时,CS:2000H,IP:0000H,CPU 将从内存 2000H*16+0000H(20000H) 处读取指令;
  2. CS,IP 寄存器中的内容送入地址加法器,地址加法器完成:物理地址=段地址 x16+偏移地址
  3. 地址加法器将物理地址送入输入输出控制电路;
  4. 输入输出控制电路将物理地址 20000H 送人地址总线;
  5. 从内存 20000H 单元开始存放的机器指令 B8 23 01 通过数据总线被送入 CPU;
  6. 输入输出电路控制电路将机器指令 B8 23 01 送入指令缓冲器。读取一条指令后,IP 中的值自动增加,长度为指令的长度(例子中的长度为 3 个字节),CPU 就可以读取下一条指令了。此时,CS:IP 指向 2000:0003H 的内存单元;
  7. 执行控制器执行指令:B8 23 01,即 mov ax, 0123H

从上面的过程中我们可以将 8086 CPU 的工作过程描述如下:

  1. 从 CS:IP 指向的内存单元读取指令,读取的指令进入指令缓冲器;
  2. IP = IP + 所读取指令的长度,从而指向下一条指令;
  3. 执行指令,转到步骤 1,重复这个过程。

代码段

对于 8086 计算机,在编程时可以根据需要将一组内存单元定义为一个段。我们可以将长度为 N (N≦64KB) 的一组代码存在一组地址连续、起始地址为 16 的倍数的内存单元中,我们可以认为这段内存是用来存放代码的,从而定义了一个代码段。

1
2
3
4
mov ax, 0000       (B8 00 00)
add ax, 0123H (05 23 01)
mov bx, ax (8B D8)
jmp bx (FF E3)

上面这段长度为 10 个字节的指令存放在 123B0H~123B9H 的一组内存单元中,我们就可以认为 123B0H~123B9H 这段内存是用来存放代码的,是一个代码段,它的段地址为 123B0H,长度为 10 个字节。

如何使得代码段中的指令被执行呢?将一段内存当做代码段仅仅是我们在编程时的一种安排,CPU 并不会由于这种人为的安排就自动地将我们定义的代码段中的指令当做指令来执行。CPU 只认被 CS:IP 指向的内存单元中的内容为指令。所以,要让 CPU 执行我们放在代码段中的指令,必须要将 CS:IP 指向所定义的代码段中的第一条指令的首地址。对于上面的例子,我们如果要让 CPU 执行这段代码,可设 CS=123BH, IP=0000H。