. : : Assembly Language : : .  |  首页  |  我提出的问题  |  我参与的问题  |  我的收藏  |  消息中心   |  游客  登录  | 
刷新 | 提问 | 未解决 | 已解决 | 精华区 | 搜索 |
  《汇编语言》论坛 ->直接定址表
  管理员: assembly   [回复本贴] [收藏本贴] [管理本贴] [关闭窗口]
主题 : :  实验16的事情——无法通过测试就是错的?  [待解决] 回复[ 2次 ]   点击[ 709次 ]  
yasin
[帖 主]   [ 发表时间:2009-10-12 08:21 ]   [引用]   [回复]   [ top ] 
荣誉值:0
信誉值:0
注册日期:2009-10-05 23:09
下面是我的实验16的程序。我测试的环境是用虚拟机VPC2007版所模拟的一个实模式DOS系统。这个中断安装例程是可以执行的。但是,我又写了一个对新安装的int 7c例程进行测试的小程序,发现无法通过测试,不是CPU Error:opcode incorrect,就是突然死机。这个情况连续困扰我几个小时。我用debug不断地调试,直到确信我的两个程序在逻辑上是正确的,寻址也没有出错。我开始怀疑我的测试环境有问题。有好几次报错都提示是一个叫emm386.exe的程序检测到的。于是我试着重新在虚拟机内装一个DOS,这一次不装载EMM386和UMB内存管理程序。装完后重新测试我的中断例程,发现完全正常。有时候不一定是程序的错,很可能是你的测试环境出了问题。这是我花了几个小时的时间买到的一个教训,希望对遇到过类似问题的同学们能够有帮助。
************************************************************************************
;实验16 编写包含多个功能子程序的中断例程

;安装一个新的int 7ch中断例程,为显示输出提供如下功能子程序。
;(1) 清屏;
;(2) 设置前景色;
;(3) 设置背景色;
;(4) 向上滚动一行。

;入口参数说明如下:
;(1)用ah寄存器传递功能号:0表示清屏,1表示设置前景色,2表示设置背景色,3表示向上滚动一行。
;(2)对于2、3号功能,用al传送颜色值,(al)∈{0,1,2,3,4,5,6,7} 。

assume cs:code,ss:stack

stack segment
       db 128 dup(0)
stack ends

code segment        
    start: 
           mov ax,stack
           mov ss,ax
           mov sp,128

           mov ax,code
           mov ds,ax
           mov si,offset setscreen

           mov ax,0
           mov es,ax
           mov di,200h
           mov cx,offset setscreenend-offset setscreen
           cld 
           rep movsb
           cli
           mov word ptr es:[7ch*4],200h
           mov word ptr es:[7ch*4+2],0
           sti

           mov ax,4c00h
           int 21h  
 
;===========================以下为新7ch中断=============================================              
        setscreen:   
                 jmp short set
                 dw sub1-setscreen,sub2-setscreen,sub3-setscreen,sub4-setscreen
         set:  
                  push bx

                  cmp ah,3               ;判断功能号是否大于3
                  ja sret
                  mov bl,ah
                  mov bh,0
                  add bx,bx  ;根据ah中的功能号计算对应子程序在table表中的偏移    
                  push cs
                  pop ds
                  add word ptr [bx+202h],200h                  
                  call word ptr [bx+202h]    ;调用对应的功能子程序
        sret:   
                  pop bx
                  iret
                  
;入口址:sub1
;功能:清屏。一屏有25行X80个字符(2B/字节)=2000个字符(4000B)。
;字符存于偶字节处(0,2,4,6,8...),颜色属性存于奇字节处(1,3,5,7,9...)。
;技巧:清屏的技巧就是把显示缓冲区中当前屏的2000个字符(即所有偶字节上的数据)全部替换为空格符。
;作为一个子程序,必须做好寄存器的保护和恢复工作。一个替代性的办法就是使用BIOS的int 10h中断和
;DOS的int 21h中断例程。但这个办法的缺点是需要使用一块大小为2000个字节的缓冲区。它的空间开销
;增大了。
sub1:  
         push bx
         push cx
         push es
         mov bx,0b800h
         mov es,bx
         mov bx,0
         mov cx,2000
sub1s:
         mov byte ptr es:[bx],' '
         add bx,2
         loop sub1s
         pop es
         pop cx
         pop bx
         ret
;入口址:sub2
;功能:设置前景色
;前景色属性在奇字节处
;技巧:前景色的属性值是由al传送的。但在传送之前必须将原来的前景色属性值置为0,否则达不到预期目的。
;这不像寄存器赋值。寄存器赋值是自动以新值代替旧值的。颜色属性值是以位的形式存在的,因此必须使用逻辑位操作
;来清除原来的属性值,再赋予新的属性值。颜色属性赋值是以or罗辑指令加上新值的,旧值如果不用and指令清除掉的
;话,结果的属性值会是新值加上旧值的一个和,而不是纯粹的新值。
sub2:
         push bx
         push cx
         push es

         mov bx,0b800h
         mov es,bx
         mov bx,1
         mov cx,2000
sub2s:
         and byte ptr es:[bx],11111000b    ;闪烁,高亮,红+蓝+绿
         or es:[bx],al
         add bx,2
         loop sub2s

         pop es
         pop cx
         pop bx
         ret  
;入口址:sub3
;功能:设置背景色。
;参数:al传送颜色值,左移4位,设置背景色。
;技巧:同上。不同之处在于前景色是对所有奇字节上的数据的第0、1、2位的值进行替换;
;而背景色的赋值是对所有奇字节上的数据的第4、5、6位的值进行替换。所以要将al的值
;左移4位,与目的数据的比特位置相符。
sub3:
         push bx
         push cx
         push es
         mov cl,4
         shl al,cl
         mov bx,0b800h
         mov es,bx
         mov bx,1
         mov cx,2000
sub3s:
         and byte ptr es:[bx],10001111b
         or es:[bx],al
         add bx,2
         loop sub3s
         pop es
         pop cx
         pop bx
         ret
;入口址:sub4
;功能:向前滚动一行。
;参数:
sub4:
         push cx
         push si
         push di
         push es
         push ds

         mov si,0b800h
         mov es,si
         mov ds,si
         mov si,160     ;ds:si指向n+1行
         mov di,0        ;es:di指向第n行
         cld
         mov cx,24      ;共复制24行
sub4s:
         push cx
         mov cx,160
         rep movsb         ;si,di在这一句执行完成后,各递增160;每次递增1,循环160次共递增160.
         pop cx              ;实际上第一行的数据完全被覆盖掉了,如果不采取备份措施,就丢失了。
         loop sub4s

         mov cx,80
         mov si,0
sub4s1:
         mov byte ptr [160*24+si],' '   ;最后一行清空
         add si,2
         loop sub4s1

         pop ds
         pop es
         pop di
         pop si
         pop cx
         ret      
setscreenend:nop
code ends
end start
ldlihuanfa
[第1楼]   [ 回复时间:2010-03-12 10:02 ]   [引用]   [回复]   [ top ] 
荣誉值:6
信誉值:0
注册日期:2009-12-18 19:53
dw sub1-setscreen,sub2-setscreen,sub3-setscreen,sub4-setscreen 这一段有意思
我也是考虑了一晚上,才想到这点,开始都糊涂了
idhyt
[第2楼]   [ 回复时间:2012-03-09 13:21 ]   [引用]   [回复]   [ top ] 
荣誉值:0
信誉值:0
注册日期:2012-01-05 18:58
dw sub1-setscreen,sub2-setscreen,sub3-setscreen,sub4-setscreen 这一段有意思
我也是考虑了一晚上,才想到这点,开始都糊涂了
------------------
回复:这一段是什么意思 求赐教,我各种想不通。。。sub1和setscreen标号的位置都是相对起始偏移量,相减应该是中箭代码长度 怎么会是偏移地址呢。
需要登录后才能回帖 -->> 请单击此处登录
    Copyright © 2006-2024   ASMEDU.NET  All Rights Reserved