汇编网首页登录博客注册
jiajiade01的学习博客
博客首页博客互动【做检测题】论坛求助

我的博客

个人首页 |  我的文章 |  我的相册 |  我的好友 |  最新访客 |  文章收藏 |  论坛提问 |  友情链接 |  给我留言  
图片载入中
学习动态
最新留言
友情链接

[2009-03-03 23:21] 王爽 《汇编语言》    实验 10

在这次实验中,我们将要编写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   

不容易!!!
评论次数(2)  |  浏览次数(1153)  |  类型(汇编作业) |  收藏此文  | 

[  游客   发表于  2009-03-04 22:44  ]

厉害啊!
我现在只完成了前两个!

[  游客   发表于  2009-06-11 22:37  ]

能问个问题吗?

我没不明白为什么我用这种方法写把内容写入显存 
但是运行什么也不显示  不知道为什么  
所有机器的显存都是那个内存位置吗???

能加吗?qq810872900

 
 请输入验证码  (提示:点击验证码输入框,以获取验证码