外中断
要及时处理外设的输入,显然需要解决两个问题:
- 外设的输入随时可能发生,CPU如何得知?
- CPU从何处得到外设的输入?
15.1 接口芯片和端口
外设的输入不直接送入内存和CPU,而是送入相关的接口芯片的端口中;CPU向外设的输出也不是直接送入外设,而是先送入端口中,再由相关的芯片送到外设。CPU还可以向外设输出控制命令,而这些控制命令也是先送到相关芯片的端口中,然后再由相关的芯片根据命令对外设实施控制。
15.2 外中断信息
有一种中断信息,来自于CPU外部,当CPU外部有需要处理的事情发生的时候,比如说,外设的输入到达,相关的芯片将向CPU发出相应的中断信息。CPU在执行完当前指令后,可以检测到发送过来的中断信息,引发中断过程,处理外设的输入。
在PC系统中,外中断源一共有以下两类。
(1)可屏蔽中断
可屏蔽中断是CPU可以不响应的外中断。CPU是否响应可屏蔽中断,要看标志寄存器的IF位的设置。如果IF=1,则CPU在执行完当前指令后响应中断,如果IF=0,则不响应可屏蔽中断。
过程如下:
- 如果IF=1,则执行下面4步;反之,则不执行
- 取中断类型码n
- 标志寄存器入栈,IF=0,TF=0
- CS、IP入栈
- (IP)=(n∗4),(CS)=(n∗4+2) ( I P ) = ( n ∗ 4 ) , ( C S ) = ( n ∗ 4 + 2 )
8086CPU提供的设置IF的指令如下:
sti,设置IF=1
cli,设置IF=0
(2)不可屏蔽中断
不可屏蔽中断是CPU必须响应的外中断。当CPU检测到不可屏蔽中断信息时,则在执行完当前指令后,立即响应,引发中断过程。
对于8086CPU,不可屏蔽中断的中断类型码固定为2,所以中断过程:
- 标志寄存器入栈,IF=0,TF=0
- CS、IP入栈
- (IP)=(8),(CS)=(0AH) ( I P ) = ( 8 ) , ( C S ) = ( 0 A H )
几乎所有由外设引发的外中断,都是可屏蔽中断。当外设有需要处理的事件发生时,相关芯片向CPU发出可屏蔽中断信息。不可屏蔽中断是在系统中有必须处理的紧急情况发生时用来通知CPU的中断信息。在这门课程中,主要讨论可屏蔽中断。
15.3 PC机键盘的处理过程
很通俗易懂,略过。
键盘输入的处理过程:
- 键盘产生扫描码
- 扫描码送入60h端口
- 引发9号中断
- CPU执行int 9中断例程处理键盘输入
15.4 编写int 9中断例程
内容自己看,也很易读。
检测点 15.1
(1)仔细分析一下上面的int 9中断例程,看看是否精简一下?其实在我们的int 9中断例程中,模拟int指令调用原int 9中断例程的程序段可以精简的,因为在进入中断例程后,IF和TF都已经置0,没有必要再进行设置了,对于程序段:
pushf
pushf
pop ax
and ah,11111100b
push ax
popf
call dword ptr ds:[0]
可以精简为:
pushf
call dword ptr ds:[0]
(2)仔细分析上面程序中的主程序,看看有什么潜在问题?在主程序中,如果在执行设置int 9中断例程的段地址和偏移地址的指令之间发生了键盘中断,则CPU将转去一个错误的地址执行,将发生错误。找出这样的程序段,改写它们,排除潜在问题。(提示,注意sti和cli指令的用法)
答:应该在执行设置int 9的CS之前将IF置0,设置int 9的IP之后将IF置1(设置新int 9的地方和设置旧int 9的地方,这2处需要将IF置0和置1)。
15.5 安装新的int 9中断例程
略过。
CPU对外设输入的通常处理方法:
- 外设的输入送入端口
- 向CPU发出外中断(可屏蔽中断)信息
- CPU检测到可屏蔽中断信息,如果IF=1,CPU在执行完当前指令后响应中断,执行相应的中断例程
- 可在中断例程中实现对外设输入的处理
实验15 安装新的int 9中断例程
安装一个新的int 9中断例程,功能:在DOS下,按下“A”键后,除非不再松开,如果松开,就显示满屏幕的“A”;其他的按键照常处理。
分析:
- 在安装新int 9的时候,将原int 9的入口地址记录下来(可以在int 9的code段之前定义一个data段,用来记录原int 9中断例程的CS和IP)
- 安装新的int 9中断例程
- 如果遇到A的断码,则执行新int 9的指令
- 否则,执行原int 9的指令,而入口地址已经被我们记录下来了