您的位置: 网站首页 > 程序开发 > 汇编语言与微机原理教程 > 第9章 80x86的寻址方式与指令系统 > 【9.3.2 算术运算指令】

9.3.2 算术运算指令

 

9.3.2  算术运算指令

算术运算指令是反映CPU运算能力的一组指令,也是编程时经常使用的一组指令。因为算术运算类指令是在ALU中完成的,所以算术运算类指令对标志寄存器的内容均有影响,必须特别注意。算术运算指令共有以下5种类型。

·    二进制无符号数的算术运算指令。

·    二进制带符号数的算术运算指令。

·    无符号组合式BCD码加减运算指令。

·    无符号分离式BCD码算术运算指令。

·    多字节数运算指令。

1.二进制无符号数的算术运算指令

(1)ADD——加法指令。

形式:ADD  目标操作数,源操作数。

功能:目标操作数←(目标操作数)+(源操作数)。

该指令有如下5种形式:

ADD  R,R            ; 通用寄存器之间相加

ADD  R,Im           ; 通用寄存器与立即数之间相加

ADD  M,Im           ; 内存数与立即数相加

ADD  M,R            ; 内存数与通用寄存器之间相加

ADD  R,M            ; 通用寄存器与内存数之间相加

例如,设(AX)=4,(BX)=200H,(DX)=6,(DI)=500H,(DS:502)=2

ADD  AX,BX          ; 语句执行后(AX)=204H

ADD  DX,2[DI]       ; 语句执行后(DX)=8

(2)SUB——减法指令。

形式:SUB  目标操作数,源操作数。

功能:目标操作数←(目标操作数)-(源操作数)。

该指令有如下5种形式:

SUB  R,R        ; 通用寄存器之间相减

SUB  R,Im       ; 通用寄存器与立即数之间相减

SUB  M,Im       ; 内存数与立即数相减

SUB  M,R        ; 内存数与通用寄存器之间相减

SUB  R,M        ; 通用寄存器与内存数之间相减

例如,设(CX)=10,(DX)=2,(BX)=5,OFFSET SW=100,(DS:105)=3

SUB  CX,DX      ; 语句执行后(CX)=8

SUB  CH,DI      ; 语句执行后(CH)=-2

SUB  DX,SW[BX]  ; 语句执行后(DX)=-1

(3)MUL——乘法指令。

形式:MUL  操作数。

功能:当操作数为字节数据时,AX←(操作数)×(AL);当操作数为字数据时,DX·AX←(操作数)×(AX)。

该指令有如下两种形式:

MUL    R    ; 8位寄存器时AX←(R)×(AL); 16位寄存器时DX·AX←(R)×(AX)

MUL    M    ; 字节类型时AX←(M)×(AL); 字类型时DX·AX←(M)×(AX)

对于单操作数的指令,要特别注意操作数的类型要明确。

MUL     [SI]

MUL     2[DI]

MUL     [BX ][SI ]

若从操作数的表示形式可以看出操作数都是M,也就是说都是内存数,但从操作数的表示形式中,我们能确定是进行字节乘法还是字乘法。所以以上指令都是错误的。

(4)DIV——除法指令。

形式:DIV  操作数。

功能:当操作数为字节数据时,AL←(AX)/(操作数),AH←(AX)MOD(操作数);当操作数为字数据时,AX←(DX·AX)/(操作数),DX←(DX·AX)MOD(操作数)。

该指令有如下两种形式:

DIV  R      ; 8位寄存器时AL←(AX)/(R), AH←(AX)MOD(R)

; 16位寄存器时AX←(DX·AX)/(R), DX←(DX·AX)MOD(R)

DIV  M      ; 字节类型时AL←(AX)/(M), AH←(Ax)MOD(M)

; 字类型时AX←(DX·AX)/ (M), DX←(DX·AX)MOD(M)

除法有溢出问题,凡字节运算商超过255或字运算商超过65535时均为溢出,0做除数也为溢出。除法出现溢出时,将立即产生0号中断,程序停止执行。

(5)CMP——比较指令。

形式:CMP  目标操作数,源操作数。

功能:(目标操作数)-(源操作数)。

该指令有如下5种形式:

CMP  R,R        ; 通用寄存器之间比较

CMP  R,Im       ; 通用寄存器与立即数之间比较

CMP  M,Im       ; 内存数与立即数相减

CMP  M,R        ; 内存数与通用寄存器之间比较

CMP  R,M        ; 通用寄存器与内存数之间比较

可以看出,比较指令与减法指令不同之处是所产生的两数之差并不取代目标操作数,指令执行后的结果仅仅体现在改变了标志寄存器的内容,为后面的具有判别功能的指令提供条件。

(6)INC——加1指令。

形式:INC  操作数。

功能:操作数←(操作数)+1。

该指令有如下两种形式:

INC  R          ; R←(R)+1

INC  M          ; M←(M)+1

(7)DEC——减1指令。

形式:DEC  操作数。

功能:操作数←(操作数)-1。

该指令有如下两种形式:

DECR           ; R←(R)-1

DECM           ; M←(M)-1

(8)NEG——求负指令。

形式:NEG  操作数。

功能:操作数←0 -(操作数)。

该指令有如下两种形式:

NEGR           ; R←0-(R)

NEGM           ; M←0-(M)

例如,8位[-3]补码=11111101B=0FDH,执行如下指令:

MOVAL,-3       ; AL←0FDH

NEGAL          ; AL←0-0FDH=03H,03H就是-3的负数

MOVAL,3        ; AL←03H

NEGAL          ; AL←0-03H=0FDH,0FDH就是3的负数

2.二进制带符号数的算术运算指令

(1)ADD/SUB——加法/减法指令。

对于二进制符号数的加减法运算,由于系统采用补码表示法,故与无符号数的加减法指令是一样的。一个二进制数既可以看成符号数,也可以看成无符号数,但由于这两种数的数值范围不同,故判断溢出的方法不同。对无符号数的加减法不存在溢出问题,只将进位或借位情况记录在CF中。对符号数的溢出要查看标志位的OF记录,(OF)=1为溢出,(OF)=0没有溢出。这是因为,对于符号数,若运算结果溢出了,那么运算结果也就是错误的,也就没有必要继续程序的执行,这时往往要转向溢出处理程序的执行。所以,对ADD或SUB进行的运算,查不查看标志位CF或OF,运算结果是否可取,这都取决于机器进行的是无符号运算还是符号数运算。这个问题只有编程者自己清楚,机器是不知道的。

(2)IMUL——符号数乘法指令。

形式:IMUL  操作数。

功能:当操作数为字节数据时,AX←(操作数)×(AL);当操作数为字数据时,DX·AX←(操作数)×(AX)。

该指令有如下两种形式:

IMUL  R     ; 8位寄存器时AX←(R)×(AL); 16位寄存器时DX·AX←(R)×(AX)

IMUL  M     ; 字节类型时AX←(M)×(AL); 字类型时DX·AX←(M)×(AX)

例如:

wNum DW 8004H   ; (wNum)=8004H

MOV    AX,5      ; AX←5

MUL    wNum      ; DX←0002H, AX←8014H

IMUL   wNum     ; DX←0FFFDH, AX←8064H

(3)IDIV——符号数除法指令。

形式:IDIV  操作数。

功能:当操作数为字节数据时,AL←(AX)/(操作数),AH←(AX)MOD OPRD;当操作数为字数据时,AX←(DX·AX)/(操作数),DX←(DX.AX)MOD OPRD。

该指令有如下两种形式:

IDIV  R     ; 8位寄存器时AL←(AX)/(R), AH←(AX)MOD(R)

; 16位寄存器时AX←(DX×AX)/(R), DX←(DX×AX)MOD OPRD

IDIV  M     ; 字节类型时AL←(AX)/(M), AH←(AX)MOD(M)

; 字类型时AX←(DX×AX)/(M), DX←(DX×AX)MOD(M)

如果商溢出(字节运算时商超过-128~127,或字运算时商超过-32768~32767),则产生0号中断。如果被除数不是除数的两倍长度,则要把被除数低一半的符号位填充到高一半中,变成除数的双倍长度。其相应的支持指令为:

形式:CBW。

功能:将AL中的符号扩展到AH中,即将一个字节的带符号数扩展成一个字。

形式:CWD。

功能:将AX中的符号扩展到DX中,即将一个字的带符号数扩展成双字。

例如:

SW      DB-9

DATA    DB 2

MOV     AL,SW

CBW

IDIV    DATA        ;(AL)=4

3.无符号组合式BCD码加减运算指令

对于无符号组合式BCD码的运算,系统是利用二进制数运算然后再进行修正的方法来实现的。由于组合式十进制数采用4位二进制数表示一个数,故4位二进制数中只有0~9是有效的,而10~15是无效的,并且4位二进制数中若有进位时,表示的是16进一,而不是10进一。这样,用二进制运算组合式BCD时就产生两个问题:一是运算的结果大于9时而不知道进位到高4位中;二是低4位进位到高4位的“1”不代表10而是16。为此,系统设立了一个辅助进位标志位AF(执行加法指令时,若低4位产生进位则AF置位,反之AF被清零。执行减法指令时若低4位产生借位则AF置位,反之AF被清零)及两个调整语句。

(1)DAA——加法调整指令。

形式:DAA。

功能:如果AL寄存器中低4位大于9或辅助进位(AF)=1,则(AL)= (AL)+6并且(AF=1);如果(AL)≥0A0H或(CF)=1,则(AL)= (AL)+60H并且(CF)=1。

(2)DAS——减法调整指令。

形式:DAS。

功能:如果AL寄存器中低4位大于9或辅助借位(AF)=1,则(AL)=(AL)-6并且(AF)=1;如果(AL)≥0A0H或(CF)=1,则(AL)=(AL)-60H并且(CF)=1。

进行组合式BCD码加法或减法运算实现用ADD语句或SUB语句,使运算结果在AL中,然后再应用DAA或DAS调整语句即可得组合式BCD加减法的正确结果。

例如:

MOVAL,43H      ;(AL)=43H

MOVBL,29H      ;(BL)=29H

ADDAL,BL       ;(AL)=6CH

DAA             ;(AL)=72H

MOVAL,43H      ;(AL)=43H

MOVBL,29H      ;(BL)=29H

SUBAL,BL       ;(AL)=IAH

DAS             ;(AL)=14H

4.无符号分离式BCD码算术运算指令

无符号分离式BCD运算也是在二进制无符号四则运算的基础上再增加4种调整功能实现的。无符号分离式BCD可进行四则运算,因而相应有4种调整指令,它都是对字节运算进行调整的。

(1)AAA——ASCII加法调整指令。

形式:AAA。

功能:如果AL的低4位大于9或(AF)=1,则(AL)=(AL)+6,(AH)=(AH)+1,(AF)=(CF)=1,AL高4位清零;否则(AF)=(CF)=0,AL高4位清零。

例如:

MOVAH,0

MOVAL, '7'     ;(AL)=37H

MOVBL, '4'     ;(BL)=34H

ADDAL, BL      ;(AL)=6BH

AAA             ;(AX)=0101H

(2)AAS——ASCII减法调整指令。

形式:AAS。

功能:如果AL的低4位大于9或(AF)=1,则(AL)=(AL)-6,(AH)=(AH)-1,(AF)=(CF))=1,AL高4位清零;否则(AF)=(CF)=0,AL高4位清零。

(3)AAM——ASCII乘法调整指令。

形式:AAM。

功能:被调整的乘积在AX中,其调整规则为AH←(AL)/10,AL←(AL)%10。

例如:

MOV  AL,'9'     ;(AL)=39H

MOV  BL,'8'     ;(BL)=38H

SUB  AL,30H     ;(AL)=09H,高4位清0

SUB  BL,30H     ;(BL)=08H,高4位清0

MUL  BL         ;(AX)=0048H

AAM             ;(AX)=0702H

(4)AAD——ASCII除法调整指令。

形式:AAD。

功能:除法运算前,先调整AX内容,使(AL)=(AL)+(AH)×10,(AH)=0,即把非压缩十进制数变成二进制数。

从以上可以看出,由于ASCII码中0~9字符的低4位用相应的0~9表示,而高4位都是用3表示,且分离式BCD的加减运算中,参加运算的数的高4位可取任意值,但在乘除运算时,参加运算数的高4位须为0。

【例9-3】 编写程序实现输入任意两个0~9之间的数字,并分别进行加法与乘法运算,运算后显示在屏幕上。

注意:由于输入与输出的数据均为ASCII码,故用分离式BCD码较为方便;又由于程序很简单,故采用寄存器CX存放数据,不设置数据段。

源程序:

.MODEL  SMALL

.   .STACK 100H

.CODE

LAA:MOV    AH,1         ; 从键盘输入两个数

INT    21H

MOV    CH,AL

MOV    AH,1

INT    21H

MOV    AH,0              ; 求和

MOV    CL,AL             ; 两个数在CX中保存

ADD    AL,CH

AAA

ADD     AX,3030H        ; 显示和

MOV     DH,AL

MOV     DI,AH

MOV     AH,2

INT     21H

MOV     DI,DH

MOV     AH,2

INT     21H

SUB     CX,3030H        ; 求积

MOV     AL,CL

MUL     CH

AAM

ADD     AX,3030H        ; 显示积

MOV     DH,AL

MOV     DI,AH

MOV     AH,2

INT     21H

MOV     DI,DH

MOV     AH,2

INT     21H

.EXIT   0

END    LAA

运行结果:

891772

5.多字节数运算指令

运用前面讲的定字长的二进制与十进制数的运算指令,配合这里讲的两条指令,就可以实现多字节的运算。

(1)ADC——带进位加法指令。

形式:ADC  目标操作数,源操作数。

功能:目标操作数←(目标操作数)+(源操作数)+CF。

该指令有如下5种形式:

ADC  R,R        ; 通用寄存器之间相加,再加进位位

ADC  R,Im       ; 通用寄存器与立即数之间相加,再加进位位

ADC  M,Im       ; 内存数与立即数相加,再加进位位

ADC  M,R        ; 内存数与通用寄存器之间相加,再加进位位

ADC  R,M        ; 通用寄存器与内存数之间相加,再加进位位

例如,380782H+65C2H的程序片段如下:

bNum1 DB 0B2H,07H,38H

bNum2 DB 0C2H,65H

文本框: … 


MOV     AL,bNum1

ADD     AL,bNum2

MOV     AH,bNum1+1

ADC     AH,bNum2+1

MOV     DI,bNum1+2

ADC     DI,0

(2)SBB——带借位减法指令。

形式:SBB  目标操作数,源操作数。

功能:目标操作数←(目标操作数)-(源操作数)-CF。

该指令有如下5种形式:

SBB  R,R        ; 通用寄存器之间相减,再减借位位

SBB  R,Im       ; 通用寄存器与立即数之间相减,再减借位位

SBB  M,Im       ; 内存数与立即数相减,再减借位位

SBB  M,R        ; 内存数与通用寄存器之间相减,再减借位位

SBB  R,M        ; 通用寄存器与内存数之间相减,再减借位位

实现多字节减法和实现多字节加法方法一样。实现多字节乘法及除法的思想可通过下面的程序来体现。

例如,380782H×C2H的程序片段如下:

bMul1 DB 82H,07H,38H   

bMul2 DB 0C2H

bResult DB  4 DUP(0)

文本框: … 


MOV AL,bMul1

MUL bMul2

MOV bResult,AL

MOV bResult+1,AH

MOV AL,bMul1+1

MUL bMul2

ADD bResult+1,AL

ADC bResult+2,AH

MOV AL,bMul1+2

MUL bMul2

ADD bResult+2,AL

ADC bResult+3,AH

又如,380782H+C2H的程序片段如下:

bDiv1 DB 0B2H,07H,38H

bDiv2 DB 0C2H

bResult DB 4 DUP(0)

文本框: … 


MOV AH,0

MOV AL,bDiv1+2

DIV bDiv2

MOV bResult,AL

MOV AL,bDiv1+1

DIV bDiv2

MOV bResult+1,,AL

MOV AL,bDiv1

DIV bDiv2

MOV bResult+2,AL

MOV bResult+3,AH