外中断

计算机除了要进行执行指令进行运算外,还需要能对外部设备进行控制;
也就是接受外设的输入或者对外设进行输出;
比如:按键盘的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
 
 
 
posted @ 2019-08-01 11:34  L丶银甲闪闪  阅读(334)  评论(0编辑  收藏  举报