. : : Assembly Language : : .  |  首页  |  我提出的问题  |  我参与的问题  |  我的收藏  |  消息中心   |  游客  登录  | 
刷新 | 提问 | 未解决 | 已解决 | 精华区 | 搜索 |
  《汇编语言》论坛 ->INT指令
  管理员: assembly   [回复本贴] [收藏本贴] [管理本贴] [关闭窗口]
主题 : :  实验13(2) 最终实现版 完整模拟 loop 所有功能  [待解决] 回复[ 8次 ]   点击[ 1596次 ]  
zhenglxd
[帖 主]   [ 发表时间: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
ilove
[第1楼]   [ 回复时间:2009-06-09 15:33 ]   [引用]   [回复]   [ top ] 
荣誉值:14
信誉值:2
注册日期:2008-10-19 21:37
中断,非常重要的一个知识点,楼主很认真,学习了。
fyjava
[第2楼]   [ 回复时间:2009-11-05 13:21 ]   [引用]   [回复]   [ top ] 
荣誉值:4
信誉值:0
注册日期:2008-12-24 23:48
我在12章卡住了 ...
linwangfeng
[第3楼]   [ 回复时间:2009-12-27 21:15 ]   [引用]   [回复]   [ top ] 
荣誉值:0
信誉值:0
注册日期:2009-04-15 18:50
书上不是给了程序了 ,怎么这么长
kdfuwe89342
[第4楼]   [ 回复时间:2010-06-04 23:29 ]   [引用]   [回复]   [ top ] 
荣誉值:0
信誉值:0
注册日期:2009-06-10 09:02
很好  很强大
dasa
[第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
上面的五进五出必要吗?太浪费精力,还要记住哪一次数据才是真正想要的数据
dasa
[第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呢?后来冥思苦想,终于明白了,
这也是该程序的可圈可点之处
dasa
[第7楼]   [ 回复时间:2017-07-28 16:49 ]   [引用]   [回复]   [ top ] 
荣誉值:0
信誉值:0
注册日期:2017-07-20 09:18
对了,调用子程序注意要养成保存寄存器数据的习惯
需要登录后才能回帖 -->> 请单击此处登录
    Copyright © 2006-2024   ASMEDU.NET  All Rights Reserved