你没有硬件基础?我也没有!所以让咱们从零开始。
IRQ(Interrupt ReQuest),中文翻译应该为“中断请求”,但实际上一些文档中说到IRQ时一般就是指“中断请求信号线”——8259A的一个引脚,一个8259A有8个这样的引脚IRQ0~IRQ7。那8259A又是什么?好问题!想到问题后咱们就来解决它,其实咱们这此普通人跟牛人的区别就在这儿。
IRQ、中断号与8259A
我们都知道计算机可以挂接上许多外部设备,比如键盘、磁盘驱动器、鼠标、声卡……等等一系列设备,而这些设备都可能在同一时刻向CPU发出中断信号(也就是外部中断),那么CPU到底应当响应哪一个设备的中断信号呢?这都通过另外一个芯片来控制,在IBM PC机中,这个芯片常常被称作:可编程中断控制器(PIC)8259A,说它可编程,是因为我们可以通过编程来改变它的功能。比如我可以通过编程设定CPU应当优先响应哪一个中断,屏蔽哪些中断等等一系列事件。它的结构图如下。
从图中可以看到,一个8259A芯片的组成可以分为5个主要的逻辑控件:中断屏蔽寄存器(IMR)、中断请求寄存器(IRR)、优先级仲裁单元(Prioriry Resolver)、中断向量寄存器(ISR)和控制逻辑单元(Control Logic)。一个8259A芯片有IRQ0~IRQ7七个IRQ引脚,一个IRQ对应着一个中断号,一个中断号对应着一个中断向量,一个中断向量对应着一个中断处理子程序(ISR,注意这个ISR是Interrupt Service Routine的缩写)。
也许你已经对硬件级的中断处理过程猜到个大概了,当一个IRQ接收到一个外部中断信号后处理的流程应该是以下几个步骤:
1.IMR判断该中断是否被屏蔽掉(IMR中相应的位置1)了,如果被屏蔽掉了结束处理,否则跳转到第2步;
2.将收到的中断请求保存到IRR中(IRR中相应的位置1,IRR相当于一个缓存,用来保存等待CPU处理的中断信号),等待CPU当前指令执行结束后向8259A发送INTA信号,表示现在CPU可以处理中断请求了,此时IRR相应位被reset,然后跳转到第3步;
3.PR根据等待处理的中断信号对应的IRQ,选择最高优先级的中断信号进行处理,IRQ0优先级最高,接着是IRQ1、IRQ2……然后跳转到第4步;
4.CPU向8259A发送INTA信号,要求被告知IRQ对应的中断号,然后根据中断号到IDT中找到相应的中断向量,跳转到对应的中断处理子程序(中断向量和中断处理了程序是什么?后面会说到,这里你只把它们当成是一个函数调用就可以了)入口地址开始执行,此时中断号对应的ISR中位被set(IRR被reset和ISR被set的过程是对应的),如果此时有更高优先级的中断信号等待处理,跳转到第3步。
值得注意的是,第2步中有个细节“等待CPU当前指令执行结束后……”,往常我们理解的中断是,当CPU接收到一个中断信号时会立即响应。其实不完全是这样的,CPU需要将当前正在执行的指令执行完毕才会响应中断。
罗罗嗦嗦到现在,IRQ跟中断号到底有什么区别啊?你能想到这个问题说明你的思考过程还没跑题,比我强多了!一般我看东西时,看着看着就把初衷给忘了……
如果IRQ还算能好理解点,那么中断号就稍稍抽象一点,中断号是可编程的,也就是说一个IRQ对应着哪个中断号由咱们程序员说得算(一种God的感觉油然而生)。默认情况下,IRQ对应的中断号是由BIOS初始化的,IRQ0~IRQ7对应着中断号0x8~0xF。而可编程表现在,我们可以将IRQ0对应的中断号修改成0~255中的任意一个数,我们设为INT_NUM,然后IRQ1~IRQ7对应的中断号就跟着变成INT_NUM+1~INT_NUM+7了。举个例子,我们将IRQ0对应的中断号改到0x10,那么IRQ1对应的中断号就是0x11、IRQ2的是0x12……IR7的是0x17。
说到这里,你应该明白了IRQ和中断号是个什么,以及它们之关的关系了。然后你又有问题了,我们可以设置IRQ对应的中断号,but how?你爷爷的,又跟我想一块儿去了,咱俩可以去拜把子了!
既然8295A是个芯片,那么自然需要程序员来做一起配置的工作,当然修改IRQ对应的中断号也算一种配置了!对8259A的编程是通过向其相应的端口发送一系列的ICW(初始化命令字)完成的。总共需要发送四个ICW,它们都分别有自己独特的格式,而且必须按次序发送,并且必须发送到相应的端口,主片的端口号为0x20,从片的端口号为0xA0。那么从片又是啥?咋这么多不懂的呢,唉……
从片是个啥?怎么设置IRQ与中断号的对应关系?
一个8259A芯片的可以接最多8个中断源,但由于可以将2个或多个8259A芯片级连(cascade),并且最多可以级连到9个,所以最多可以接64个中断源。早期,IBM PC/XT只有1个8259A,. 但设计师们马上意识到这是不够的,于是到了IBM PC/AT,8259A被增加到2个以适应更多外部设备的需要,其中一个被称作Master,另外一个被称作Slave,Slave以级连的方式连接在Master上。如今绝大多数的PC都拥有两个8259A,这样最多可以接收15个中断源。两个8259A芯片级连如下图所示。
从片弄明白了,IBM的工程师原来也是有时代局限性的,不会用发展的眼光看问题啊……言归正传,上面说了我们可以通过4个ICW1~ICW4可配置8259A,IRQ与中断号的对应就是通过ICW2(一个8位的数)来完成的。
ICW2:发送到0x21(主片)及0xA1(从片)端口
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
A7 | A6 | A5 | A4 | A3 | 0 | 0 | 0 |
ICW2用来指示出IRQ0使用的中断号是什么,因为最后三位均是零,因此要求IRQ0的中断号必须是8的倍数,这又是一个很巧妙的设计。因为IRQ1的中断号就是IRQ0的中断号+1,IRQ2的中断号就是IRQ0的中断号+2,……,IRQ7的中断号就是IRQ0的中断号+7,刚好填满一个8个的中断向量号空间。
到这里,基本弄明白中断硬件级的原理了,至于其他的三个ICW,各位看官可以参考张昆藏的《IBM PC/XT微型计算机接口技术》,不错的一本书。
最后一个问题了,中断向量是个什么东西?
我所理解的中断向量
中断向量实际上就是中断号,一般是可以这么理解的,但是按我的习惯(请允许我修改下概念),我把中断向量理解为中断号与中断服务子程序的一个映射,如果用y表示中断服务子程序、x表示中断号,那么y=f(x)中的运算法则f就是中断向量了。中断向量实际上就是一个程序入口,很多时候中断向量就是一个jmp指令(看官可以思考一下,这里为什么不用call),例如jmp isrClock,跳转到相应的中断处理子程序(例子里的isrClock);而中断向量表就是所有中断向量组成的一张表,对应到代码就是N个jmp指令。当CPU根据IRQ获得中断号的时候,就会计算“中断向量表的起始地址+中断号”得到相应的中断向量,然后进行跳转。
好了,说到这里各位看官也许已经看烦了,其实学习的过程是很枯燥的,但是成功的人会很享受这种枯燥,这也是我们差的那一步!
一句话,学习的过程中应该能够“耐得住寂寞,经得起诱惑……”
注:以下源自张昆藏的《IBM PC/XT微型计算机接口技术》,讲了下模块设计规则,大家可以看下。他就把中断号和中断向量理解为一个概念,很多书中也都是这么讲的,千万不要因为我的理解而出现混淆。
这里出现了一个中断向量的概念,其实它就是一个被送往CPU数据线的一个整数。CPU给每个IRQ分配了一个类型号,通过这个整数,CPU来识别不同类型的中断。这里可能很多朋友会寻问为什么还要弄个中断向量这么麻烦的东东?为什么不直接用IRQ0~IRQ15就完了?比如就让IRQ0为0,IRQ1为1……,这不是要简单的多么?其实这里体现了模块化设计规则以及节约规则。
首先我们先谈谈节约规则,所谓节约规则就是所使用的信号线数越少越好,这样如果每个IRQ都独立使用一根数据线,如IRQ0用0号线,IRQ1用1号线……这样,16个IRQ就会用16根线,这显然是一种浪费。那么也许马上就有朋友会说:那么只用4根线不就行了吗(24=16)?
对于这个问题,则体现了模块设计规则。我们在前面就说过中断有很多类,可能是外部硬件触发,也可能是由软件触发,然而对于CPU来说中断就是中断,只有一种,CPU不用管它到底是由外部硬件触发的还是由运行的软件本身触发的,因为对于CPU来说,中断处理的过程都是一样的:中断现行程序,转到中断服务程序处执行,回到被中断的程序继续执行。CPU总共可以处理256种中断,而并不知道,也不应当让CPU知道这是硬件来的中断还是软件来的中断,这样,就可以使CPU的设计独立于中断控制器的设计,因为CPU所需完成的工作就很单纯了。CPU对于其它的模块只提供了一种接口,这就是256个中断处理向量,也称为中断号。由这些中断控制器自行去使用这256个中断号中的一个与CPU进行交互。比如,硬件中断可以使用前128个号,软件中断使用后128个号,也可以软件中断使用前128个号,硬件中断使用后128个号,这于CPU完全无关了,当你需要处理的时候,只需告诉CPU你用的是哪个中断号就行,而不需告诉CPU你是来自哪儿的中断。这样也方便了以后的扩充,比如现在机器里又加了一片8259芯片,那么这个芯片就可以使用空闲的中断号,看哪一个空闲就使用哪一个,而不是必须要使用第0号,或第1号中断。其实这相当于一种映射机制,把IRQ信号映射到不同的中断号上,IRQ的排列或说编号是固定的,但通过改变映射机制,就可以让IRQ映射到不同的中断号,也可以说调用不同的中断服务程序,因为中断号是与中断服务程序一一对应的,这一点我们将在随后的内容中详细描述。8259A将中断号通知CPU后,它的任务就完成了,至于CPU使用此中断号去调用什么程序它就不管了。
本文出自 “New World” 博客,请务必保留此出处http://snower.blog.51cto.com/2918921/557678