第二章:8086/8088的指令系统(一)
8086指令系统
- 从功能上包括6大类:
- 数据传送
- 算术运算
- 逻辑运算和移位
- 串操作
- 程序控制
- 处理器控制
- 学习指令的时候要注意一下几点:
- 指令码的含义
- 指令对操作数的要求
- 指令的对标志位的影响
- 指令的功能
数据传送指令
- 分为下面四小类
- 通用数据传送
- 输入输出
- 地址传送
- 标志位操作
- 注意: 除了标志传送指令外其他指令的执行对标志位不产生影响。
通用数据传送指令
- 分为如下几小类
- 一般数据传送指令
- 堆栈操作指令
- 交换指令
- 查表转换指令
- 字位扩展指令
- 一般数据传送指令MOV
- 格式:MOV dest ,src
- 操作: 将操作数src复制传送到操作数dest,即src->dest
- 注意点:
- 两操作数字长必须相同;
- 两操作数不允许同时为存储器操作数;
- 两操作数不允许同时为段寄存器;
- 在源操作数是立即数时,目标操作数不能是段寄存器;
- IP和CS不作为目标操作数,FLAGS一般也不作为操作数在指令中出现。
- 注意了:前说过段寄存器的初始化不能由程序员控制,但是初始化之后可以
- 举例:(略)
- 堆栈操作指令
- 堆栈是内存中一段特定的存储区域,常用来存放中断断点,调用子程序的调用现场,程序运行中需要临时保存的数据等内容。对堆栈区间的访问遵循“先进后出”的原则
- 8086、8088微机中堆栈的段基址是由堆栈寄存器SS确定的,而堆栈区间的具体大小是由用户在程序中指定的,在微机中用堆栈指针SP表示,SP始终指向堆栈顶部(栈顶)。
- 堆栈操作的原则:
- 先进后出
- 以字(2个字节)为单位,也就是说堆栈操作的操作数一定为16位。
- 堆栈操作指令( OPRD:可以为16位的寄存器,或者内存的2个单元。)
- 压栈指令
- 格式:
PUSH OPRD
- 功能: 将指定的寄存器或存储单元的内容存入到栈顶
- 执行过程:
- SP-1 ->SP,然后操作数的高位字节送至SP所指向的单元
- SP-1-> SP,然后操作数的低位字节送至SP所指向的单元
- 格式:
- 压栈指令
- 格式:
pop OPRD
- 功能: 将栈顶的数据复制到指定的寄存器或内存单元中
- 执行过程:
- SP所指向单元的数据送至操作数的低位字节,SP+1 -> SP
- SP所指向单元的数据送至操作数的高位字节,SP+1 -> SP
- 格式:
-
举例:
1. 压栈 PUSH AX 若此时(AX) = 1234H, (SS) = 2000H, (SP) = 0100H,则指令的执行流程如下: 第一步: SP-1 -> SP,即(SP) = 00FFH, (200FFH) = 12H; 第二步: SP-1 -> SP,即(SP) = 00FEH, (200FEH) = 34H; 2. 出栈 POP [BX] 若此时(BX)= 0010H,(SS) = 2000H,(DS) = 3000H,(SP) = 00FEH,则指令执行过程如下: 第一步:(SP)->(30010h),SP+1->SP,即(SP) = 00FFH; 第二步:(SP)->(30011h),SP+1->SP,即(SP) = 0100H;
- 栈操作指令说明:
- 指令的操作数必须是16位
- 操作数可以是寄存器或存储器2个单元,但不能是立即数
- 不能从栈顶弹出一个字给CS;
- PUSH和POP指令在程序中一般成对出现;
- PUSH指令的操作方向是从高地址向低地址,而POP指令的操作正好相反。
- 压栈指令
- 交换指令
- 指令格式:
XCHG dest, src
- 功能: 将目的操作数dest与源操作数src的内容相互交换。
- 注意:
- 两个操作数必须有一个是寄存器操作数
- 不允许使用段寄存器。
- 2个操作数位数必须相同。
- 指令格式:
- 查表指令:
- 指令格式:
XLAT 或 XLAT 表首地址
- 功能:((BX) + (AL) -> (AL)),把内存数据段中的一个字节的数据复制进AL,该数据的偏移地址是(BX)+(AL)
- 可以把内存数据段中以BX为偏移地址的一段连续的存储空间看成是一张表,而AL是表中具体数据项距表头的唯一量(索引值)。只要知道了这个位移量,就能利用XLAT指令方便地找到表中的数据。
- 说明: 用BX的内容代表表格首地址,AL内容为表内偏移量,BX+AL得到要查找元素的偏移地址
- 操作:将BX+AL所指向单元的内容送AL
- 指令格式:
- 字位扩展指令
- 作用:将8位扩展为16位,或者将16位扩展为32位
- 前提:
- 全部针对的是有符号数的扩展
- 将符号数的符号位扩展到高位
- 指令位零操作数指令,采用隐含寻址,隐含操作数为AX及AX,DX
- 无符号数的扩展规则为在高位补0
- 字到字节的扩展指令
- 格式:
CBW
- 操作:
将AL内容扩展到AX
- 规则: 若最高位=1,则执行后AH=FFH;若最高位=0,则执行后AH = 00H;
- 格式:
- 将字扩展到双字的扩展指令
- 格式:
CWD
- 操作: 将AX内容扩展到DX AX
- 规则: 若最高位=1,则执行后DX=FFFFH;若最高位=0,则执行后DX = 0000H;
- 格式:
地址传送指令
- 顾名思义就是取地址的指针
- 这类指令一共有3条:
- 去偏移地址指令LEA->取近地址指针
- *LDS指令->取远地址指针
- *LES指令->取远地址指针
- LEA指令
- 格式:
LEA REG, MEM
- 功能: 把源操作数
MEM
的地址偏移量送至目的操作数REG - 注意:
- 源操作数必须是一个内存操作数,目标操作数通常是间址寄存器。
-
举例:
假设源操作数为内存中的数据段 MOV BX, [1200H] 析: 将内存数据段中偏移地址为1200H的2个单元的存储内容复制到BX寄存器中 LEA BX, [1200H] 析: 将内存数据段中[1200H]数据的偏移地址(即1200H)复制到BX寄存器中,(BX) = 1200H
- 格式:
- LDS/LES指令
- LDS:从源操作数src指示的存储单元开始,连续取出4个字节的数据,这4个字节的数据组成一个完整的内存逻辑地址,即段基址(16位):偏移地址(16位),其中较低地址单元的两个字节的数据作为偏移地址送至目的寄存器dest,而较高地址单元的两个字节的数据作为段基址送至附加段寄存器ES;
- LES:从源操作数src指示的存储单元开始,连续取出4个字节的数据,这4个字节的数据组成一个完整的内存逻辑地址,即段基址(16位):偏移地址(16位),其中较低地址单元的两个字节的数据作为偏移地址送至目的寄存器dest,而较高地址单元的两个字节的数据作为段基址送至数据段寄存器DS;
- 注意:
- 源操作数src必须是一个内存操作数
- 目的操作数dest必须是一个16位的通用寄存器。
标志传送指令
- LAHF
- 将FLAGS(标志寄存器)的低8位装入AH
- SAHF
- 将AH内容写入到FALGS的低8位。
- 标志压栈指令
- 指令格式:
PUSHF
- 功能: 将标志寄存器FR的内容存入到栈顶
- 指令格式:
- 标志出栈指令
- 指令格式:
POPF
- 功能: 将SP所指向的栈顶子单元的内容送至标志寄存器FR.
- 指令格式:
输入输出指令
- 关于I/O端口
- I/O端口
- I/O接口中用于存储数据、可以直接被CPU访问的寄存器
- 我们知道CPU与外部设备之间的交互是需要输入输出接口的。
- 什么是端口: 就是输入输出接口中用来存放数据可以被CPU直接访问的一些寄存器
- 因为CPU内部也有寄存器,为了在名字上不要出现冲突,所以接口中的寄存器给取了另外一个名字–端口
- 通俗的说就是寄存器不一定CPU内部才有,I/O接口中也有,但是I/O接口中的寄存器不叫寄存器,叫端口。
- I/O端口
- 输入输出指令是专门针对I/O端口进行的操作。
- 无论是输入还是输出,都必须通过累加器AX或AL才能与I/O端口上的数据进行通讯
- 输入指令:
- 直接输入指令
- 格式:
IN AL, PORT 或 IN AX,PORT
- 其中PORT为I/O端口地址,范围为00H->FFH,此时可不是立即数了
- 功能: (PORT)-> (AL),将地址为PORT的I/O端口中的一个字节的数据复制到寄存器AL中; 或者(PORT+1)-> (AH),(PORT)-> (AL),即将地址为PORT+1,PORT的I/O端口中的两个字节的数据复制到寄存器AX中
- 格式:
- 间接输入指令
- 格式:
IN AL, DX 或 IN AX,DX
- 其中,DX寄存器中的内容就是I/O端口的地址,范围是0000H~FFFFH
- 功能:(DX)-> (AL),将以DX中的内容为地址的I/O端口中的一个字节的数据复制到寄存器AL中; 或者(DX+1)-> (AH),(DX)-> (AL),即以DX+1,PORT中的内容为地址的I/O端口中的两个字节的数据复制到寄存器AX中
- 格式:
- 直接输入指令
- 输出指令:
- 直接输出指令:
- 格式:
OUT PORT, AL 或 OUT PORT, AX
- 其中PORT为I/O端口地址,范围为00H->FFH,此时可不是立即数了
- 功能: (AL)-> (PORT),将寄存器AL中的内容复制到地址为PORT的I/O端口中;或(AH)->(PORT+1),(AL)->(PORT),即寄存器AX中的内容复制到地址为PORT+1,PORT的I/O端口中
- 格式:
- 间接输出指令:
- 格式:
OUT DX, AL 或 OUT DX, AX
- 其中DX寄存器中的内容为I/O端口地址,范围为0000H->FFFFH
- 功能: (AL)-> (DX),将寄存器AL中的内容复制到以DX中的内容为地址的I/O端口中;或(AH)->(DX+1),(AL)->(PORT),即寄存器AX中的内容复制到以DX+1,DX中的内容为地址的I/O端口中
- 格式:
- 直接输出指令:
算术运算指令
- 常见的算术运算指令如下:
- 加法运算指令
- 减法运算指令
- 乘法运算指令
- 除法运算指令
- 算术运算指令的执行大多对状态标志位会产生影响
加法指令
注意: 加法指令对操作数的要求与MOV指令相同
- 普通加法指令ADD
- 通常用在两个字节、两个字相加的情况下。
- 格式:
ADD dest, src
- 操作: 源操作数和目标操作数按位相加结果送到目标地址:(dest)<-(dest)+(src)
- ADD指令的执行对全部6个状态标志位都产生影响。
- 带进位的加法指令ADC
- 用于多个字节的数据相加,会产生进位
- 指令格式、对操作数的要求、对标志位的影响与ADD指令完全一样。
- 区别: (dest)<-(dest)+(src) +CF ,就是目标与源操作数求和之后还要加上CF的状态
- 注意:ADC多用于多字节数相加,使用前要先将CF清零。
- 自加1指令INC
- 对标志位的影响不同,不会影响CF,只会影响其余5个标志位,而上面2种对每个标志位都会产生影响。
- 格式:
INC dest
- 操作数不能是段寄存器、不能是立即数
- 操作:(dest)<-(dest)+1;
- 常用于在程序中修改地址指针
减法指令
注意: 减法指令对操作数的要求与对应的加法指令相同
- 普通减法指令SUB
- 格式:
SUB dest,src
- 操作: (dest)<- (dest) - (src)
- 对标志位的影响与ADD相同,使用场合业余ADD相同。
- 格式:
- 考虑借位的减法指令SBB
- 指令格式、对操作数的要求、对标志位的影响与SUB指令完全一样。
- SBB指令多用于两个多字节数的相减运算
- 自减1指令DEC
- 格式:
DEC dest
- 操作: (dest)<- (dest)-1
- 指令对操作数的要求以及对标志位的影响与INC相同
- 指令常用于在程序中修改计数值
- 格式:
- 比较指令CMP
- 格式:
CMP dest,src
- 操作: (dest)- (src),用目标操作数-源操作数,只影响标志位,然后结果舍弃,不影响目标操作数dest
- 用途: 用于比较2个数的大小,可作为条件转移指令转移的条件
- 指令对操作数的要求以及对标志位的影响与SUB相同
- 格式:
- 求补指令NEG(取负指令)
- 格式:
NEG dest
- 操作数要求: 8/16位寄存器或存储器操作数
- 操作:(dest)<- 0 - (dest)
- 对一个负数取补码就相当于用零减去此数
- 执行NEG指令后,一般情况下都会使CF为1,除非给定的操作数为零才会使CF为0.
- 当指令的操作数的值为80H(-128)或8000H(-32768),则执行NEG指令后,结果不变,但OF置1,其他情况下OF均置0.
- 用0减去操作数,可以得到负数的绝对值。
- 格式:
乘除运算指令
- 说明:
- 有分别针对有符号数和无符号数运算指令
- 有不同的指令助记符
- 乘、除运算指令均采用隐含寻址方式
- 请注意该类指令对操作数的要求
- 有分别针对有符号数和无符号数运算指令
- 乘法指令:
- 无符号的乘法指令MUL
- 带符号的乘法指令IMUL
- 注意点:
- 乘法指令采用隐含寻址,隐含了存放被乘数的累加器AL或AX,以及存放结果的AX或AX,DX;
- 两个8位二进制数相乘他的结果无论是大还是小,一律都是16位字长; 同理,两个16位数相乘,结果都是32位字长。
- 那么2个字节(8位)数相乘结果可以放在一个16位寄存器中,在乘法计算中默认放在AX寄存器中;2个字(16位)数相乘结果为32位,那么久没有一个32位的寄存器了,因此必须借助另外一个寄存器DX,用它来存放运算结果的高16位。
- 无符号数的乘法指令:
- 格式:
MUL dest
- 功能:
- 若dest是字节操作数,则(AL)* (dest)->(AX),若此时(AH)!= 0,则CF = OF = 1,表示相乘后操作数长度扩展,否则,CF = OF = 0;
- 若dest是字操作数,则(AX)* (dest)->(DX)(AX),若此时(DX)!= 0,则CF = OF = 1,表示相乘后操作数长度扩展,否则,CF = OF = 0;
- 注意:dest 不能是立即数
- 格式:
- 有符号数的乘法指令:
- 格式:
IMUL dest
- 指令功能:
- 指令的操作数类型,存放方式的规定与MUL指令相同。无论是字节数据或字数据相乘,首先将两个数的绝对值相乘,再根据乘数的符号确定积的符号,最后所得的积是补码形式的带符号数。 若乘积的高位(AH) 或(DX)不是低位(AL)或(AX)的符号扩展,则CF= OF = 1.表示乘积的高位含有有效数据,否则 CF=OF=0;
- 格式:
- 除法指令:
- 无符号数的除法指令:
- 格式:
DIV dest
- 功能:
- 若dest是字节操作数,则(AX)/ (dest)->(AL),(AX)mod(dest)->(AH),即商在AL,余数在AH;
- 若dest是字操作数,则(DX)(AX)/ (dest)->(AX),(DX)(AX)mod(dest)->(DX),即商在AX,余数在DX;
- 除法运算不影响标志位
- 格式:
- 有符号数的除法指令
- 格式:
IDIV dest
- 指令功能:
- 指令的操作数类型,存放方式的规定与DIV指令相同。无论dest是字节数据或字数据,首先将两个数的绝对值相除,再根据被除数和除数的符号确定商和余数的符号,最后所得的商和余数是补码形式的带符号数。 8086、8088规定余数的符号与被除数的符号相同。
- 格式:
- 无符号数的除法指令:
- 算术运算指令小结
- 指令执行影响状态标志位
- 乘法指令执行结果为相乘数的双倍字长;除法指令要求被除数是除数的双倍字长。
逻辑运算指令
- 简介:
- 8086、8088的逻辑运算指令包括”与“、”或“、”非“、”异或“这4种,均是对操作数的对应位按位进行逻辑运算,同时对状态标志位有不同的影响。
- 对操作数的要求
- 大多数与MOV指令相同
- “非”运算指令要求操作数不能是立即数
- 对标志位的影响
- 除”非“运算指令,其余指令的执行都会影响除AF外的5个标志
- 无论执行结果如何,都会是标志位OF=CF= 0;
- ”非”运算指令的执行不影响标志位。
“与”指令
- 格式:
AND dest,src
- 功能:将两个操作数按位相与结果送回目标操作数,即(dest)& (src)-> (dest).
- 特点:任何二进制位与1相与保持不变,与0相与结果为0.
- 应用场合:
- 实现两个操作数按位相与的运算.举例:
AND BL,[SI]
- 使目标操作数的某些位不变,某些位清零. 举例:
AND AL,0FH
- 在操作数不变的情况下是CF和OF清零。举例:
AND AX,AX
- 实现两个操作数按位相与的运算.举例:
“或”指令
- 格式:
OR dest,src
-
功能:将两个操作数按位相或结果送回目标操作数,即(dest) (src)-> (dest). - 特点:任何二进制位与0相或保持不变,与1相或结果为1.
- 应用场合:
- 实现两个操作数按位相或的运算.举例:
OR AX,[DI]
- 使某些位不变,某些位置1. 举例:
OR CL,0FH
- 在操作数不变的情况下是CF和OF清零。举例:
OR AX,AX
- 实现两个操作数按位相或的运算.举例:
“非”指令
- 格式:
NOT dest
- 功能:将目的操作数dest按位取反,送回目的操作数,(dest^)-> (dest).
“异或”指令
- 格式:
XOR dest,src
- 功能:将两个操作数按位相异或结果送回目标操作数
- 特点:任何二进制位与0相异或保持不变,与1相异或结果取反.
- 应用场合:
- 实现两个操作数按位相异或的运算.举例:
XOR BL,80H
- 在操作数不变的情况下是CF和OF清零。举例:
XOR AX,AX
- 实现两个操作数按位相异或的运算.举例:
“测试”指令
- 格式:
TEST dest,src
- 功能:将两个操作数按位与,结果丢弃,目的只影响各个状态标志位。即(dest)&(src);
- 应用场合:
- 常用于测试某些位的状态
移位指令
- 控制二进制位向左或向右移的指令
- 主要分为以下2类:
- 非循环移位指令
- 循环移位指令
- 移位指令的说明
- 指令格式在形式上为双操作数,本质上为单操作数
- 指令的目标操作数为被移动的对象,源操作数为移动的次数
- 当目标操作数为存储器操作数时,需要说明其字长
- 移动1位时由指令直接给出;移动2位以及以上位次数必须由CL指定
- 即指令的源操作数只能是1或者CL
非循环移位指令
- 包含以下2类
- 逻辑移位
- 把进行移位的操作数当做是无符号数,总是用0填补已空出的位。
- 算术移位
- 对带符号数进行移位,在移位过程中必须保持操作数的符号不变。
- 逻辑移位
- 逻辑左移指令:
- 格式:
SHL dest,1 或者 SHL dest,CL
- 功能:将目的操作数dest左移1位或左移CL中预置的位数,最高位移入CF中,其他依次左移,低位补0.
- 格式:
- 逻辑右移指令:
- 格式:
SHR dest,1 或者 SHR dest,CL
- 功能:将目的操作数dest右移1位或右移CL中预置的位数,最低位移入CF中,其他依次右移,高位补0.
- 格式:
- 算术左移指令:
- 格式:
SAL dest,1 或者 SAL dest,CL
- 功能:同逻辑左移一样
- 格式:
- 算术右移指令:
- 格式:
SAR dest,1 或者 SAR dest,CL
- 功能:将目的操作数dest右移1位或右移CL中预置的位数,最低位移入CF中,其他依次右移,最高位用原数值的最高位补足。
- 格式:
- 非循环移位指令的应用场合
- 左移可以实现乘法运算
- 右移可以实现除法运算
循环移位指令
- 不带进位的循环左移指令
- 格式:
ROL dest,1 或者 ROL dest,CL
- 功能: 将目的操作数dest循环左移1位或者CL中预置的位数,最高位移入CF的同时,也移入最低位,其他位依次左移,原CF中的内容消失。
- 格式:
- 不带进位的循环右移指令
- 格式:
ROR dest,1 或者 ROR dest,CL
- 功能: 将目的操作数dest循环右移1位或者CL中预置的位数,最低位移入CF的同时,也移入最高位,其他位依次右移,原CF中的内容消失。
- 格式:
- 带进位的循环左移指令
- 格式:
RCL dest,1 或者 RCL dest,CL
- 功能: 将目的操作数dest连同进位标志位CF一起循环左移1位或者CL中预置的位数,将CF的值移入最低位,其他位依次左移,原数值dest的最高位移入CF中。
- 格式:
- 带进位的循环右移指令
- 格式:
RCR dest,1 或者 RCR dest,CL
- 功能: 将目的操作数dest连同进位标志位CF一起循环右移1位或者CL中预置的位数,将CF的值移入最高位,其他位依次右移,原数值dest的最低位移入CF中。
- 格式:
- 应用场景:
- 用于对某些位状态的测试
- 高位部分和低位部分的交换
- 与非循环移位指令一起组成32位或更长字长数据的移位