==================================================================================================
在计算机上执行的程序通常需要一些输入,输入可能来自于键盘、鼠标、硬盘、话筒、数码相机等,同时,处理后还需要输出,要送到输出设备,如显示器、硬盘、打印机、网络设备等。
一个程序只做自己的事,当它等待输入,或者等待输出时,它面对的是比处理器慢得多的外部设备。典型的情况下,硬盘的工作速度比处理器至少慢几千万甚至几亿倍,像打印机这类设备就更不用说了。在等待的时候,处理器唯一所能做的,就是不停地观察外部设备的状态变化。
计算机革命的早期,硬件资源极其昂贵和稀少。据说20世纪60年代,一台计算机的价格抵得上300辆野马跑车,月租金超过一万美金(此时的美金可比现在值钱许多)。这么昂贵的东西,不好好利用它就是一种罪过。
为了分享计算能力,处理器应当能够为多用户多任务提供硬件一级的支持。在单处理器的系统中,允许同时有多个程序在内存中等待处理器的执行。当一个程序正在等待输入输出时,允许另一个程序从处理器那里得到执行权。
如何把多个程序调入内存,是操作系统的事情。现在的问题是,当一个程序执行时,它是不会知道还有别的程序正眼巴巴地等着执行。在这种情况下,中断(Interrupt)这种工作机制就应运而生了。
中断就是打断处理器当前的执行流程,去执行另外一些和当前工作不相干的指令,执行完之后,还可以返回到原来的程序流程继续执行。这就好比是你正在用手机听歌,突然来电话了。处理器(当然,手机也是有处理器的)必须中断歌曲的播放,来处理这件更为重要的事件。
==================================================================================================
在正式开始之前,我们要了解一下中断的分类,中断可以分为两类:外部中断和内部中断。
一.
外部中断
顾名思义,外部中断,就是从处理器外面来的中断信号。当外部设备发生错误,或者有数据要传送(比如,从网络中接收到一个针对当前主机的数据包),或者处理器交给它的事情处理完了(比如,打印已经完成),它们都会拍一下处理器的肩膀,告诉它应当先把手头上的事情放一放,来临时处理一下。
如图所示,外部中断是通过两个信号线引入处理器内部的。从很早的时候起,也就是8086处理器的时代,这两根线的名字就叫NMI和INTR(即Non
Maskable Interrupt——不可屏蔽中断 和 maskable INTRrupt
可屏蔽中断)。
http://s14/mw690/002Dc71Vzy6HS548Z8p5d&690“蛋疼”的8259芯片(1)" TITLE="第一节 “蛋疼”的8259芯片(1)" />
正是因为这两根引脚,外部中断可以分为不可屏蔽中断和可屏蔽中断:
1.
不可屏蔽中断
在某些具有怀疑精神的人眼里,用两根信号线来接受外部设备中断可能是多余的,也许只需要一根就可以了。这似乎有此道理,但是,来自外部设备的中断很多,也不是每一个中断都是必须处理的。有些中断,在任何时候都必须及时处理,因为事关整个系统的安全性。比如,在使用不间断电源的系统中,当电池电量很低的时候,不间断电源系统会发出一个中断,通知处理器快掉电了。再比如,内存访问电路发现了一个校验错误,这意味着,从内存读取的数据是错误的,处理器再努力工作也是没有意义的。在所有这些情况下,处理器必须针对这些中断采取必要的措施,隐瞒真相必然会对用户造成不可挽回的损失。除此之外,更多的中断是可以被忽略或者延迟处理的,如果某个程序希望不被打扰的话。
在这种情况下,处理器的设计者希望通过两个引脚来明确区分不同性质的中断,这是很自然的事。首先,所有的严重事件都必须无条件地加以处理,这种类型的中断是不会被阻断和屏蔽的,称为非屏蔽中断(Non
Maskable Interrupt,NMI)。
中断信号的来源,或者说,产生中断的设备,称为中断源。如上图所示,在传统的兼容模式下,NMI的中断源通过一个与非门连接到处理器。处理器的NMI引脚是高电平有效的,而中断信号(即内存校验错和I/O校验错)是低电平有效的。当不存在中断的时候,与非门的所有输入都为高,因此处理器的NMI引脚为低电平,这意味着没有中断发生。
http://s10/mw690/002Dc71Vzy6HSfKTSC559&690“蛋疼”的8259芯片(1)" TITLE="第一节 “蛋疼”的8259芯片(1)" />
当有任何一个非屏蔽的中断产生时,与非门的输出为高。Intel处理器规定,NMI中断信号由0跳变到1后,至少要维持4个以上的时钟周期才算是有效的,才能被识别。
当一个中断发生时,处理器将会通过中断引脚NMI和INTR得到通知。除此之外,它还应当知道发生了什么事,以便采取适当的处理措施。每种类型的中断都被统一编号,这称为中断类型号、中断向量或者中断号。但是,由于不可屏蔽中断的特殊性——几乎所有触发NMI的事件对处理器来说都是致命的,甚至是不可纠正的。在这种情况下,努力去搞清楚发生了什么,通常没有太大的意义,这样的事最好留到事后,让专业维修人员来做。
也正是这个原因,在实模式下,NMI被赋予了统一的中断号2,不再进行细分。一旦发生2号中断,处理器和软件系统通常会放弃继续正常工作的“念头”,也不会试图纠正已经发生的问题和错误,很可能只是由软件系统给出一个提示信息(Windows下的蓝屏)。
2.
可屏蔽中断
和NMI不同,更多的时候,发往处理器的中断信号通常不会意味着灾难。这类中断有两个特点,第一是数量很多,毕竟有很多外部设备;第二是它们可以被屏蔽,这样处理器就像是没听见、没看见一样,不会对它们进行处理。所以,这类硬件中断称为可屏蔽中断。
可屏蔽中断是通过INTR引脚进入处理器内部的,像NMI一样,不可能为每一个中断源都提供一个引脚。而且,处理器每次只能处理一个中断。在这种情况下,需要一个代理,来接受外部设备发出的中断信号。还有,多个设备同时发出中断请求的机率也是很高的,所以该代理的任务还包括对它们进行仲裁,以决定让它们中的哪一个优先向处理器提出服务请求。
如下图所示,在个人计算机中,用得最多的中断代理就是8259芯片,它就是通常所说的中断控制器,从8086处理器开始,它就一直提供着这种服务。即使是现在,在绝大多数单处理器的计算机中,也依然有它的存在。
Intel处理器允许256个中断,中断号的范围是0~255,8259负责提供其中的15个,但中断号并不固定。之所以不固定,是因为当初设计的时候,允许软件根据自己的需要灵活设置中断号,以防止发生冲突。该中断控制器芯片有自己的端口号,对于x86处理器而言,可以像访问其他外部设备一样用in
和out指令来改变它的状态,包括各引脚的中断号。正是因为这样,它又叫可编程中断控制器(Programmable
Interrupt Controller,PIC)。
http://s1/mw690/002Dc71Vzy6HSfZbzWM60&690“蛋疼”的8259芯片(1)" TITLE="第一节 “蛋疼”的8259芯片(1)" />
不知道是怎么想的,反正每片8259只有8个中断输入引脚,而在个人计算机上使用它,需要两块。如上图所示,第一块8259芯片的代理输出INT
直接送到处理器的INTR
引脚,这是主片(Master);第二块8259芯片的INT输出送到第一块的引脚2上,是从片(Slave),两块芯片之间形成级联(Cascade)关系。
如此一来,两块8259芯片可以向处理器提供15个中断信号。当时,接在8259上的15个设备都是相当重要的,如PS/2键盘和鼠标、串行口、并行口、软磁盘驱动器、IDE硬盘等。现在,这些设备很多都已淘汰或者正在淘汰中,根据需要,这些中断引脚可以被其他设备使用。
8259的主片引脚0(IR0)接的是系统定时器/计数器芯片;从片的引脚0(IR0)接的是实时时钟芯片RTC,这是重中之重。总之,这两块芯片的固定连接即使是在硬件更新换代非常频繁的今天,也依然没有改变。
前面已经说过,在PC/AT系列兼容机中使用了级联的两片8259A可编程控制器(PIC)芯片,共可管理15级中断向量。其中从芯片的INT引脚连接到主芯片的IR2引脚上。主8259A芯斤的端口基地址是0x20,从芯是0xA0。一个8259A芯片的逻辑框图见下图所示。
http://s15/mw690/002Dc71Vzy6HSgd0Afc0e&690“蛋疼”的8259芯片(1)" TITLE="第一节 “蛋疼”的8259芯片(1)" />
中断请求寄存器IRR
(lnterrupt Request Register)用来保存中断请求输入引脚上所有请求服务中断级,寄存器的8个比特位(D7-DO)分别对应引脚IR7-IRO。
中断屏蔽寄存器IMR(Interrup
MaskRegister)用于保存被屏蔽的中断请求线对应的比特位,寄存器的8位也是对应8个中断级。哪个比特位被置1就屏蔽哪一级中断请求。即IMR对IRR进行处理,其每个比特位对应IRR的每个请求比特位。对高优先级输入线的屏蔽并不会影响低优先级中断请求线的输入。
优先级解析器PR(Priority
Resolver)用于确定IRR中所设置比特位的优先级,选通最高优先级的中断请求到正在服务寄存器ISR
(In-ServiceRegister)中。ISR中保存着正在接受服务的中断请求。
控制逻辑方框中的寄存器组用于接受CPU产生的两类命令。在8259A可以正常操作之前,必须首先设置初始化命令字ICW
(lnitialization CommandWords)寄有器组的内容。而在其工作过程中,则可以使用写入操作命令字OCW
(Operation CommandWords)寄存器组来随时设置和管理8259A的工作方式。
A0线用于选择操作的寄存器。在PC/AT微机系统中,当A0线为0时芯片的端口地是0x20和0xA0
(从芯片),当A0=I时端口就是0x21和0xA1。
在实际编程中,当你操作0x20或0xA0端口时,相当于A0等于0;当你操作0x21或0xA1时A0就等于1。
来自各个设备的中断请求线分别连接到8259A的IR0-IR7中断请求引脚上。当这些引脚上有一个或多个中断请求信号到来时,中断请求寄存器IRR中相应的比特位被置位。此时若中断屏蔽寄存器IMR中对应位被置位,则相应的中断请求就不会送到优先级解析器中。对于未屏蔽的中断请求被送到优先级解析器之后,优先级最高的中断请求会被选出。
此时8259A就会向CPU
发送一个INT信号,而CPU则会在执行完当前的一条指令之后向8259A发送一个INTA来响应中断信号。8259A在收到这个响应信号之后就会把所选出的最高优先级中断请求保存到正在服务寄存器ISR中,即ISR中对应中断请求级的比特位被置位。与此同时,中断请求寄存器IRR中的对应比特位被复位,表示该中断请求开始正被处理中。
此后,CPU会向8259A发出第2个INTA脉冲信号,该信号用于通知8259A送出中断号。因此在该脉冲信号期间8259A就会把一个代表中断号的8位数据发送到数据总线上供CPU读取。
到此为止,CPU中断周期结束。如果8259A使用的是自动结束中断AEOI(
Automatic End of Interrupt)方式,那么在第2个INTA脉冲信号的结尾处(即将中断号发送之后)正在服务寄存器ISR中的当前服务中断比特位就会被复位。
否则的话,若8259A处于非自动结束方式,那么在中断服务程序结束时程序就需要向8259A发送一个结束中断(EOI)命令以复位ISR中的比特位。如果中断请求来自接联的第2个8259A芯片,那么就需要向两个芯片都发送EOI命令。此后8259A就会去判断下一个最高优先级的中断,并重复上述处理过程。
下面我们先给出初始化命令字和操作命令字的编程方法,然后再对其中用到的一些操作方式作进一步说明。
初始化命令字编程:
可编程控制器8259A主要有4种工作方式:
①全嵌套方式;
②循环优先级方式;
③特殊屏蔽方式;
④程序查询方式。
通过对8259A进行编程,我们可以选定8259A的当前工作方式。编程时分两个阶段。
一.在8259A工作之前对每个8259A芯片4个初始化命令字(ICWI-ICW4)寄存器的写入编程;
二.在工作过程中随时对8259A的3个操作命令字(OCWI-OCW3)进行编程。
在初始化之后,操作命令字的内容可以在任何时候写入8259A。下面我们先说明对8259A初始化命令字的编程操作。初始化命令字的编程操作流程见下图所示。由图可以看出,对ICW1和ICW2的设置是必需的。而只有当系统中包括多片8259A芯片并且是接连的情况下才需要对ICW3进行设置。这需要在ICW1的设置中明确出。另外,是否需要对ICW4进行设置也需要在ICW1中指明。
http://s7/mw690/002Dc71Vzy6HSgZrzbE56&690“蛋疼”的8259芯片(1)" TITLE="第一节 “蛋疼”的8259芯片(1)" />