标志操作指令
8086/8088指令集中,有一部分指令是专门对标志寄存器或标志位进行的。包括四条标志寄存器传送指令和七条专门用于设置或者清除某些标志位的指令。
1.标志传送指令
标志传送指令属于数据传送指令组。
(1)指令LAHF(Load AH with Flags)
指令LAHF采用固定寻址方式,其指令格式如下:
LAHF
该条指令把标志寄存器的低8位(包括标志SF,零标志ZF,辅助进位标志AF,奇偶标志PF和进位标志CF)传送到寄存器AH的指定位,即相应地传送至寄存器AH的位7,6,4,2和0,其他的位(位5,3和1)的内容无定义。
这条指令本身不影响这些标志位和其他标志。
(2)指令SAHF采用固定寻址方式,其格式如下:
SAHF
该条指令与指令LAHF刚好相反,把寄存器AH的指定位送至寄存器低8位的SF,ZF,AF,PF和CF标志位。因而这些标志的内容就要受到影响,并取决与AH中相应位的状态。但是这条指令不影响溢出标志OF,方向标志DF,中断标志IF和追踪标志TF,也既不能影响寄存器标志的高位字节,例如:
MOV AH,0C1H
SAHF ;CF = 1,PF = 0,AF = 0,ZF = 1,SF = 1
(3)指令PUSHF
指令PUSHF的格式如下:
PUSHF
该指令把标志寄存器的内容压入堆栈,即先把堆栈指针寄存器SP的值减2,然后把标号寄存器的内容送入有SP所指的栈顶。
这条指令不影响标志。
(4)指令POPF
指令POPF的格式如下:
POPF
该条指令把当前堆栈顶的一个字传送到标志寄存器,同时相应的修改堆栈指针,即把堆栈指针寄存器SP的值加2.
在执行该指令后,标志寄存器各位会发生相应的变化。
这条指令和PUSHF指令一起用可以保存和恢复标志寄存器的内容,即保存和恢复各标志的值。另外,这两条指令也可以用来改变追踪标志TF。在8086/8088指令系统中,没有专门设置清楚TF标志的指令,为了改变TF标志,可先用PUSHF指令将标志压入堆栈,然后在设法改变栈顶字单元中的第八位(那整个标志寄存器看成一个字),再用POPF指令把该字弹回到标志寄存器,这样其余的标志不受影响,而只有TF标志需要改变了。
2.标志位操作
标志位操作指令属于处理器控制指令组,它们仅对指令规定的标志产生指令规定的影响,对其它标志没有影响。
(1)清进位标志指令CLC(Clear Carry flag)
清进位标志指令的格式如下:
CLC
该指令使进位标志为0
(2)置进位标志指令STC(Set Carry flag)
STC
该指令使进位标志为1
(3)进位标志取反指令CMC(CoMplement Carry flag)
进位标志取反指令的格式如下:
CMC
该条指令使进位标志取反。如CF为1,则使CF为0;如果CF为0,则CF为1。
(4)清方向标志CLD(Clear Direction flag)
清方向标志指令的格式如下:
STD
该指令使方向标志DF为1.从而在执行串操作指令时,使地址按递减方式变化。
(6)清中断指令CLI(Clear Interrupt enable flag)
清中断指令的格式如下:
CLI
清中断允许标志IF为0,于是CPU就不响应来自外部的可屏蔽中断。
但对不可屏蔽中断和内部中断都没影响。
(7)置中断允许标志STI(Set Interrupt enable flag)
置中断允许标志指令格式如下:
STI
该条指令是中断允许标志IF为1,则CPU可以响应可屏蔽中断。
加减运算指令
8086/8088提供加,减,乘和除四种基本运算操作。这些操作都可以用于字节或字的运算,也可以用于无符号的运算或有符号数的运算。有符号数用补码表示。加减运算指令不再分为无符号数运算指令和有符号数运算指令,而乘除运算指令还分为无符号数运算和有符号数运算指令。另外,8086/8088还提供了各种十进制算数运算调整指令。
关于加减运算指令,有如下几点通用说明,请予以注意:
(1)加减运算指令对无符号数和有符号数的处理一视同仁。即作为无符号数而影响CF和AF,也有作为有符号数影响标志OF和SF,当然总会影响标志ZF。加减运算指令也要影响标志PF。有些指令稍有例外。
(2)总是只有通用寄存器或存储单元可用于存放运算结果。如果参与运算的操作数有两个,则最多只能有一个存储器操作数。
(3)如果参与运算的操作数有两个,则他们的类型必须一致,即同时为字节,或同时为字。
(4) 存储取操作数可采用标准四种存储器操作数寻址方式。
1.加法指令
(1)普通加法指令ADD
普通加法指令的格式如下:
ADD OPRD1,OPRD2
这两条指令完成两个操作数相加,结果送至目的操作数OPRD1,即:
OPRD1 <= OPRD1 + OPRD2
例如:
ADD AL, 5
ADD AL, AH
ADD DI, DI
ADD BL, VARB ;VARB是字节变量
ADD VARW,SI ;VARW是字变量
ADD [BX+SI-3],AX
我们用下面的程序片段说明加法指令及其对标志的影响,同时说明8位数据寄存器与16位数据寄存器间的关系。
MOV AX,7896H ;AX=7896H,即AH=78,AL=96
;各标志位保持不变
MOV AL,AH ;AL=0EH,AH=78,即AX=780EH
;CF=1,ZF=0,SF=0,OF=0,AF=0,PF=0
ADD AH,AL ;AH=86H,AL=0EH,即AX=860EH
;CF=0,ZF=0,SF=1,OF=1,AF=1,PF=0
ADD AL, 0F2H ;AL=00H,AH=86H,即AX=8600H
;CF=1,ZF=1,SF=0,OF=0,AF=1,PF=1
ADD AX, 1234H ;CF=0,ZF=0,SF=1,OF=0,AF=0,PF=0
(2)带进位加指令ADC(Add with Carry)
带进位加指令的格式格式如下:
ADC OPRD1,OPRD2
这条指令与ADD指令类似,完成两个操作数相加,但是要把进位CF的现行值加上去,把结果送至目的操作数OPRD1,即:
OPRD1 <= OPRD1 + OPRD2 +CF
例如:
ADC AL,[SI]
ADC DX,AX
ADC DX,VARW ;VARW是字变量
ADC指令主要用于多字节运算中。尽管在8086/8088中可以进行16位运算,但是16位二进制数能表达的整数的范围还是很有限的,为了扩大数的范围,仍然需要多字节运算。例如,有两个四字节的数相加,加法要分两次进行,先进行低两字节相加,然后再做高两字节相加。在高两字节相加时,要把低两字节相加以后可能出现的进位考虑进去,用ADC指令实现这点很方便。
下面的程序片段实现两个四字接数相加,注意传送指令不影响标志:
MOV AX,FIRST1 ;FIRST1是存放第一个数低两字节的变量
ADD AX,SECOND1 ;SECOND1是存放第二个数低两字节的变量
MOV THIRD1,AX ;保存低两字节相加的结果到THIRD1变量中
MOV AX,FIRST2 ;FIRST2是存放第一个数高两字节的变量
ADC AX,SECOND2 ;SECOND2是存放第二个数高两字节的变量
MOV THIRD2,AX ;保存结果的高两字节到THIRD2变量中
(3)加1指令INC(INCrement)
加1指令的格式如下:
INC OPRD
这条指令完成对操作数OPRD加1,然后把结果送回OPRD,即:
OPRD <= OPRD + 1
例如:
INC AL
INC VARB ;VARB是字节变量
操作数DST可以是通用寄存器,也可以是存储单元。这条指令执行的结果影响标志ZF,SF,OF,PF和AF,但它不影响CF。
该指令主要用于调整地址指针和计数器。
2.减法指令
(1)普通减法指令SUB
普通减法指令的格式如下:
SUB OPRD1, OPRD2
这条指令完成两个操作数相减,从OPRD1中减去OPRD2,结果送到目标操作数OPRD1中,即:
OPRD1 <= OPRD1 – OPRD2
例如:
SUB AH,12
SUB BX,BP
SUB AL,[BX]
SUB BX,VARW ;VARW是字变量
SUB [BP-2],AX
我们用下面的程序片段说明减法指令及其对标志的影响,同时再次说明8位数据寄存器与16位数据寄存器的关系。
MOV BX,9048H ;BX=9048H,即BH=90H,BL=48H
SUB BH,BL ;BH=48H,BL=48H,即BX=4848H
;CF=0,ZF=0,SF=0,OF=1,AF=1,PF=1
SUB BL,BH ;BL=00H,BH=48H,即BX=4800H
;CF=0,ZF=1,SF=0,OF=0,AF=0,PF=1
SUB BL,5 ;BL=FBH,BH=48H,即BX=48FBH
;CF=1,ZF=0,SF=1,OF=0,AF=1,PF=0
SUB BX,8F34H ;BX=B9C7H,即BH=B9H,BL=C7H
;CF=1,ZF=0,SF=1,OF=1,AF=0,PF=0
(2)带进(借)位减指令SBB(Subtract with Borrow)
带借位指令的格式如下:
SBB OPRD1,OPRD2
这条指令与SUB指令类似,在操作数OPRD1减去OPRD2的同时还要减借位(进位)标志CF的现行值,即:
OPRD1 <= OPRD1 - OPRD2 – CF
例如:
SBBAL,DL
SBBDX,AX
该指令主要用于多字节数相减的场合
(3)减1指令DEC
减1指令的格式如下:
DEC OPRD
这条指令把操作数OPRD减1,并把结果送回OPRD,即:
OPRD <= OPRD – 1
例如:
DEC BX
DEC VARB ;VARB是字节变量
操作数OPRD可以是通用寄存器,也可以是存储单元。在相减时,把操作数作为一个无符号对待。这条指令执行的结果影响标志ZF,SF,OF,PF和AF,但它不影响CF。
该指令主要用于调整地址指针和计数器。
(4)取补指令NEG
取补指令的格式如下:
NEG OPRD
这条指令对操作数取补,就是用零减去操作数OPRD,再把结果送回OPRD,也即:
OPRD <= 0 – OPRD
例如:
NEG AL
NEG VARW[SI] ;
(5)比较指令CMP
比较指令CMP的格式如下:
CMP OPRD1,OPRD2
这条指令完成操作数OPRD1减去操作数OPRD2,运算结果不送到OPRD1,但影响CF,ZF,SF,OF,AF和PF。例如:
CMP SI,DI
CMP CL,5
CMP DX,[BP-4]
比较指令主要用于比较两个数的关系,是否相等,谁大谁小。在执行比较指令后,可根据ZF是否置位,判断两者是否相等;如果两者是无符号数,则可根据CF判断CF大小;如果两者是有符号数,则要根据SF和OF判断大小。
例,设有两个64位数按“高高低低”原则存放在同一个段的两个缓冲区DATA1和DATA2中,现在需要计算DATA1-DATA2。下面程序片段计算DATA1-DATA2,结果存放在DATA1中,可能发生的借位保留在CF中:
.....
MOV CX,4
SUB BX,BX
NEXT: MOV AX,DATA2[BX]
SBB DATA1[BX],AX
INC BX
INC BX
DEC CX
JNZ NEXT