一、实验目的
掌握数据传送、算术指令和循环指令的用法。
二、实验内容
将两个多位十进制数相加。要求加数,被加数均以ASCII码形式存放在以DATA1和DATA2为首的5个内存单元中( 低位在前),结果存在DATA1处。
三、程序清单
CRLF MACRO ;建立宏命令,利用INT中断实现回车换行的功能,方便后续直接调用
MOV DL,0DH
MOV AH,02H
INT 21H ;光标移到第一列
MOV DL,0AH
MOV AH,02H
INT 21H ;光标移到下一行
ENDM
DATA SEGMENT
DATA1 DB 33H,39H,31H,37H,34H ;被加数ASCII码
DATA2 DB 36H,35H,30H,38H,32H ;加数ASCII码
DATA ENDS
STACK SEGMENT STACK ;堆栈段
STA DB 20 DUP(?)
TOP EQU LENGTH STA
STACK ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:STACK,ES:DATA
START: MOV AX,DATA
MOV DS,AX
MOV AX,STACK
MOV SS,AX
MOV AX,TOP
MOV SP,AX
MOV SI,OFFSET DATA2 ;SI存放数据地址
MOV BX,05 ;BX中存放数字长度
CALL DISPL ;显示加数
CRLF
MOV SI,OFFSET DATA1 ;源地址指向被加数
MOV BX,05
CALL DISPL ;显示被加数
CRLF
MOV DI,OFFSET DATA2 ;目的地址指向加数
CALL ADDA ;调加法运算子程序
MOV SI,OFFSET DATA1
MOV BX,05
CALL DISPL ;显示结果
CRLF
MOV AX,4C00H
INT 21H ;返回DOS
DISPL PROC NEAR ;显示子程序
DS1: MOV AH,02
MOV DL,[SI+BX-1] ;显示字符串中一个字符
INT 21H
DEC BX
JNZ DS1
RET
DISPL ENDP
ADDA PROC NEAR ;加法运算子程序
MOV DX,SI
MOV BP,DI
MOV BX,05
AD1: SUB BYTE PTR [SI+BX-1],30H ;将ASCII码转换位二进制数
SUB BYTE PTR [DI+BX-1],30H
DEC BX
JNZ AD1
MOV SI,DX
MOV DI,BP
MOV CX,05 ;五位数加法, 5 作为循环次数
CLC ;清进位标志
AD2: MOV AL,[SI]
MOV BL,[DI]
ADC AL,BL ;带进位加法
AAA ;非组合BCD码调整
;如果al的低4位是在0到9之间,保留低4位,清除高4位,如果al的低4位在10到15之间
;则通过加6,来使得低4位在0到9之间,然后再对高4位清零。
;如果al的低4位是在0到9之间,ah值不变,CF和AF标志清零,否则,ah=ah+1,并设置CF和AF标志
MOV [SI],AL ;结果存被加数区
INC SI ;指向下一位
INC DI
LOOP AD2 ;没有加够 5 位转
MOV SI,DX ;恢复加数,被加数地址指针
MOV DI,BP
MOV BX,05
AD3: ADD BYTE PTR [SI+BX-1],30H ;转换为ASCII码
ADD BYTE PTR [DI+BX-1],30H
DEC BX
JNZ AD3
RET
ADDA ENDP
CODE ENDS
END START
四、实验过程
1.用编辑器建立源文件D101-2.ASM
2.用汇编程序MASM.EXE对源文件进行汇编,产生目标文件,再用连接程序LINK产生可执行文件
3.使用调试工具DEBUG进行程序调试
先用U命令反汇编,以便了解指令地址。显示结果如下,具体调试结果见第五部分。
五、实验结果分析
1.程序调试及结果
可以看到在076D:0015地址处的指令是调用显示子程序DISPL来显示加数,被加数的显示类似,使用G命令执行到076D:0039处,查看显示结果。
使用-G 0076命令执行到ADDA子程序中,使用D命令查看ASCII码被转化为十六进制数后在内存中的存放情况,如下
使用-G 008f命令执行到BCD加法结束,查看被加数内存区域数值如下,因为28056+47193=75249,因此内存区域由低地址到高地址应依次为09 04 02 05 07,使用-d ds:0命令进行查看,与理论值一致。
继续使用G命令运行程序,直到将计算结果转化为ASCII码后,结果为
最后,运行到程序结束,将结果打印到屏幕上,如下:
2.分析总结
首先,在MASM编译器Microsoft ® Macro Assembler Version 5.00版本下,纠正实验指导书中出现的一个小问题。实验指导书中对“CRLF”命令宏的建立代码放在了文件最开头,然而在该版本编译器下编译会报错:Out of memory,将该宏命令放入代码段后编译即可编译成功,后续又将其放在文件开头编译,又可以编译成功没任何报错信息,对此迷惑不解,具体原因还需查阅相关资料。
本次实验的核心在于数据的传送指令、算数指令和循环指令的用法,其中比较重要的指令有:AAA(ASCII adjust after addition)指令,是BCD指令集中的一个指令,用于在两个未打包的BCD值相加后,调整al和ah寄存器的内容;BCD(Binary-coded decimal)数是指2进制编码的10进制数,占据一个字节的低4位,只有0-9是有效值。AAA指令做两件事情:(1)如果al的低4位是在0到9之间,保留低4位,清除高4位,如果al的低4位在10到15之间,则通过加6,来使得低4位在0到9之间,然后再对高4位清零。(2)如果al的低4位是在0到9之间,ah值不变,CF和AF标志清零,否则,ah=ah+1,并设置CF和AF标志。此外,还要搞清楚ADC等带进位加法指令与不带进位加法ADD指令的区别,将这些搞明白,则本实验的核心内容就没有什么问题了。