指令是使计算机执行某种特定操作的二进制编码。
8086 CPU指令系统有133条指令,通常分为数据寻址方式和程序寻址方式
8086指令是不定长,一般为1~6个字节。
数据寻址方式
隐含寻址
指令已经默认对CPU中的某个寄存器进行操作,不用在指令中指明所使用的寄存器,即隐含了规定的操作数,这样的寻址方式称为隐含寻址。立即数寻址
寄存器寻址
存储器操作数寻址
执行单元EU根据指令中给出的寻址方式计算出16位的偏移量,称为有效地址(EA)送到总线接口单元BIU,经过加法器生成20位实际物理地址,在存储器读写总线周期对存储器进行操作,一般在表示EA时,用 [操作数] 表示。
由于计算EA需要时间,进行总线操作比较慢,因此存储器操作寻址比前三种要慢。
直接寻址
例:MOV SI, [2000H]
默认使用DS段,若需使用其他段可使用段超越:MOV SI, ES:[2000H]-
寄存器间接寻址
可间接寻址的寄存器有:BX、BP、SI、DI
例:MOV AL, [BX]BX用于间接寻址时,默认段寄存器为DS,允许段超越 BP用于间接寻址时,默认段寄存器为SS,允许段超越 SI用于间接寻址时,默认段寄存器为DS,允许段超越 DI用于间接寻址时,只有在串操作指令中,默认段寄存器为ES,其余情况默认段寄存器均为DS,不允许段超越
注:IP只能在代码段中(CS)寻址,SP只能在堆栈段(SS)中寻址
-
寄存器相对寻址
基址寻址
操作数的有效地址是一个基址寄存器的内容加上一个8位或者16位的偏移量,基址寄存器是BX或者BP。
例:MOV AX,[BX+1000H]
有时也写成 MOV AX,1000H[BX]或MOV AX,[BX]1000H变址寻址
操作数的有效地址是一个变址寄存器的内容加上一个8位或者16位的偏移量,变址寄存器是SI和DI。
例:MOV AX, ARRAY[SI]基址加变址寻址
操作数的有效地址是由基址寄存器和变址寄存器的内容相加产生
例:MOV AX, [BP+SI]相对的基址加变址寻址
操作数的有效地址是由基址寄存器、变址寄存器和偏移量三者相加产生。
例:MOV AX, [BX+SI+3H]
也可写成MOV AX,3H[BX][SI]或MOV AX,3H[BX+SI]数据串寻址
DS:SI指示源串,ES:DI指示目的串,串长度计数用CX,并自动修改指针和计数器值,只用于串操作命令。
例:MOVSB ;((ES:DI))((DS:SI)),CX=CX-1,SI=SI+1,DI=DI+1
- I/O端口寻址
操作数存放在I/O端口中,指令执行时必须通过累加器(AX或AL)实现对端口的访问
直接端口寻址
指令直接提供8位端口的地址。
例:IN AL, 63H
当端口地址用一个字节来表示时,可使用直接端口寻址间接端口寻址
由DX寄存器给出16位端口地址。
例:MOV DX, 162H
IN AX, DX
程序寻址方式
段内直接寻址
短跳转:把IP的内容加上一个字节的补码数作为新的IP,往前最多跳-128个字节,往后最多跳127个字节。
近跳转:把IP的内容加上两个字节的补码数作为新的IP,往前最多跳-32768个字节,往后最多跳32767个字节。
段内间接寻址
将寄存器或存储器操作数的内容赋给IP
段间直接寻址
直接在指令中给出新的CS和IP内容
段间间接寻址
用存储器操作数的内容赋给CS和IP
8086指令格式
指令一般由1~6个字节组成,具体格式如下图:
- 字节1
OPCODE:指令操作码
-
D:操作数传输方向(立即数指令和串操作指令除外)
- D=0,Reg为源操作数
- D=1,Reg为目的操作数
-
W:操作数字节长度
- W=0,字节操作
- W=1,字操作
- 字节2,寻址方式
- MOD:寻址方式字段
- 00=存储器方式,指令中无偏移量
- 01=存储器方式,指令中有8位偏移量
- 10=存储器方式,指令中有16位偏移量
- 11=寄存器方式,指令中无偏移量
- Reg:寄存器编码字段
000=AL/AX | 100=AH/SP | 001=CL/CX | 101=CH/BP |
---|---|---|---|
010=DL/DX | 110=DH/SI | 011=BL/BX | 111=BH/DI |
- R/M:寄存器/存储器字段
- 在MOD=11,寄存器模式下,R/M给出第二个操作数的寄存器编码。
-
在MOD≠11,存储器模式下,R/M给出计算有效地址的方法。
- 字节3~字节6
DISP:存储器操作数地址偏移量,长度由MOD字段定义
DATA:指令中的立即数
8086指令系统
操作数符号表示
符号 | 含义 |
---|---|
DST | 目的操作数 |
SRC | 源操作数 |
TARGET | 循环、转移和调用指令操作数 |
imm | 立即操作数,字节或字 |
acc | 累加器AL或AX |
reg | 寄存器操作数 |
seg_reg | 段寄存器 |
mem | 存储器操作数 |
short_label | 短标号(8位偏移量) |
near_label | 近标号(16位地址或偏移) |
far_label | 远标号(32位地址) |
数据传送指令
通用数据传送指令 MOV DST,SRC
堆栈及堆栈操作
堆栈是一种按先进后出(FILO)原则存取的存储器,它由堆栈指针寄存器SS:SP和RAM中的一部分组成,主要用于子程序调用或中断子程序的现场保护和恢复,以及参数传递等。
SP的内容总是指向栈顶,即最后推入信息所在单元。
进栈指令 PUSH SRC
出栈指令 POP DST
交换指令 XCHG DST,SRC
-
累加器专用传送指令
- 输入指令 IN AL/AX,PORT/DX
- 输出指令 OUT PORT/DX,AL/AX
PORT为8位直接地址 - 换码指令 XLAT : (AL)←((BX)+(AL))
-
地址传送指令
- 有效地址传送指令 LEA reg16,SRC:(reg16) ←SRC
- 指针送寄存器和DS
LDS reg16,mem32 :(reg16) ←(mem32);(DS) ←(mem32+2) - 指针送寄存器和ES
LES reg16,mem32 :(reg16) ←(mem32); (ES) ←(mem32+2)
-
标志寄存器传送
- LAHF : (AH) ←(flag低字节)
- SAHF : (flag低字节) ←(AH)
- PUSHF : (SP) ←(SP)-2, ((SP)+1),(SP)) ←flag
- POPF : flag ←((SP)+1),(SP)), (SP) ←(SP)+2
算术指令
- 加法指令
- ADD DST,SRC : (DST) ← (SRC) + (DST)
- ADC DST,SRC : (DST) ← (SRC) + (DST)+CF
- INC DST : (DST) ←(DST)+1 //不影响进位标志CF
- 减法指令
- SUB DST,SRC : (DST) ←(DST)-(SRC)
- SBB DST,SRC : (DST) ←(DST)-(SRC)-CF
- DEC DST : (DST) ←(DST)-1 //不影响进位标志CF
- NEG DST : (DST)=0-(DST) //求补指令
- CMP DST,SRC : (DST)-(SRC),仅影响标志 //比较指令
- 乘法指令
无符号数乘法
MUL SRC : (AX) ←(AL)*(SRC)或(DX,AX) ←(AX)*(SRC)有符号数乘法
IMUL SRC : (AX) ←(AL)(SRC)或(DX,AX) ←(AX)(SRC)
- 除法指令 //除数必须为被除数一半字长
无符号数除法指令 DIV SRC
(AL) ←(AX)/(SRC);(AH) ←(AX)%(SRC)
或(AX)←(DX,AX)/(SRC);(DX) ←(DX,AX)%(SRC)有符号数除法指令 IDIV SRC : 操作与DIV相同
- 类型转换指令
字节转换成字指令(有符号数)CBW
若(AL) <80H则(AH)←0,否则(AH) ←FFH即将AL符号位扩展到AH有符号字转换成双字指令CWD
若(AX)<8000H,则(DX) ←0,否则(DX) ←FFFFH
- BCD码调整指令
加减运算非压缩BCD码高4位的值可不为0,乘除时高4位必须是0。
-
压缩BCD码调整指令
- DAA :对BCD码加法运算结果(AL)进行调整。
- DAS :对BCD码减法运算结果(AL)进行调整。
-
非压缩BCD码调整
- AAA :对非压缩BCD码加法运算结果进行调整,进位送(AH)中
- AAS :对非压缩BCD码减法运算结果进行调整
- AAM :对非压缩BCD码乘法运算进行调整
- AAD :对非压缩BCD码除法运算进行调整
逻辑指令
- 逻辑运算指令
- AND DST,SRC (DST) ←(DST)&(SRC)
- OR DST,SRC (DST) ←(DST)|(SRC)
- NOT DST ~DST
- XOR DST,SRC (DST) ←(DST)^(SRC)//异或
- TEST DST,SRC (DST)&(SRC),仅影响标志
- 移位指令
- 逻辑左移指令 SHL DST,count :DST左移count位,每左移一位,最低位补0,最高位进入CF
- count可以为数字,也可以为CL做移位计数。
- 算术左移指令 SAL DST,count :同SHL
- 逻辑右移指令 SHR DST,count :最高位添零,最低位进入CF
- 算术右移指令 SAR DST,count :最高位不变,最低位进入CF
- 循环左移指令 ROL DST,count :最高位进入CF和最低位
- 循环右移指令 ROR DST,count :最低位进入CF和最高位
- 带进位循环左移指令 RCL DST,count
- 带进位循环右移指令 RCR DST,count
串处理指令
- 数据串传送指令:唯一的目的操作数和源操作数都在存储器中的指令
-
串传送指令 MOVSB/MOVSW :DST与SRC做类型检查
- MOVSB : ((ES:DI)) ←((DS:SI)),(SI) ←(SI)±1, (DI)←(DI)±1
- MOVSW :((ES:DI)) ←((DS:SI)),(SI) ←(SI)±2, (DI) ←(DI)±2
其中,加、减地址指针SI和DI由FLAG中的DF决定,DF=0地址增加,DF=1地址减小。
-
建立方向标志指令
- CLD ;DF←0
- STD ;DF←1
REP重复前缀
例:REP MOVSB :以CX寄存器做计数器,每传送一个数(CX)减1,直到(CX)为0。
REPZ/REPE : 若(CX)≠0且ZF=1时继续执行,否则退出。
REPNZ/REPNE : 若(CX)≠0且ZF=0(比较不相等)时继续执行,否则退出。-
存入串指令 STOSB/STOSW : DST做类型检查
- STOSB : ((ES:DI)) ←(AL), (DI) ←(DI)±1
- STOSW : ((ES:DI)) ←(AX),(DI) ←(DI)±2
由DF决定方向,可加入前缀REP。
-
从串中取指令 LODSB/LODSW :SRC做类型检查
- LODSB : (AL) ←((DS:SI)) , (SI) ←(SI)±1
- LODSW : (AX) ←((DS:SI)) ,(SI) ←(SI)±2
地址增减由DF决定
- 字符串扫描和比较指令
-
串比较指令 CMPS : SRC和DST仅做类型检查
- CMPSB ;((DS:SI))-((ES:DI)), (SI) ←(SI)±1, (DI) ←(DI)±1
- CMPSW ;((DS:SI))-((ES:DI)), (SI) ←(SI)±2, (DI) ←(DI)±2
串比较仅影响标志,地址增减由DF决定。
-
串扫描指令 SCAS : DST做类型检查
- SCASB : (AL)-((ES:DI)) ,(DI) ←(DI)±1
- SCASW : (AX)-((ES:DI)) ,(DI) ←(DI)±2
仅影响标志,地址增减由DF决定,可加条件前缀。
控制转移指令
- 无条件转移指令:JMP TARGET
- JMP short_label :(IP)<-(IP)+short_label 短跳转
- JMP near_label :(IP)<-(IP)+near_label 近跳转
- JMP far_label :(CS:IP)<-far_label 远跳转
- 条件转移指令
- 根据单个标志转移
指令 | 含义 | 测试条件 |
---|---|---|
JZ short_label | 结果为0转移 | ZF=1 |
JE short_label | 结果相等转移 | ZF=1 |
JNZ short_label | 结果不为0则转移 | ZF=0 |
JNE short_label | 结果不相等则转移 | ZF=0 |
JS short_label | 结果为负则转移 | SF=1 |
JNS short_label | 结果非负则转移 | SF=0 |
JNO short_label | 结果不溢出则转移 | OF=0 |
JO short_label | 结果溢出则转移 | OF=1 |
JP short_label | 奇偶为1则转移 | PF=1 |
JPE short_label | 偶转移 | PF=1 |
JNP short_label | 奇偶为0则转移 | PF=0 |
JPO short_label | 奇转移 | PF=0 |
JB short_label | 有借位转移 | CF=1 |
JNAE short_label | 不大于等于转移 | CF=1 |
JC short_label | 有进位转移 | CF=1 |
JNB short_label | 无借位转移 | CF=0 |
JAE short_label | 大于等于转移 | CF=0 |
JNC short_label | 无进位转移 | CF=0 |
- 两个无符号数比较转移
A大于 | B小于 | E等于 |
---|---|---|
JB/JNAE/JC | CF=1 | 小于 |
JNB/JAE/JNC | CF=0 | 不小于 |
JBE/JNA | CF|ZF=1 | 不大于 |
JNBE/JA | CF|ZF=0 | 大于 |
- 两个有符号数比较转移
G大于 | L小于 | E等于 |
---|---|---|
JL/JNGE | SF^OF=1 | 小于 |
JNL/JGE | SF^OF=0 | 不小于 |
JNLE/JG | (SF^OF)|ZF=0 | 大于 |
JLE /JNG | (SF^OF)|ZF=1 | 不大于 |
- 测试CX值,为0则转移
JCXZ short_label :(CX)=0则转移
- 循环指令
- LOOP short_label : (CX) ←(CX)-1,(CX)≠0则转移
- LOOPZ/LOOPE short_label : (CX) ←(CX)-1,(CX)≠0且ZF=1则转移
LOOPNZ/LOOPNE short_label :(CX) ←(CX)-1,(CX)≠0且ZF=0则转移
- 子程序调用与返回
子程序调用指令 CALL TARGET
具体指令
CALL near_proc;段内调用
CALL far_proc;段间调用
CALL mem16/regp16/mem32;返回指令 RET
带立即数返回 RET IMM16
在RET指令的基础上,当从堆栈中弹出IP和CS后,再将SP加上一个字的立即数,使得返回后(SP) ← (SP) + IMM16
中断调用与返回
- 中断调用
INT n
依次将FLAG,当前CS和IP(即断点地址)放入堆栈,清除IF和TF。执行中断类型码为n的中断服务程序。
注: INT n 的机器码为 CDH n,INT 3 的机器码特殊,为 CCHINTO
在有符号数运算结束以后,可以使用INTO,若OF=1,则执行中断指令INT 4,否则无操作。IRET
中断返回指令,从中断程序返回主程序,恢复断点和FLAG
控制类指令
- 标志处理指令
- CLC/STC/CMC 对CF 清0 / 置位 /取反
- CLD/STD 对DF 清0 / 置位
- CLI/STI 对IF 清0 / 置位
- 处理器控制指令
NOP | 空操作指令 | 占用一个字节的机器码,不执行任何操作 |
---|---|---|
HLT | (Halt)停机指令 | 该指令使处理器处于停机状态,以便等待一次外部中断到来 |
WAIT | 等待指令 | 该指令使处理器处于空转状态,也可用来等待外部中断的到来 |
ESC | (Escape)换码指令,用作前缀 | 格式:ESC MEM,其中MEM指出一个存储单元,ESC指令把该存储单元的内容送到数据总线去 |
LOCK | 封锁指令,用作前缀 | 该指令与其他指令联合,用来维持总线的封锁信号直到与其联合的指令执行完为止 |