未组合BCD码的算术运算调整指令
1).未组合的BCD码加法调整指令AAA(ASCII Adjust for Addition)
未组合的BCD码加法调整指令的格式如下:
AAA
这条指令对在AL中的核(由两个未组合的BCD码相加后的结果)进行调整,产生一个未组合的BCD码。调整方法如下:
(1)如AL中的低4位在0~ 9之间,且AF为0,则转(3);
(2)如AL中的低4位在A~ F之间,或AF为1,则AL (AL) 6,AH (AH) 1,AF位置1;
(3)清楚AL的高4位;
(4)AL位的值送CF位。
该指令影响标志AL和CF,对其他标志均无定义。
下面是为了说明该指令而写的一个程序片段,每条指令执行后的结果作为注释给出,请注意比较:
MOV AX,7
ADD AL,6 ;AL=0DH, AH=00H, AF=0, CF=0
AAA ;AL=03H, AH=01H, AF=1, CF=1
ADC AL,5 ;AL=09H, AH=01H, AF=0, CF=0
AAA ;AL=09H, AH=01H, AF=0, CF=0
ADD AL,39H ;AL=42H, AH=01H, AF=1,CF=0
AAA ;AL=08H, AH=02H,A F=1, CF=1
2).未组合的BCD码减法调整指令AAS(ASCII Adjust Subtraction)
未组合的BCD码减法调整指令的格式如下:
DAS
这条指令对在AL中的差(由两个未组合的BCD码相减后的结果)进行调整,产生一个未组合的BCD码。调整方法如下:
(1)如AL中的低4位在0~ 9之间,且AF为0,则转(3);
(2)如AL中的低4位在A~ F之间,或AF为1,则AL (AL)-6,AH (AH)-1,且AF位置1
(3)清除AL的高4位;
(4)AF位的值送CF位。
该指令影响标志AF和CF,对其他标志均无定义。
下面是为了说明该指令而写的一个程序片段,每条指令执行后的结果作为注释给出,请注意比较:
MOV AL,34H
SUB AL,09H ;AL=2BH, AF=1, CF=0
AAS ;AL=05H, AF=1, CF=1
3.未组合的BCD码乘法调整指令AAM(ASCII Adjust for Multiplication)
未组合的BCD码乘法调整指令的格式如下:
AAM
这条指令对在AL中的积(由两个组合的BCD码相乘的结果)进行调整,产生两个未组合的BCD码。调整方法如下:
把AL中的值除以10,商放在AH中,余数放在AL中。
该指令影响标志SF,ZF和PF,对其他标志无影响。
下面是为了说明该指令而写的一个程序片段,每条指令执行后的结果作为注释给出,请注意比较:
MOV AL,03H
MOV BL,04H
MUL BL ;AL=0CH, AH=00H
AAM ;AL=02H, AH=01H
4.未组合的BCD码除法调整指令ADD(ASCII Adjust for Division)
ADD
该指令和其他调整指令的使用次序上不同,其他调整指令均安排在有关算术运算指令后,而这条指令应安排在除运算指令之前。它的功能是:把存放在寄存器AH(高位十进制数)及存放在寄存器AL中的两位非组合BCD码,调整为一个二进制数,存放在寄存器AL中。调整的方法如下:
AL<=AH*10 (AL)
AH<=-0
由于采用上述调整方法,存放在AL和AH中的非组合BCD的高四位应为0。
该指令影响标志SF,ZF和PF,对其他标志无影响。
下面是为了说明该指令而写的一个程序片段,每条指令执行后的结果作为注释给出,请注意比较:
MOV AH,04H
MOV AL,03H
MOV BL,08H
ADD ;AL=2BH, AH=00H
DIV BL ;AL=05H, AH=03H
3.应用举例
例2.3:设在缓冲区DATA中存放着12个组合的BCD码,求它们的和,把结果存放到缓冲区SUM中。
有关的程序片段如下:
……
NUM1 DB 23H, 45H, 67H, 89H, 32H, 93H, 36H, 12H, 66H, 78H, 43H, 99H
RESULT DB 2 DUP (0)
……
MOV AX,SEG NUM1
MOV DS,AX
MOV BX,OFFSET DATA
MOV CX,10 ;准备循环
XOR AL,AL
XOR AH,AH
NEXT: ADD AL,[BX] ;加
DAA ;调整
ADC AH,O ;考虑进位
XCHG AH,AL
DAA ;调整
XCHG AH,AL
INC BX ;修改指针
LOOP NEXT ;下一个
XCHG AH,AL ;准备高位低地址存放
MOV WORD PTR RESULT,AX
……
例2.4:利用DAA指令改写八一位十六进制数转换为对应的ASCII码符的子程序HTOASC.
下面的子程序巧妙地利用了加法调整指令DAA,使得在子程序中没有条件转移指令。
;子程序名:HTOASC
;功 能:把一位十六进制数转换为对应的ASCII码
;入口参数:AL的低4位为要转换的十六进制数
;出口参数:AL含对应的ASCII码
HTOASC PROC
AND AL,OFH
ADD AL,90H
DAA
ADC AL,40H
DAA
RET
HTOASC ENDP
请读者仔细考虑上述子程序。选几个十六进制数试试。
例2.5:写一个能实现两个十进制数的加法运算处理的程序。设每个十进制数最多10位。
如果不采用十进制数算术运算调整指令,那么在接收了以ASCII码串表示的十进制数后,要把它转换为二进制数。在对二进制数进行运算后,还要把结果转换为十进制数的ASCII码。当要处理的十进制数位数较多时,这种转换较麻烦。现采用十进制数算术运算调整指令完成它。
该程序分为如下四步:(1)接收按十进制表示的被加数,并作适当的处理;(2)接收按十进制表示的加数,也作适当的处理;(3)进行加法处理;(4)显示结果。为此,设计三个子程序。它们分别是:子程序GETNUM接收按十进制数表示的数串并作适当的处理;子程序ADDITION进行加法处理;子程序DISPNUM显示结果。
在子程序ADDITION中,使用非组合BCD码加调整指令AAA,所以十位的被加数和加数均保持非组合BCD码串形式,产生的11位和也是非组合BCD码串。子程序GETNUM通过DOS的OAH号系统功能调用,接收一个字符串,然后检查用户输入是否确实输入了一个十进制数,最后形成一个十位的非组合BCD码串(部租用0补足—)。子程序DISPNUM比较容易,先跳过结果中可能存在的前导的0,然后把非组合的BCD码转换为ASCII码后显示之。
;程序名:T6-2.ASM
;功 能:完成两个由用户输入的10位十进制数的加法运算
;常数定义
MAXLEN = 10 ;最多位数
BUFFLEN = MAXLEN 1 ;缓冲区长度
;数据段
DSEG AEGMENT
BUFF1 DB BUFFLEN,0,BUFFLEN DUP (?) ;存放被加数
NUM1 EQU BUFF1 2
BUFF1 DB BUFFLEN,0,BUFFLEN DUP (?) ;存放加数
NUM2 EQU BUFF2 2
RESULT DB BUFFLEN DUP(?),24H ;存放和
DIGITL DB ’0123456789’ ;有效的十进制数字符
DIGLEN EQU $ - DIGITL
MESS DB’Invalid number!’,0DH,0AH,24H
DSEG ENDS
;代码段
CSEG SEGMENT
ASSUME CS:CSEG,DS:CSEG,ES:CSEG
START: MOV AX,DSEG
MOV DS,AX ;置DS和ES
MOV ES,AX
MOV DX,OFFSET BUFF1
CALL GETNUM ;(1)接收被加数
JC OVER ;不合法时,处理
MOV DX,OFFSET BUFF2
CALL GETNUM ;(2)接收加数
JC OVER ;不合法时,处理
MOV SI,OFFSET NUM1
MOV DI,OFFSET NUM2
MOV BX,OFFSET RESULT
MOV CX,MAXLEN
CALL ADDITION ;(3)加运算
MOV DX,OFFSET RESULT
CALL DISPNUM ;(4)显示结果
JMP SHORT OK
OVER: MOV DX,OFFSET MESS ;出错处理
MOV AH,9
INT 21H
OK: MOV AH,4CH
INT 21H
;
;子程序名:GETNUM
;功 能:接收一个十进制数字串,且扩展成10位
;入口参数:DX=缓冲区偏移
;出口参数:CF=0,表示成功;CF=1,表示不成功
GETNUM PROC
MOV AH,10 ;接收一个字符串
INT 21H
CALL NEWLINE ;产生回车和换行
CALL ISDNUB ;判是否位十进制数字串
JC GETNUM2 ;不是,转
MOV SI,DX
INC SI
MOV CL,[SI] ;取输入的数字串长度
XOR CH,CH
MOV AX,MAXLEN
STD
MOV DI,SI
ADD DI,AX
ADD SI,CX
SUB AX,CX
REP MOVSB ;数字串向高地址移让出低地址
MOV CX,AX
JCXZ GETNUM1
XOR AL,AL ;低地址的高位用0补足
REP STOSB
GETNUM1:CLD
CLC
GETNUM2:RET
GETNUM ENDP
;子程序名: ADDITION
;功 能: 多为非组合BCD码数加
;入口参数:SI=代表被加数的非组合BCD码串开始地址偏移
; DI=代表家属的非组合BCD码串开始地址偏移
; CX=BCD码串长度(字节数)
; BX=存放结果的缓冲区开始地址偏移
;出口参数:结果缓冲区含结果
;说 明:在非组合的BCD码中,十进制数的高位在低地址
ADDITION PROC
STD ; 准备从在高地址的低位开始处理
ADD BX,CX ;BX指向结果缓冲区最后一字节
ADD SI,CX
ADD DI,CX
DEC DI ;SI指向被加数串最后一字节
DEC DI ;DI指向加数串最后一字节
XCHG DI,BX ;BX指向加数串,DI指向结果串
INC BX
CLC
ADDP1: DEC BX
LODSB ;取一字节被加数
ADC AL,[BX] ;加上加数(带上低位的进位)
AAA ;调整
STOSB ;保存结果
;LOOP ADDP1 ;循环处理下一个
MOV AL,0
ADC AL,0 ;考虑最后一次进位
STOSB ;保存之
CLD
RET
ADDITION ENDP
;子程序名:DISPNUM
;功 能:显示结果
;入口参数:DX=结果缓冲区开始地址偏移
;出口参数:无
DISPNUM PROC
MOV DI,DX
MOV AL,0
MOV CX,MAXLEN
REPZ SCASB ;跳过前导的0
DEC DI
MOV DX,DI
MOV SI,DI
INC CX
DISPNU2: LODSB ;把非组合BCD码串转换成ASCII码串
ADD AL,30H
STOSB
LOOP DISPNU2
MOV AH,9 ;显示结果
INT 21H
RET
DISPNUM ENDP
;子程序名:ISDNUM
;功 能:判一个利用DOS的0AH号功能调用输入的字符串是否为数字串
;入口参数:DX=缓冲区开始地址偏移
;出口参数:CF=0,表示事;CF=1,表示否
ISDNUM PROC
MOV SI,DX
LODSB
LODSB ;AL=字符串长度
MOV CL,AL
XOR CH,CH
JCXZ ISDNUM2 ;字串认为非数字串
ISDNUM1: LODSB ;取一个字符
CALL ISDECM ;判该字符是否为数字符
JNZ ISDNUM2 ;不是,转
LOOP ISDNUM1 ;是,下一个
RET
ISDNUM2: STC
RET
ISDNUM ENDP
;子程序名:ISDECM
;功 能:判一个字符是否为十进制数字符
;入口参数:AL=字符
;出口参数:ZF=1,表示是;ZF=0,表示否
ISDECM PROC
PUSH CX
MOV DI,OFFSET DIGITL
MOV CX,DIGLEN
REPNZ SCASB
POP CX
RET
ISDECM ENDP
;子程序说明信息略
NEWLINE PROC
;该子程序的代码同T4-3.ASM中同名子程序
NEWLINE ENDP
CSEG ENDS
END START