Intel 8086/8088 指令系统(二)

时间:2022-10-31 00:43:24

二、 算术运算类指令

 

这类指令包括加、减、乘、除4种指令。不过注意两个操作数不能同时为存储器操作数,且目的操作数不能是立即数(不然你结果放哪儿?)。

 

指令名

指令格式

指令功能

标志位备注

加法指令

ADD DEST,SRC

DEST←(SRC)+(DEST)

按结果置OFSFZFAFPFCF

带进位加法

ADC DEST,SRC

DEST←(SRC)+(DEST)+CF

按结果置OFSFZFAFPFCF

1指令

INC DEST

DEST←(DEST)+1

按结果置OFSFZFAFPF,不影响CF

减法指令

SUB DEST,SRC

DEST←(DEST)-(SRC)

按结果置OFSFZFAFPFCF

带借位减法

SBB DEST,SRC

DEST←(DEST)-(SRC)-CF

按结果置OFSFZFAFPFCF

1指令

DEC DEST

DEST←(DEST)-1

按结果置OFSFZFAFPF,不影响CF

乘法指令

MUL SRC

DEST←[AL/AX]

DEST←DEST*SRC

按结果置OFCFZFAFPF,不影响SF

带符号乘法

IMUL SRC

DEST←[AL/AX]

DEST←DEST*SRC

按结果置OFCFZFAFPFSF

除法指令

DIV SRC

DEST←[AL/AX]

DEST←DEST/SRC

按结果置OFCFZFAFPF,不影响SF

带符号除法

IDIV SRC

DEST←[AL/AX]

DEST←DEST/SRC

按结果置OFCFZFAFPFSF

求补指令

NEG DEST

DEST←0-(DEST)

按结果置OFSFZFAFPFCF

比较指令

CMP DEST,SRC

(DEST)-(SRC)

按结果置OFSFZFAFPFCF

 

1.       ADD指令

 

功能: 加法指令

语法: ADD OP1,OP2

格式: ADD r1,r2

ADD r,m

ADD m,r

ADD r,data

影响标志: C,P,A,Z,S,O

 

ADD指令是需要重点掌握的指令,它将两个字或字节的操作数相加,结果送到目的操作数。这个指令很重要,特别是它要影响到6个状态标志,所以必须注意以下几点:

 

第一,参与运算的两个操作数应该同时带符号或不带符号。那么,这里就出现第一个问题了,系统如何区分带不带符号的操作数呢?这个问题先放在这儿。

 

第二,参与运算的两个操作数必须长度一致。针对8086/8088系统,操作数的长度只有两种:字节和字,即8位和16位。那么,当操作数是字节时如果是带符号,则表示范围为-127~127,不带符号的表示范围为0~255;当操作数是字时,如果是带符号则表示范围为-32767~32767,不带符号的表示范围为0~ 65535。好,第二个问题出现了,系统如何判断操作数是字节还是字呢?

 

第三,与MOV一样,该指令的操作数可以是通用寄存器、基址或变址寄存器、存储器,但不能同时为存储单元,立即数只能为源操作数,不能作目的操作数。

 

好了,我们就来集中解决刚才出现的两个问题。其实这两个问题都是一个问题,那就是ADD指令是一个非常非常低级的指令。刚才出现的问题完全不是ADD指令所考虑的范围,它所考虑的,只是如何影响标志寄存器的那些位的值。明白了这一点,这两个问题就迎刃而解。先来回答第二个问题,ADD指令根本不需要判断操作数的长度。因为,比如我执行ADD AX, 85H,而AX又是16位的,那么这个就肯定是字操作,后面的那个立即数85H就把前面的字节全用0不齐就OK了。如果要进行字节操作,你可以执行ADD AL,85H,这不就得了。

 

回到第一个问题,两个数是否是带符号的数也是不需要判断的。我们知道,8086/88088体系是一个补码体系。这里补充一下补码的规则,不管是字节补码还是字补码,其最高位为1则是负数,为0则为正数。前面已经说了,不需要判断操作数的长度,所以这里我们不妨设为字节操作数(字操作数也是一样的):ADD AL,B5HAL中的值为77H。若看成无符号数,则运算结果理论为12CH。但是,由于是字节操作数,最高位产生进位并自动丢失,所CF产生1,于是实际结果为2CH+CF。当然,你不能说这个结果是不正确的,后面ADC指令会谈到。

 

若看成有符号数,则77H是正数,因为翻译成二进制为01110111,符号位为0B5H对应二进制数为10110101,是负数,根据补码规则,这个数是4BH的补码。忘了补码规则?好吧我来教教你:先把4BH换算成二进制:01001011,再求个反:10110100,再加110110101不就是B5H了吧。于是乎,ADD AL,B5H其意思其实是77H-4BH,结果等于2CH

 

我们看到,不管是看成有符号还是无符号,结果是不是都是2CH?第一个问题就完美的解决了。不过前面都是以例子来解释这个问题的,缺少理论的支撑。要总结出一个理论来,不是那么容易,还是同学们自己去体会吧。这里,再最后提一下,ADD是个很低级的指令,它并不会做那些复杂的逻辑判断,只会去影响那些状态寄存器的某些标志:CF=1则说明在如果是无符号运算,则有进位;SF=1则说明如果是有符号运算时,结果为负,即最高位为1OF=1则不管是否有符号运算,只要有溢出就置1。最后再注意一下,CFOF很容易搞混淆,网上对他们的解释也是五花八门,其实很简单,CF是仅仅是针对无符号运算,但OF并不是只针对有符号运算,而是n位字长,也就是跟符号无关。不管是否是有符号操作数,只要结果超过了-2n-1~2n-1就置1,就这么低级。我们的例子中,CF1了,说明有进位;而OF肯定为0,因为最后的结果2CH没有超过7F,也就是十进制的127。当然,PFAFZF太简单,就不去解释了。

 

2.       ADC指令

 

功能: 加法指令

语法: ADC OP1,OP2

格式: ADC r1,r2

ADC r,m

ADC m,r

ADC r,data

影响标志: C,P,A,Z,S,O

 

这是一条带进位的加法指令,其操作与ADD基本相同,唯一的差异是若在ADC指令执行前CF已置位,则在两操作数只和中再加1

 

这条指令主要用于多字节加法运算。我们知道,ADD只支持字长8位和16位的操作数,而我们计算机的科学计算有可能涉及到成百上千位的计算,那就会变成多个字节运算。例如有一个32位带符号整数存放在AX(高16位,带符号)和BX(低16位,不带符号),现在要加上一个常数276425H,这时可用下面两条指令实现:

ADD BX,6245H

ADC AX,27H

 

其中第一条把16位常数6245H加在BX中,如果它产生进位,即CF=1,则在第二条指令完成高16位加法时,用ADC指令就同时把低16位的进位一起加上了。

 

3.       INC指令

 

功能: OP的值加一

语法: INC OP

格式: INC r/m

影响标志: P,A,Z,S,O

 

这是一条常用的单操作数指令,注意,它不会影响CF状态,即到了FFHFFFFH后,有循环回0。操作数可以是通用寄存器、基址或变址寄存器、存储器,但不能是段寄存器或立即数。

 

4.       SUB指令

 

功能:减法指令

语法: SUB OP1,OP2

格式: SUB r1,r2

SUB r,m

SUB m,r

SUB r,data

SUB m,data

影响标志: C,P,A,Z,S,O

 

SUB指令与ADD指令类似,我们还是举例说明:

MOV AX, 65A0H

MOV BX, B79EH

SUB AX,BX

 

若操作数看成是两个无符号数,目的操作数小于源操作数,则有借位,CF1;而运算结果为AE02H,其最高位为1,属于补码,SF1,其原码为-51FE。至于如何又补码换算成原码,这里不再赘述。

 

若操作数看成是两个有符号数,则参加运算的两个数为补码,其中源操作数是正数,目的操作数B79EH是一个负数的补码,那么一个正数减去一个负数就该是个正数了,而这里运算结果AE02H显然是个负数,这不扯淡吗?别着急,这个结果显然已经超过16位数的补码的,OF1

 

5.       SBB指令

 

功能:带借位减法指令

语法: SBB OP1,OP2

格式: SBB r1,r2

SBB r,m

SBB m,r

SBB r,data

SBB m,data

影响标志: C,P,A,Z,S,O

 

带借位的减法指令,同ADC类似,用于多字节的减法运算。例如有一个32位无符号整数00D50017H已存放在AX(高16位)和BX(低16位)中,现在要去减去一个存放在CX(高16位)和DX(低16位)中的一个32位常数00450048H,这时,可以用以下两条指令实现:

SUB BX,DX

SBB AX,CX

 

6.       DEC指令

 

功能: OP的值或减一

语法: DEC OP

格式: DEC r/m

影响标志: P,A,Z,S,O

 

7.       NEG指令

 

功能: OP的符号反相(取二进制补码)

语法: NEG OP

格式: NEG r/m

影响标志: C,P,A,Z,S,O

 

注意,NEG指令执行取补码运算,即求反加一运算。操作数可以是通用寄存器、基址或变址寄存器、存储器,但不能是段寄存器或立即数。若指令在执行时,操作数的值为-128(字节)或-32768(字),其结果不变但OF要置位;CF总被置为1,除非操作数为00的补码还是0

 

8.       CMP指令

 

功能: 比较OP1OP2的值

语法: CMP r/m,r/m/data

标志位: C,P,A,Z,O

 

CMP指令也是一个重点指令,用得非常多,用于两个操作数的比较,其方法是用目的操作数去减去源操作数,但结果不送回目的操作数,两操作数保持不变,只是标志位发生相应的改变。

 

9.       MUL指令

 

功能: 无符号数乘法指令

语法: MUL OP

格式: MUL r/m IMUL r/m

影响标志: C,P,A,Z,O(注,不会影响S标志)

 

乘法指令MUL是单操作数的,执行无符号数乘法。MUL的规则是由累加寄存器(ALAX)中的数作为乘数,操作数作为被乘数。但是注意,结果并不存放在操作数所对应的那个存储介质中。如果操作数是字节,则与来自AL的乘数相乘,乘积是字,放在AX中;如果操作数是字,则与来自AX的乘数相乘,乘积是双字,放在AXDX中。

 

注意,操作数不能是立即数,但可以是来自AXDX的字操作数,这样导致的结果无非就是乘方而已。

 

10.   IMUL指令

 

功能: 带符号数乘法指令

语法: IMUL OP

格式: IMUL r/m

影响标志: C,P,A,Z,S,O(注,会影响S标志)

 

IMULMUL类似,不在赘述,这里提一下,乘积(结果)的高位(字节相乘来自AH,字相乘来自DX)如果不全为0MUL指令);或是低位(ALAX)的符号被置1,则CF=1OF=1,表示AHDX中含有乘积的有效位。

 

例如,AL=0B4HBL=11H,执行MUL BL后,AX=0BF4H,即十进制数的3060;而执行指令IMUL BL后,AX=0FAF4H,即十进制数的-1292。这是因为AL中的0B4H在看成有符号数是-76,无符号数则是180BL=11H,不管有符号还是无符号都是十进制数中的17

 

11.   DIV指令

 

功能:不带符号数除法指令

语法: DIV OP

格式: DIV r/m

 

DIV规定用累加器中的内容作为被除数,除以位于指令中的源操作数。如果源操作数是8位字节数据,则要求被除数为16位,须放在AX中,所得商放在AL中,余数放在AH中;如果源操作数是16位字数据,那么就要去被除数为32位,放在DXAX中,所得的商放在AX中,余数在DX中。

 

这里有个著名的问题,如果商超过了ALAX的最大值怎么办?有人会问了,会有这种情况吗。其实,这就是单指操作数为0的情况,这就会触发著名的0号中断。

 

12.   IDIV指令

 

功能:带符号数除法指令

语法: IDIV OP

格式: IDIV r/m

 

13.   CBWCWD 指令

 

功能: 有符号数扩展指令

语法: CBW

CWD

 

如果是带符号的数据进行除法,会有个问题,有时需要把短位数的被除数转换成位数更长的数据类型。比如,要用BL中的数据去除AL,但根据除法指令的规定:除数是8位,则被除数必须是AX,于是就涉及到AH的取值问题。

 

为了方便说明,假设:(AH)=1H(AL)=90H=-112D(BL)=10H。假设在作除法时,不管AH中的值,这时,(AHAL)/BL的商是19H,但我们知道:AL/BL的商应是-7,这就导致:计算结果不是所预期的结果,所以,在作除法运算前,程序员必须要处理AH中的值。

 

那么,作无符号数除法时,可强置AH的值为0,于是,可得到正确的结果。但是,如果作有符号数除法时,如果强置AH0,则AX=0090H,这时,AX/BL的商为9,显然结果也不正确。看出问题来没有,如果把AL的符号位1,扩展到AH中,得:AX=0FF90H=-112D,这时,AX/BL的商就是我们所要的正确结果。

 

所以,CBWCWD就闪亮登场了,CBW是将AL中的数的符号扩展到AH寄存器中,而CWD是将AX的符号扩展到DX寄存器中。

 

14.   AAA,AAS,AAM,AAD指令

 

功能: 非压BCD码运算调整指令

语法: AAA AAS AAM AAD

影响标志: A,C(AAA,AAS) S,Z,P(AAM,AAD)

 

15.   DAA,DAS指令

 

功能: 压缩BCD码调整指令

语法: DAA DAS

影响标志: C,P,A,Z,S