|
主题 : : 实验13(2) 最终实现版 完整模拟 loop 所有功能 [待解决] |
回复[ 8次 ]
点击[ 1596次 ] | |
|
|
|
|
[帖 主]
[ 发表时间:2009-06-05 15:35 ]
[引用]
[回复]
[ top ] | |
荣誉值:30
信誉值:0
注册日期:2009-04-09 10:05 |
总共有3个部分
1是完整实现版
2是实验用代码在加载运行1的前提下 运行2,用来实验 loop超范围时报错
3是实验用代码在加载运行1的前提下 运行3 用来实验 13(2)打印80个'!'
(2和3 你们可以自己写代码实验我发出来给懒人直接用看效果的)
其实 实验13(2)还是蛮有意思的,当然泛用类代码是非常好些的,不过我特意选了比较难的方式来写其实也不算什么了,调适过程中,发现了无数错误,同时水品也渐长了,发现错误,解决错误,是提高自身的最快途径了。个人感觉这个代码还可以精简,不过是在没什么精力啦。。连续写10多个小时写到后面感觉人进入奇怪的状态,脑袋模糊迟钝,但是偏偏有些写法和思路,自己会蹦出来!
1.完整实现版
;完整的程序具有超出循环报错,指明超界范围,几乎和loop功能一致.
;loop的的位移范围是1~255,由于用BX来存放所以BX范围为0xffffH~0xff01H 如bx为0表示循环地址为自循环(无意义循环)
;疲劳作业果然不可取,昨天这题debug了n小时无果,今天早上坐公车的时候偶尔思考下变知道哪里出了问题!
;稍微优化了下代码。
;。。恩 6个多小时加上昨天n个小时。。才完成的。发现调试是提高水品的最好办法。。之一!
assume cs:code
code segment
mov ax,0
mov es,ax
mov word ptr es:[7ch*4],200H
mov word ptr es:[7ch*4+2],0
; 安装7ch中断类型码处理程序入口为0:200H
mov ax,cs
mov ds,ax
mov si,offset loop_0
;安装程序-源地址
mov ax,0
mov es,ax
mov di,200H
;安装程序-目标地址
cld ; 正向递增
mov cx,offset loop_0end-offset loop_0
rep movsb
;执行安装
mov ax,4c00H
int 21H
;参数 (cx)=循环次数,(bx)=位移
loop_0:push bp
mov bp,sp
add bp,2
n_detest:nop ;这个2个空指令的作用是跳转指令-不在每次loop都重复检测其是否超过范围
nop
n_tag:cmp bh,0ffH ;bh位不为ff则超出范围
jne err_jmp ;检测是否超出loop循环范围
cmp bl,1 ;检测bl位必须大于1
jb err_jmp ;
mov si,offset n_detest-offset loop_0+200H ;对应n_detest 第一个nop
mov byte ptr cs:[si],0EBh ; 0ebh=jmp
mov byte ptr cs:[si+1],offset lp_detest-offset n_tag
lp_detest: dec cx
cmp cx,0
je l_over ;检测是否循环结束
add ss:[bp],bx ;bx=循环成立返回的位移
l_over:pop bp
iret
err_jmp : jmp tksrom
show_err: db "error A2053: Jump out of range"
tksrom : mov ax,0b800H
mov es,ax
mov di,160*12 ;输入显存地址
mov ax,cs
mov ds,ax
mov ax,offset show_err-offset loop_0+200H
mov si,ax ;输入显存数据
mov cx,30
cld
el: movsb
mov byte ptr es:[di],2
add di,1
loop el
;######################################################
mov ax,0ffffH
sub ax,bx
sub ax,255 ;ax存储了超出范围的值.
call near ptr divs
shows : mov ax,0b800H ;确定显存所在段
mov es,ax ;(di指针为######上面的di)
mov ax,cs ;改变ds段为show
mov ds,ax
add si,16 ;si=暂存数据段地址+16
cld
sel:mov al,ds:[si] ;检测字符窜是否输出结束.
cmp al,0
je s_over
movsb
mov byte ptr es:[di],3
add di,1
loop sel
s_over:mov ax,4c00H
int 21H
divs:jmp d_jmp
d_store:db 32 dup ('0') ;暂存数据用,0~15为保存原始商数据,16~31用于保存商的位数交换.
d_jmp: push di ;保存########上面的di数据保证显示数据的连贯性
mov si,10 ;除数
mov dx,cs
mov ds,dx
mov dx,offset d_store-offset loop_0+200H
mov di,dx ;ds:di=暂存数据段
push di ;di入栈供后面程序调用
push di
divs2:mov dx,0 ;高位清0
cmp ax,0 ;检测商是否为0
je next ;遇到0表示商为0. 跳转到next
div si ;否则进行除法
add dl,30H ;余数+30H表示数字字符窜的ASCII码
mov ds:[di],dl ;用ds:di段暂存数据
add di,1 ;di表示这个字符窜ASCII码长度
loop divs2
next: mov ax,cs
mov ds,ax ;ds=0
pop ax ;把di初始赋给 ax
push di ;保存源指针di
sub di,ax ;确定字符窜长度
mov cx,di ;确定字符窜交换次数
pop si ;si=源指针
mov bx,0 ;bx是目标指针 变址
pop di ;di=暂存段初始偏移地址
changer: mov al,ds:[si-1] ;因为上面程序多加了1,所以这里-1
mov ds:[di+bx+16],al;送入ds:di的后16位内存单元中
dec si
inc bx
loop changer
mov byte ptr ds:[di+bx+16],0 ;添加0表示字符窜结束
push di ;将暂存段初始偏移地址入栈,用与被si交换
pop si ;用si来保存暂存数据段偏移地址
pop di ;还原di为#######上的数据
ret
loop_0end:nop
code ends
end
2. 实验用代码在加载运行1的前提下 运行2,用来实验 loop超范围时报错
assume cs:data
data segment
a: db 253 dup ('a')
start:mov bx,-300
int 7ch
dec word ptr ds:[24]
mov ax,(ds:[bx]+cs:[si])
mov byte ptr data:[0],1
mov ax,offset s
mov ds:[0],ax
jmp word ptr ds:[0]
rep add ax,2
mov ax,0
mov ax,0
s:mov bx,0
ret 4
aa segment
db "a"
aa ends
push ss:[0]
data ends
end start
3 实验用代码在加载运行1的前提下 运行3 用来实验 13(2)打印80个'!
assume cs:code
code segment
start: mov ax,0b800h
mov es,ax
mov di,160*12
mov bx,offset s-offset se
mov cx,80
s: mov byte ptr es:[di],'!'
mov byte ptr es:[di+1],2
add di,2
int 7ch
se:nop
mov ax,4c00H
int 21h
code ends
end start | | |
|
|
|
|
[第1楼]
[ 回复时间:2009-06-09 15:33 ]
[引用]
[回复]
[ top ] | |
荣誉值:14
信誉值:2
注册日期:2008-10-19 21:37 |
|
|
|
|
|
[第2楼]
[ 回复时间:2009-11-05 13:21 ]
[引用]
[回复]
[ top ] | |
荣誉值:4
信誉值:0
注册日期:2008-12-24 23:48 |
|
|
|
|
|
[第3楼]
[ 回复时间:2009-12-27 21:15 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:0
注册日期:2009-04-15 18:50 |
|
|
|
|
|
[第4楼]
[ 回复时间:2010-06-04 23:29 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:0
注册日期:2009-06-10 09:02 |
|
|
|
|
|
[第5楼]
[ 回复时间:2017-07-28 16:41 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:0
注册日期:2017-07-20 09:18 |
昨天下午加今天上午的debug,并不像楼上说的很好,很强大,喜忧参半吧~
n_tag:cmp bh,0ffh
jne err_jmp ;检测bh位是否为0ffh
cmp bl,1
jb err_jmp ;检测bl位必须大于1
那么上面这几句就是推定转移的位移为-128--127了吗。可以说无法完成该范围内的判断
如ff01h=-241,ff70h=-144,ff01h、ff70h都在条件之内,但已超出范围
正确的范围应该在ff80h--ffffh和0--127之间。
s_over:mov ax,4c00h ;这二句是程序的结束
int 21h
当调用int 7ch时,即使是bx超出范围,它也是在调用int 7ch时之后来判断的,如果用-p执行int 7ch
那程序必然不会正常返回,本人已试过。
call near ptr divs ;该子程序完成call dtoc功能,将数字转换成字符,但里面的代码写得繁琐
见程序,
divs:jmp d_jmp
d_store:db 32 dup ('0')
d_jmp:push di ;一次入栈
mov si,10
mov dx,cs
mov ds,dx
mov dx,offset d_store-offset loop_0+200
mov di,dx
push di ;二次入栈
push di ;三次入栈
divs:mov dx,0
cmp ax,0
je next
div si
add dl,30h
mov ds:[di],dl
add di,1
loop divs2 ;没有cx做循环次数,用jmp short divs2不更好些吗?
next:mov ax,cs
mov ds,ax
pop ax ;一次出栈
push di ;四次入栈
sub di,ax
mov cx,di ;数字的长度,用个bp,bx记住就行,减法,压栈、出栈弄了三、四条指令,必要吗?
pop si ;二次出栈
mov bx,0
pop di ;三次出栈
change:mov al,ds:[si-1]
mov ds:[di+bx+16],0
push di ;五次入栈
pop si ;四次出栈
pop di ;五次出栈
ret
上面的五进五出必要吗?太浪费精力,还要记住哪一次数据才是真正想要的数据 | | |
|
|
|
|
[第6楼]
[ 回复时间:2017-07-28 16:47 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:0
注册日期:2017-07-20 09:18 |
可喜的是
在程序中设置了不能正常执行的提示信息
当bx超出范围时,屏幕会提示‘error a2053:Jump out of range***’,***代表几个数字
增加了程序的完整性
偏移地址的取得
如:mov si,offset n_detest-offset loo_0+200h
mov ax,offset show_err-offset loop_0+200h
为什么要加上200h呢?后来冥思苦想,终于明白了,
这也是该程序的可圈可点之处 | | |
|
|
|
|
[第7楼]
[ 回复时间:2017-07-28 16:49 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:0
注册日期:2017-07-20 09:18 |
|
|