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
