第 3 章 8086/8088的指令系统
1. 8086 指令概述
(1)基本概念
汇编指令: 指令的助记符形式。例如:MOV AL ,12H 。
小汇编 = 指令 + 语法
宏汇编 = 汇编指令 + 伪指令 + 语法
可变长的指令(8086/8088): 1 ~ 7 个字节。
(2)指令中的操作数类型
-
立即数操作数: 常数
-
寄存器操作数: 8 个通用寄存器和 4 个段寄存器
- 通用寄存器:AX , BX , CX , DX , SI , DI , BP , SP
- 段寄存器:CS , DS , ES , SS
-
存储器操作数: 指令中实际给出的是存储单元的地址。
类型 占用存储单元个数 字节 1 字 2 双字 4
基本语法:
- 立即数(常数) 不能是目的操作数。
- 专用(段)寄存器 的内容只能作为段基地址使用,不能用来进行运算,赋值也有严格限制。
- 指令两个操作数类型至少有一个确定(至少有一个寄存器,或者需要加特殊指令),且一致。
- 只有 SI , DI , BX 和 BP 可作间接寻址寄存器。
(3)指令的执行时间
寄存器最快,其次是立即数,最后是储存器。
结论:
- 尽量使用寄存器作为操作数
- 如果可能,用移位代替乘除法
- 尽量使用简单的寻址方式
(4)8086/8088 系统属于 CISC 复杂指令系统。
(5)部分常用的 8086 指令
-
MOV 指令
可实现 8 位或 16 位数据的传送,传送类型取决于指令中寄存器的位数。
1)专用寄存器的传送
不能由专用寄存器传送到专用寄存器。
-
用 AX 作桥梁
通用寄存器 ← 段寄存器
MOV AX , DS
MOV ES , AX
段寄存器 ← 立即数
MOV AX , 1000H
MOV DS , AX
2)储存器用法
(1)用 AX 作桥梁
MOV AX , MEM1
MOV MEM2 , AX
(2)用位运算符 PTR(强制转换类型)
MOV byte PTR[BX] , [1000]
-
XCHG 交换指令
不能都是存储器,两操作数中必须有一个是寄存器,并且操作数不能是段寄存器或立即数。
(考点) XCHG 不能在专用寄存器和通用寄存器中使用,例 ES 和 AX 之间。
-
不带进位的加法指令 ADD
操作数不能是段寄存器。
-
带进位的加法指令 ADC
这个与 ADD 的区别是运算时还要加上进位标志 CF 的内容。
它可以处理无符号数的溢出:
低四位运算 A379 + 7E4F 会溢出,将溢出的 1 放入 CF ,再进行高四位运算时加上即 7 + 6 + CF = E ,这样得到的 8 位运算才是正确的。
-
加 1 指令 INC
它的作用类似于 ++ 操作,对指定的操作数加 1 。
-
DAA 指令
压缩 BCD 码加法调整,将 AL 中的两个压缩 BCD 码相加的结果调整为正确的结果。
eg. DAA 的调整**(考点)**
MOV AL , 58H
ADD AL , 25H
DAA
最终答案 AL = 83H ,加上 DAA 就相当于变成了十进制的运算。
-
循环控制指令 LOOP
格式: LOOP label(地址)
作用: 跳转到 label 这个地址。
短转移:-128 ~ +127
CX 条件: CX 不等于 0 时转移。
这里我们就可以用 ADC 进行溢出处理了:
下面这个例子用 LOOP 循环运算,将 1000H 处向下的四个数相加,当加到 F2H 时,就会发生溢出,而 ADC 就是将溢出的数加到高 4 位即 AH 上。
-
不带借位的减法指令 SUB
语法规则同加法相同。
-
带借位的减法指令 SBB
与 SUB 的区别是运算时还要减去借位标志 CF 的内容。
-
减 1 指令 DEC
它的作用类似于 – 操作,对指定的操作数减 1 。
2. 8086 的寻址方式
(1)立即寻址 —— 立即数即数据在代码段
操作数就在指令中,紧跟在操作码后面,作为指令一部分存放在内存的代码段中,这种操作数称为立即数。
eg. MOV AX , 34EAH ; MOV BL , 20H
错误示例: MOV 2A00H , AX ; MOV BL , 8000H
注意: 立即数只能用于源操作数,并且类型要一致。
(2)寄存器寻址 —— 在 CPU 内部,速度最快
操作数在寄存器中,指令中源操作数和目的操作数都可用这种寻址方式。
eg. MOV SI , AX ; MOV AL , AH
错误示例: MOV DS , CS
注意: 只能由通用寄存器到专用寄存器,反过来不行。
(3)直接寻址 —— 数据在数据段,除非有段超越
指令中直接给出操作数的偏移地址,也称为有效地址 EA 。
eg. MOV AX , [3E4CH] ; MOV [1234H] , BL
错误示例: MOV [1234H] , [3E4CH]
注意: 一般两个操作数都不能是储存器。
段地址在默认的段寄存器中(通用数据读写一般为DS),但也可以显式地指定其他段寄存器(称为段超越前缀)。
eg. MOV DX , ES : [2A00H]
(4)寄存器间接寻址(基址寻址)—— 核心
内存单元的逻辑偏移地址通过寄存器间接给出。
eg. MOV SI , 61A8H ; MOV DX , [SI]
错误示例: MOV AX , [DX] ; MOV CL , [AX]
注意: 只有 SI , DI , BX 和 BP 可作间接寻址寄存器即 [ ] 中只能放这四个寄存器。
(5)寄存器相对寻址(相对基址寻址) —— 表现形式多样,数据在堆栈段
EA = 间址寄存器的内容加上一个位移量。
eg. MOV CX , 36H [BX] ; MOV CX , 36H + [BX] ; MOV CX , [BX + 36H]
(6)基址加变址寻址
基址寄存器的内容和变址寄存器的内容相加而形成操作数的偏移地址,称为基址 + 变址寻址。
eg. MOV AX , [BX] [SI] ; MOV AX , [BX + DI] ; MOV AX , DS : [BP] [DI]
考点: 不能基址加基址寄存器,也不能变址加变址寄存器。
(7)相对基址加变址寻址
基址寄存器的内容和变址寄存器的内容相加,再加上制定的位移量而形成操作数的偏移地址,称为相对基址 + 变址寻址。
eg. MOV AX , 8AH [BX] [SI] ,该例中 EA = 8AH + BX + SI ,物理地址 = DS × 10H + 8AH + BX + SI 。
(8)隐含寻址
在指令中没有明显的标出,而指定寄存器参加操作。
eg.
3. 数据传送指令
(1)通用数据传送指令
MOV 指令和 XCHG 交换指令。
(2)堆栈操作指令
-
PUSH 进栈指令
eg. PUSH AX
错误示例: PUSH 1234H ; PUSH AL
操作数不允许为常数,并且不允许为 8 位数。
-
POP 出栈指令(规则与入栈相同)
eg. POP BX
-
标志寄存器传送指令
- PUSHF : 将 FR 寄存器推入堆栈
- POP : 从栈顶中弹出存入 FR 寄存器
(3)累加器专用传送指令
-
输入指令 IN
eg.
注意: 小于 8 位的指令可以直接传送,大于 8 位的指令必须只能用 DX 进行转换。
-
输出指令 OUT
eg.
(4)目标地址传送指令 —— LEA 指令
将 16 位偏移地址送到指定的寄存器。
eg.
4. 算术运算指令
其中 ADD , ADC , INC , DAA , SUB , SBB , DEC 前面已经详细讲过,现在还剩下 CMP 指令。
比较指令 CMP 是将两个操作数相减,但结果不送目的操作数,只将状态反映在标志位上。
根据 ZF 判断两个数是否相等。若 ZF = 1 ,则两数相等,否则不相等。
若两个数不相等,则分两种情况考虑:
- 比较的数是无符号数
- 比较的数是有符号数
5. 条件转移指令
Jxx 标志位跳转指令,条件转移指令根据标志位的状态来决定是否进行分支转移。
(1)根据单个标志位设置的条件转移指令
考点: 其中没有 AF 。
(2)无符号数条件转移指令
(3)带符号数条件转移指令
6. 逻辑运算指令
运算规则:按位操作,没有进/借位,语法同算数运算。
考点: 可将标志位 CF 、OF 清零。
(1)逻辑 “非” 指令 NOT
用途: 把指定操作数的所有位都变反。
eg. MOV AX , 1234H ; NOT AX
注意: 不能直接对 1234H 操作 NOT 。
(2)逻辑 “与” 指令 AND
用途: 将 0 位屏蔽。
(3)逻辑 “或” 指令 OR
用途: 将 1 位保留,可将两个操作数组合起来。
(4)逻辑 “异或” 指令 XOR
用途: 把寄存器清零(自身异或),可将操作数的某几位取反(与 1 异或)。
eg. 下列将寄存器清零操作中,第二个异或操作是最快的。
(5)测试指令 TEST
操作与 AND 指令类似,但不将 “与” 的结果传送到目的操作数,只影响标志位。
用途: 测试某位为 1 或 0 。
7. 逻辑移位指令
(1)非循环移位指令
算术/逻辑左移(SAL/SHL): x 向左移动 k 位,丢弃最高的 k 位,并在右端补 k 个 0 。
逻辑右移(SAR): 在左端补 k 个 0 。
算术右移(SHR): 在左端补 k 个最高有效位。
注意一:
- 算术移位: 把操作数看做有符号数。
- 逻辑移位: 把操作数看做无符号数。
注意二:
左移和右移,移出的的位都进入 CF 标志。
- 左移后最高位和 CF 位不相等,则 OF = 1 ,否则为 0 。
- 右移后最高位和次高位不相等,则 OF = 1 ,否则为 0 。
注意三:
如果结果未溢出:
- 左移 1 位等价操作数乘以二。
- 右移 1 位等价操作数除以二。
(2)循环移位指令
循环左移指令 ROL
如果移一位直接 ROL AX , 1 即可,如果移多位要先将数字移到 CL 中:
MOV CL , 4 ; ROL AX , CL
其它指令同理。
循环右移指令 ROR
含进位位的循环左移指令 RCL
含进位位的循环右移指令 RCR
注意: 格式语法和非循环移位指令相同,并且循环移位各位的信息不会丢失。
8. 程序控制转移指令
8086 提供了五种控制转移指令:无条件转移指令,条件转移指令,循环控制指令,子程序调用指令和中断指令。除中断指令外,其他转移类指令都不影响状态标志。
程序控制指令的实质是设法改变当前的 CS 和 IP 值,以使 CPU 转移到一个新的地址处执行程序。
无条件转移指令 —— JMP
根据设置 CS 、IP 的方法,JMP 指令分成四种情况:
(1)段内直接转移
转移的目标地址由指令直接给出。
格式:
JMP SHORT OPRD(8 位 -128 ~ 127 —— 短转移)
JMP NEAR PTR OPRD(16 位 -32768 ~ 32767 —— 近转移)
eg.
JMP NEAR PTR 0120H ;直接转向 1020H
JMP SHORT LP ;转向 LP
(2)段内间接转移 (重点)
转移的目标地址由寄存器或存储单元的内容给出。
eg. JMP CX
若 (CX) = 1200H ,则指令执行后,(IP) = 1200H ,于是转向代码段的偏移地址 1200H 处开始执行。
eg. JMP WORD PTR[ BX + DI ]
考点: 这里 WORD 不能改成 BYTE ,因为 BYTE 只能找 8 位,这里要找 16 位。
(3)段间直接转移
在指令中直接给出转移到的目的段地址和偏移地址。
eg. JMP 2000H : 1000H
执行时,(IP) ← 1000H ,(CS) ← 2000H
注意: 直接地址为符号地址时,段间直接转移指令中的符号地址前应加操作符 FAR PTR 。
JMP FAR PTR far_label(远类型的标号)
(4)段间间接转移
转移的目的地址(段和偏移)在两个相邻的字存储单元中。
eg. JMP DWORD PTR[SI]
设指令执行前:(DS) = 4000H ,(SI) = 1212H 且 (41212H) = 1000H ,(41214H) = 4A00H 。
则指令执行后:(IP) = 1000H ,(CS) = 4A00H 。
考点: 这里要用 DWORD 双字而不能是 WORD ,因为要找 32 位。
9. 处理器控制指令
(1)标号操作指令
用来设置标志位的状态。
-
CF 设置指令
CLC 0 → CF
STC 1 → CF
CMC CF 变反
-
DF 设置指令
CLD 0 → DF(串操作的指针移动方向从低到高)
STD 1 → DF(串操作的指针移动方向从高到低)
-
IF 设置指令
CLI 0 → IF(禁止 INTR 中断)
STI 1 → IF(开放 INTR 中断)
(2)外部同步指令
-
暂停指令 HLT
执行 HLT 指令时,CPU 进入暂停状态,设置该指令通常是为了等待中断。
-
等待指令 WAIT
使处理器处于空转等待状态,等待 TEST 管脚上的信号有效。
-
空操作指令 NOP
NOP 指令不做任何实质性的操作,但占用 3 个时钟周期,然后执行下一条指令。多用于延时或预留存储空间(占位子)。