当前位置: 代码迷 >> 汇编语言 >> 求教 为什么在dos形式里运行不正常,但在debug中调式却正常
  详细解决方案

求教 为什么在dos形式里运行不正常,但在debug中调式却正常

热度:133   发布时间:2016-05-02 04:37:56.0
求教 为什么在dos方式里运行不正常,但在debug中调式却正常
在dos方式里运行不是显示除法溢出就是显示有问题,但在debug里面跟踪却是正确的晕,
;这是王爽书实验10那个课程设计1 设计思路就是共显示21行,每行显示4列
;在debug中我直接看了loop ms这行对应的地址,然后用g直接运行这个地址,屏幕上显示
;是正确,麻烦帮忙看下
assume cs:code
data segment
;时间
db '1975','1976','1977','1978','1979','1980','1981','1982','1983','1984','1985','1986'
db '1987','1988','1989','1990','1991','1992','1993','1994','1995'

;公司收入
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514,345980
dd 590827,803530,1183000,1843000,2759000,3753000,4649000,5937000

;雇员
dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037
dw 5635,8226,11542,14430,15275,17800
data ends
stack segment
db 63 dup (0) ;最前面用来当临时数据转存区,倒数开始用来当栈 
stack ends
code segment
main:
mov ax,stack ;确定栈(在开头放这个是为了call子程序时入栈)
mov ss,ax
mov sp,64

mov cx,21 ;寻环21次
mov dh,3 ;初始行号(0-24)

mov si,4 ;初始先设置读取年份位置在即1976注意不是1975那个位置
mov ax,data
mov ds,ax

;每行4列数据
ms: 
push cx ;先保存寻环值

;把下个要读取年份保存到ss:0开始位置暂存
mov ax,ds:[si] 
mov bx,ds:[si+2] 
mov ss:[0],ax 
mov ss:[2],bx

;每行第10列位置显示年份
mov word ptr ds:[4],0 ;让第4个(即第5个字节置0)让字串变成这样形 ‘1975’0 方便show_str调用
mov dl,10 ;年份统一显示在每行的第10列
mov cl,0cah ;用户指定的颜色
mov bx,dx ;保存行列因为后面dx会被用来当被除数高16位值
call show_str ;显示年

;显示被除数
mov ax,ds:[di+84] ;读取dword低16
mov dx,ds:[di+2+84] ;读取dword高16
push dx ;保存被除数高位
push ax ;保存低位
call dtoc ;转成字串
mov cl,0cah ;指定字串颜色
mov dx,bx ;还原行列
mov dl,25 ;显示到第25列
call show_str ;显示被除数

;显示除数
mov dx,0 ;除数是word型数据只用到ax不会用到dx但防止上面dx有余值专过来so清0
mov ax,ds:[bp+168] ;读取除数
push ax ;保存除数
call dtoc ;转成字串
mov cl,0cah ;指定字串颜色
mov dx,bx ;还原行列
mov dl,45 ;显示到第45列
call show_str ;显示除数

;每行第60列开始显数商
pop cx ;还原除数
pop ax ;还原被除数低位
pop dx ;还原被除数高位
call divdw ;相除,ax存商低16位,dx存商高16位,cx存余数,但看原题目得知商取整不要余数
;且看被除数除以除数可知商只要用ax存就可以了不会用到dx
call dtoc ;商转成字串
mov cl,0cah ;指定字串颜色
mov dx,bx ;还原行列
mov dl,60 ;显示到第60列
call show_str ;商显示到屏幕上

mov ax,ss:[0] ;读取要还原的年份
mov dx,ss:[2]
mov ds:[0],ax ;还原到ds
mov ds:[2],dx
add si,4 ;指向下一个要读取年份
add di,4 ;指向下一个要读取被除数位置
add bp,2 ;指向下一个除数位置
mov dx,bx ;还原行列
inc dh ;字串要显示的行号
pop cx ;还原寻环
loop ms

mov ax,4c00h
int 21h
divdw: ;解决dword除法
push bx
push si
push bp

;这里=书上公式int(H/N)*65536
mov bp,ax ;先保存ax原值后面用到
mov ax,dx ;dx转存到ax因为16位除法默认被除数在低位在ax
mov dx,0H ;高位在dx
div cx ;除以cx后,此时商在ax,余数在dx
mov bx,ax ;保存商
;这里=书上公式;[rem(H/N)*65536+L]/N 
mov ax,bp ;还原ax
div cx ;此时被除数(dx保存高位,ax保存低位)除cx后ax=商 dx=余数
mov cx,dx ;先确定余数
mov dx,bx ;再把第一次除的给dx此时dx=商高16位,ax=商低16位 cx=余数

pop bp
pop si
pop bx
ret

show_str: ;在屏幕上显示
push ax ;保存要用到的寄存器
push bx
push si
push di
push es
push dx
push cx

mov si,0
mov ax,0b800H ;确定屏幕内存入口地址
mov es,ax

mov ax,data ;指向要显示的字串
mov ds,ax
mov ch,0 ;只使用cl表示颜色所以ch置0
mov bx,dx ;把用户行列保存,因为dx在乘法时会复盖掉

;行列算法 (行(col*160),列(row+row))+0b8000H=视频确切地址
;这里确定行
mov al,0a0h
mov ah,0
mul dh
;这里确定列
add dl,dl
mov dh,0
mov bx,dx ;必须,bx用来寻址
;行+列转换视频要显示的偏移地址(和视频入口0b8000H相+则为实际显示地址)
add bx,ax

mov dl,cl ;保存cl,因为cx用来寻环,但初始保存是用户指定颜色

i:
mov cl,ds:[si] ;读要显示1个字符
mov ch,cl ;如果是最后一个字符0则这样cx就=0
jcxz j ;cx=0结束显示,否则继续下面
mov ch,dl ;设置颜色
mov es:[bx],cx ;在屏幕上显示
inc si
add bx,2
jmp i
j:
pop cx
pop dx
pop es
pop di ;还原用到的寄存器
pop si
pop bx
pop ax
ret

dtoc: ;解决dword转字串(方法就是ax=低16,dx=高16 先用ax进行16位除法然后余转成字符入栈,然后现判断dx是有值
;有,把dx赋ax,再调用原先ax进行16位除法过程,再把余转字符入栈此时栈内就是dx转成字符+ax转成字符的数据
;在把其写到ds:0开始的地方并以0结尾
push ax
push bx
push si
push di
push dx
push cx

mov si,0
mov di,0
push si ;字串结束标志首先入栈

k:
mov cx,0ah ;除数为10(必须放在寻环中以便每次都设成10)
call divdw ;入口参数ax为低16位,dx为高16位 cx为除数 结果返回商低在ax,高在dx 余在cx
add cx,30h ;余数转成字符
push cx ;入栈
mov cx,ax ;判断商低16位的ax是否为0
jcxz ax0 ;为0则跳转判断商的dx高16位是否也为0
jmp k ;假如低16位ax不为0则不必再判断高16位dx直接返回再除

ax0:
mov cx,dx ;判断商高16位
jcxz dx0 ;为0说明已除尽(此时商低16位和高16都为0)
jmp k ;不为0则变成低16位ax=0 而高16位dx<>0则必须再除下去

dx0: ;如果商dx高16位和ax低16位都为0说明已除尽(已转成字符了)可以pop了
pop cx
jcxz exit ;如果cx=0说明pop结束跳到退出
mov ds:[si],cl ;否则还原栈值到从ds:0开始直到遇到0结束符为止
  相关解决方案