- [游客] 表示每次运行到cx=2的时候就不能再往下一步进行了! 谁能告诉我是哪里的问题? 06/11 23:38
- [游客] 这是C下的么?main中的 int c[]={6,7,8,9} ; int *p = c; 08/06 15:33
- [游客] 实现队列?呵呵,以前学C的时候也弄过队,循环队列等东西,锻炼了很多思维逻辑上的东西。 博主可以自己 08/06 15:30
- [maxm] 这实验没难度,关键是细心 几个易出错的地儿我都在注释中做了标记 希望大家别跟我一样犯糊涂 (*^ 06/04 20:58
- [maxm] 感谢fangyugirl分享心得 05/08 18:47
- [fangyugirl] 看到你说你在这章徘徊了两周,我跟你差不多的。我是做BIOS的,上班时没有事情了就看书,做课程设计一时 04/23 13:44
- [maxm] 哎,没有自己电脑。 03/19 20:57
- [游客] 然后继续编程 呵呵 03/18 20:56
- [游客] 我被卡在这一章了,就因为这个实验。 03/18 15:31
- [maxm] 最后加了点注释,程序改动如下: ;------------------------------ 03/13 15:52
[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。
本人分析的确实有点啰嗦,不过应该说清楚了吧 ^_^ ^_^ 欢迎拍砖。
[ 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