这篇文章详细介绍8086/8088指令集中的大部分重要指令。
指令集说明
1.分组
与早先的8位微处理器相比,8086/8088的指令系统丰富,而且指令功能强大。大多指令既能处理字数据,又能处理字节数据;算术运算和逻辑运算不局限于累加器,存储器操作数也可以直接参加算术逻辑运算。
8086/8088的指令系统可以分为如下六个功能组:
(1)数据传送
(2)算数运算
(3)逻辑运算
(4)串操作
(5)程序控制
(6)处理器控制
2.指令表示格式
在汇编语言中,指令语句可由四部分组成,一般格式如下:
[标号] 指令助记符 [操作数1] [操作数2] [注释]
指令是否带有操作数,完全取决于指令本身,有的指令误无操作数,有的指令只有一个操作书,有的指令需要两个操作数。标号的使用取决与程序的需要。请注意:
标号只被汇编程序识别它与指令本身无关。
3.其他说明
对于每一条指令程序员要注意以下几点:
(1)指令的功能
(2)适用于指令的操作数寻址方式
(3)指令对于标志的影响
(4)指令的长度和执行时间
数据传送指令
数据传送指令是使用的最为频繁的指令,其格式如下:
MOV DST,SRC
此指令把一个字节或一个字从源操作数SRC送至目的操作数DST。
源操作数可以是累加器,寄存器,存储单元以及立即数,而目的操作数可以是累加器,寄存器和存储单元。传送不改变源操作数。
具体地说,数据传送指令能实现下列传送功能:
(1)CPU内部寄存器之间的数据传送。例如:
MOV AH,AL
MOV DL,BH
MOV BP, SP
MOV AX, CS
MOV DS, BX
就寄存器之间传送数据而言,下列情况是例外:
(1)源和目的不能同时是段寄存器
(2)代码段寄存器CS不能作为目的
(3)指令指针IP既不能作为源,也不能作为目的
这些例外永远存在。
(2)立即数送至通用寄存器或存储单元(各种存储器寻址方式)。例如:
MOV AL,3
MOV SI,-5
MOV VARB,-1 ;VARB是变量名,代表一个存储单元
MOV VARW,3456H ;VARW是一个字变量
MOV [SI],6543H
注意,立即数不能直接传送到段寄存器,立即数永远不能作为目的操作数。
(3)寄存器与存储器间的数据传送。例如:
MOV AX,VARW ;VARW是一个字变量,存储器操作数作为直接寻址
MOV BH,[DI] ;存储器操作数为寄存器间接寻址
MOV DI,ES:[SI+3] ;存储器操作数作为相对变地寻址,使用段超越前缀
MOV BP,[BX+SI+3] ;存储器操作数为相对基址加变址寻址
MOV VARB,DL ;VARB是一个字节变量
MOV [BP],AX ;使用SS段寄存器
MOV DS:[BP],DL ;使用段超越前缀
MOV VARW,DS ;VARW是一个字变量
MOV ES,VARW
对于存储器操作数而言,可采用各种存储器寻址方式,这一点对其他指令也一直成立。关于MOV指令,除了前面的例外,还要遵循下列规则:
(1)源操作数和目的操作数类型要一致。即同时为字节或字,不能一个是字节,另一个是字。
(2)除了串操作指令外,源操作数和目的操作数不能同时是存储器操作数。
这些例外和规定不仅适用于MOV指令,也同样适用于所有涉及操作数的指令。
如果要在两个存储单元间传送数据,那么可利用通用寄存器过度的方法,例如:
MOV AX,VARW1 ;把字变量VARW1的内容送到字变量VARW2
MOV VARW2,AX
这种利用通用寄存器过度的方法,也适用于段寄存器间的数据传送,例如:
MOV AX,CS ;把CS的内容送到DS
MOV DS,AX
交换指令
交换指令可以方便地实现通用寄存器与通用寄存器或存储单元的交换,交换指令格式如下:
XCHG OPRD1,OPRD2
此指令把操作数OPRD1的内容与操作数OPRD2的内容交换。操作数同时是字节或者字。例如:
XCHG AL,AH
XCHG SI,BX
OPRD1和OPRD2可以是通用寄存器和存储单元。但不包括段寄存器,也不能同时是存储单元,还不能有立即数,这符合以介绍的例外和规定。可采用各种存储器寻址方式来指定存储单元,例如:
XCHG [SI+3],AL
XCHG [DI+BP+3],BX
地址传送指令
8086/8088有如下三条地址传送指令。
(1)指令LEA(Load Effective Address)
指令LEA称为传送有效地址指令,其格式如下:
LEA REG,OPRD
该指令把操作数OPRD的有效地址传送到操作数REG。操作数OPRD必须是一个存储器操作数,操作数REG必须是一个16位的通用寄存器,例如:
LEA AX,BUFFER
LEA DX,[BX+3]
LEA SI, [BP+DI+4]
请注意,LEA指令与把存储单元中的数据传送到寄存器的MOV指令有本质上的区别。假设变量BUFFER的偏移是1234H,该字变量的值为5678H,那么在执行万指令“LEA AX,BUFFER”后,AX寄存器中的值为5678H,而不是1234H。
(2)指令LDS(Load pointer into DS)
段值和段内偏移构成32位的地址指针。该指针传送32位地址指针,其格式如下:
LDS REG,OPRD
该指令把操作数OPRD中所包含的一个32位地址指针的段值部分送到段寄存器DS,把偏移部分送到指令给出的通用寄存器REG。操作数OPRD必须是一个32位的存储器操作数,操作数REG可以是一个16位的通用寄存器,但实际使用的往往是变地寄存器或指针寄存器。例如:
LDS DI,[BX]
LDS SI,FARPOINTER ;FARPOINTER是一个双字变量
假设双字变量FARPOINTER包含的32位地址指针的段值为5678H,偏移为1234H,那么在执行指令“LDS SI,PARPOINTER”后,段寄存器DS的值为5678H,寄存器SI的值为1234H。32位地址指针的偏移部分存储在双字变量的低位地址中,段值部分存储在高地址字中。
(3)指令LES(Load pointer into ES)
LES指令也传送32位地址指针,其格式如下:
LES REG,OPRD
该指令把操作数OPRD中所含的32位地址指针段值部分送到附加段寄存器ES,把偏移部分送到指令给出的通用寄存器REG。其他说明同指令LDS。
堆栈操作指令
8086/8088系统中,堆栈是一段RAM区域。称为栈底的一端地址较大,称为栈顶的一端地址较小。堆栈的段值在堆栈段寄存器SS中,堆栈指针寄存器SP始终指向栈顶。只要重新设这SS和SP的值(例如MOV指令)就可以改变堆栈的位置。堆栈的深度SP的初值决定。
堆栈操作始终遵守“后进先出”的原则,所有数据的存入和取出都在栈顶进行。在8086/8088系统中,进出堆栈的数据均已字为单位。
我们先列出堆栈的如下主要用途:
(1)现场和返回地址的保护
(2)寄存器内容的保护
(3)传递参数
(4)存储局部变量
堆栈操作指令分为两种,进栈指令PUSH和出栈指令POP。
1.进栈指令PUSH
进栈指令把16位数据压入堆栈,其格式如下:
PUSH SRC
该指令把源操作数SRC压入堆栈。它先把堆栈指针寄存器SP的值减2,然后把源操作数SRC送入由SP所指的栈顶。
操作数SRC可以是通用寄存器和段寄存器,也可以是字存储单元,例如:
PUSH SI
PUSH DS
PUSH VARW ;VARW是字变量
PUSH [SI]
2.出栈指令POP
出栈指令从堆栈弹出16位数据,其格式如下:
POP DST
该指令从栈顶弹出一个字数据到目的操作数DST。它先把堆栈指针寄存器SP所指的字数据传送至目的操作数DST,然后SP值加2,使其仍指向栈顶。
目的操作数DST可以是通用寄存器和段寄存器(但CS例外),也可以是字存储单元。例如:
POP [SI]
POP VARW ;VARW是字变量
POP ES
POP SI
下面程序片段说明了堆栈的一种用途,临时保存寄存器的内容:
PUSH DS ;保护DS
PUSH CS
POP DS ;使DS的内容与CS的内容相同
.....
POP DS ;恢复DS