实验九
实验结论
实验任务1
补全程序 t1.asm如下,完成在屏幕上输出内存单元中的十进制两位数。
data segment
db 12
db ?,? ; 前一个字节用于保存商,后一个字节用于保存余数
data ends
code segment
start:
××××
×××× ; 补全指令,使得ds <-- data段地址
mov ah,0
mov al,ds:[0] ; ax <-- data段字节单元的被除数12
mov bl,10
div bl
mov ××,al ; 补全代码,让商保存到data段注释中指定的单元
mov ××,ah ; 补全代码,让余数保存到data段注释中指定的单元
mov dl,×× ; 补全代码,使得dl <-- data段中保存的商的字节单元数值
×××× ; 补全代码,使得dl中的数值转换为数字字符
int 21h
mov dl,×× ; 补全代码,使得dl <-- data段中保存余数的字节单元数值
×××× ; 补全代码,使得dl中的数值转换为数字字符
int 21h
int 21h
code ends
end start
![](https://img2018.cnblogs.com/blog/1481991/201812/1481991-20181208151423247-629080044.png)
在本实验任务中,将 2 放入 ah,将待输出字符或其 ASCll 码放入 dl,实现的是 int 21h 的 2 号子功能,完成单个字符的输出。但是在有一次编程中,我将红框中的 mov ah, 2 删掉了,然而运行结果却与上图一模一样,所以我就进入了 debug 调试环境,试图找出原因,经过观察发现是因为通过 div 操作,ah 中存储的余数正好是 12 整除 10 的余数 2,所以可以实现输出 12,当我把 12 换成 13 后,就没有办法实现上图结果了。
实验任务2
补全程序 t2.asm,完成在屏幕上输出 data 段定义的 5 个十进制两位数,数据和数据 之间以空格间隔。
assume cs:code, ds:data
data segment
db 12,35,96,55,67
data ends
code segment
start:
; 补全程序,参考t1.asm,综合应用以下知识完成:
; (1) loop指令、内存单元地址的灵活表示
; (2) div指令, 数字→数字字符的转换
; (3) int 21h的2号子功能,完成单个字符输出的方法,即:
; mov ah,2
; mov dl,待输出字符或其ASCⅡ码
; int 21h
; (4) 数据和数据之间以空格间隔的实现: 使用(3)输出空格字符
mov ax,4c00h
int 21h
code ends
end start
补全后的源程序:
运行结果:
本实验任务其实就是实验任务 1 的拓展,从输出一个两位数变成输出五个两位数,只要运用一次循环就可以实现。
实验任务3
编程:在屏幕中间分别显示绿色、绿底红色、白底蓝色的字符串 'welcome to masm!'。
(1)源程序(使用三次独立循环):
通过阅读实验九提示中的内同可知:由于题目要求的是显示在屏幕中间,并且整个屏幕共计有25行,也就是说要显示在11,12,13行,所以偏移地址分别为 06e0h 、0780h 和 0820h。
运行结果:
(2)接着尝试改进,只使用一次循环来解决这个问题,源程序如下:
运行结果与(1)中一样:
在本实验任务中,使用了两个新的寄存器,一个是si——源变址寄存器,另一个是di——目标变址寄存器,这两个寄存器的功能与 bx 相近,所以可以借助它们来实现更灵活的内存地址定位方法,但是这两个寄存器不能分成两个 8 位寄存器来使用。
总结与体会
1、由于之前的实验我都是在 DOSBox 中直接写入并执行的,这是第一次使用 Masm for Windows集成实验环境,所以接下来总结以下我在此次实验中发现的这个环境中的两条编码规则(也许并不全面):
(1)在内存单元前必须加上 ds:,这个环境不像 DOSBox 中一样,只要定义了数据段就会默认不写段地址的内存单元是在 ds 中。
(2)在实验任务 3 中,发现在写偏移地址时,一定要将寄存器写在立即数的前面:
es:[di + bx + 06e0h] √
es:[di + 06e0h + bx] ×
2、在实验任务 3 中,我一开始想用二重循环来做,但是发现缺少一个计数的寄存器。由于红框中的 bx 每次是加 a0h 的,所以没有办法正确取到储存在数据段中的属性值。于是后来只好退而求其次,用一次循环来做了,源程序如下:(不知道是不是因为我没有考虑周到,所以才没有找到解决方案?)