数据传送指令是一种简单而又基本的语句,它常用于给寄存器、内存变量置初值或赋新值。当需要把一些信息传送到某处时,就要用数据传送指令。下面介绍最常用的5种数据传送指令。
形式:MOV 目标操作数,源操作数。
功能:目标操作数←(源操作数)。
该指令有如下9种形式:
MOV R,R ; 通用寄存器间传送
MOV R,Im ; 立即数送通用寄存器
MOV M,Im ; 立即数送内存单元
MOV M,R ; 通用寄存器送内存单元
MOV R,M ; 内存数送通用寄存器
MOV SegR,R ; 通用寄存器送段寄存器(CS除外)
MOV R,SegR ; 段寄存器送通用寄存器
MOV SegR,M ; 内存数送段寄存器(CS除外)
MOV M,SegR ; 段寄存器送内存单元
使用MOV指令应注意:
(1)源操作数和目的操作数不能同时为内存数,即MOV M,M的指令形式是非法的。
(2)两个操作数的类型属性要一致,例如,MOV AX,BL指令中的两个操作数,一个是字操作数,一个是字节操作数,两个操作数的类型不一致,所以是非法指令。
(3)操作数不能出现二义性,即至少一个操作数的类型要明确,例如,MOV [BX],1000H指令中的两个操作数的类型都不明确,不知是字还是字节。更要特别注意的是,立即数是没有类型的,不能把16位二进制数当作字类型,也不能把8位二进制数当字节类型。
形式:XCHG 目标操作数,源操作数。
功能:目标操作数 源操作数。
该指令有如下3种形式:
XCHG R,R ; RR
XCHG R,M ; RM
XCHG M,R ; MR
微处理器有3条指令专门传送地址,它们的目标操作数均是16位的通用寄存器,源操作数都是内存数。
(1)LEA——传送偏移地址指令。
形式:LEA 目标操作数,源操作数。
功能:目标操作数←源操作数的偏移地址。
该指令只有如下一种形式:
LEA R 16,M ; R16←OFFSET M
该指令的意义是将按源操作数M提供的寻址方式计算的偏移地址送16位通用寄存器。该指令通常用来给某个16位通用寄存器设置偏移地址的初值。
假设BUFF是内存变量名,例如:
LEA SI,BUFF
该指令的功能是将BUFF的偏移地址送入SI寄存器,源操作数是直接寻址。
MOV SI,OFFSET BUFF
该指令的功能是将BUFF的偏移地址送入SI寄存器,所以该指令与上条指令是等价的,不过该指令的源操作数是立即寻址。
MOV SI,BUFF
该指令的功能是将BUFF单元的内容送入SI寄存器。
(2)LDS——传送数据段地址指令。
形式:LDS 目标操作数,源操作数。
功能:目标操作数←(源操作数),DS←(源操作数+2)。
该指令只有如下一种形式:
LDS R16,M ; R16←(M),DS←(M+2)
该指令的意义是将存于M的逻辑地址(双字)的段地址送DS,偏移地址送16位通用寄存器。
例如:
LDS SI,[BX] ;SI←(DS:[BX]),(DS:[BX+1]),Ds←(DS:[BX+2]),(DS:[BX+3])
(3)LES——传送附加段地址指令。
形式:LES 目标操作数,源操作数。
功能:目标操作数←(源操作数),ES←(源操作数+2)。
该指令只有如下一种形式:
LES R16,M ; R16←(M),DS←(M+2)
该指令的意义是将存于M的逻辑地址(双字)的段地址送ES,偏移地址送16位通用寄存器。
例如:
LES SI,[BX] ;SI←(DS:[BX]),(DS:[BX+1]),ES←(DS:[BX+2]),(DS:[BX+3])
例如有一数据段定义如下:
mydata SEGMENT
ORG 1000H
dPt1 DD 15780100H
dPt2 DD 20001000H
wEa DW 4765H
mydata ENDS
有如下语句:
LEA SI,dPt1 ; SI←1000H
LEA BP,dPt2 ; BP←1004H
LDS DI,dPt1 ; DI←0100H,DS←1578H
LES BX,dPt2 ; BX←1000H,ES←2000H
LDS DI,wEa ; 非法指令,源操作数若为内存变量,类型需为双字
形式:XLAT。
功能:AL←(DS:[BX+AL])。
该指令的操作数都是隐含的,所执行的操作是将以BX为基地址,AL为位移量的字节存储单元中的数送AL。该指令可以很方便地将一种代码转换为另一种代码。
【例9-1】 数字0~7对应的格雷码为:
数字 格雷码 十六进制值
0 000 00H
1 001 01H
2 011 03H
3 010 02H
4 110 06H
5 111 07H
6 101 05H
7 100 04H
要求从键盘输入一位0~7的十进制数码,把它变成格雷码再输出到显示器上。
注意:因为十进制数码与格雷码之间没有函数关系,所以必须用查表指令来实现转换,不过应在数据段首先建立格雷码表。
源程序:
.MODEL SMALL
.STACK 200H
.DATA
bGlm DB 00H,01H,03H,02H
DB 06H,07H,05H,04H
.CODE
start:MOV AX,@DATA
MOV DS,AX
MOVAH, 1
INT 2IH ; 等待从键盘输入数码→AL
SUB AL,30H ; 将ASCII码转换成数值
LEA BX,bGlm
XLAT ; AL←对应的格雷码
ADD AL,30H ; AL←将格雷码转换成ASCII码
MOV DI,AL
MOVAH, 2
INT 21H ; 在CRT显示
.EXIT 0
END start
运行结果(带下画线表示输入的字符)如下:
46
堆栈是以“后进先出”的规则存取信息的一种存储机构。在微机中,堆栈就是在内存中定义的一部分空间。为了保证堆栈区能按“后进先出”的规则存取信息,该存储区的存取地址由一个专门的地址寄存器(SP)来管理,这个地址寄存器称为堆栈指针或称为堆栈指示器。当信息存入堆栈时,堆栈指针将自动递减,然后将信息存入堆栈指针所指示的存储单元中;当需要从堆栈中取出信息时,首先将堆栈指针所指示的存储单元的内容读出,然后堆栈指针将自动递增。所以,堆栈指针始终指向堆栈中最后存入信息的那个单元,我们称该单元为堆栈顶。在信息的存与取的过程中,栈顶是不断移动的,而栈底是固定不变的。对堆栈的操作主要有两大类:进栈(信息的存入)和出栈(信息的取出)。
(1)进栈。
形式:PUSH操作数16。
功能:系统自动完成两步操作,即SP←SP-2,SP←操作数16。
该指令有如下3种形式:
PUSH R16 ; SP←SP-2,SP←R16
PUSH SegR ; SP←SP-2,SP←SegR
PUSH M16 ; SP←SP-2,SP←M16
(2)出栈。
形式:POP 操作数16。
功能:系统自动完成两步操作,即操作数16←(SP),SP←SP-2。
该指令有如下3种形式:
POP R16 ; R16←(SP),SP←SP-2
POP SegR ; SegR←(sP),sP←sP-2,(CS除外)
POP M16 ; M16←(SP),SP←SP-2
【例9-2】 在例9-1中显示的界面不美观,因为从键盘输入的数据和格雷码混在一起。为了有所区分,希望显示格式为:
键盘输入的数据——对应的格雷码
注意:为了实现所要求的显示格式,我们只需在例9.1中显示格雷码前加显“-”。但是,加显“-”的系统程序的调用改变了AL寄存器值。为了保护AL中的值,通常做法都是将其压入堆栈,显示“-”后,再将其从堆栈中取出传给AL。
源程序:
.MODEL SMALL
.STACK 200H
.DATA
bGlm DB 00H,01H,03H,02H
DB 06H,07H,05H,04H
.CODE
start:MOV AX,@DATA
MOV DS,AX
MOVAH, 1
INT 21H ; 等待从键盘输入数码→AL
SUB AL,30H ; 将ASCII码转换成数值
LEA BX,bGlm
XLAT ; AL←对应的格雷码
PUSH AX ; 保护AL寄存器值
MOV DI,'-'
MOV AH,02H
INT 21H ; 显示“-”
POP AX ; 恢复AL寄存器值
ADD AL,30H ; AL←将格雷码转换成ASCII码
MOV DI,AL
MOVAH, 2
INT 21H ; 在CRT显示
.EXIT 0
END start
运行结果:
4-6
现在我们来分析该程序的堆栈定义及操作。该程序中的语句“.STACK 200H”就是对堆栈的定义,即在内存中划分出200H字节作为堆栈区,其地址为SS:0000H~SS:01FFH,那么堆栈指针SP的初值为0200H,如图9-1所示。程序中的堆栈操作语句有:
PUSH AX
该语句SP←01FEH,(SS:01FE)←(AL),(SS:01FF)←(AH),堆栈变化如图9-2所示。
POP AX
该语句AL←(SS:01FE),AH←(SS:01FFH),SP←0200H,堆栈变化如图9-3所示。
图9-1 堆栈的定义 图9-2 进栈操作 图9-3 出栈操作