《汇编语言》第三版有关中断处理的学习笔记。
相关概念
- 什么是中断? - 一种来自CPU内部或者外部的中断信息,被CPU检测到,CPU在执行完当前正在执行的指令后,可以立即对所接收到的信息进行处理。 - Wiki上的解释更为简单点: - In digital computers, an interrupt is an input signal to the processor indicating an event that needs immediate attention. 
- 中断可分为哪些类型? - 按照是否发生在CPU内部,分为: - 内中断:发生在CPU内部的中断, 比如溢出。 
- 外中断:发生在CPU外部的中断,比如外部设备输入 
 
- 中断处理的基本机制是什么? - 一般分四步: - 获取中断类型码 N
- 标志寄存器入栈,TF,IF 设置为0
- CS,IP入栈
- (IP)= (N * 4), (CS) = (N * 4 + 2)
 - 其中,外中断与内中断在第一步,即获取中断类型码N稍有不同, 因为外中断的中断信息来自CPU外部,中断类型码通过数据总线送入CPU的, 而内中断的中断类型码是直接在CPU内部产生的。 - 中断后面的三步可转换成如下汇编语言: - ; 标志寄存器入栈 pushf ; 设置 TF,IF 为0,TF,IF为标志寄存器的8,9位 pushf pop bx and bh, 11111100b push bx popf ; CS,IP入栈 push CS push IP- 这里解释下为什么要设置 TF=0, IF=0。 - TF 与单步中断有关 - 单步中断的类型码为1, CPU检测TF,如果 TF =1,则产生单步中断,CPU会去执行1号中断处理程序,故这里将TF设置为0。 
- IF与外中断相关 - CPU可以不响应的外中断称为 可屏蔽中断。CPU通过IF的值决定是否响应可屏蔽中断。 - 当 IF=1,CPU执行完当前指令后,响应中断,引发中断过程。IF=0,CPU不响应可屏蔽中断。 - 所以这里设置IF=0,这样,在进入中断例程后,便禁止了其他的可屏蔽中断。 
 
- 如何根据中断类型码找到对应的中断例程的入口地址? - 通过中断向量表 IDT Interrupt description table。 - 对8086机,中断向量表指定存放在内存地址0处,共有256种中断类型,一个表项存放一个中断例程的入口地址,即CS:IP,故整个中断向量表占用 4 byte * 256 = 1024 byte,即内存地址从0000:0000 到 0000:03FF的1024个单元中存放着中断向量表。 
- 中断例程有哪些? - 中断例程分两种: - 程序员自己编写的 
- 系统自带的:可由 BIOS 或 DOS提供。 - BIOS:基本输入输出系统,存放在ROM中。 - BIOS 中主要包括的中断: - 外部中断和内部中断的中断例程
- 用于对硬件设备进行 I/O操作的中断例程 「比如在屏幕进行打印,int 10h」
- 其他和硬件系统相关的中断例程
 - 操作系统DOS 也提供了中断处理,注意,和硬件设备相关的DOS 中断例程中,一般都调用了BIOS中的中断例程。 - BIOS, DOS 提供的中断例程,都是使用ah 来传递子程序的编号。 - 比如(ah)=9, 表示调用第 N 号中断例程的9号子程序。 - 8086支持的中断例程列表:bios and dos interrupts 
 
- 程序员如何自己编写中断处理程序? - 三步走: - 编写中断处理程序 
- 将中断处理程序复制到指定的内存地址中 
- 设置中断向量表 
 - 这里,将中断处理程序复制到内存中哪个地方合适? - 内存地址从0000:0000 到 0000:03FF的1024个单元中,存放着256种中断类型的入口地址,但实际上,系统要处理的中断事件远没有达到256个,一般情况下,从0000:0200 到 0000:02FF 的256个字节所对应的中断向量表项都是空的,可以安放在此处。 
- 有哪些常见的中断例程? - int 10h: - BIOS 提供, (ah)=2h, 表示调用第 10h 号中断例程的2号子程序,置光标, (ah)=9h, 表示调用第 10h 号中断例程的9号子程序,在光标位置显示字符。 - int 21h: - DOS 提供, (ah)=4ch, 表示调用第 21h 号中断例程的4c号子程序,即退出程序, (ah)=9h, 表示调用第 21h 号中断例程的9号子程序,在光标位置显示字符串。 - int 9h: - BIOS 提供。从60h端口读出输入的扫描码,并将其转化为相应的ASCII码或状态信息,存储在内存的指定空间(键盘缓冲区/状态字节)中。 - Int 16h - BIOS提供,该中断例程包含的0号子程序,可以从键盘缓冲区中读取一个键盘的输入。 
端口读写
外中断的处理,涉及到端口读写,来了解下。
CPU 可以直接读写3个地方的数据:
- CPU内部的寄存器
- 内存单元
- 端口
CPU 对端口的读写只有两个指令: in (读取), out(写入).
读写端口,只能通过 ax / al, 即读入的信息和写入的信息都通过 ax / al 传递。
端口地址范围:0~65535
- 0~255的端口读写: - in al, 20h out 20h, al
- 256~65535的端口读写: - mov dx, 3ffh ;需要一个16位寄存器来存放端口地址 in al, dx out dx, al
有关外中断
主要为处理外部设备的输入输出,比如键盘的输入。
外设与CPU交互通过端口实现:
外设的输入先送入相关的接口芯片的端口,CPU通过访问端口来读取外设的输入。
同样,CPU向外设的输出也不是直接送入外设,而是先送入端口,再由相关芯片送入外设,即端口相当于一个中间站。CPU通过端口与外设联系。
外中断分为两类:
- 可屏蔽中断: CPU 可以不响应的外中断 - 通过 标志寄存器中的 IF位来判断是否屏蔽。 - 8086CPU提供了设置IF的指令: - sti ,设置 IF=1 - cli,设置 IF=0 - 几乎所有由外设引发的外中断,都是可屏蔽中断。 
- 不可屏蔽中断:CPU必须响应的外中断 - 对于8086CPU, 不可屏蔽中断的中断类型码固定为2。 - 不可屏蔽中断是系统中,有必须处理的紧急情况发生时,用来通知CPU的中断信息。 
以键盘输入引发的中断为例:
松开或者按下键盘时,会产生一个扫描码,该扫描码会被送入60h 端口,引发9号中断,CPU检测到该中断后,如果IF=1,则响应中断,引发中断过程,去执行int 9h 中断例程。
即整个流程为:
- 键盘产生扫描码
- 扫描码送至60h端口
- 引发9号中断
- CPU执行BIOS提供的 int 9h 中断例程