实验16 : 编写包含多个功能的子程序的中断例程
实际运行
实验16 编写包含多个功能子程序的中断例程.png
完整源码
assume cs:code
code segment
start: ;------ 安装功能程序到 0000:0200H 开始 --------
mov ax,cs
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
;------ 在中断向量表 N = 7CH 号表项处写入
; 中断处理程序的入口地址0000:0200h -----
mov ax,0
mov es,ax
mov word ptr es:[7CH*4],200H
mov word ptr es:[7CH*4+2],0
mov ax,4c00H
int 21H
;org 200h
;---------- 7CH 号中断处理程序本身 ---------
; 用ah传递功能号,0-清屏 1-设置前景色 2-设置背景色 3-向上滚动一行
setscreen: cmp ah,0
je do1
cmp ah,1
je do2
cmp ah,2
je do3
cmp ah,3
je do4
jmp short sret
do1: call sub1
jmp short sret
do2: call sub2
jmp short sret
do3: call sub3
jmp short sret
do4: call sub4
sret: iret
; 清屏,将幸存中当前屏幕中的字符设为空格符
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
; 设置前景色 用al传送颜色值
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
; 设置背景色 用al传送颜色值
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
; 滚动一行:依次将第n+1行的内容复制到第n行;最后一行为空
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
sub4s: push cx
mov cx,160
rep movsb
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
assume cs:code
code segment
begin:
mov ah,1
mov al,10001100B ; 闪烁 背景R G B 高亮 前景R G B
int 7CH
mov ax,4c00h
int 21H
code ends
end begin
代码说明
- 使用书上第二种
setscreen
实现
-
sret
后面写上中断程序返回用的iret
,而不是书上的call
子程序返回用 ret
- 增加
setscreenend: nop
用于计算安装时需要复制的代码长度,搭配mov cx,offset setscreenend - offset setscreen
使用
- 注意区分 iret 和 setscreenend: nop 的作用、代码放置位置
setscreenend: nop 位置一定是放在全部sub子程序后面的,不然怎么算的出要复制的代码长度
iret 被复制到内存之后要发挥功能的,在实际执行过程中会作用于中断程序的返回过程
本质上来说,这次要安装的是一个包含很多子程序的中断处理程序,
每一个子程序sub的最后都有一个ret 用于返回来自call的调用,这里要清楚!
而在书上原本的 sret 标号之后也是一个ret,
这是因为书上的代码是把整个代码当做一个子程序使用call来调用的,
所以书上的是ret,书上的ret要与call呼应。
但是作为实验16就不同了,实验16是要安装的程序的中断处理程序,中断处理程序就需要用iret来返回。
代码心得
- 直接用
table dw sub1,sub2,sub3,sub4
会 受苦,table[si] 本质是 cs:N[si],此cs非彼cs,况且N又是多少?谁知道。
代码参考(几种解决思路)
- 不受苦的解决方案
https://blog.csdn.net/wyf12138/article/details/54412411
- 强调 table不是单纯的table
http://tieba.baidu.com/p/2548780631
- 意☆义☆不☆明的
org 200H
https://blog.csdn.net/lixiang0522/article/details/8434450
- offset 设置偏移地址
https://blog.csdn.net/love_jing_forever/article/details/53415036