打印一个ASCII表在高级程序设计语言中是一个非常简单的程序,但是用汇编又该如何编写呢?
一、设计思路
我们可以按15行*16列的表格形式显示ASCII码为10H一100H的所有字符,即以行为主的顺序及ASCII码递增的次序依次显示对应的字符。每16个字符为一行,每行中的相邻两个字符之间用空白符(ASCII为0)隔开。
显示每个字符可使用功能号为02的显示输出功能调用,使用方法如下:
Movah,02h
Movdl,输出字符的ASCLL码
Int21h
可把dl初始化为10H,然后不断使其加1(用INC指令)以取得下一个字符的ASCLL码。
显示空白符时,用其ASCLL码0置入dl寄存器。每行结束时,用显示回车(ASCLL为0dh)和换行符(ASCLL为0ah)来结束本行并开始下一行。
由于逐个显示相继的ASCLL字符时,需要保存并不断修改dl寄存器的内容,而显示空白,回车,换行符时也需要使用dl寄存器,为此可使用堆栈来保存相继的ASCLL字符。具体用法是:在显示空白或回车,换行符前用指令
Pushdx
把dl的内容保存到堆栈中去。在显示空白或回车,换行符前用指令
Popdx
恢复dl寄存器的原始内容。
二、程序实现代码
采用类似于C语言的双层循环输出的方式,在外层循中输出一行,总共循环15次,输出15行;在内层循环中输出一行中的16个字符,循环16次。用DX寄存器保存对应的字符的ASCII值,并增加DX的值来得到下一个ASCII码。
具体实现如下:
assume cs:codesg
codesg segment
;设置寄存器初值
mov dx, 0000H
mov dl, 10H ;从ASCII码为10H的字符开始显示
mov cx, 000FH ;设置外循环的次数15,即要显示的行数
mov ax, 0000H
r:
mov ah, 02H ;设置显示方式
push cx ;保存外循环次数的计数
mov cx, 0010H ;设置内循环次数16,即一行16个字符
c:
int 21H ;显示ASCII值为[dl]的字符
push dx ;保存dx的值
mov dl, 00H ;输出空格
int 21H
pop dx ;恢复dx的值,并加1,产生下一个ASCII字符
inc dx
loop c
;已经进行完了一次内循环
pop cx ;恢复外循环次数的计数
push dx ;保存dx的值
mov dl, 0dH ;输出回车换行
int 21H
mov dl, 0aH
int 21H
pop dx ;恢复dx的值
loop r
;外循环结束,程序的功能完成
mov ax, 4c00H
int 21H
codesg ends
end
运行结果如下:
三、程序分析
代码采用类似于C语言的双层循环输出的方式,在外层循中输出一行,总共循环15次,输出15行;在内层循环中输出一行中的16个字符,循环16次。用DX寄存器保存对应的字符的ASCII值,并增加DX的值来得到下一个ASCII码。
由于在输出空格、回车和换行时,会破坏DX中原来的值,所以在用空格、回车和换行的ASCII值覆盖DX寄存器原来的内容时,先把DX寄存器中的内容压入栈中保存,即PUSHDX。输出空格、回车和换行后,调用POPDX恢复DX寄存器的值。以便下次直接把DX的值加1产生后继字符。
由于本程序中使用了两个循环,而每一个循环中都要用CX保存和记录循环的次数,所以在进入内层循环时,要先把外层循环的计数,即用PUSHCX,把CX的值压栈保存。在内层循环结束时,再恢复外层循的计数,即POPCX。然后在LOOP指令中判断外层循环是否完成退出。
PS:由于所用的操作系统问题,在运行程序时后面一些行(ASCII码为128及以后的行)有时会显示乱码。可用虚拟软件虚拟16位系统或在Debug中运行该程序即可正确输出。