3.2.1 数据传送类指令数据传送指令用于实现寄存器与存储器之间、寄存器之间、累加器AL/AX与I/O端口之间、立即数到寄存器或存储器之间的字节或字的传送。
这类指令的共同特点是不影响标志寄存器的内容(SAHF,POPF除外)。
堆栈操作指令、标志位传送指令和地址传送指令也归入这一类中,共14条指令,又可分为4组,如表3.4所示。
1.通用数据传送指令通用数据传送指令包括传送指令MOV、堆栈操作指令PUSH、POP、输入/输出指令(累加器传送指令)、数据交换指令XCHG和查表转换指令XLAT。
这类指令是唯一允许以段寄存器作为操作数的指令(XCHG除外)。
表3.4 数据传送类指令指令类型指令书写格式指令功能通用数据传送指令MOV 目标,源PUSH 源POP 目标XCHG 目标,源XLAT 字节或字传送字压入堆栈字弹出堆栈字节或字交换字节翻译目标地址传送指令LEA 目标,源LDS 目标,源LES 目标,源装入有效地址装入DS寄存器装入ES寄存器标志位传送指令LAHFSAHFPUSHFPOPF 将FR低字节装入AH寄存器将AH内容装入FR低字节将FR内容压入堆域从堆栈弹出FR内容I/O数据传送指令IN 累加器,端口OUT 端口,累加器从端口输入字节或字将字节或字输出到端口(1)MOV 传送指令指令格式:MOV OPD,OPS指令功能:将源操作数OPS传送到目的操作数OPD,即(OPD)→(OPS)。
源操作数OPS可以是8/16位的通用寄存器、段寄存器、存储器中某单元或8/16位的立即数。
(2)PUSH进栈(压入)指令指令格式:PUSH OPS指令功能:将源操作数OPS压入堆栈,即SP–2 → SP,OPS → (SPH,SP)。
源操作数0PS可以是16位通用寄存器、段寄存器或存储器中的数据字,以保证堆栈按“字”操作。
源操作数OPS不能是立即数。
由于堆栈是按“后进先出”方式工作,所以每次执行PUSH指令时,总是首先修改栈指针(S P)–2 → SP (即SP先减2),使之指向新栈顶,然后把源操作数压入堆栈中SP所指示的位置,高字节在较高地址单元,低字节在较低地址单元中(真正的栈顶单元)。
由于堆栈总是按字操作,所以,SP总是指向字地址单元,堆栈段基址由SS确定。
堆栈最大容量为64K。
(3)POP出栈(弹出)指令指令格式:POP OPD指令功能:将堆栈中当前SP所指示的栈顶的一个字传送到指定的目的操作数OPD中,同时修改栈指针,即(SP+1,SP)→ OPD,(SP)+ 2 → SP,出栈操作是进栈操作的逆过程。
目的操作数OPD可以是16位通用寄存器、段寄存器或存储单元,但CS不能作目的操作数。
和进栈指令不同的是,出栈操作时是先将数据弹出送入目标地址,然后修改栈指针,即将S P减2送SP,这时SP向高地址端移动,指向新的栈顶。
(4)XCHG数据交换指令指令格式:XCHG OPD,OPS指令功能:把一个字或字节的源操作数OPS与目的操作数OPD互相交换位置。
即(OPD)→ OPS,(OPS)→ OPD。
源操作数OPS可为通用寄存器或存储器,目的操作数OPD只能为通用寄存器。
因此,交换指令可以在通用寄存器之间、通用寄存器与累加器之间、通用寄存器与存储器之间进行。
段寄存器不能作为操作数。
(5)XLAT查表转换指令(换码指令)指令格式:XLAT 转换表或XLAT指令功能:将[BX]为首址,[AL]为位移量的字节存储器单元中的数据→ AL,即[BX+AL] → AL。
查表转换指令XLAT可用来将一种代码转换成另一种代码,或者说可使累加器中的一个值变换为内存表格中的某一个值。
具体实现是这样的:使用XLAT指令之前必须先在内存(数据段)中建立一个表格,表格的内容就是所需要转换的代码,表格最多不超过256个字节,将表格的起始地址事先装入BX寄存器中,AL中存放所要查找的对象(表中某一项)到表首地址间的位移量。
执行XLAT指令时,就将BX 中的内容和AL中的内容相加作为有效地址,将表格中与该地址相对应的单元中的内容取出并传送到AL中。
也就是说,指令执行后所要查找的对象(即转换后的代码)就在AL中,BX中内容保持不变。
可见,只要改变AL的值即可从表中找到不同的代码。
例:利用XLAT指令将一位十六进制数转换为对应的ASCII码。
为实现这一转换,首先应在内存数据段建立一个表格,表中存放着十六进制数0,1,…,F 的ASCII码,并将表格的首地址置于BX中,AL中置入所要查找的十六进制数距表头的位移量,比如现在要查找表中第5项内容,则AL中应置入4。
实现上述操作的程序如下:DATA SEGMENTTAB DB ‘0 1 2 3 4 5 6 7 8 9 A B C D E F’DATA ENDMOV BX,OFFSET TAB ;变量TAB的有效地址FA → BX,即表示首址MOV AL,4 ;TAB表中第5项的位移量4 → ALXLAT TAB ;([BX+AL])=(TAB+4)=34H → AL上述过程如图3.5所示。
程序中DATA SEGMENT到DATA END之间的语句是十六进制数的ASCII码表。
2.地址传送指令8086/8088指令系统中有3条专门用于传送地址的指令:LEA、LDS和LES。
可用来传送操作数的段地址或偏移地址。
(1)LEA取有效地址指令指令格式:LEA OPD,OPS指令功能:按源操作数OPS提供的寻址方式计算偏移地址(即EA),并将该偏移地址传送到目的操作数OPD所指示的16位寄存器中。
注意:LEA指令中要求源操作数OPS所提供的必须是一个存储器单元地址,而目的操作数OPD必须是一个除段寄存器以外的16位寄存器。
另外,使用LBA指令时应注意它与MOV 指令的区别,MOV指令传送的是源操作数中的内容,而LEA指令传送的是源操作数的有效地址。
注意下面两条指令的区别:MOV AX,[SI] ;将SI所指示的存储单元中的内容送AXLEA AX,[SI] ;将SI所指的存储单元的EA送AX下列两条指令是等价的,都是将变量NUM的EA送SI中。
MOV SI,OFFSET NUM ;将变量NUM的EA送SI中,;OFFSET为数值返回运算符LEA SI,NUM ;与上条MOV指令等效,将NUM的EA送SI;这说明有时可用MOV指令来代替LEA指令。
(2)LDS送偏移地址及数据段首址指令指令格式:LDS OPD,OPS指令功能:(OPS)→ OPD,(OPS+2)→ DS该指令执行时是把从源操作数OPS所指示的连续4个字节(双字)存储器单元中的操作数送到目的寄存器OPD和DS中,其中低位地址的两个字节传送到OPD指示的寄存器中,高位地址的两个字节传送到段寄存器DS中。
可见,LDS指令要求:OPD一定要是一个16位通用寄存器,常用SI寄存器。
OPS所提供的一定要是一个存储器地址,且是一个地址指针,从指针所指示的地址单元开始,连续4个字节单元的内容分别送入OPD和DS中。
(3)LES传送偏移地址及附加数据段首址指令指令格式:LES OPD,OPS指令功能:(OPS)→ OPD,(OPS+2)→ ESLES指令功能与LDS类似,所不同的是将OPS所指示的4个连续单元中的后两个字节(高地址)单元中的内容送入附加数据段寄存器ES中而不是送入DS,前两个字节(低地址)单元中的内容送OPD所指示的16位寄存器中。
3.标志位传送指令标志位传送指令共有4条:LAHF(标志装入AH)、SAHF(AH的内容存入标志寄存器)、PUSHF(标志压入堆栈)和POPF(标志出栈)。
这些都是单字节指令,指令的操作数是隐含的,因此这些指令都是无操作数指令。
通过这些指令的执行,可以读出当前标志寄存器中的内容,也可以对标志寄存器设置新值。
(1)LAHF标志寄存器低字节送AH指令指令格式:LAHF指令功能:把标志寄存器FR中SF,ZF,AF,PF和CF(8080和8085所具有的标志)分别送到AH中第7,6,4,2和0位,AH中第5,3,1位内容未定义,可任意,标志寄存器本身内容不变。
(2)SAHF AH送标志寄存器低字节指令指令格式:SAHF指令功能:SAHF的功能与LAHF指令相反,是将AH中第7,6,4,2和0位状态传送至标志寄存器FR中的SF,ZF,AF,PF和CF位,取代这些标志位原内容,而OF,IF,TF,DF标志不受影响。
可见,通过该指令可以对标志位进行重新设置,所以该指令也叫设置标志指令。
(3)PUSHF标志进栈指令指令格式:PUSHF指令功能:把整个标志寄存器的内容压入堆栈,同时修改栈指针,即SP–2 → SP,该指令执行后不影响标志位。
(4)POPF标志出栈指令指令格式:POPF指令功能:POPF的功能正好与PUSHF相反,是将当前堆栈指针SP所指的一个字传送到标志寄存器FR中,同时修改栈指针即SP+2 → SP。
PUSHF和POPF这两条指令用于人为地保存和恢复标志寄存器,常用过程调用和中断服务程序的开头与结尾,用来保存主程序的状态标志。
这两条指令的另一个用途是用来改变跟踪单步标志TF,8086/8088指令系统中没有能直接改变TF的指令,若要改变TF,可先用PUSHF指令将标志寄存器压入堆栈,然后设法改变栈顶单元中D8位(TF位),然后再用POPF指令把堆栈中修改过的内容送回标志寄存器。
这样,只有TF位被改变,其它标志位不变。
4.输入/输出指令(累加器专用传送指令)输入/输出数据传送指令简称I/O指令,共两条,一条是输入指令IN,另一条是输出指令OUT。
I/O指令用来完成累加器AL/AX与I/O端口问的数据传送,指令中给出I/O端口的地址,当端口地址值≤255时,端口地址由指令中直接给出,当端口地址值≥256时用间接方式,先将端口地址位置于DX中,然后指令中用DX作间址方式表示。
因此,I/O指令有两种格式。
(1)IN输入指令指令格式:直接方式(长格式):IN AL,端口地址;字节(8位)传送IN AX,端口地址;字(16位)传送间接方式(短格式):IN AL,DX ;端口地址放在DX寄存器中IN AX,DX指令功能:将端口地址中的8位或16位数传送到AL或AX中,将端口中的16位数输入时,先将指定端口中的字节数送入AL中,再将端口地址+1,然后将该端口中的字节数送入A H中。
由上可知,IN指令有两种格式,当端口地址为00~FFH时用直接方式,端口地址值包含在指令中;当端口地址为0000~FFFFH时,用间接方式,即先将端口地址放在DX中,指令中用DX代替端口地址。
注意,这时指令的书写形式与寄存器寻址方式相似,但这里实际上是间址方式。
例:IN AL,02FH ;将02FH端口的一个字节数送入ALIN AX,060H ;将060H端口的内容送AL,将061H端口的内容送AHMOV DX,300H ;先将端口地址300H送人DX中IN AL,DX ;将300H端口的内容送入AL中(2)OUT输出指令指令格式:直接方式:OUT端口地址,AL ;字节(8位)输出OUT端口地址,AX ;字(16位)输出间接方式:OUT DX,AL ;DX中为端口地址OUT DX.AX指令功能:将累加器(AL/AX)中的内容输出传送到指定的I/O端口中。