4.3.2 定点算术运算指令

4.3.2 定点算术运算指令

对加减运算来说,无符号数和有符号数可采取同一套指令,但是,无符号数和有符号数进行加、减运算能够采用同一套指令也是有条件的,要求加减运算的两个操作数,必须同为无符号数或同为有符号数。对乘除运算来说,两者不能采用同一套指令,所以它们有各自的乘除运算指令。

所有的算术运算指令都会影响标志位,总的来说,有这样一些原则:

(1)运算结果向前产生进位或借位时,则CF=1。

(2)最高位向前进位和次高位向前进进位不同时产生时,则OF=1。

(3)如果运算结果为0,则ZF=1。

(4)如果运算结果最高位为1,则SF=1。

(5)如果运算中有偶数个1,则PF=1。

1.加法指令ADD

ADD 实现两个操作数相加,结果存入目的操作数中。

加法操作可以在通用寄存器间、通用寄存器与存储器间、立即数与通用寄存器间、立即数与寄存器间进行,但不允许两个存储器操作数间进行加法运算。

例如:addw $0x0cf8,%ax

若在指令执行前,(AX)=5623 H,则指令执行后,(AX)=25CBH,且CF=1,OF=0,SF=0,ZF=0,AF=0,PF=1。

例如:

2.带进位加法指令ADC

源操作数加上目的操作数再加进位标志CF的和送至目的操作数。即如果进位标志已被置位,则两个操作数相加的结果在存入目的操作数之前再加上1,否则加上0。

两个操作数要同时为字节(8位数)或同时为字(16位数)。ADC 指令多用于多字节加法运算,需要分步计算时使用。例如,有两个两字节的数相加,0AF8AH+0A90H,先进行低字节相加,然后做高字节相加,并且要加上进位,示意如图4.15所示。

图4.15 ADC带进位的加法

例如:adcb%dl,%bh;(BH)=(BH)+(DL)+CF

设指令执行前(BH)=96H,(DL)=6DH,CF=1,则执行后(BH)=04 H,(DL)不变,SF=0,PF=0,ZF=0,OF=0,CF=1,AF=1。

【例4.3】 假设R[ax]=FFFAH,R[bx]=FFF0H,则执行Intel格式指令“addw %bx,%ax”后,AX、BX 中的内容各是什么? 标志CF、OF、ZF、SF 各是什么? 要求分别将操作数作为无符号数和带符号整数解释并验证指令执行结果。

解:功能:R[ax]←R[ax]+R[bx],指令执行后的结果如下:

R[ax]=FFFAH+FFF0 H=FFEAH,BX 中内容不变

  CF=1,OF=0,ZF=0,SF=1

若是无符号整数运算,则CF=1,说明结果溢出。

验证:FFFA 的真值为65535-5=65530,FFF0的真值为65515

FFEA 的真值为65535-21=65514≠65530+65515,即溢出

若是带符号整数运算,则OF=0,说明结果没有溢出。

验证:FFFA 的真值为-6,FFF0的真值为-16

FFEA 的真值为-22=-6+(-16),结果正确,无溢出

3.减法指令SUB

SUB实现两个操作数目的操作数和源操作数的相减,结果存入目的操作数中。

目的操作数为任一通用寄存器或存储器操作数,源操作数为立即数或任一通用寄存器或存储器操作数。

例如:subw%cx,%bx

若在指令执行前,(BX)=9543H,(CX)=28A7H,则指令执行后,(BX)=6C9CH,(CX)=28A7H,CF=0,OF=1,ZF=0,SF=0,AF=1,PF=1。

4.带借位的减法指令SBB

目的操作数减去源操作数,其结果再减去进位标志的内容,将最后的结果送至目的操作数,两个操作数要同时为字或字节,在进行减法运算时,若有借位就置CF 为1,否则CF 清零。故当执行SBB指令时,若CF已置1(即在这以前有借位产生)时,则其差再减1;若CF为0(即没有借位产生)时,则其差就减0。

减法实际上是用加法做的,即两个源操作数的补码相加,把CF也取反求补码[0的补码为0,-1的补码为11111111(8位时)或1111111111111111(16位时)],然后再做加法。

例如:(DL)=03H,(BL)=64H,CF=1。

指令:sbbb%dl,%bl的执行结果是:(BL)=60H,运算过程如下。

5.单目运算指令INC和DEC

INC指令用于使某数加1后送给自己,DEC指令用于使某数减1后送给自己。

此两条指令通常用于循环程序中修改指针和循环次数。

例如:

6.乘法指令MUL

指令中只给出一个源操作数,另一个源操作数隐含在累加器AL/AX/EAX 中,将源操作数和累加器内容相乘,结果存放在AX(16位时)或DX-AX(32位时)或EDX-EAX(64位时)中。DX-AX 表示32 位乘积的高、低16 位分别在DX 和AX 中。其操作如图4.16所示。

图4.16 乘法运算

例如:若AL为05 H,BL为16 H,则执行mulb%bl指令,执行后AX=?

MUL指令的功能是乘法指法,且隐含了被乘数AL,乘数为BL,所以(AX)=(AL)∗(BL)=05H∗16H=6EH。

乘法指令MUL也可以明显地给出两个操作数或三个操作数。若指令中给出两个操作数DST 和SRC,则将DST 和SRC 相乘,结果存放在DST 中。若指令中给出三个操作数REG、SRC和IMM,则将SRC和立即数IMM 相乘,结果存放在寄存器REG 中。

【例4.4】 假设R[eax]=000000B4 H,R[ebx]=00000011H,M[000000F8H]=000000A0H,请问:执行指令“mulb%bl”后,哪些寄存器的内容会发生变化? 是否与执行“imulb%bl”指令所发生的变化一样? 为什么? 请用该例给出的数据验证自己的结论。

解:“mulb%bl”的功能为R[ax]←R[al]×R[bl],执行结果如下:

7.除法指令DIV

格式:DIV SRC

功能:参加运算的除数和被除数是无符号数,使用DIV 指令,其商和余数也均为无符号数。除法指令DIV 只能明显给出除数,用累加器AL/AX/EAX中的内容除以指令中指定的除数。若源操作数为8位,则16位的被除数隐含在AX 寄存器中,商送为AL,余数在AH 中;若源操作数为16位,则32的被除数隐含在DX-AX 寄存器中,商送加AX,余数在DX 中;若源操作数是32位,则64位的被除数隐含在EDX-EAX 寄存器,商送回EAX,余数在EDX 中。

其操作如图4.17所示。

图4.17 除法运算

例如:若AX 为1005H、BL为17H,则divb%bl指令执行后AX=?

无符号数除法直接相除,所以1005H/17H=4101/23,商为178,余数为7,即(AL)=B2H、(AH)=07H,因此,(AX)=07B2H。

8.比较指令CMP

计算目的操作数-源操作数,但并不保存结果,仅仅根据计算结果对标志寄存器进行设置。

该指令与SUB指令一样执行减法操作,但有一点不同,该指令不保存结果,即指令执行后,目的操作数和源操作数两个操作数的内容不会改变,执行这条指令的主要目的是根据操作的结果设置状态标志。CMP指令后,通常紧跟着一条条件转移指令,根据比较结果使程序产生分支,比较指令执行后影响所有的状态标志位,根据状态标志位便可判断两个操作数的比较结果。

比如,指令CMP AX,AX,做(AX)-(AX)运算,结果为0,但结果并不在AX 中保存,仅影响FLAG 中的相关状态标志位。指令执行后:ZF=1,PF=1,SF=0,CF=0,OF=0。

下面的指令:

执行后:(AX)=8,(BX)=3,ZF=0,PF=0,SF=0,CF=0,OF=0。

如何利用状态标志位来判断两操作数的关系呢? 其实,我们通过CMP指令执行后,从相关状态标志位的值就可以看出比较的结果。

CMP AX,BX

如果(AX)=(BX),则(AX)-(BX)=0,所以ZF=1;

如果(AX)≠(BX),则(AX)-(BX)≠0,所以ZF=0;

如果(AX)<(BX),则(AX)-(BX)将产生借位,所以CF=1;

如果(AX)≤(BX),则(AX)-(BX)即可能借位,结果可能为0,所以CF=1或ZF=1;

如果(AX)>(BX),则(AX)-(BX)既不必借位,结果又不为0,所以CF=0 并且ZF=0;

如果(AX)≥(BX),则(AX)-(BX)不必借位,所以CF=0。

可以看出比较指令的设计思路是通过做减法运算,影响标志寄存器,标志寄存器的相关位记录了比较的结果。

反过来看上面的例子。指令CMP AX,BX 的逻辑含义是比较AX 和BX 中的值,如果执行后: