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

我的博客

个人首页 |  我的文章 |  我的相册 |  我的好友 |  最新访客 |  文章收藏 |  论坛提问 |  友情链接 |  给我留言  
图片载入中
  •  做不了第一个就做最好的, 做不了最好的就做第一个。
  • 『姓名』:
  • 『性别』:保密『发送消息
  • 个人说明:不要执着于学习步骤, 宁愿多看点知识
  • 详细信息『加为好友』
学习动态
最新留言
友情链接

[2009-03-10 16:16] 实验10b  难啃的骨头--除法溢出

图片载入中
做这实验比较开心,因为耳麦里传来的是邓丽君绵绵的情歌^_^。废话少说先看偶代码(有参考的):
-------------------------------------------------------
assume cs:code, ss:stack

stack segment
        dw 8 dup(0)
stack ends

code segment
start:        mov ax,stack
        mov ss,ax
        mov sp,10h
        mov ax,4240h
        mov dx,0fh
        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 : 高16位
;        N : 除数
;        H : X 的高16位
;        L : X 的低16位
;        int():        描述性运算符,取商,比如,int(38/10)=3
;        rem():        描述性运算符,取余数,比如,rem(38/10)=8
;------------------------------------------------------
divdw:        ;push dx        ;注意这里不用入栈保存dx,因为它用处会变
        push bx                
        push ax
        mov ax,dx        ;ax暂存高16位
        mov dx,0        
        div cx                ;dx暂存余数
        mov bx,ax        ;bx暂存商,根据公式,这里的商其实就是最后的结果的高16位        
        pop ax
        div cx                ;这时前面的余数(正好在dx中)作为本次除法的被除数的高16位,觉得这里就是本程序最巧妙处^_^
        mov cx,dx        ;cx暂存余数
        mov dx,bx
        pop bx
        ;pop dx                ;当然也不用出栈,一出栈dx不就存放原先被除数的高16位了嘛?
                        ;我们要让它存放最终结果的高16位的^^
code ends
end start
-------------------------------------------------------

         !!!公式公式公式!!!本实验关关关键就是公式(如上面程序中注释)的理解:
        int(H/N) 乘 65536 表明 :int(H/N) 是结果的高16位。后面的加数整个为结果的低16位。
        再单独看后面的这个加数:就一除法,只不过将H/N的余数即rem(H/N) 作为了这个除法的高16位 ,所以给它乘以65536嘛^_^, L 呢就是X的低16位喽(附注里有很详细的证明)。
        按照题目的要求,我们要做的只是把被除数的高16位除以除数先,然后将商暂存起来作为后面整个结果的高16位(以dx返回);接着把被除数的高16位和除数相除的结果的余数暂存起来作为被除数的高16位,L(X的低16位)作为被除数的低16位,然后除以N。
         本人分析的确实有点啰嗦,不过应该说清楚了吧 ^_^ ^_^ 欢迎拍砖。
评论次数(20)  |  浏览次数(1569)  |  类型(实验) |  收藏此文  | 

[  maxm   发表于  2009-03-10 16:21  ]

结果如附图:
(dx)=0001h
(ax)=86A0h
(cx)=0000h (余数为0)
^^ 没有错误 ^^

[  maxm   发表于  2009-03-10 16:29  ]

说来惭愧,这些天就因为这个实验没理解,
所以一直没有看后面的,现在解决了。
偶又可以继续捣鼓了 (*^__^*) 嘻嘻……

[  maxm   发表于  2009-03-10 16:37  ]

本实验1和3偶会附在这里^^
谢谢光临吼 o(∩_∩)o
多多提意见           (*^__^*)

[  maxm   发表于  2009-03-10 16:42  ]

:-) 我都忘记了自己检测题做到哪儿了
:-) 好像有一阵子没做了 ^_^

[  maxm   发表于  2009-03-10 16:53  ]

实验10,一
----------------------------------------------
assume cs:code

data segment
        db 'welcome to masm!',0
data ends

code segment
start:                mov ax,data
                mov ds,ax
                mov si,0
                mov dh,8        ;行号
                mov dl,3        ;列号
                mov cl,2        ;绿色,这里cl有点鸡肋 ,我后面始终是没用到它
                call show_str
                mov ax,4c00h
                int 21h

show_str:        ;显示子程序
                ;push dx        ;因为后面都8位乘法,所以dx可以不用入栈
                push si
                push cx

s0:                mov ah,0                                
                mov al,0a0h        ;每行0a0h个字节,注意不要写成是 0ah 啊 ,我开始就犯这错死活没找到原因
                dec dh                ;要累加的是dh前面的行,所以减 1
                mul dh
                mov bx,ax        ;ax 中存放前面7行的字节数
                mov ah,0
                mov al,2        ;每列2字节        
                dec dl                ;要累加的是dl前的列 ,所以减 1
                mul dl                        
                add bx,ax
                mov ax,0b800h
                mov es,ax
                mov di,0

s:                mov cl,ds:[si]
                mov ch,0
                jcxz ok
                mov byte ptr es:[bx+di],cl
                mov byte ptr es:[bx+di+1],2        ;硬编码颜色,找不到好办法来使用前面定义颜色的cl
                inc si
                add di,2
                jmp short s

ok:                pop cx
                pop si
                ;pop dx                ;当然也不用出栈了
                ret

code ends
end start
----------------------------------------------
:-) 我这机子显示的行数来数去都是7,不知道啥原因。
:-) 程序是没错的

[  maxm   发表于  2009-03-10 17:25  ]

突然有种感觉:
后面的内容会越来越简单 (*^__^*)

[  younggay   发表于  2009-03-10 20:55  ]

博主的热情被点燃了,熊熊火焰啊。
呵呵,加油,烧的更旺些。

[  maxm   发表于  2009-03-11 10:13  ]

:-)感谢楼上支持

[  maxm   发表于  2009-03-11 14:12  ]

感觉自己的试验10a不时很好
找了个别人的对比对比。下面。

[  maxm   发表于  2009-03-11 14:13  ]

;==========================================================================

;文件名:exp10a.asm

;目的:完成并测试在指定的位置,用指定的颜色,显示一个用0结束的字符串的子程序

;==========================================================================

assume cs:code,ds:data

data segment

 str db '^_^Welcome to masm! ^_^',0

data ends

code segment

start:

  mov ax,data

  mov ds,ax

  mov dh,12

  mov dl,30

  mov cl,10001010b

  mov si,0

  call show_str

  mov ax,4c00h

  int 21h

;==============================================================

;名称:show_str

;功能:在指定的位置,用指定的颜色,显示一个用0结束的字符串

;参数:(dh)=行号(取值范围0~24),(dl)=列号(取值范围0~79),

;  (cl)=颜色,ds:si指向字符串的首地址

;返回:无

;==============================================================

show_str: 

  push dx

  push si

  push di

  push cx

  push ax

        mov ax,0b800h

        mov es,ax

  mov ax,160

  mul dh

        mov dh,0

        add ax,dx

        add ax,dx

  sub ax,2

  mov di,ax

        mov ah,cl

output:  

        mov ch,ds:[si]

        mov cl,0

  jcxz ok

        mov byte ptr es:[di],ch

        mov byte ptr es:[di+1],ah

  inc si

  inc di

  inc di

        jmp short output

ok:

  pop ax

  pop cx

  pop di

  pop si

  pop dx

  ret

code ends

end start
============================================================

[  maxm   发表于  2009-03-11 14:50  ]

大家看见没?
-------------------------
        mov ch,ds:[si] 

        mov cl,0 
-------------------------
人在子程序中用ch来暂存 ds:[si]
这样前面就可以用ah 来暂存 cl
这样我们就不用硬编码颜色了,用下面这句问题就解决了。
--------
mov byte ptr es:[bx+di+1],ah 
--------
一直没想到^^ ,cl 跟 ch 可以灵活运用的。
赞一个 (*^__^*)

[  maxm   发表于  2009-03-11 14:58  ]

还有人用加法代替乘法,效率确实高了 
学习     o(∩_∩)o

[  maxm   发表于  2009-03-11 15:03  ]

看来我还没怎么学活

[  maxm   发表于  2009-03-11 15:07  ]

上面说的有点误,其实只要加句 : mov ah,cl
来暂存颜色属性就ok了,后面再传递ah ,
别的不用变 。。。。。

[  maxm   发表于  2009-03-11 15:08  ]

^^ 哦 天 ,大脑缺氧了,得吃午饭了 ^^

[  maxm   发表于  2009-03-12 17:28  ]

10c:
晚上手边没电脑,纸上写的10c的程序,如下。
----------------------------
assume cs:code, ds:data

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,4
        mov dl,4
        mov cl,2
        call show_str

        mov ax,4c00h
        int 21h

dtoc:        push ax
        push bx
        mov di,si
        mov bx,0ah
getd:        mov dx,0
        div bx
        mov cx,ax                        ;cx暂存商做为jcxz指令的条件
        mov byte ptr ds:[si],dl                ;暂存余数
        jcxz toasc                                ;商为0跳出
        inc si
        jmp short getd
        mov cx,si                                
toasc:        mov bl,ds:[si]                        ;bl暂存余数
        add bl,30h                        ;bl变为数字对应的ascii码
        mov byte ptr ds:[di],bl
        dec si
        inc di
        loop toasc
        pop bx
        pop ax
        ret



show_str:        ;显示子程序
                ;push dx        ;因为后面都8位乘法,所以dx可以不用入栈
                push si
                push cx

s0:                mov ah,0                                
                mov al,0a0h        ;每行0a0个字节,注意不要写成是 0ah啊 ,我开始就犯这错死活没找到原因
                dec dh                ;要累加的是dh前面的行,所以减 1
                mul dh
                mov bx,ax        ;ax 中存放前面7行的字节数
                mov ah,0
                mov al,2                ;每列2字节        
                dec dl                ;要累加的是dl前的列 ,所以减 1
                mul dl                        
                add bx,ax
                mov ax,0b800h
                mov es,ax
                mov di,0

s:                mov cl,ds:[si]
                mov ch,0
                jcxz ok
                mov byte ptr es:[bx+di],cl
                mov byte ptr es:[bx+di+1],2        ;硬编码颜色,找不到好办法来使用前面定义颜色的cl
                inc si
                add di,2
                jmp short s

ok:                pop cx
                pop si
                ;pop dx                ;当然也不用出栈了
                ret


code ends
end start

[  maxm   发表于  2009-03-12 18:06  ]

上面程序 masm link 都不报错,好运行,天!死循环!!!赶紧仔细检查涉及到循环和跳转的地方,恁是没看出来。还好生成了exe文件,火速debug,一步一步的眼睛都快瞅瞎了,有句话说的好:功夫不负有心人,终于被我发现了,jcxz toasc,问题就在这句,要让程序跳转到toasc,只有(cx)==0,也就说在我的 toasc 这个loop循环开始前 cx(循环次数)的值为0,然后就是ffff,fffe等,这肯定是不对的。循环开始前cx应该存放12666转化成的穿的字符个数嘛。赶紧改过来 ^_^
----------------------
assume cs:code, ds:data

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:        push ax
        push bx
        mov di,si
        mov bx,0ah
getd:        mov dx,0
        div bx
        mov cx,ax                        ;cx暂存商做为jcxz指令的条件
        mov byte ptr ds:[si],dl                ;暂存余数
        jcxz toasc                        ;商为0跳出
        inc si
        jmp short getd
        
        
toasc:        mov cx,si
        mov bl,ds:[si]                        ;bl暂存余数
        add bl,30h                        ;bl变为数字对应的ascii码
        mov byte ptr ds:[di],bl
        dec si
        inc di
        loop toasc
        pop bx
        pop ax
        ret



show_str:        ;显示子程序
                ;push dx        ;因为后面都8位乘法,所以dx可以不用入栈
                push si
                push cx

s0:                mov ah,0                                
                mov al,0a0h        ;每行0a0个字节,注意不要写成是 0ah啊 ,我开始就犯这错死活没找到原因
                dec dh                ;要累加的是dh前面的行,所以减 1
                mul dh
                mov bx,ax        ;ax 中存放前面7行的字节数
                mov ah,0
                mov al,2        ;每列2字节        
                dec dl                ;要累加的是dl前的列 ,所以减 1
                mul dl                        
                add bx,ax
                mov ax,0b800h
                mov es,ax
                mov di,0

s:                mov cl,ds:[si]
                mov ch,0
                jcxz ok
                mov byte ptr es:[bx+di],cl
                mov byte ptr es:[bx+di+1],2        ;硬编码颜色,找不到好办法来使用前面定义颜色的cl
                inc si
                add di,2
                jmp short s

ok:                pop cx
                pop si
                ;pop dx                ;当然也不用出栈了
                ret


code ends
end start
----------------
运行。ok,有结果了,但是结果不对,显示的竟然是126b☺,天这样确实好看多了,但我们要的可不是这个欧(*^__^*) 。debug,果然犯了一个不可原谅的错误,上面程序中有这样一段:
---------
toasc:        mov cx,si
        mov bl,ds:[si]                        ;bl暂存余数
        add bl,30h                        ;bl变为数字对应的ascii码
        mov byte ptr ds:[di],bl
        dec si
        inc di
        loop toasc
---------------------------------
这样写肯定不对的,想想啊“12666”是5个字符,如果按照上面的程序执行,那么到想显示第二个6的时候,拷贝过去的不是36h而是62h 啊,大家可以debug试试,真寒!!!。

[  maxm   发表于  2009-03-12 18:39  ]

那么是否可以考虑用栈来解决呢?

[  游客   发表于  2009-03-13 15:22  ]

果然用栈可以很容易就解决了问题,修改后代码如下:
---------------------------------------------
assume cs:code, ds:data 

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:    push ax 
    push bx 
    mov di,si 
    mov bx,0ah 
getd:    mov dx,0 
    div bx 
    mov cx,ax            ;cx暂存商做为jcxz指令的条件 
    ;mov byte ptr ds:[si],dl        ;暂存余数 
    push dx                        ;余数入栈
    inc si
    jcxz toasc            ;商为0跳出 
     
    jmp short getd
     
     
toasc:    mov cx,si 
    pop bx                ;bx暂存余数,(bh)肯定是0
    ;mov bl,ds:[si]            ;bl暂存余数 
    add bl,30h            ;bl变为数字对应的ascii码 
    mov byte ptr ds:[di],bl 
    dec si 
    inc di 
    loop toasc 
    pop bx 
    pop ax 
    ret 



show_str:    ;显示子程序 
        ;push dx    ;因为后面都8位乘法,所以dx可以不用入栈 
        push si 
        push cx 

s0:        mov ah,0                 
        mov al,0a0h    ;每行0a0个字节,注意不要写成是 0ah啊 ,我开始就犯这错死活没找到原因 
        dec dh        ;要累加的是dh前面的行,所以减 1 
        mul dh 
        mov bx,ax    ;ax 中存放前面7行的字节数 
        mov ah,0 
        mov al,2    ;每列2字节     
        dec dl        ;要累加的是dl前的列 ,所以减 1 
        mul dl             
        add bx,ax 
        mov ax,0b800h 
        mov es,ax 
        mov di,0 

s:        mov cl,ds:[si] 
        mov ch,0 
        jcxz ok 
        mov byte ptr es:[bx+di],cl 
        mov byte ptr es:[bx+di+1],2    ;硬编码颜色,找不到好办法来使用前面定义颜色的cl 
        inc si 
        add di,2 
        jmp short s 

ok:        pop cx 
        pop si 
        ;pop dx        ;当然也不用出栈了 
        ret 


code ends 
end start 
---------------------------------------------
masm link run, ok,12666要的就是这个结果。
看来得把分析写进正文去了。

[  maxm   发表于  2009-03-13 15:52  ]

最后加了点注释,程序改动如下:

;--------------------------------------------------------------
;名称:exp10c.asm
;功能:编程将数据 12666 以十进制的形式在屏幕的8行3列,用绿色显示出来
;--------------------------------------------------------------
assume cs:code, ds:data 

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子程序开始-------------------
;名称:dtoc
;功能:将word型数据转化为表示十进制的字符串
;参数:(ax) = word 型参数
;        ds:si 指向字符串首地址
;返回:无
;--------------------
dtoc:   push ax 
        push bx 
        mov di,si 
        mov bx,0ah 
getd:   mov dx,0 
        div bx 
        mov cx,ax                                ;cx暂存商做为jcxz指令的条件 
        ;mov byte ptr ds:[si],dl                ;暂存余数 
        push dx                                        ;余数入栈暂存
        inc si
        jcxz toasc                                ;商为0跳出 
     
        jmp short getd
     
     
toasc:  mov cx,si 
        pop bx                                        ;bx暂存余数,(bh)肯定是0
        ;mov bl,ds:[si]                                ;bl暂存余数 
        add bl,30h                                ;bl变为数字对应的ascii码 
        mov byte ptr ds:[di],bl 
        dec si 
        inc di 
        loop toasc 
        pop bx 
        pop ax 
        ret                                        
;--------------dtoc 子程序结束---------------------


;---------------show_str子程序开始-------------
;名称:show_str
;功能:在制定的位置用指定的颜色,显示一个用0结束的字符串
;参数:(dh) = 行号(0~24),(dl) = 列号(0~79)
;        (cl) = 颜色,ds:si指向字符串的首地址
;返回:无
;------------------------
show_str:
        ;push dx                                ;因为后面都8位乘法,所以dx可以不用入栈 
        push si 
        push cx 

s0:     mov ah,0                 
        mov al,0a0h                                ;每行0a0个字节,注意不要写成是 0ah啊 ,我开始就犯这错死活没找到原因 
        dec dh                                        ;要累加的是dh前面的行,所以减 1 
        mul dh 
        mov bx,ax                                ;ax 中存放前面7行的字节数 
        mov ah,0 
        mov al,2                                ;每列2字节     
        dec dl                                        ;要累加的是dl前的列 ,所以减 1 
        mul dl             
        add bx,ax 
        mov ax,0b800h 
        mov es,ax 
        mov di,0 
        mov ah,cl                                ;ah暂存颜色属性

s:      mov cl,ds:[si] 
        mov ch,0 
        jcxz ok 
        mov byte ptr es:[bx+di],cl 
        mov byte ptr es:[bx+di+1],ah                ;ah就是颜色属性 
        inc si 
        add di,2 
        jmp short s 

ok:     pop cx 
        pop si 
        ;pop dx                                        ;当然也不用出栈了 
        ret 
;----------------------show_str子程序结束-------

code ends 
end start

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