实验任务一
要求:补全程序 t1.asm,完成在屏幕上输出内存单元中的十进制两位数。
1 ;t1.asm 2 ; 在屏幕上输出内存单元中的十进制两位数 3 assume cs:code, ds:data 4 data segment 5 db 12 6 db ?,? ; 前一个字节用于保存商,后一个字节用于保存余数 7 data ends 8 code segment 9 start: 10 ×××× 11 ×××× ; 补全指令,使得ds <-- data段地址 12 13 mov ah,0 14 mov al,ds:[0] ; ax <-- data段字节单元的被除数12 15 mov bl,10 16 div bl 17 mov ××,al ; 补全代码,让商保存到data段注释中指定的单元 18 mov ××,ah ; 补全代码,让余数保存到data段注释中指定的单元 19 20 mov ah,2 21 mov dl,×× ; 补全代码,使得dl <-- data段中保存的商的字节单元数值 22 ×××× ; 补全代码,使得dl中的数值转换为数字字符 23 int 21h 24 25 mov ah,2 26 mov dl,×× ; 补全代码,使得dl <-- data段中保存余数的字节单元数值 27 ×××× ; 补全代码,使得dl中的数值转换为数字字符 28 int 21h 29 30 mov ax,4c00h 31 int 21h 32 code ends 33 end start
补充好的代码为:
运行结果:
小结:
此题要求输出一个十进制两位数,以目前所学知识还不能一次性打印2个甚至多个字符,只能一个一个的分别获取该数字的个位和十位,然后依据ASCLL码转换为对应的字符进行输出。而关键就在于如何获取个位和十位数字,这里我们采用了除法(div)指令来达到这个目的。
让10除两位数,得到的商即是该两位数的十位数字,得到的余数即是该两位数的个位数字。
实验任务二
要求:补全程序 t2.asm,完成在屏幕上输出 data 段定义的 5 个十进制两位数,数据和数据之间以空格间隔。
1 ;t2.asm 2 assume cs:code, ds:data 3 data segment 4 db 12,35,96,55,67 5 data ends 6 code segment 7 start: 8 ; 补全程序,参考t1.asm,综合应用以下知识完成: 9 ; (1) loop指令、内存单元地址的灵活表示 10 ; (2) div指令, 数字→数字字符的转换 11 ; (3) int 21h的2号子功能,完成单个字符输出的方法,即: 12 ; mov ah,2 13 ; mov dl,待输出字符或其ASCⅡ码 14 ; int 21h 15 ; (4) 数据和数据之间以空格间隔的实现: 使用(3)输出空格字符 16 17 mov ax,4c00h 18 int 21h 19 code ends 20 end start
补充好的代码为:
运行结果:
小结:
此题可认为是任务一的进阶,需要输出的数字更多了,并且增加了输出空格的要求。不过也不困难,设计一个单层循环即可解决。
实验任务三
要求:根据材料编程,在屏幕中间分别显示绿色、绿底红色、白底蓝色的字符串“welcome to masm!”。
材料(摘要):
编写好的代码为:
运行结果:
小结:
此题做出来也许并不难,难的是追求以一种更简洁的方式来完成任务。这是我目前想到的比较简洁的方法,采用了两层嵌套循环。
大体思路:
外层循环是bx在不同行之间切换,内层循环是si在指定行的某一位置开始依次移动并输出相应字符。
遇到的困难:
为了把data段的字符传送到显存中,还需要一个指针在这些字符间移动来传递字符,初期想让si身兼两职,让si也来充当这个角色,但是发现,显存中是用2个字节来表示一个字符的,即显存中的指针是递增2的,而data段中的指针只需要递增1,两者不兼容,所以。。。si还是专心当好它显存指针的职能吧,我另找了di来作为data段的指针。可是问题又来了,虽然字符传送的问题是解决了,但是每行字符的属性都不一样,我似乎还需要一个指针在这些属性值间游走来传递属性值,可是已经没有额外的指针寄存器可用了。为了最大化利用已有的指针寄存器,只能从寻找规律入手了。发现控制外层循环次数的cx是递减1的,而我们需要的属性值指针是递增1的,二者的和应当不变。于是便有了上面的解法。我还是采用di寄存器,因为一行字符的属性是一样的,可以在内层循环开始之前就将这一行的属性值设置好,这样在进入内循环的时候di也就被空了出来。