1.显示字符串
问题
显示字符串是现实工作中经常要用到的功能,应该编写一个通用的子程序来实现这个功
能。我们应该提供灵活的调用接口,使调用者可以决定显示的位置(行、列)、内容和颜色。
子程序描述
名称:show str
功能:在指定的位置,用指定的颜色,显示一个用0结束的字符串。
参数:(dh)=行号(取值范围024), (d1)=列号(取值范围079),
(c1)=颜色,dsai指向字符串的首地址
返回:无
应用举例:在屏幕的8行3列,用绿色显示data段中的字符串。
提示
(1)子程序的入口参数是屏幕上的行号和列号,注意在子程序内部要将它们转化为显存中的地址,首先要分析1下屏幕上的行列位置和显存地址的对应关系;
(2)注意保存子程序中用到的相关寄存器:
(3)这个子程序的内部处理和显存的结构密切相关,但是向外提供了与显存结构无关
的接口。通过调用这个子程序,进行字符串的显示时可以不必了解显存的结构,为编程提供了方便。在实验中,注意体会这种设计思想。
assume cs:code data segment db 'welcome to masm!',0 data ends code segment start: mov dh,8 mov dl,3 mov cl,2 mov ax,data mov ds,ax mov si,0 call show_str mov ax,4c00h int 21h show_str: push dx push cx push si mov di,0 mov bl,dh dec bl mov al,160 mul bl mov bx,ax add dl,dl add bl,dl mov ax,0b800h mov es,ax mov al,cl s: mov ch,0 mov cl,ds:[si] jcxz ok mov es:[bx+di],cl mov es:[bx+di+1],al add di,2 inc si loop s ok: pop dx pop cx pop si ret code ends end start
2,解决除法溢出的问题
前面讲过,div指令可以做除法。当进行8位除法的时候,用al存储结果的商,ah存储结果的余数;进行16位除法的时候,用ax存储结果的商,dx存储结果的余数。可是,现在有一个问题,如果结果的商大于al或ax所能存储的最大值,那么将如何?
比如,下而的程序段:
mov bh,1 mov ax,1000 div bh
进行的是8位除法,结果的商为1000,而1000在al中放不下。
mov aX,1000H mov dx,1 mov bx,1 diV bX
进行的是16位除法,结果的商为11000H,而11000H在ax中存放不下。
我们在用div指令做除法的时候,很可能发生上面的情况:结果的商过大,超出了寄存器所能存储的范围。当CPU执行div等除法指令的时候,如果发生这样的情况,将引发CPU的一个内部错误,这个错误被称为:除法溢出。我们可以通过特殊的程序来处理这个错误,但在这里我们不讨论这个错误的处理,这是后面的课程中要涉及的内容。
assume cs:code,ss:stack stack segment dw 8 dup (0) stack ends code segment start: mov ax,stack mov ss,ax mov sp,16 mov ax,4240h mov dx,00fh mov cx,0ah call divdw mov ax,4c00h int 21h divdw: push ax mov ax,dx mov dx,0 div cx mov bx,ax pop ax div cx mov cx,dx mov dx,bx ret code ends end start
3.数值显示
问题
编程,将data段中的数据以十进制的形式显示出来。
data segment dw 123,12666,1,8,3, 38 data ends
这些数据在内存中都是二进制信息,标记了数值的大小。要把它们显示到屏幕上,成为我们能够读懂的信息,需要进行信息的转化。比如,数值12666,在机器中存储为二进制信息:001100010111101 oB}31 }AH>,计算机可以理解它。而要在显示器上读到可以理解的数值12666,我们看到的应该是一串字符:"12666"。由于显卡遵循的是ASCII编码,为了让我们能在显示器上看到这串字符,‘占在机器中应以ASCII码的形式存储为:
31H, 32H, 36H, 36H, 36H(字符“0”一“9”对应的ASCII码为30H}39H) o
通过上面的分析可以看到,在概念世界中,有一个抽象的数据12666,它表示了一个数值的大小。在现实世界中它可以有多种表示形式,可以在电子机器中以高低电平(二进制)的形式存储,也可以在纸上、黑板上、屏幕上以人类的语言“12666”来书写。现在,我们面临的问题就是,要将同一抽象的数据,从一种表示形式转化为另一种表示形式。 可见,要将数据用十进制形式显示到屏幕上,要进行两步工作:
(1)将用二进制信息存储的数据转变为十进制形式的字符串;
(2)显示十进制形式的字符串。
第二步我们在本次实验的第一个子程序中己经实现,在这里只要调用一下show str即可。我们来讨论第一步,因为将二进制信息转变为十进制形式的字符串也是经常要用到的功能,我们应该为它编写一个通用的子程序。
子程序描述
名称:dtoc
功能:将word型数据转变为表示一十进制数的字符串,字符串以0为结尾符。
参数:(ax)=word型数据
dsai指向字符串的首地址
返回:无
应用举例:编程,将数据12666以十进制的形式在屏幕的8行3列,用绿色显示出
来。在显示时我们调用本次实验中的第一个子程序show str
assume cs:code data segment db 10 dup (0) data ends stack segment dw 8 dup(0) stack ends code segment start: mov ax,42243 mov bx,data mov ds,bx mov bx,stack mov ss,bx mov sp,10h mov si,0 call dtoc mov dh,8 mov dl,3 mov cl,2 call show_str mov ax,4c00h int 21h dtoc: push ax push bx push si mov bx,10 mov si,0 s0: mov dx,0 div bx add dx,30h push dx mov cx,ax inc si inc cx loop s0 mov cx,si mov si,0 s1: pop ds:[si] inc si loop s1 pop si pop bx pop ax ret show_str: push ax push dx push cx push si mov di,0 mov bl,dh dec bl mov al,160 mul bl mov bx,ax add dl,dl add bl,dl mov ax,0b800h mov es,ax mov al,cl s: mov ch,0 mov cl,ds:[si] jcxz ok mov es:[bx+di],cl mov es:[bx+di+1],al add di,2 inc si loop s ok: pop si pop cx pop dx pop ax ret code ends end start