外中断
计算机除了要进行执行指令进行运算外,还需要能对外部设备进行控制;
也就是接受外设的输入或者对外设进行输出;
比如:按键盘的k键,会在屏幕上显示字符k;
计算机为了及时处理外设的输入,需要考虑两个问题:
1】cpu从何处得到外设的输入;
2】外设输入随时可能发生,cpu如何得知;
1.接口芯片和端口
cpu通过端口和外设联系:
计算机中装有各种接口芯片;
接口芯片内部有寄存器,这些寄存器被当做端口;
外设的输入会送入端口,而不是直接送入内存和cpu;
cpu向外设的输出也是送入端口,再由相关芯片送入外设;
2.外中断信息
cpu提供了外中断机制来处理随时可能发生的外设输入;
当cpu外部有需要处理的事情发生时(比如外设的输入到达),相关芯片会向cpu发出相应的中断信息;
cpu在执行完当前指令后,会检测到发送过来的中断信息,引发中断过程,处理外设输入;
在pc系统中外中断源有两类:
1】可屏蔽中断;
2】不可屏蔽中断;
1)关于可屏蔽中断
可屏蔽中断是cpu可以不响应的外中断;
标志寄存器的IF位影响cpu对可屏蔽中断的响应;
当cpu检测到可屏蔽中断时;如果if=1,cpu在执行完当前指令后响应中断;如果if=0,cpu不响应中断;
可屏蔽中断引发的中断过程和内中断相似:
1】取中断类型码n;
可屏蔽中断的中断类型码是通过数据总线送入cpu的,而内中断的中断类型码是在cpu内部产生的;
2】标志寄存器入栈,IF=0,TF=0;
if置0是为了在进入中断处理程序后,禁止其它可屏蔽中断;
3】cs、ip入栈;
4】ip=(n*4);cs=(n*4+2);
从中断向量表中获取中断处理程序的入口;
2)不可屏蔽中断
不可屏蔽中断是cpu必须响应的外部中断;
检测到该中断后,cpu在执行完当前指令后,立即响应,引发中断过程;
不可屏蔽中断的中断过程:
1】标志寄存器入栈,IF=0,TF=0;
不可屏蔽中断的中断类型码固定为2,所以没有取中断类型码的过程;
2】cs、ip入栈;
3】ip=(8),cs=(0AH);
2*4=8;2*4+2=Ah;因为中断类型码为2,从中断向量表中的2号表项中获取中断处理程序的入口地址;
3)几乎所有的由外设引发的外中断都是可屏蔽中断
3.计算机对于键盘的处理
键盘上每一个键相当于一个开关,键盘上有一个芯片对键盘上每一个键的开关状态进行扫描;
按下按键的处理过程为:
按下按键 ->开关接通 ->接口芯片产生扫描码 ->扫描码送入芯片寄存器即端口60h ->引发9号中断 ->执行int 9中断例程
松开按下的按键也将产生一个记录了键盘位置的扫描码并送入端口60h;
扫描码分为两类:
通码 ->按下按键时产生;长度为1个字节;第7位为0;
断码 ->松开按键时产生,长度为1个字节,第7位为1;
断码=通码+80h;也就是说通码与断码只有最高位不同;
例如:g键的通码为22h,断码为a2h;
如图:部分键盘按键的通码
1)关于int 9中断例程
bios提供了int 9中断例程,用作基本的键盘输入处理;
功能为:
1】读出60h端口中的扫描码;
2】如果是字符键的扫描码,将扫描码和它所对应的ascii码送入内存中的bios键盘缓冲区;
如果是控制键和切换键的扫描码,则将其转变为状态字节,写入内存中储存状态字节的单元;例如ctrl、capsLock等;
3】对键盘系统进行相关的控制;比如向相关芯片发出应答信息;
关于bios键盘缓冲区:
是用于存放int 9中断例程所接收的键盘输入的内存区;
该内存区可以存储15个键盘输入;
一个键盘输入用一个字单元保存;高位字节放扫描码,低位字节放扫描码对应的ascii码;
关于状态字节:
0040:17 单元存储键盘状态字节;
该字节记录了键盘控制键和切换键的状态;
该字节各个位表示的含义如图:
2)自定义int 9中断例程
例如:按esc键字体变色的程序
assume cs:code,ds:data,ss:stack
stack segment
db 128 dup (0)
stack ends
data segment
dw 0,0
data ends
code segment
start: mov ax,data
mov ds,ax
mov ax,stack
mov ss,ax
mov sp,128
mov ax,0
mov es,ax
push es:[9*4] ;将原来的int 9中断例程的入口地址放入数据段中保存
pop ds:[0]
push es:[9*4+2]
pop ds:[2]
mov word ptr es:[9*4+2],offset int9
mov word ptr es:[9*4],cs
mov ax,0b800h
mov es,ax
mov ah,'a'
s: mov es:[80*2*12+40*2],ah
call delay
inc ah
cmp ah,'z'
jna s ;和ah的值比较,如果不大于z则循环,达到循环输出的目的
mov ax,0 ;还原int 9的中断向量表
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,10h ;循环100000h次,以此拖时间
mov ax,0
l: sub ax,1
sbb dx,0 ;借位减法,dx=dx-0-cf,如果ax-1的结果有借位则cf=1,反之cf=0;
cmp ax,0
jne l
cmp dx,0
jne l
pop dx
pop ax
ret
int9: push ax ;自定义的int9中断处理例程
push bx
push es
in al,60h ;从60h端口中读取数据
pushf
pushf
pop bx
and bh,11111100b ;TF和IF置0
push bx
popf
call dword ptr ds:[0]
cmp al,1 ;esc键的扫描码为1
jne int9ret
mov ax,0b800h
mov es,ax
inc byte ptr es:[160*12+40*2+1]
int9ret:pop es
pop bx
pop ax
ret
code ends
end start