15.1 接口芯片和端口
-
CPU通过端口和外部设备进行联系。
外设的输入不直接送入内存和CPU ,而是送入相关的接口芯片的端口中;
CPU向外设的输出也不是直接送入外设,而是先送入端口中,在由相关芯片送到外设;
15.2 外中断信息
外中断源分为以下2类:
1.可屏蔽中断
可屏蔽中断是 CPU可以不响应的外中断。
-
当CPU检测到可屏蔽中断信息时,
如果IF=1,则CPU在执行完当前指令后响应中断,引发中断过程;
如果IF=0,则不响应可屏蔽中断。 -
中断过程中将IF设置为0的原因:
在进入中断处理程序后,禁止其他的可屏蔽中断。 -
8086CPU 提供的设置IF的指令:
sti,设置IF=1;
cli,设置IF=0.
2.不可屏蔽中断
不可屏蔽中断是CPU 必须响应的外中断。当CPU检测到不可屏蔽中断信息时,则在执行完当前指令后,立即响应,引发中断过程。
- 对于8086CPU,不可屏蔽中断的中断类型码固定为2,所以中断过程中,不需要取中断类型码。不可屏蔽中断的中断过程如下:
(1) 标志寄存器入栈,IF=0,TF=0;
(2) CS、IP入栈;
(3) (IP)=(8),(CS)=(0AH).
15.3 PC机键盘的处理过程
1.键盘输入
- 键盘上的每一个键相当于一个开关,键盘中有一个芯片对键盘上的每一个键的开关状态进行扫描。
- 按下一个键是,开关接通,该芯片就产生一个扫描码,扫描码说明了按下的键在键盘上的位置。扫描码被送入主板上的相关接口芯片的寄存器中,该寄存器的端口地址为60h。
- 松开按下的键时,也产生一个扫描码,扫描码说明了松开的键在键盘上的位置。松开按键时产生的扫描码也被送入60h端口中。
- 一般将按下一个键时产生的扫描码称为 通码,松开一个按键产生的扫描码称为 断码。扫描码长度为1个字节,通码 的第7位为0,断码的第7位为1,即:
断码=通码+80h
2.引发9号中断
- 键盘的输入到达60h端口时,相关的芯片就会向CPU发出中断类型码为9的可屏蔽中断信息。CPU检测到该中断信息后,如果IF=1,则响应中断,引发中断过程,转去执行int 9中断例程。
3.执行int 9 中断例程
-
BIOS 提供了int 9 中断例程,用来进行基本的键盘输入处理。主要工作如下:
(1) 读出60h端口中的扫描码;
(2)- 如果是字符键的扫描码,将该扫描码和它所对应的字符码(即ASCII码)送入内存中的BIOS键盘缓冲区;
- 如果是控制键(如Ctrl)和切换键(如CapsLock)的扫描码,则将其转变为状态字节(用二进制记录控制键和切换键状态的字节)写入内存中存储状态字节的单元;
(3) 对键盘进行相关的控制,如,向相关芯片发出应答信息。
- BIOS 键盘缓冲区是系统启动后,BIOS用于存放int 9 中断例程所接收的键盘输入的内存区。该内存区可以存储15个键盘输入,因为int 9 中断例程除了接收扫描码外,还要产生和扫描码对应的字符码,所以在BIOS键盘缓冲区中,一个键盘输入用1个字单元存放,高位字节存放扫描码,低位字节存放字符码
- 0040:17 单元存储键盘状态字节,该字节记录了控制键和切换键的状态。
- 键盘状态字节各位记录的信息如下:
15.4 编写int 9 中断例程
键盘输入的处理过程:
①键盘产生扫描码;
②扫描码送入60h端口;
③引发9号中断;
④CPU执行 int 9 中断例程梳理键盘输入。
编程,在屏幕中间显示a~z,并可以让人看清,在显示的过程中,按下Esc键后,改变显示的颜色。
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
mov ax,0
mov es,ax
push es:[9*4] ;(IP)=(N*4),(CS)=(N*4+2)
pop ds:[0]
push es:[9*4+2]
pop ds:[2] ;将原来的int 9 中断例程的入口地址保存在ds:0\ds:2单元中
mov word ptr es:[9*4],offset int9
mov es:[9*4+2],cs ;在中断向量表中设置新的int 9 中断例程入口地址
mov ax,0b800h ;依次显示a~z
mov es,ax
mov ah,'a'
s: mov es:[160*12+40*2],ah
call delay
inc ah
cmp ah,'z' ;根据2值相减结果修改标志寄存器相应位
jna s ;jna 不大于,如果ah的值≤ z的ASCII码值 跳转到s
mov ax,0
mov es,ax
push ds:[0]
pop es:[9*4]
push ds:[2]
pop es:[9*4+2]
mov ax,4c00h
int 21h
delay: push ax
push dx
mov dx,0010h ;循环100000h次
mov ax,0
s1: sub ax,1 ;(ax)=(ax)-1
sbb dx,0 ;借位减,(dx)=(dx)-0-CF
cmp ax,0
jne s1 ;(ax)≠0 转到s1
cmp dx,0
jne s1 ;(dx)≠0 转到s1
pop dx
pop ax
ret
int9: push ax
push bx
push es
in al,60
pushf
pushf
pop bx
and bh,11111100b
push bx
popf
call dword ptr ds:[0] ;对int 指令进行模拟,调用原来的int 9中断例程
cmp al,1
jne int9ret
mov ax,0b800h
mov es,ax
inc byte ptr es:[160*12+40*2+1] ;将属性值+1改变颜色
int9ret:pop es
pop bx
pop ax
iret
code ends
end start
15.5 安装新的int9 中断例程
任务:安装一个新的int 9 中断例程
功能:在DOS 下,按F1键后改变当前屏幕的显示颜色,其他的键照常处理。
assume cs:code
stack segment
db 128 dup(0)
stack ends
code segment
start: mov ax,stack
mov ss,ax
mov sp,128
push cs
pop ds
mov ax,0
mov es,ax
mov si,offset int9 ;设置ds:si指向源地址
mov di,204h ;设置es:di指向目的地址
mov cx,offset int9end-offset int9 ;设置cx为传输长度
cld ;设置传送方向为正
rep movsb
push es:[9*4]
pop es:[200h]
push es:[9*4+2]
pop es:[202h]
cli
mov word ptr es:[9*4],204h
mov word ptr es:[9*4+2],0
sti
mov ax,4c00h
int 21h
int9: push ax
push bx
push cx
push es
in al,60h
pushf
call dword ptr cs:[200h] ;当此中断例程执行时(CS)=0
cmp al,3bh ;F1的扫描码为3bh
jne int9ret
mov ax,0b800h
mov es,ax
mov bx,1
mov cx,2000
s: inc byte ptr es:[bx]
add bx,2
loop s
int9ret:pop es
pop cx
pop bx
pop ax
iret
int9end:nop
code ends
end start
To be continue…