在这次实验中,我们将要编写3个子程序,通过它们来认识几个常见的问题和掌握解决这些问题的方法.在后面的课程中,将要用到这个实验中编写的3个子程序.
1.显示字符串
问题:显示字符串是现实工作中经常要用到的功能,应该编写一个通用的子程序来实现这个功能.我们应该提供灵活的调用接口,是调用者可以决定显示的位置(行、列)、内容和颜色.
应用举例:在屏幕的8行3列,用绿色显示data段中的字符串.
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
;功能:在指定的位置,用指定的颜色,显示一个用0结束的字符串.
;参数:(dh)=行号(取值范围0~24),(dl)=列号(取值范围0~79),
; (cl)=颜色,ds:si指向字符串的首地址,(ds)=字符串所在的段
; 地址,(si)=字符串首地址
;返回:无
show_str:
push es
push ax
push dx
push di
push cx
push bx
push si
mov ax,0b800h
mov es,ax
mov al,160
mul dh
mov di,ax ;确定行
add dl,dl ;列乘2是字符
mov dh,0
mov bx,dx
mov al,cl
s:mov ah,[si] ;以下写入显存
mov es:[di][bx],ah
mov es:[di][bx+1],al
mov ch,0
mov cl,[si]
jcxz ok
add bx,2
inc si
jmp s
ok:
pop si
pop bx
pop cx
pop di
pop dx
pop ax
pop es
ret
code ends
end start
2.解决除法溢出的问题
应用举例:计算1000000/10(0f4240h/0ah)
assume cs:code
code segment
start:
mov ax,4240h
mov dx,0000fh
mov cx,0ah
call divdw
mov ax,4c00h
int 21h
;子程序描述
;名称:divdw
;功能:进行不会产生溢出的除法运算,被除数为dword型,除数为word型
; 结果为dword型.
;参数:(ax)=dword型数据的低16位
; (dx)=dword型数据的高16位
; (cx)=除数
;返回:(dx)=结果的高16位,(ax)=结果的低16位,(cx)=结果的余数.
;公式:X/N=int(H/N)*65536+[rem(H/N)*65536+L]/N
; X:被除数.范围:[0,FFFFFFFF]
; N:除数.范围:[0,FFFF]
; H:X高16位,范围:[0,FFFF]
; L:X低16位,范围:[0,FFFF]
; int():描述性运算符,取商
; rem():描述性运算符,取余数
;这个公式将可能产生溢出的除法运算:X/N,转变为多个不会产生溢出的
;除法运算.
;因为公式中[rem(H/N)*65536+L]/N小于65536,所以int{rem(H/N
;)*65536+L]/N}就是32位返回值的低16位,而rem{rem(H/N)*65536
;+L]/N}就是返回值的余数. 因int(H/N)小于65536,所以int(H/N
;)*65536中的int(H/N)就是返回值的高16位.也就是说,假设返回值为
;m(0≤m≤FFFFFFFF)的自然数,任意一个0≤m≤FFFFFFFF的数m都可以分
;解为a*65536+b+c(余数),如果设定bx中存放m的高16位,那么a就放在
;bx中,(bx)的实际意义是m中的a*65536.
;不知我的理解是否正确,请老师指导.
divdw:
push bx
push ax ;暂存X的低16位L
push dx ;暂存X的高16位H
;处理int(H/N)*65536
mov dx,0 ;置H为dword型,(dx)是H的高16位
pop ax ;dx出栈送入ax中作为H的低16位
div cx ;H/N
mov bx,ax ;(ax)是int(H/N)作为返回值的高16位暂存在bx中
;处理[rem(H/N)*65536+L]/N.设rem(H/N)*65536+L=a,rem(H/N)
;作为dword型数据a的高16位放在dx中,L作为低16位放在ax中
pop ax ;(dx)=rem(H/N),(ax)=L
div cx ;[rem(H/N)*65536+L]/N
mov cx,dx ;(dx)作为返回值的余数送入cx中
mov dx,bx ;返回值的高16位.(ax中存放的是返回值的低16位)
pop bx
ret
code ends
end start
程序执行完毕后其实cpu并不认为dx存放的是返回值的高16位,也不知道ax中存放的是返回值的低16位,只有我们知道他们是什么.
有个疑问,对于这个公式,被除数N的取值范围我觉得有点不全面,应该是0~65535的自然数,其实公式本身也是按照自然数去处理的.否则,如果0<N<1,比如N=0.0000002,那么这个公式就不适合了.不知是我对公式的包含的意义没参透,还是其本身存在的瑕疵?
3.数值显示
应用举例:
编程,将data段中的数据以十进制的形式显示出来.
assume cs:code
data segment
db 10 dup (0)
data ends
code segment
start:
mov ax,12666
mov bx,data
mov ds,bx
mov si,0
call dtoc
mov dh,8
mov dl,3
mov cl,2
call show_str
mov ax,4c00h
int 21h
;子程序描述
;名称:dtoc
;功能:将word型数据转变为表示十进制数的字符串,字符串以0为结尾符
;参数:(ax)=word型数据
; ds:si指向字符串的首地址
;返回:无
dtoc:
push di
push ax
push dx
push cx
push si
mov di,0
push di ;作为后面所处理的数位ASCII码的结束标志
mov di,10 ;置除数为word型数据
s1:mov dx,0 ;为避免溢出,把被除数置为dword型数据,做32位除法
div di
add dx,30h ;把10进制数位置为对应的ASCII码
push dx ;按照求得的数位ASCII码从低到高的顺序入栈
mov cx,ax
jcxz s2 ;这两条指令判断除法是否结束,依据是ax作为商送入
;cx中,如cx为零则除法结束并转到s2处去处理求得的
;数位ASCII码,如果不为零则继续求余.
jmp s1 ;商ax作为被除数继续求余
s2:pop cx ;数位的ASCII码按照从高到低的顺序依次出栈送入cx
;中并逐个处理,当遇到上面最先入栈的0时,表明数位
;处理结束,这样做的目的是我们不用理会数位有几位.
;因(cx)<0ah+30h,所以(ch)=0,(cl)=数位的
;ASCII码
jcxz go ;当(cx)=0时,转到go处对字符串做最后的处理
mov ds:[si],cl ;在指定的内存单元处依次写入字符串内容
inc si ;指向下一个内存单元
jmp s2 ;继续处理下一个数位的ASCII码
go:
mov byte ptr ds:[si],0 ;标志字符串结束
pop si
pop cx
pop dx
pop ax
pop di
ret
;以上为子程序dtoc
show_str:
push es
push ax
push dx
push di
push cx
push bx
push si
mov ax,0b800h
mov es,ax
mov al,160
mul dh
mov di,ax ;确定行
add dl,dl ;列乘2是字符
mov dh,0
mov bx,dx
mov al,cl
s:mov ah,[si] ;以下写入显存
mov es:[di][bx],ah
mov es:[di][bx+1],al
mov ch,0
mov cl,[si]
jcxz ok
add bx,2
inc si
jmp s
ok:
pop si
pop bx
pop cx
pop di
pop dx
pop ax
pop es
ret
code ends
end start
不容易!!!
- [springaccount] O(∩_∩)O哈哈~ 谢谢老师的精彩点评 我又有激情了…… 01/06 17:10
- [游客] 谢谢你啊 呵呵 12/23 11:15
- [游客] 252025628 如果我说的不对,希望博主联系我,还请赐教 09/17 05:51
- [游客] s:mov [bx],bx 也不对吧 应该是 mov [bx],bl 因为内存单元是字节数据,而b 09/17 05:49
- [游客] 能问个问题吗? 我没不明白为什么我用这种方法写把内容写入显存 但是运行什么也不显示 不知 06/11 22:37
- [rswjf] 你的子程序描述的太好了,向你学习!!! 06/03 23:10
- [rswjf] 刚刚做完这个课程,真花时间。一看就知道你做得过程很清楚。我的。。。。。明天再改了。 06/03 22:57
- [游客] 第5题要把mov bx,0放在循环外吧 05/23 13:33
- [游客] 很好很强大 值得学习 顶了 04/20 18:13
- [jiajiade01] 谢谢老师的鼓励.您们才是让我们这些学习者值得尊敬的,在百忙中抽出时间认真的批阅这些枯燥的数据是很不容 03/24 22:07
[ 游客 发表于 2009-03-04 22:44 ]
厉害啊!
我现在只完成了前两个!
[ 游客 发表于 2009-06-11 22:37 ]
能问个问题吗?
我没不明白为什么我用这种方法写把内容写入显存
但是运行什么也不显示 不知道为什么
所有机器的显存都是那个内存位置吗???
能加吗?qq810872900