1. 预备知识
参考上文 在屏幕中间依次显示 ‘a’ ~ ‘z’,并可以让人看清 的实验介绍。
2. 实验任务
安装一个新的 int 9 中断例程,功能:在 DOS 下,按下 A 键后,如果松开,就显示满屏幕的 A;如果不松开则不显示;其他的键照常处理。
- 在 80×25 彩色字符模式显示缓冲区中,显示器可以显示 25 行字符、每行 80 个,共显示 2000 个字符。可通过次数为 2000 的循环显示满屏幕的 A:
assume cs:code
code segment
start:
mov ax,0b800h
mov es,ax
mov si,0
mov cx,2000
s:
mov byte ptr es:[si],'A'
mov byte ptr es:[si+1],2h
add si,2
loop s
mov ax,4c00h
int 21h
code ends
end start
程序运行结果:
- 实验要求如果松开则显示满屏 A 而不松开时不显示,松开时 A 的断码为 1Eh+80h=9Eh。和上一实验类似,将按 esc 改变颜色部分程序改为显示满屏 A 的程序,同时将扫描码设置为 9Eh。同时,使用延时程序 delay 等待用户的键盘输入。整体代码为:
assume cs:code
stack segment
db 128 dup (0)
stack ends
data segment
dw 0,0
data ends
code segment
start:
mov ax,stack
mov ss,ax
mov sp,128
mov ax,data
mov ds,ax
;======== 保存原int 9中断例程地址 ========;
mov ax,0
mov es,ax
push es:[9*4]
pop ds:[0]
push es:[9*4+2]
pop ds:[2] ;将原来int 9中断例程的入口地址保存在ds:0和ds:2单元
cli
mov word ptr es:[9*4],offset int9
;在中断向量表中设置新的int 9中断例程的偏移地址
mov es:[9*4+2],cs
;在中断向量表中设置新的int 9中断例程的段地址
sti
;======== 保存原int 9中断例程地址 ========;
call delay ;延时等待键盘输入
;======== 恢复原int 9中断例程地址 ========;
mov ax,0
mov es,ax
cli
push ds:[0]
pop es:[9*4]
push ds:[2]
pop es:[9*4+2] ;恢复原int 9中断例程的地址
sti
;======== 恢复原int 9中断例程地址 ========;
mov ax,4c00h
int 21h
delay: ;共执行循环1000h*1000h次
push ax
push dx ;保护现场
mov dx,10h
mov ax,0
help:
sub ax,1
sbb dx,0
cmp ax,0
jne help
cmp dx,0
jne help
pop dx
pop ax ;恢复现场
ret
int9:
push ax
push bx
push es ;保护现场
in al,60h
;======== 模拟int指令调用 ========;
pushf ;标志寄存器入栈
call dword ptr ds:[0]
;CS和IP入栈,且目的CS由内存单元高地址给出、IP由低地址给出
;======== 模拟int指令调用 ========;
cmp al,9Eh ;通码为9Eh
jne int9ret
mov ax,0b800h
mov es,ax
mov si,0
mov cx,2000
s_show: ;显示满屏A
mov byte ptr es:[si],'A'
mov byte ptr es:[si+1],2h
add si,2
loop s_show
int9ret:
pop es
pop bx
pop ax ;恢复现场
iret
code ends
end start
程序运行结果:
3. 总结
- 本文是在上文的基础上,再次基于 int 9 中断例程实现屏幕显示相关内容的功能。