汇编语言中的指令系统

8086/8088 共有 92 条指令,正确理解和掌握每一条指令的功能和格式,是汇编语言程序设计的基础。

一、指令系统概述

(一)指令分类

92 条指令构成了 8086/8088 指令系统,它们可分为六大类。

(1)传送类指令(Transfer instructions)。

(2)算术运算类指令(Arithmetic instructions)。

(3)位操作类指令(Bit manipulation instructions)。

(4)串操作类指令(String instructions)。

(5)程序转移类指令(Program transfer instructions)。

(6)处理器控制类指令(Processor Control instructions)。

(二)指令格式

8086/8088 指令系统中的指令有 3 种格式。

(1)双操作数指令:OPR DEST,SRC

(2)单操作数指令:OPR DEST

(3)无操作数指令:OPR

其中,OPR 是指令操作符,也称为指令助记符,它表示指令要执行何种操作。双操作数指令指定两个操作数,第一个为目的操作数,第二个为源操作数,两操作数之间要用逗号“,”分隔,它们的位置不能互换,操作的结果一般在目的操作数中。因此,目的操作数不能是常数,而只能是寄存器操作数或存储器操作数。语句执行后,目的操作数原来的内容将发生改变,而源操作数的内容不会改变。

单操作数指令只需要一个操作数,它或是源操作数(SRC),或是目的操作数(DEST)。

对于无操作数指令,虽然指令本身未指明操作数是什么、在哪里,但指令却隐含规定了操作数及存放地点。

(三)指令规则

8086/8088 指令在使用时有较严格的规定,要正确地掌握和运用这些指令,首先要准确地掌握这些规则。8086/8088 汇编语言指令共同遵守如下规则。

(1)规则 1:除通用数据传送指令(MOV、PUSH、POP)之外,段寄存器不允许作为操作数。

(2)规则 2:段寄存器不能直接用立即数赋值。

(3)规则 3:代码段寄存器 CS 和立即数不能作为目的操作数。

(4)规则 4:指令中两个操作数不能同时为段寄存器。

(5)规则 5:指令中两个操作数不能同时为存储器操作数(串指令除处)。

(6)规则 6:指令中两个操作数的类型(字节类型或字类型等)必须一致。

(7)规则 7:指令中至少要有一个操作数的类型是明确的,否则须用操作符PTR临时指定操作数类型。

下面介绍 8086/8088 指令。

二、传送类指令

传送类指令共有 12 条,包括通用数据传送指令(MOV、PUSH、POP)、交换指令(XCHG)、查表指令(XLAT)、地址传送指令(LEA、LDS、LES)和标志传送指令(PUSHT、POPT、LAHF、SAHF)。它们可以将各种类型的操作数从源传送到目的,其传送途径见图 1。图中实线表示合法传送途径,虚线为非法传送途径。所有的传送类指令对标志位均无影响。

数据的传送途径

图 1 数据的传送途径

(一)通用数据传送指令

这种指令共有3条。

  1. 传送指令(Mov)

    格式:MOV DEST,SRC

    功能:把源操作数的内容传送给目的操作数,即 DEST←SRC。

    说明:当 MOV 指令执行完后,源操作数和目的操作数都将有相同的内容,目的操作数原有的内容消失。MOV 指令可以进行字节数据传送,也可进行字数据的传送。

    例:

    MOV 指令

    而下面的指令是非法的(参见指令规则):

    非法的 MOV 指令

  2. 进栈指令(Push Word Onto Stack)

    格式:PUSH SRC

    操作:

    (1)堆栈指针减2指向新的栈顶,SP←SP-2。

    (2)将给定的操作数放入 SP 指示的字单元中。

    说明:进栈指令的操作数是一个 16 位的寄存器操作数或存储器操作数,不允许是立即数。

    例:

    进栈指令

  3. 出栈指令(Pop Word Off Stack Into Destination)

    格式:POP DEST

    操作:

    (1)将栈顶的字数据送入操作数 DEST 中,DEST←(SP+1,SP)。

    (2)堆栈指针加2指向新栈顶,SP←SP+2。

    例:

    出栈指令

通用数据传送指令的通用性在于它适合所有的操作数,比如可使用段寄存器作为操作数,而除了这 3 条通用数据传送指令之外,任何 8088 指令都不能在指令中出现段寄存器(见指令规则 1)。

(二)交换指令(Exchange)

格式:XCHG DEST,SRC

操作:将两个操作数的内容互换,即(DEST)←→(SRC)。

例:

交换指令

若进行两个内存单元 D1_BYTE 和 D2_BYTE 之间的数据交换,可用如下 3 条指令实现:

1
2
3
MOV   AL,D1_BYTE
XCHG  AL,D2_BYTE
XCHG  AL,D1_BYTE

下面的指令是非法的(参见指令规则):

非法的交换指令

(三)查表指令

格式:XLAT

功能:将数据段(DS)中偏移地址为 BX+AL 的内存字节单元的内容送入 AL 中,即 AL←(BX+AL)。

说明:XLAT 指令用于查表。表的开始地址即表头地址由BX给出。AL 中的原始值是要查找的表中元素的地址位移量。

例如:如图 2 所示,在内存符号地址 TABLE 开始有一个 0~9 的数的平方表。假如要查5的平方值,把被查数 5 放入 AL 中(这正好就是它本身的平方值在表中存放的位移量),将表头地址送入 BX 中(MOV BX,OFFSET TABLE),使用 XLAT 指令后在 AL 中就能得到 5 的平方值。

平方查表示意

图 2 平方查表示意

(四)地址传送指令

这种指令共3条,它们不是传送存储器操作数的内容,而是传送它的地址(偏移量,段基值)。

  1. 装入有效地址(Load Effective Address)

    格式:LEA DEST,SRC

    功能:把源操作数的偏移量(即有效地址EA)送给目的操作数的通用寄存器。本指令中SRC必须是一个存储器操作数,而DEST一定是16位通用寄存器。

    例:

    装入有效地址

  2. 装入地址指针(Load Address of Point)

    地址指针的值是由 16 位段基值和 16 位偏移量两部分构成的,装入地址指针指令能用一条指令实现将存放在内存中的地址指针值的段基值送入段寄存器,同时将偏移量部分送入指令规定的寄存器中。

    格式:

    (1)LDS DEST,SRC

    (2)LES DEST,SRC

    功能:将双字长存储器操作数 SRC 的低地址字单元内容送入指定的寄存器 DEST 中,而将双字长存储器操作数 SRC 的高地址字单元内容送入 DS(LDS)或 ES(LES)。

    说明:指令的目的操作数(DEST)要存放地址指针的偏移值部分,因此,必须是一个 16 位通用寄存器,而 SRC 一定是存储器操作数。

    例如,设 SI 间址寄存器所指的内存单元存放的数据如图 3 所示,若有下面指令:

    LDS BX,[SI]

    则该指令执行后,DS 内容为 9010H,BX 内容为 302FH。

    LDS 指令的传送

    图 3 LDS 指令的传送

(五)标志传送指令(Flags Transfer)

8086/8088 设计了 4 条指令专门用于标志寄存器的存取操作。它们都是无操作数指令。

  1. 取标志寄存器

    格式:LAHF

    功能:把标志寄存器的低8位传送给 AH 寄存器。

  2. 存储标志寄存器

    格式:SAHF

    功能:把寄存器 AH 中的第 7、6、4、2、0 位的内容分别送入标志寄存器 SF、ZF、AF、PF 和 CF 各标志位。标志寄存器 OF、DF、IF 和 TF 各位均不受影响。

  3. 标志进栈

    格式:PUSHF

    功能:首先把堆栈指针 SP 减 2,然后将 16 位标志寄存器的全部内容(含所有标志位)送入 SP 指向的堆栈顶部。标志寄存器中各标志位本身不受影响。

  4. 标志出栈

    格式:POPF

    功能:首先将现行堆栈顶部(由 SP 决定)的一个字的内容送入标志寄存器,然后 SP+2。标志寄存器中各标志位的状态,由从堆栈中弹出字的相应位的内容所决定。

标志寄存器中只有少数几个标志位(如 CF、DF、IF)有专门的指令进行置 0 或置 1 操作,其余大部分标志位都没有指令直接对它们进行设置或修改。例如要修改 SF,那么可首先用 LAHF 指令把含有 SF 标志位的标志寄存器低 8 位送入 AH,然后对 AH 的第 7 位(对应 SF 位)进行修改或设置,再用 SAHF 指令送回标志寄存器。

三、算术运算类指令

8086/8088 的算术运算指令提供加、减、乘、除四类运算,可对 4 种数据进行处理。这 4 种数据如下。

(1)无符号二进制数。

(2)带符号二进制数。

(3)无符号组合十进制数(组合BCD码)。

(4)无符号非组合十进制数(非组合BCD码)。

(一)二进制加法运算指令

二进制加法指令有 3 条,指令格式和功能如下。

  1. 加法指令

    格式:ADD DEST,SCR

    功能:将源操作数SCR和目的操作数 DEST 相加,结果存入 DEST 中,即 DEST←DEST+SCR。

    说明:加法指令可以进行字节或字的加法,其结果放在目的操作数中,源操作数原有的内容不变(对任何指令都是如此)。

    例:

    1
    2
    
    ADD  AX,X
    ADD  AL,0A4H
    
  2. 带进位加指令

    格式:ADC  DEST,SCR

    功能:将源操作数 SCR、目的操作数 DEST 及进位标志 CF 位相加,结果存入 DEST 中,即 DEST←DEST+SCR+CF。

    说明:ADC 指令主要用于大于 16 位(多字节)数的加法中。例如,有一个 32 位二进制数已存放在 AX(高 16 位)和 BX(低 16 位)中,现要加上常数 208A9F88H,可用下面两条指令来实现:

    1
    2
    
    ADD  BX,9F88H
    ADC  AX,208AH
    

    其中,第一条指令把低16位常数9F88H加在BX中,若它们相加高16位有进位时,则把进位记录在CF中。在第二条指令完成高16位加时,用ADC指令同时把低16位的进位一起加上。

  3. 加1指令

    格式:INC  DEST

    功能:将目的操作数 DEST 自身加1,结果存入 DEST 中,即 DEST←DEST+1。

    说明:INC 指令主要用于某些计数器的计数和地址指针值的修改。

    例:

    1
    
    INC  SI  ;SI←SI+1
    

    注意:加法指令会按其执行结果设置 6 个状态标志的状态,但 INC 指令对进位标志 CF 无影响。

(二)二进制减法运算指令

  1. 减法指令

    格式:SUB  DEST,SRC

    功能:将目的操作数 DEST 内容减去源操作数 SRC 内容,结果送入 DEST 中,即 DEST←DEST-SRC。

  2. 带借位减法指令

    格式:SBB  DEST,SRC

    功能:将目的操作数 DEST 内容减去源操作数 SRC 内容及 CF 位,结果送入 DEST 中,即 DEST←DEST-SRC-CF。

    说明:SBB 指令在使用上类似于 ADC 指令,主要用于大于 16 位的多精度数的减法,把低位部分相减的借位引入高位部分的减法中。

  3. 减 1 指令

    格式:DEC DEST

    功能:将目的操作数 DEST 内容减 1,结果送入 DEST 中,即 DEST←DEST-1。

    说明:DEC 指令使用上类似于 INC 指令,主要用于计数和修改地址指针,但方向与 INC 指令相反。DEC 操作不影响进位标志 CF。

  4. 比较指令

    格式:CMP DEST,SRC

    功能:目的操作数 DEST 减去源操作数 SRC,即 DEST←DEST-SRC。

    说明:CMP 指令将两个操作数相减,但相减的结果并不保留,两个操作数都保持原值不变,只是将相减结果的特征反映在各个状态标志位上。比如当 CMP 指令执行后,如果标志位 ZF=1,说明被比较的两数相等,可以在 CMP 指令后,用单标志判断转移指令或条件判断转移指令来确定比较的结果(大于、小于、等于)。

  5. 取补指令

    格式:NEG  DEST

    功能:零减去目的操作数 DEST,结果存入目的操作数 DEST,即 DEST←0-DEST。

    说明:NEG 指令是求操作数的负数,即改变操作数的符号,这对带符号数来说就是求其补码。因此 NEG 也叫取补指令。NEG 对标志位影响有特殊规定,如果被取补的操作数非 0,NEG 操作后,CF 置 1,否则 CF=0。

(三)二进制乘法运算指令

  1. 无符号数乘法指令

    格式:MUL  SRC

    功能:若 SRC 为字节长度,则 AX←AL×SRC;若 SRC 为字长度,则 DX:AX←AX×SRC。

    说明:乘法指令格式中只出现源操作数,根据这个操作数的类型(字节类型或字类型)决定是 8 位乘还是 16 位乘。因此,SRC 不能是立即数(立即数无类型属性),而目的操作数(被乘数)隐含约定为累加器 AL(8 位乘)或 AX(16 位乘),运算的结果约定在 AX 中(8 位乘法的积)或 DX:AX 中(16 位乘法的积),如图 4 所示。

    乘法指令操作示意

    图 4 乘法指令操作示意

  2. 带符号数乘法指令

    格式:IMUL SRC

    功能:功能同 MUL 指令

    说明:乘法指令对标志的影响有特殊规定,它只影响标志位 CF 和 OF。对于 MUL,如果乘积的高半部(8 位乘时为 AH,16 位乘时为 DX)为零,CF=0,OF=0;否则 CF=1,OF=1(表示 AH 或 DX 中有乘积的有效数字)。对于 IMUL,若积的高半部是低半部的符号扩展,则 CF=0,OF=0;否则 CF 和 OF 均为 1。

(四)二进制除法指令

二进制除法运算指令包括无符号数除法(DIV)和带符号数除法(IDIV)。对带符号数来说,还有两条符号扩展指令(CBW、CDQ)。

  1. 无符号数除法指令

    格式:DIV SRC

    功能:若 SRC 为字数据,则 AX/SRC,AL←商,AH←余数;若 SRC 为字数据,则 DX:AX/SRC,AX←商,DX←余数。

  2. 带符号数除法指令

    格式:IDIV SRC

    功能:同 DIV 指令。

    说明:同乘法指令类似,除法指令中的操作数 SRC 为除数,它不能是立即数。目的操作数(被除数)也有两种情况,当除数为 8 位时被除数隐含为 AX,运算结果商约定在 AL 中,余数约定在 AH 中;当除数为 16 位时,被除数隐含在 DX:AX,运算结果约定在 AX 中,余数在 DX 中,如图 5 所示。

    除法指令操作示意

    图 5 除法指令操作示意

    注意:

    (1)除法指令对标志位的影响无意义。

    (2)除数必须足够大,使得商值小于等于8位或16位数表示的范围;否则,将产生除法错误。

  3. 字节扩展指令

    格式:CBW

    功能:对 AL 中的带符号数进行符号扩展。若 AL<0,AH=0FFH,否则 AH=0。

(五)十进制算术运算指令

大家知道,计算机只能处理二进制信息,但在实际的生产和生活中,人们习惯使用十进制数。因此,需要计算机处理的原始数据大部分是十进制数据。人们希望计算机能接收这些十进制数,并将处理的结果以十进制形式输出。这时从外部来看,好像计算机在进行十进制数运算一样。

每一位十进制数在计算机内部,通常是用 4 位二进制数表示的,它是十进制数的二进制编码。8086/8088 CPU 实现十进制运算的方法是仍将这些十进制数(BCD 码)看作二进制数,使用二进制加、减、乘、除指令进行运算,不过在运算后(或前)用调整指令进行调整以得到十进制(BCD 码)结果。故此,针对非组合和组合 BCD 码,8086/8088 提供了6 条算术运算相应的 BCD 码调整指令。

  1. 非组合十进制调整指令

    (1)加法调整指令(ASCII Adjust for Addition)。

    格式:AAA

    功能:若 AL 中的低 4 位值大于 9 或 AF=1,则将 AL 加 6 和 AH 加 1,并将 AF 和 CF 置 1,然后将 AL 的高 4 位清 0;否则只进行清 AL 高 4 位操作。

    受影响的状态标志位:AF、CF(OF、ZF 和 PF 的状态不确定)。

    (2)减法调整指令(ASCII Adjust for Subtraction)。

    格式:AAS

    功能:如果 AL 中的低 4 位大于 9 或 AF=1,那么就将 AL 减 6 且 AH 减 1,并将 AF 和 CF 置 1,然后将 AL 的高 4 位清 0;否则只进行清 AL 高 4 位操作。

    受影响的状态标志位:AF、CF(OF、SF、ZF 和 PF 的状态不确定)。

    (3)乘法调整指令(ASCII Adjust for Multiply)。

    格式:AAM

    功能:将 AL 中的内容除以 10,商送入 AH 中,余数送入 AL 中。

    受影响的状态标志位:SF、ZF、PF(OF、AF、CF 状态不确定)

    说明:AAM 指令将两个有效的非组合十进制数相乘后得到的乘积调整为一个有效的非组合十进制数,AAM 指令执行后被调整字节的高 4 位为 0。

    (4)除法调整指令(ASCII Adjust for Division)。

    格式:AAD

    功能:将 AH 中的内容乘以 10 后与 AL 相加,结果存到 AL 中,然后将 AH 清 0。

    受影响的状态标志位:SF、ZF、PF(OF、AF、CF 状态不确定)。

    说明:AAD 指令在两个有效的非组合十进制数做除法之前调整 AL 中的内容,以使除法得到的商数为一个有效的非组合十进制数。为了使跟在其后的 DIV 指令能产生一个正确的结果,AH 必须为 0。除法指令执行后,商存放在 AL 中,余数存放在 AH 中,它们的高 4 位都为 0。

  2. 组合十进制调整指令

    (1)加法调整指令(Decimal Adjust for Addition)。

    格式:DAA

    功能:如果 AL 中的低 4 位大于 9 或 AF=1,那么就将 AL 加 6,并将 AF 置 1;如果 AL 的高 4 位大于 9 或 CF=1,则将 60H 加到 AL 中,并将 CF 置 1。

    受影响的状态标志位:OF、SF、ZF、AF、PF、CF。

    (2)减法调整指令(Decimal Adjust for Subtraction)。

    格式:DAS

    功能:如果 AL 中的低 4 位大于 9 或 AF=1,那么就将 AL 减 6,并将 AF 置 1;如果 AL 的高 4 位大于 9 或 CF=1,则从 AL 中减去 60H,并将 CF 置 1。

    受影响的状态标志位:SF、ZF、AF、PF、CF(OF 不确定)。

    总结:

    所谓十进制算术运算(BCD 码运算)指令,就是在二进制算术运算指令之后加上一个相应的调整指令(除法指令是先调整后跟除法指令),因此,可以将十进制算术运算指令看成一个由两条指令构成的复合指令,例如,组合十进制加法指令为:

    十进制算术运算

注意:调整指令仅对累加器 AL 的内容进行调整,因此,在进行十进制算术运算时,目的操作数必须使用累加器。

四、位操作指令

位操作指令是指按位进行操作的指令,包括逻辑运算指令、移位和循环移位指令两种。

(一)逻辑运算指令(logical)

共有 5 条逻辑运算指令,它们的指令格式和功能如下。

  1. 逻辑“与”指令

    格式:AND  DEST,SRC

    功能:DEST←DEST∧SRC;CF=0,OF=0。

  2. 逻辑“或”指令

    格式:OR  DEST,SRC

    功能:DEST←DEST∨SRC;CF=0,OF=0。

  3. 逻辑“异或”指令

    格式:XOR  DEST,SRC

    功能:DEST←DEST⊕SRC;CF=0。OF=0。

  4. 逻辑“非”指令

    格式:NOT  DEST

    功能:DEST←DEST。

  5. 测试指令

    格式:TEST  DEST,SRC

    功能:DEST∧SRC。

总结:

(1)逻辑操作指令对标志位的影响有特殊规定。

① NOT 指令对标志位没有影响。

② 执行除 NOT 指令之外的逻辑指令后,OF 和 CF 两个标志都被清 0,而 AF 状态不确定,其他标志反映操作结果的状态。

(2)TEST 指令对两个操作数进行“与”操作,但不保留“与”的结果,只是通过标志状态的判断,得出测试结果。主要用于测试一个操作数(目的操作数)某一位或几位的状态。

(3)逻辑指令主要用于字节或字中某些位的组合、分离或位设置等。

例:

逻辑运算指令

(二)移位和循环移位指令

移位和循环移位指令共有8条,它们的指令格式和操作如表 4 所示。

移位和循环移位指令

表 4 移位和循环移位指令

说明:

(1)目的操作数 dest 可以是通用寄存器或存储器操作数,cnt 为移位次数,可以是 1,或由 CL 指出(移位次数大于1时必须用 CL 给出移位次数),位移结束后 CL 值不变。

(2) CF 的值总是最后一次被移入的值。

(3)移位指令影响标志位 CF、OF、SF、ZF。而循环移位指令仅影响 CF 和 OF 位。

(4)对 OF 影响的规定是:在移动 1 位的情况下,如果移位后操作数的最高位改变了,OF 就被置 1,否则 OF 被置 0。若移位次数大于 1,那么 OF 不确定。

五、转移类指令

在 8086/8088 汇编语言程序中,指令执行的顺序由代码段寄存器 CS 和指令指针 IP 所确定,在正常情况下,程序总是顺序执行的。CPU 每执行完一条指令,就自动修改 IP 的值使之指向下一条指令。转移指令可以实现程序流向的控制和转移,这是通过改变 CS 和 IP 值实现的。若转移在同一段内进行(段内转移),就只需要修改 IP 值;若是在两个段之间进行转移(段间转移),则 CS 和 IP 都需要修改。

根据转移的范围将转移分为3类。

(1)远转移(段间转移):转移的目标地址为 32 位。可以实现一个段到任意其他代码段的转移。

(2)近转移(段内转移):转移的目标地址为 16 位。转移的距离限定在当前段内,最大 64KB。

(3)短转移:转移的目标地址为 8 位。转移范围限定在从转移指令的下一条指令算起的 -128~+127 个字节的地址空间以内。

转移类指令包括无条件转移指令、条件转移指令、循环控制指令、调用/返回指令、中断指令等。本节只介绍前 3 种。

(一)无条件转移指令

无条件转移指令仅有一条,它可以实现远转移、近转移或短转移。格式:JMP targ

功能:

(1)段内转移:IP←目标的偏移地址。

(2)段间转移:IP←目标的偏移地址,CS←目标所处代码段基址。

说明:JMP 指令使程序无条件地转移到目标 targ 指明的地址处执行。根据 targ 的类型会自动产生一个远转移、近转移或短转移指令。指令中的 targ 可以是标号、寄存器或存储器操作数,JMP 对标志位无影响。

例:

JMP 指令

(二)条件转移指令

条件转移指令是根据 CPU 中状态标志位当前的状态决定程序执行的流程,既可能产生程序转移,也可能不产生程序转移。条件转移指令是以对不同的状态标志的测试为条件,如果条件成立,则控制转移到指令中所给出的转移目标,如果条件不成立,程序将顺序执行。

条件转移指令共有 18 条,它们都是两个字节长的指令,其中一个字节为操作码,另一个字节为转移目标的偏移量(本指令的下条指令与目标的相对字节距离)。由于相对转移目标仅 8 位长,因此,所有的条件转移指令都仅能实现短转移。

条件转移指令见表 5,这些指令对标志位无影响。条件转移指令中的 targ 是要转向的指令语句标号,经汇编产生一个相对位移量,是一个 8 位带符号数。

条件转移指令一般用在算术运算、逻辑运算,或某些比较、测试指令之后,根据这些指令操作后的结果(反映在各状态标志上)判断转移。

条件转移指令

表 5 条件转移指令

(三)循环控制指令

在转移类指令中,有 3 条循环控制指令,用来支持循环结构程序设计。它们和条件转移指令相同,仅能实现短转移。这 3 条指令均约定用 CX 作为循环次数计数器,因此,这种指令只能用在循环次数已知的循环程序中。在执行循环控制指令时,自动对 CX 进行减 1 操作,并自动判断 CX 是否减为 0,这样,用循环控制指令比用条件转移指令来控制循环更简洁、方便。

  1. 无条件循环控制指令

    格式:LOOP  targ

    功能:若 CX-1≠0 则转移,否则退出循环。相当于两条指令:

    1
    2
    
    DEC  CX
    JNZ  targ
    

    该指令使循环体无条件循环 CX 中指定的次数。

  2. 相等循环控制指令

    格式:LOOPZ  targ 或 LOOPE  targ

    功能:若 CX-1≠0(规定的循环次数没完)且 ZF=1(比较相等)则转移,否则退出循环。

  3. 不等循环控制指令

    格式:LOOPNZ  targ 或 LOOPNE  targ

    功能:若 CX-1≠0(规定的循环次数没完)且 ZF=0(比较不等)则转移,否则退出循环。

    另外还有一条JCXZ指令也可用于循环控制。

    格式:JCXZ  targ

    功能:若 CX=0 则转移,否则执行后续指令。

六、串操作指令

用字节或字组成的一组数据称为数据串。组成数据串的字节或字称为数据串元素。如字符串‘abcdef’是一个字节数据串,串中每一个字符的 ASCII 码构成了该数据串的元素。

对数据串的传送、比较、搜索、存取等操作是非常典型、常用的操作。为此,汇编语言设计了 5 条专门用于上述操作的串指令。并且设计了 3 个重复前缀,它们加在串操作指令前,使得用一条指令就可完成一个循环程序的功能,而且不用考虑指针如何移动、循环如何控制等问题,极大地方便了程序设计。

(一)串操作指令的隐含规定

5 条串操作指令隐含地使用了相同的寄存器、标志位和符号。隐含规定如下。

(1)源串指针:DS:SI,目的串指针:ES:DI。

(2)重复次数计数器:CX(加重复前缀时)。

(3)操作方向:DF=0,正向(SI、DI自动增量修改);DF=1,负向(SI、DI 自动减量修改)。操作方向可用 CLD 和 STD 指令设置。

(4)指令 SCAS、LODS、STOS 约定累加器为一个操作数。

(二)串操作指令格式与功能

串操作指令可以实现字节和字串的操作,指令分别如下。

  1. 串传送指令

    (1)MOVSB  ;将源串一字节传送到目的串,并自动修改指针值。

    ;[ES:DI]←[DS:SI],SI←SI±1,DI←DI±1

    (2)MOVSW  ;将源串一字传送到目的串,并自动修改指针值。

    ;[ES:DI]←[DS:SI],SI←SI±2,DI←DI±2

  2. 串比较指令

    (1)CMPSB  ;源串一字节与目的串一字节相减比较,并自动修改指针值。

    ;[DS:SI]-[ES:DI],SI←SI±1,DI←DI±1

    (2)CMPSW  ;源串一字与目的串一字相减比较,并自动修改指针值。

    ;[DS:SI]-[ES:DI],SI←SI±2,DI←DI±2

  3. 串搜索指令

    (1)SCASB  ;将 AL 内容与目的串内容进行比较,并自动修改指针值。

    ;AL- [ES:DI], DI←DI±1

    (2)SCASW  ;AX- [ES:DI],DI←DI±2

  4. 从源串中取数指令

    (1)LODSB  ;AL←[DS:SI], SI←SI±1

    (2)LODSW  ;AX←[DS:SI], SI←SI±2

  5. 往目的串中存数指令

    (1)STOSB  ;[ES:DI] ←AL,DI←DI±1

    (2)STOSW  ;[ES:DI] ←AX,DI←DI±2

注意:

(1)修改地址指针时加减由DF状态决定。DF=0 时增量修改,DF=1 时减量修改。

(2)5 条串操作指令都有另一种带操作数的格式:

MOVS dest,src

CMPS dest,src

SCAS dest

LODS src

STOS dest

因上述格式不常用,所以在指令格式中未列出。

(三)串操作的重复前缀

串操作指令与普通指令相比,只是多了一个自动修改地址指针的功能。加入重复前缀,才使得串操作指令得以重复执行。

  1. 无条件重复前缀指令

    格式:REP

    功能:使 REP 后的指令无条件重复 CX 值指定的次数。用于 MOVS、STOS 指令前。

  2. 相等重复前缀指令

    格式:REPZ/REPE

    功能:当 CX≠0(规定的重复次数没完)同时 ZF=1(比较相等)时,重复执行该前缀后的指令,否则,终止(CX 已为 0)或中止(CX≠0,但 ZF=0)重复。该前缀只能用于 CMPS 和 SCAS 前,在两个数据串中找出不同的元素。

  3. 不相等重复前缀指令

    格式:REPNZ/REPNE

    功能:当 CX≠0(规定的重复次数没完)同时 ZF=0(比较不相等)时,重复执行该前缀后的指令;否则,终止(CX 已为 0)或中止(CX≠0,但 ZF=1)重复。该前缀只能用于 CMPS 和 SCAS 前,在两个数据串中找出相同的元素。

注意:

(1)CX 是否为 0 的判断(即重复操作是否完成的检测)是在串操作之前进行的,因此,若 CX 的初值为 0,则串操作一次也不会执行。

(2)对比较和搜索的串操作结束,有两种可能:一种是重复了规定的次数(CX 已为 0),也没有找到要找的元素;另一种是中途或最后找到了要找的元素。这两种情况可通过对标志ZF的判断确定:如果 ZF 的状态和重复的条件相同(不相等重复时 ZF=0,相等重复时 ZF=1),则为第一种情况,否则为第二种情况。

(3)操作结束后,SI、DI 中为下一个元素的偏移地址,其方向由 DF 确定。

下面通过例子体会一下串操作指令的应用。

【例 1】 将以 SBUF 为首址的 200 字节的数据块传送到 DBUF 开始的区域,可用以下程序段实现:

1
2
3
4
5
CLD
LEA  SI,SBUF
LEA  DI,DBUF
MOV  CX,200
REP  MOVSB

【例 2】 STRING 为一个 30 字节长的字符串,查找该串中最后一个字母‘B’,若找到将其地址存入 BX 中,否则将 0 送入 BX。

这个问题可以使用带不相等重复前缀的串搜索指令完成。要查找串中最后一个字母‘B’,可从后面开始反向查找。程序段如下:

串操作指令的应用

七、处理器控制类指令

这一类指令主要包括以下 3 种。

(一)标志位操作指令

它们均是无操作数指令,即它们的操作数隐含在标志寄存器中某些标志位上。能直接操作(修改)的标志位有 CF、IF 和 DF。

(1)清除进位标志指令:     CLC ;置 CF=0

(2)进位标志置位指令:     STC ;置 CF=1

(3)进位标志取反指令:     CMC ;CF 取反

(4)清除方向标志指令:     CLD ;置 DF=0(正向)

(5)方向标志置位指令:     STD ;置 DF=1(反向)

(6)清除中断标志(关中断)指令: CLI ;置 IF=0

(7)中断标志置位(开中断)指令: STI ;置 IF=1

注意:上述 7 条指令功能是把对应的标志位置 0、置 1 或取反而不改变其他标志位。

(二)空操作指令

格式:NOP

功能:这条指令使 CPU 执行一次空操作,不影响任何寄存器、存储单元和标志位,仅占据 CPU 的 3 个时钟周期。在软件延时程序中,可用 NOP 指令作少量的延时调整。

(三)外部同步指令

这方面指令有 WAIT、ESC、LOCK、HLT 等。这些指令的执行涉及其他知识,故这里不讨论这些指令。在实际应用中,需要用这些指令时,可查阅有关资料。

请参阅

(完)

comments powered by Disqus