CPU不论处理内中断仍是外中断都是经过中断类型码来选择要执行的中断例程。外中断可分为可屏蔽和不可屏蔽,当IF=0时,会屏蔽掉可屏蔽中断。oop
以键盘输入为例。当按下一个键时,就会产生一个扫描码,并传到端口60h,此时相关芯片会向CPU发送中断类型码为9的可屏蔽中断。spa
端口的读写指令是 in/out。这里不作具体展开,假设要读取端口60h的数据,可用 in al,60h。code
假设如今要在int 9中断例程的基础上加点东西,好比但愿按下esc键后改变屏幕输出。blog
可行的思路是,修改中断向量表中9号中断例程的入口地址为子程序的地址,队列
当IF = 1且有键盘输入时,进入到子程序,子程序要先执行原先的9号中断例程(先pushf,再call)。所以要先将原先的9号中断例程的地址记录下来。注意每一个子程序/中断例程内部结束处都会有ret/iret,因此这里执行了pushf和call,中断例程内部结束处会有iret来执行ret和popf。class
执行完中断例程后再执行添加的指令。完整程序以下基础
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] pop ds:[0] push es:[9*4+2] pop ds:[2] pushf pop ax mov word ptr es:[9*4],offset int9 mov es:[9*4+2],cs mov ax,0b800h mov es,ax mov ah,'a' s: mov es:[160*12+40*2],ah call delay inc ah cmp ah,'z' jna s mov ax,4c00h int 21h delay: push ax push dx mov dx,10 mov ax,0 s1: sub ax,1 sbb dx,0 cmp ax,0 jne s1 cmp dx,0 jne s1 pop dx pop ax ret int9: push ax push bx push es in al,60h pushf call dword ptr ds:[0] cmp al,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 iret code ends end start
int 9h中断例程是在有键按下的时候向键盘缓冲区写入数据,这里的键盘缓冲区是双向队列,可存放15个键盘输入,每一个键盘输入包含扫描码和ASCII码(这里会检查状态字节,结合原字符获得ASCII码)。对应的,若是要从键盘缓冲区读取数据,可用int 16h,其功能号为0(有的中断例程须要功能号或一些其余的参数),指令为程序
mov ah,0call
int 16h数据
经过该语句,ax被赋值,其中(ah) = 扫描码,(al) = ASCII码。
假设如今想经过按下r/g/b键令显示区的字符全为红/绿/蓝,
assume cs:code code segment start: mov ah,0 int 16h mov ah,1 cmp al,'r' je red cmp al,'g' je green cmp al,'b' je blue jmp short sret red: shl ah,1 green: shl ah,1 blue: mov bx,0b800h mov es,bx mov bx,1 mov cx,2000 s: and byte ptr es:[bx],11111000b or es:[bx],ah add bx,2 loop s sret: mov ax,4c00h int 21h code ends end start