汇编语言 第15章 外中断
前言
由14章内容我们知道,CPU与外设交互是通过端口。 CPU发送信息给外设需要通过接口芯片(接口内部的寄存器); 外设给CPU发送信息也是通过接口芯片(接口内部的寄存器)。 而外设的寄存器被抽象为统一的地址,端口。
以上说明了底层通信机制, 那现在还有有几个实现上的问题需要考虑:
- 外设的输入随时发生,CPU如果得知? 答:通过外中断(对不起,不管CPU先生您现在在忙什么,现在有外设输入,先中断手头的任务)
- CPU从何处得到外设的输入? 答:当然是端口咯。
- CPU获得什么消息?
可屏蔽/不可屏蔽外中断
外中断也分为两种类型:(a) 可屏蔽外中断 (b) 不可屏蔽外中断
不可屏蔽外中断
可CPU必须现在、立刻、马上处理的外中断,比如,我猜测强行关机或者Ctrl + Alt + Del之类的应该是不可屏蔽中断吧,毕竟出现死循环的情况下,需要强行介入啊。
设置不可屏蔽外中断的方法
简单来说,就是中断码为2的外中断,为不可屏蔽外中断。
可屏蔽外中断
即Mr. CPU可能现在在忙于一个重要的事情(例如另一个中断之类的),如果这时候被打断可能会出现死循环,死锁之类的。 因此不希望被非紧急情况下的中断给打扰了,先处理完手头上的事情再马上处理中断。 这些可以先等一等的中断就是可屏蔽外中断。实际上绝大多数中断都是可屏蔽外中断。
那么问题来了,如何知道CPU现在是否可以被立即打断呢? 答案就是标志寄存器中的IF(Interrupt-enable Flag)位。
如果IF位被设置为1,CPU就是在声明,我现在可以被打断,来吧! 如果IF为被设置为0,CPU就是在声明,不好意思,我现在忙于重要的事情,现在不便于处理可屏蔽的外中断。
回忆一下内中断的处理过程:
- 取中断类型码n
- pushf,IF = 0,TF = 0
- push CS, push IP
- (IP) = (n4),(CS) = (n4 +2)
- 转到n号中断程序处理中断。
其中有一项IF = 0
,就是在说,我现在在处理中断任务,不宜跳出处理其他中断。
而TF = 0
则是说,如果debug单步执行,本中断指令完整执行,而不单步。
结合第11章各标志寄存位, 以及第12章了解到的TF(Trap Flag)标记寄存位用来控制单步循环。 现在又学会了IF寄存位的作用。 那还有AF未知。
设置IF的指令
sti ;set interrupt 设置IF = 1
cli ;clean interrupt 设置IF = 0
以键盘处理过程为例
键盘上有一个芯片对每一个按键进行扫描,当按下一个按键时,产生一个扫描码(称为通码);放开一个按键时,产生另一个扫描码(称为断码)。
《汇编语言》中关于扫描码的内容有些过时,估计仅针对8086之类的老机器,故不详述。 现在很多硬件设计的扫描码不同,但都映射为统一标准的键盘虚拟码,详情参见此文
8086中按键引发的中断消息
键盘与8086的通信通过60h端口,当有按键事件发生时,产生int 9的中断。
整个过程为:
- 键盘产生扫描码
- 扫描码送入60h端口
- 引发9号中断,int 9
- CPU执行9号中断中的例程
还有一个问题,比如shift+a,ctrl + s之类还有控制键或者切换键insert之类的,系统如何知道呢? 8086是这样实现的:
- 对于字符键,例如a、b、q之类可屏显的按键,将扫描码和字符对应ASCII码一起送入机器。
- 对于控制键,有特定扫描码,其效果是改变键盘状态字节的状态。
例如,对于8086,键盘状态字节存储在0040:17内,0~7bit分别代表右shift,左shift、Ctrl、Alt、Scrolllock、Numlock、Capslock、Insert的状态。