第 3 章 8086
一. 基本数据类型
Section titled “一. 基本数据类型”1. 字、双字的对齐
Section titled “1. 字、双字的对齐”数据保存在内存时一个单元存放一个字节
数据保存时低字节(0~7位)占用内存中的低地址,此地址就是操作数的地址
在进行数据保存时,字和双字在内存中尽量做到对齐自然边界
对于不对齐的存储访问,处理器要求做两次存储访问操作;而对于对齐的访问,只要做一次存储访问操作。
2. 数字数据类型
Section titled “2. 数字数据类型”2.1. 无符号整数
Section titled “2.1. 无符号整数”2.2. 带符号整数
Section titled “2.2. 带符号整数”3. 指针数据类型
Section titled “3. 指针数据类型”3.1. 近指针
Section titled “3.1. 近指针”16 位,分段存储模式中用于同一段内的存储器引用
3.2. 远指针
Section titled “3.2. 远指针”32 位,分段存储模式中的跨段存储引用

4. 串数据类型
Section titled “4. 串数据类型”串是位、字节、字或双字的连续序列
二. 8086 的指令格式
Section titled “二. 8086 的指令格式”[<标号>: ] | <指令助记符> | [<操作数>] | [; <注释>] |
|---|---|---|---|
LOADREG: | MOV | AX, BX | ; AX <- AX + BX |
8086机器指令包含零个或多个操作数。某些操作数是显式规定的,有的是指令中隐含的(eg. 偏移地址)。操作数能定位在 立即数 寄存器 存储单元 I/O 端口 中
指令中并不直接给出操作数的数值,而给出操作数存放的地址、寄存器的地址或存储单元的地址。操作数的地址也不直接给出,给出计算方法。
三. 8086 指令的操作数寻址方式
Section titled “三. 8086 指令的操作数寻址方式”1. 立即数
Section titled “1. 立即数”大部分算术指令均允许源操作数是立即数,但 DIV 和 IDIV 等不允许源操作数是立即数
ADD AX, 142. 寄存器寻址
Section titled “2. 寄存器寻址”操作数在寄存器中,寄存器的内容就是操作数的数值,操作数用寄存器的符号来表示
INC AX
3. 存储器寻址
Section titled “3. 存储器寻址”操作数在存储器中,出入微处理器都需经过总线
当 EU 读写一个存储器操作数时,须将一个偏移地址传送给 BIU,BIU 经过地址运算后产生一个 20 位物理地址,然后执行存取该操作数所需的总线周期
EU 为一个存储器操作数而计算出来的偏移量称为操作数的有效地址 EA,这是一个 16 位无符号数,表示该操作数所在存储单元与所在段起始地址的距离(以字节为单位)
内存操作数地址 = (段地址 << 4) + 偏移地址
3.1. 规定段地址
Section titled “3.1. 规定段地址”[[undergraduate/Intel8086/c2-IA32-8086#^memory-organization]]
3.2. 规定偏移量
Section titled “3.2. 规定偏移量”内存地址的偏移量部分或者直接作为一个静态值(称为位移量)规定或者由以下一个或多个成员通过计算得到地址:
- 位移量:一个 8 位或 16 位值
- 基地址:在通用寄存器中的值
- 索引:在通用寄存器中的值
作为基地址或索引的通用寄存器限制如下:
- SP 寄存器不能用作索引寄存器
- 当 SP 或 BP 寄存器用作为基地址,SS 段是默认的段
- 在其他情况下 DS 段是默认段
3.2.1. 位移量
Section titled “3.2.1. 位移量”位移量代表操作数的直接(不计算)偏移。因为位移量是编码在指令中的,地址的这种形式称为绝对或静态地址。

EA = (DS << 4) + MASKAX = [EA]3.2.2. 基地址
Section titled “3.2.2. 基地址”单独一个基地址表示操作数的间接偏移量,因为在基地址寄存器(BX/BP)中的值能够改变,它能用于变量和数据结构的动态存储。

EA = (SS << 4) + BP3.2.3. 基地址 + 位移量
Section titled “3.2.3. 基地址 + 位移量”以基址寄存器 BX 或 BP 的内容为基准地址,指令再给出一个地址位移量 D(D8或D16),它们组合而得存储器操作数的有效地址。
当使用 BP 作基址寻址时,若无指定段替换,则内定在堆栈段内寻址。
可以作为数组的索引,位移量作为到数组开始处的静态偏移,基地址寄存器来确定到数组中规定的元素的偏移。
可以用来访问记录中的一个字段,其中基地址寄存器保持记录的开始地址,而位移量是字段的静态偏移。

EA = (DS << 4) + SI + COUNT3.2.4. 索引(变址)+ 位移量
Section titled “3.2.4. 索引(变址)+ 位移量”当数组的元素是 2、4 或 8 字节时,这种地址方式为索引进入静态数组提供了有效的方法。位移量定位数组的开始,索引寄存器(即变址寄存器 SI/DI)保持所希望的数组元素的下标
EA = MASK + SI3.2.5. 基地址 + 索引(变址)
Section titled “3.2.5. 基地址 + 索引(变址)”用两个寄存器一起提供访问的存储单元的有效地址,即操作数的有效地址用一个基址寄存器(BX/BP)和一个变址寄存器(SI/DI)的内容之和表示。
在不使用段超越前缀的情况下,规定如果有效地址中含有 BP,则缺省的段寄存器为 SS;否则,缺省的段寄存器为 DS。
EA = (SS << 4) + BP + SIEA = (DS << 4) + BX + SI3.2.6. 基地址 + 索引 + 位移量
Section titled “3.2.6. 基地址 + 索引 + 位移量”用两个寄存器和位移量一起提供访问的存储单元的有效地址,即操作数的有效地址用一个基址寄存器(BX/BP)中的内容和一个变址寄存器(SI/DI)中的内容,以及一个位移量的和表示。

EA = (DS << 4) + SI + BX + MASK4. I/O 端口寻址
Section titled “4. I/O 端口寻址”X86 支持 8 位 I/O 端口地址空间,I/O 接口的端口地址为 0000H ~FFFFH,共计 65536 个 I/O 端口。在 I/O 地址空间中也可以定义 16 位和 32位 的端口。
若端口地址为 00H~FFH,可以用立即数直接寻址;超出字节范围的端口地址必须存放在 DX 寄存器中,间接寻址。
- I/O 端口用立即数寻址,只能用 8 位立即数,可寻址 I/O 地址空间的前 256 个端口
- I/O 端口用 DX 寄存器间接寻址,可寻址全部 I/O 地址空间
IN AL, <端口地址/DX>OUT <端口地址/DX>, AL四. 8086 的通用指令
Section titled “四. 8086 的通用指令”- 指令
- 一条指令对应一条基本操作。
- 指令由操作码(OP)和操作数(OD)组成。
- 操作码(OP)是指令操作功能,操作数(OD)是指令的操作数据。
- 指令系统
- 全部指令的集合。
- 指令系统是计算机硬件实现软件编程的基础。
- 字节/字
- B : 字节 8 bit
- W : 字 16 bit
1. 数据传送指令
Section titled “1. 数据传送指令”| 助记符 | 功能 | 备注 | |
|---|---|---|---|
| 通用数据传送指令 | MOV | 传送字节或字 | |
| ^^ | PUSH | 字入栈 | SP <- SP - 2 |
| ^^ | POP | 字出栈 | SP <- SP + 2 |
| ^^ | XCHG | 交换字或字节 | |
| ^^ | XLAT | 字节转换 | |
| 地址目标传送指令 | LEA | 装入有效地址 | |
| ^^ | LDS | 将指针变量装入寄存器及 DS | |
| ^^ | LES | 将指针变量装入寄存器及 ES | |
| 标志传送指令 | LAHF | 标志寄存器低字节送 AH | |
| ^^ | SAHF | AH 值送标志寄存器低字节 | |
| ^^ | PUSHF | 标志寄存器内容进栈 | |
| ^^ | POPF | 标志寄存器内容出栈 | |
| I/O 指令 | IN | 输入字节或字 | IN AX, <端口地址/DX> |
| ^^ | OUT | 输出字节或字 | OUT <端口地址/DX>, AX |
2. 算术运算指令
Section titled “2. 算术运算指令”| 助记符 | 功能 | 备注 | |
|---|---|---|---|
| 加法指令 | ADD | 加法 | dest <- dest + src |
| ^^ | ADC | 带进位的加法 | dest <- dest + src + CF |
| ^^ | INC | 增量 1 | src <- src + 1 |
| ^^ | AAA | 加法的 ASCII 修正 | |
| ^^ | DAA | 加法的十进制修正 | |
| 减法指令 | SUB | 减法 | dest <- dest - src |
| ^^ | SBB | 带借位的减法 | dest <- dest - src - CF |
| ^^ | DEC | 减量 1 | src <- src - 1 |
| ^^ | NEG | 求补(变负) | |
| ^^ | CMP | 比较 | 置位 AF CF OF PF SF ZF |
| ^^ | AAS | 减法的 ASCII 修正 | |
| ^^ | DAS | 减法的十进制修正 | |
| 乘法指令 | MUL | 无符号乘法 | B : AX <- AX * src |
| ^^ | IMUL | 整数乘法 | ^^ W : DX:AX <- AX * src |
| ^^ | AAM | 乘法的 ASCII 修正 | |
| 除法指令 | DIV | 无符号除法 | B : AL <- AX / src, AH=余数 |
| ^^ | IDIV | 整数除法 | ^^ W : AX <- DX:AX / src, DX=余数 |
| ^^ | AAD | 除法的 ASCII 修正 | |
| ^^ | CBW | 字节转换为字 | |
| ^^ | CWD | 字转换为字节 |
3. 逻辑运算和移位指令
Section titled “3. 逻辑运算和移位指令”| 助记符 | 功能 | 备注 | |
|---|---|---|---|
| 逻辑运算指令 | AND | 与 | dest <- dest & src |
| ^^ | OR | 或 | dest <- dest 丨 src |
| ^^ | NOT | 非 | src <- ~src |
| ^^ | XOR | 异或 | dest <- dest ^ src |
| ^^ | TEST | 测试(与) | 仅改变标志位 |
| 移位指令 | SHL | 逻辑左移 | dest <- dest << src 移出位放入 CF |
| ^^ | SAL | 算数左移 | dest <- dest << src 移出位放入 CF |
| ^^ | SHR | 逻辑右移 | 左侧补 0 移出位放 CF |
| ^^ | SAR | 算术右移 | 左侧补符号位 移出位放 CF |
| 循环移位指令 | ROL | 循环左移 | 直接将移出放入移入 |
| ^^ | ROR | 循环右移 | ^^ 并将移出的位放入 CF |
| ^^ | RCL | 通过 CF 循环左移 | 将移出放入 CF |
| ^^ | RCR | 通过 CF 循环右移 | ^^ 并将 CF 放进移入 |
4. 控制转移指令
Section titled “4. 控制转移指令”| 助记符 | 功能 | 备注 | |
|---|---|---|---|
| 无条件跳转指令 | CALL | 调用过程(子过程) | |
| ^^ | RET | 从过程(子程序)返回 | |
| ^^ | JMP | 无条件转移 | |
| 条件跳转指令 | JA/JNBE | Jump above | 无符号 |
| ^^ | JAE/JNB | Jump above equal | ^^ |
| ^^ | JB/JNAE | Jump below | ^^ |
| ^^ | JBE/JNA | Jump below equal | ^^ |
| ^^ | JC | Jump CF == 1 | |
| ^^ | JE/JZ | Jump equal/zero | |
| ^^ | JG/JNLE | Jump greater | 带符号 |
| ^^ | JGE/JNL | Jump greater equal | ^^ |
| ^^ | JL/JNGE | Jump less | ^^ |
| ^^ | JLE/JNG | Jump less equal | ^^ |
| ^^ | JNC | Jump CF == 0 | |
| ^^ | JNE/JNZ | Jump not equal/zero | |
| ^^ | JNO | Jump not overflow | |
| ^^ | JNP/JPO | Jump PF == 0 | |
| ^^ | JNS | Jump SF == 0 | |
| ^^ | JO | Jump overflow | |
| ^^ | JP/JPE | Jump PF == 1 | |
| ^^ | JS | Jump SF == 1 | |
| ^^ | JCXZ | Jump CX == 0 | |
| 重复控制指令 | LOOP | 循环 | CX != 0 循环,CX-- |
| ^^ | LOOPE/LOOPZ | 等于/为零循环 | CF != 0 && ZF == 1 |
| ^^ | LOOPNE/LOOPNZ | 不等于/不为零循环 | CF != 0 && ZF == 0 |
| 中断指令 | INT | 中断 | |
| ^^ | INT3 | 断点中断 | |
| ^^ | INTO | 溢出中断 | |
| ^^ | IRET | 中断返回 |
5. 串操作指令
Section titled “5. 串操作指令”串指令对字节串、字串操作,允许它们移至存储器或从存储器传送;
基本串操作指令采用寄存器 SI 寻址源操作数,且假定是在现行的数据段区域中(段地址保存在段寄存器 DS 中);
采用寄存器 DI 寻址目的操作数,且假定是在现行的附加段区域中(段地址保存在段寄存器 ES 中);
[[undergraduate/Intel8086/c2-IA32-8086#^memory-organization]]
串操作时,地址指针会自动修改,具体由标志位 DF 控制。如 DF==1 则每次操作后 SI 和 DI 自减;如 DF==0 则 SI 和 DI 自增。
| 助记符 | 功能 | 备注 | |
|---|---|---|---|
| 串操作指令 | MOVS(MOVSB/MOVSW) | 串传送 | [ES:DI] <- [DS:SI] |
| ^^ | CMPS(CMPSB/CMPSW) | 串比较 | FLAGS <- [DS:SI] - [ES:DI] |
| ^^ | STOS(STOSB/STOSW) | 存入串 | FLAGS <- AX - [ES:DI] |
| ^^ | LODS(LODSB/LODSW) | 取出串 | AX <- [DS:SI], SI=SI.next |
| ^^ | SCAS(SCASB/SCASW) | 扫描串 | [ES:DI] <- AX, DI=DI.next |
| ^^ | INS(INSB/INSW) | 输入串 | [ES:DI] <- [DX] |
| ^^ | OUTS(OUTSB/OUTSW) | 输出串 | [DX] <- [DS:SI] |
| 重复前缀 | REP | 重复操作 | |
| ^^ | REPE/REPZ | 等于/为零重复 | |
| ^^ | REPNE/REPNZ | 不等于/不为零重复 |
实现 100 个操作数的传送
利用循环
MOV SI, OFFSET SOURCE MOV DI, OFFSET DEST ; 获取操作数开始地址 MOV CX, 100 ; 计数器设置AGAIN: MOVS DEST, SOURCE ; 数据传送 DEC CX ; 计数器设置 JNZ AGAIN ; 非零则继续循环利用重复前缀
MOV SI, OFFSET SOURCE MOV DI, OFFSET DEST ; 获取操作数开始地址 MOV CX, 100 ; 计数器设置REP MOVS DEST, SOURCE ; 采用REP重复前缀^repeat-op
6. 处理器控制指令
Section titled “6. 处理器控制指令”| 助记符 | 功能 | |
|---|---|---|
| 标志操作 | STC | CF = 1 |
| ^^ | CLC | CF = 0 |
| ^^ | CMC | CF = ~CF |
| ^^ | STD | DF = 1 |
| ^^ | CLD | DF = 0 |
| ^^ | STI | IF = 1 |
| ^^ | CLI | IF = 0 |
| 外同步 | HLT | 暂停直至中断或复位 |
| ^^ | WAIT | 等待 TEST 信号有效 |
| ^^ | ESC | 交权给外部处理机 |
| ^^ | LOCK | 在下一条指令期间封锁总线 |
| 空操作 | NOP | 空操作 |