汇编网首页登录博客注册
njutyangxiao的学习博客
博客首页博客互动【做检测题】论坛求助

我的博客

个人首页 |  我的文章 |  我的相册 |  我的好友 |  最新访客 |  文章收藏 |  论坛提问 |  友情链接 |  给我留言  
图片载入中
  •  原泉混混,不舍昼夜。盈科而后进,放乎四海,有本着如是,是之取尔!
  • 『姓名』:杨逍
  • 『性别』:男『发送消息
  • 个人说明:
  • 详细信息『加为好友』
学习动态
最新留言

[2009-09-17 14:07] 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] 

分析:对于本实验,第一点是:各个子程序的编写,这并不难,参考书上很轻松就能搞定。第二点是:设置int 7ch的中断向量表项是关键,刚开始我也发现是调用时子程序的地址不对,但是还是没得解决。上论坛看过之后,采取了程序中这种比较简单的方法。具体的在程序中有分析。第三点就是编写测试程序。这点受到了sirius的思路指引。

具体源代码如下:

assume cs:codesg,ds:datasg

datasg        segment 
fun_table dw  funShowA,  funClrSc, funChFgC, funChBgC,  funRoOnL, funExitP, inpFunNu, inpColNu,errInpFu,errInpCo, space 

funShowA    db '0 Show character A','$' 
funClrSc    db '1 Clear Screen','$' 
funChFgC    db '2 Change Foreground Color','$' 
funChBgC    db '3 Change Background Color','$' 
funRoOnL    db '4 Roll Up One Line','$' 
funExitP    db '5 Exit Program','$' 
inpFunNu    db 'Input Function Number:[0,1,2,3,4,5]:','$' 
inpColNu    db 'Input Color Attribute:[0,1,2,3,4,5,6,7]:','$' 
errInpFu    db 'Error!Input Function Number Range:[0,1,2,3,4]','$' 
errInpCo    db 'Error!Input Color Attribute Range:[0,1,2,3,4,5,6,7]','$' 
space       db '                                                   ','$'
row        db 5,6,7,8,9,10,12,13,14,15 
datasg        ends 
  
stacksg segment
    db 128 dup (0)
stacksg ends     

codesg segment
;;;;;;;;;;;以下是int 7ch中断程序;;;;;;;;;;;;;;;;;;;;;;
     setscreen:
     jmp short set
     table dw  showchar,clearscreen, setForeground,  setBackground ,scrolloneline
     
     set:
     push bx
     
    
     cmp ah,4
     ja setret ;判断所输入的功能号,大于4就是非法输入
     cmp ah,0
     jb setret ;判断所输入的功能号,小于零也是非法输入
     mov bl,ah
     mov bh,0
     add bx,bx;因为table定义的是字型数据,所以要把bx的值乘以2,才是其对应的子程序的入口地址 
     
     call word ptr table[bx];调用相应的子程序
     
   setret:
     pop bx
     iret

;此子程序是显示满屏的字母'A'
showchar:
     push ax
     push bx
     push cx
     push es
     
     mov ax,0b800h
     mov es,ax
     mov bx,0
     mov cx,2000;在第0页上显示满屏的'A',循环2000次
     
   lp_showchar:
     mov byte ptr es:[bx],41h;显示'A' 
     add bx,2
     loop lp_showchar  
     
     pop es
     pop cx
     pop bx
     pop ax
     
     ret

;清屏
clearscreen:
     
     push ax
     push bx
     push cx
     push es
     
     mov ax,0b800h
     mov es,ax
     mov bx,0
     mov cx,2000
     
lp_clrscr:
     mov byte ptr es:[bx],20h;清屏的关键就是在偶地址位上填充空格
     add bx,2
     loop lp_clrscr  
     
     pop es
     pop cx
     pop bx
     pop ax
     
     ret 

;设置前景色,
setForeground:
     push ax
     push bx
     push cx
     push es
     
     mov bx,0b800h
     mov es,bx
     mov bx,1;因为奇数地址位存放的是显示颜色属性字节,所以偏移地址bx从1开始
     mov cx,2000
     
   lp_setFG:
     and byte ptr es:[bx],11111000b;这一步骤很关键,因为与前景色有关的颜色属性字节位
     ;是0,1,2三位,所以我要保留之前颜色属性的其他位不变,把这三位清零
     or byte ptr es:[bx],al ;接着是用要设置的前景色的颜色属性值与原来的颜色属性值逻辑或后,就更改了前景颜色属性值
     add bx,2
     loop lp_setFG  
     
     pop es
     pop cx
     pop bx
     pop ax
     
     ret  
 
;设置背景色
setBackground:
     push ax
     push bx
     push cx
     push es
     
     mov cx,0
     mov cl,4
     shl al,cl
     
     mov bx,0b800h
     mov es,bx
     mov bx,1
     mov cx,2000
     
   lp_setBG:
     and byte ptr es:[bx],10001111b;道理同设置前景色,与设置背景色有关的是颜色属性值字节位是4,5,6三位,
     ;所以也要保留之前颜色属性值的其它位不变,把此三位清零
     or byte ptr es:[bx],al;接着是用要设置的前景颜色属性值与原来的颜色属性值逻辑或后,就更改了背景颜色属性值 
     add bx,2
     loop lp_setBG  
     
     pop es
     pop cx
     pop bx
     pop ax
     
     ret 
 ;向上滚动一行    
 scrolloneline:
     push ax
     push bx
     push cx
     push es
     push ds
     push si
     push di
     
     
     
     mov bx,0b800h
     mov es,bx
     mov ds,bx;因为要做的事是:依次把第n+1行的内容复制到第n行;然后最后一行清空,而目的段地址都是0b800h
     mov si,160;因为ds:[si]是数据源,所以设置初始值是你为0,即n+1为1。即初始是把第二行的复制到第一行,
     ;而一行的大小是160B。所以si初始值是160
     mov di,0;es:[di]就是目的地址了。而目的是要把第n+1行的内容复制到第n行。所以di的值为0
     cld
     mov cx,24
     
lp_copyOL:
     push cx
     mov cx,160
     rep movsb
     add bx,2 
     pop cx
     loop lp_copyOL 
     
     mov cx,80
     mov si,0
lp_setSpace:
     mov byte ptr [160*24+si],20h
     add si,2
     loop lp_setSpace;把最后一行清空
     
     pop di
     pop si
     pop ds
     pop es
     pop cx
     pop bx
     pop ax
     
     ret 
 
 setend:nop
;;;;;;;;;;;到这里中断程序结束了;;;;;;;;;;;;;;;;;;;;;;;;; 

;;;;;;;;;;;以下是主程序;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    start:
     mov ax,stacksg
     mov ss,ax
     mov sp,128 

;;;;;复制 int 7ch 的中断程序;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;     
     mov ax,cs
     mov ds,ax
     mov si,offset setscreen
     
     mov ax,0
     mov es,ax
     mov di,200h
     
     mov cx,offset setend - offset setscreen
     cld
     rep movsb
;;;;;;;;复制 int 7ch 的中断程序结束;;;;;;;;;;;;;;;;;;;;;;;


;;;;;;;设置int 7ch的中断向量表项;;;;;;;;;;;;;;;;;;;;;;;;;;
     mov ax,0
     mov es,ax
     mov word ptr es:[7ch*4],0h
     mov word ptr es:[7ch*4+2],20h;这里的设置很关键,把中断程序拷贝到了0000:0200h开始处。
     ;原本设置cs=0000,而ip=0200h的。但是调用中断例程后ip的值是0,所以为了设置ip的值是0
     ;就只有设置cs=0020h了,因为0000:0200h和0020:0000h所表示的地址是一样的,都是00200h。但是
     ;通过这样设置之后,可以使得ip的值是0,以便能找到中断程序的子程序
;;;;;;;设置int 7ch的中断向量表结束束;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;以下的程序是测试程序,它提供了一个图形化的界面,用户输入相应的功能测试上面的中端程序的相关功能;;;;;;;;;;;;;;;;;;;;;;;;;;
   
     mov ax,datasg 
     mov ds,ax 

;循环输出菜单
menu:
     mov bx,offset fun_table;把在datasg段定义的菜单信息的首地址给bx
     mov si,offset row ;把在datasg段定义的行信息的首地址给si
     mov cx,7;循环7次的目的是输出菜单的功能信息和提示信息。但是错误信息不要输出
print_menu: 
        call showstr ;调用此子程序输出菜单信息
        inc si;
        add bx,2;
        loop print_menu      
        
        mov ah,0 
        int 16h ;因为int 16h的功能是从键盘读取一个字符。入口参数是把0送给ah。
        ;出口参数是al中的内容是字符码,ah中的内容是扫描码。
        ;所以调用int 16h的0号子程序读取从键盘输入入的字符
        cmp al,'0'
        je show_char_A;0就是显示满屏的字母A
        cmp al,'1' 
        je clear_screen;1是清屏
        cmp al,'2' 
        je change_color ;2改变前景色
        cmp al,'3' 
        je change_color ;3改变背景色
        cmp al,'4' 
        je roll_up_oneline ;4屏幕向上滚动一行
        cmp al,'5' 
        je exit_program  ;退出程序
   
        ;如果范围不在0到5之间就说嘛输入有错误,应该提示功能号输入误的信息
        mov si,offset row+7 ;row+7也就是在13行显示错误信息
        mov bx,offset fun_table+10h ;fun_table+10h存放的是功能号输入错误的信息
        call showstr;调用输出字符子程序输出错误信息
        call delay
        mov si,offset row+7 
        mov bx,offset fun_table+14h;等待用户重新输入之前要把错误信息清除,而fun_table+14h存放的就是清屏要用到的空格符
        call showstr;清除错误信息 
        jmp menu;一直循环直到用户输入5退出程序

;调用int 7ch的0号功能显示满屏的字母A
show_char_A:
        mov ah,0
        int 7ch
        call delay
        jmp menu

;调用int 7ch的1号功能清屏
clear_screen:
        mov ah,1;
        int 7ch              
        
        call delay 
        jmp menu 

;调用int 7ch的4号功能屏幕向上滚动一行
roll_up_oneline: 
        mov ah,4 
        int 7ch 
        call delay 
        jmp menu 

;调用int 7ch的5号功能退出程序
exit_program: 
        mov ax,4c00h 
        int 21h 

;这里是判断是设置前景色或者背景色
change_color:
        mov dl,al;al里是用户输入的功能号,不是2就是3

loop_color_attri:         
        mov si,offset row+8 
        mov bx,offset fun_table+14 ;在row+8也就是第14行显示提示颜色属性值的信息
        ;(fun_table+14中存放提示颜色属性值输入的信息字符串的偏移地址)
        call showstr;输出提示输入颜色属性值的信息 
        mov ah,0 
        int 16h;调用16h的0号功能获得用户的输入
        mov ah,'0' 
        mov cx,8 

;判段颜色属性值的正确性,它的范围只能是0到7
test_color:
        cmp al,ah 
        je setFG_or_setBG;如果输入是合理的就跳转到setFG_or_setBG处判断是设置前景色还是设置背景色
        add ah,1
        loop test_color;这里循环8次,检查输入的颜色属性值是否合理
        
        ;如果循环进行完之后没有跳转到setFG_or_setBG,就说明颜色属性值输入有错,需提示错误信息

        mov si,offset row+9
        mov bx,offset fun_table+18 
        call showstr;同理显示颜色属性输入错误的信息 
        call delay 
        mov si,offset row+9 
        mov bx,offset fun_table+20 
        call showstr;把颜色提示信息清空 
        jmp loop_color_attri;一直循环到用户输入正确的颜色属性值 
setFG_or_setBG: 
        mov si,offset row+8
        mov bx,offset fun_table+20 
        call showstr;拿到合适的颜色属性之后要把提示输入颜色属性值的信息清除
        cmp dl,'3' 
        je set_bg_color ;判断如果是3号功能就是设置背景色

;调用int 7ch的2号功能设置前景色
set_fg_color:         
        mov ah,2 
        int 7ch 
        jmp menu
        
;调用int 7ch的3号功能设置背景色景色
set_bg_color: 
        mov ah,3 
        int 7ch 
        jmp menu 

;;;;;;;显示字符串的子程序;;;;;;;;;;;;;;;;;;;;;
showstr: 
        push bx 
        push dx 
        push ax 
        push si
         
        mov bh,0 ;显示在第0页
        mov dh,ds:[si] ;行号
        mov dl,20 ;列号
        mov ah,2 ;要调用int 10h的2号子程序
        int 10h;调用了int 10h的2号子程序对光标进行定位
      
        mov dx,ds:[bx];设置ds:dx指向要显示的字符串的首地址 
        mov ah,9  
        int 21h ;调用int 21h的第9号子程序显示字符串
        
        pop si 
        pop ax 
        pop dx 
        pop bx 
        ret 
;;;;;;;显示字符串的子程序的结束;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;这里是延时程序的开始;;;;;;;;;;;;;;;;;;;;;;
delay:         
        push ax 
        push dx 

        mov dx,2000h 
        mov ax,0
         
loop_delay: 
        sub ax,1 
        sbb dx,0 
        cmp ax,0 
        jne loop_delay 
        cmp dx,0 
        jne loop_delay 

        pop dx 
        pop ax 
        ret 
;;;;;;;;;这里是延时程序的结束;;;;;;;;;;;;;;;;;;;;;;     
     
     mov ax,4c00h
     int 21h



    
 codesg ends
 end start
评论次数(0)  |  浏览次数(737)  |  类型(汇编作业) |  收藏此文  | 
 
 请输入验证码  (提示:点击验证码输入框,以获取验证码