一、基本概念和分类
计算机在执行程序的过程中,有时会遇到一些异常情况或者特殊请求;这时就需要计算机暂停正在运行的程序,转而先去处理这些异常或特殊请求,处理结束之后再返回程序的断点处继续执行。这种处理方式就被称为 "中断 ",计算机的这种功能就称为 中断处理 ;实现这种功能所需的软硬件技术统称为 中断技术。
很显然,对于一些突发情况和实时传来的外部信号,相比时刻查询的方式,使用中断技术可以大大地提高计算机的整体效率。
能够引发中断的因素有很多,比如电源掉电、打印机请求、运算溢出、缺页 等等。通常将能够引起中断的各种因素称为 中断源。根据各种中断源的类型,可以对中断进行不同的分类。
1.中断和异常
从中断的来源看,直观上可以分成两类:一类是由外部设备向 CPU 发出的请求(比如打印),或者突发的外部事件或环境对计算机造成了影响(比如电源掉电),在 CPU 外部产生;另一类是 CPU 在执行指令时遇到的异常情况,在 CPU 内部产生。
通常将 CPU 内部产生的中断称为 异常(Exception) ,也称作 内中断 。异常一般是 CPU 的控制单元(CU)在执行指令时遇到了意外情况、因而必须暂停处理;由于一定会在一条指令执行结束后才发出中断,因此也被叫做 同步中断。
与之对应,来自于 CPU 外部其它硬件设备的中断,就被称为 外中断 ,或者直接叫做(狭义的) 中断(Interrupt) 。它们通常是外部设备依照 CPU 时钟随机产生的,因此也被叫做 异步中断。
事实上,对于中断(狭义)和异常,CPU 的处理流程都是先中止当前正在执行的程序、转而去执行相应的中断处理程序(称为 "中断服务程序 "),完成中断响应之后,再回到断点处继续执行。因此,一般可以把它们统称为(广义的)中断。
2.中断和异常的分类
中断请求并不一定都非常急迫、必须立刻响应。CPU 可以对中断进行判别、选择,屏蔽某些中断源的请求;根据是否可以被屏蔽,中断(狭义)又可以分成两类:
-
可屏蔽中断:可屏蔽中断有 "屏蔽" 和 "非屏蔽" 两种状态;处在屏蔽状态的中断,CPU 将不予以响应。I/O 设备的中断请求都属于可屏蔽中断。
-
不可屏蔽中断:一些急迫事件 CPU 必须予以响应,发出的中断不能屏蔽。例如电源掉电就属于不可屏蔽中断。
而对于异常,由于它跟指令的执行有关,因此根据中断处理完成后、接下来指令执行的情况,可以进一步进行分类:
-
故障(Fault):通常可以纠正,一旦纠正则程序可以重新执行原先产生中断的那条指令;也称为 "程序性事故"。例如运算溢出、缺页异常。
-
陷阱(Trap):这种异常是人为设置的,表示自愿停止现行程序、转入中断处理,因此也叫 "自愿中断"、"自陷"。一般计算机中都会设置陷阱指令,执行到它就会转至别处做特殊处理,完成之后就返回到陷阱指令的下一条指令继续执行。例如调试程序时的断点设置、执行系统调用等。
-
异常中止(Abort):如果发生了严重的错误,程序无法继续执行,那么就只能把控制权交给异常中止处理程序;而现行程序只能强制停止运行。例如硬件故障、系统表中无效的值等。
3.中断系统
中断改变了计算机执行程序的顺序,因此需要 CPU 进行特别的处理。为了实现中断处理的功能,CPU 中一般会设置专门的处理机构,这就是 中断系统。
中断系统主要需要解决以下一些问题:
-
中断源怎样向 CPU 发出中断请求;
-
当有多个中断源同时发出请求时,怎样确定响应顺序;
-
CPU 怎样响应中断请求;
-
CPU 响应中断之后,怎样保护现场;
-
CPU 响应中断后,怎样暂停原程序的执行、找到中断服务程序的入口地址;
-
中断处理结束后,CPU 如何恢复现场、返回原程序的断点处;
-
如果中断处理时又有新的中断请求,应该怎样处理。
接下来我们就通过学习中断系统,来解决这些问题。
二、中断的检测
在 CPU 的指令周期中,最后一个阶段就是 中断周期 。在一条指令执行阶段的最后时刻,CPU 会发出 中断查询信号,检测是否有中断请求。如果有,则进入中断周期进行中断处理。
1.中断请求标记
不同的中断源都可以向 CPU 发出中断请求,为了区分中断源,中断系统中会专门设置一个 中断请求标记触发器 ,简称 中断请求触发器 ,用 INTR 表示。当某个中断源的触发器 INTRi 为 "1" 时,就表示该中断源发来了请求。
这些触发器可以分散在各个中断源的接口电路中,也可以集成在 CPU 中,组成一个 中断请求标记寄存器。
寄存器里的每一位就对应着一个中断源的请求触发器。任意一个触发器为 1,就表示对应的中断源发出了中断请求。
2.中断判优
在中断系统中,同一时刻只能响应一个中断源的请求。如果有多个中断源同时发出了请求,那就需要中断系统按照设定好的优先顺序来依次响应;这被称为 中断判优。中断源的优先级是依据重要性和急迫性而定的。
中断判优就是要对一组中断请求按优先级进行 "排队",可以用硬件和软件两种方式实现。
(1)硬件排队
硬件排队是直接用硬件电路实现中断请求的排队,具体方法很多,主要有两种:一种是在 CPU 内统一设置一个 "排队器";另一种是在中断源设备的接口电路中分别设置排队器。
在 CPU 内设置排队器:各中断源的请求触发器按优先级依次排列,高优先级的请求信号通过接入一个多输入的与非门,来 "封住" 低优先级的中断请求。
在接口电路中设置排队器:每个接口电路中都设置一个反相器和一个与非门,与非门的输出接入下一级,就可以实现对更低优先级中断请求的封锁。它们彼此之间直接连成链状,因此也称为 "链式排队器"。
(2)软件排队
软件排队,就是直接通过编写查询程序实现中断请求的排队。
程序按照中断源的优先级,从高到低依次判断是否有中断请求,这样就保证了中断响应的顺序。
三、中断的响应
1.中断响应的条件
由于在处理中断时,CPU 不应受到新中断请求的打扰,因此需要有 "开关中断" 的功能。在中断系统中,这是由 允许中断触发器 EINT 和专门的指令来实现的。
EINT 可以被 开中断指令 置 "1",这时表示 CPU 打开了中断功能,允许响应中断源的请求;EINT 也可以被 关中断指令 置 "0",这意味着 CPU 关闭中断功能,禁止响应中断。
在 x86 架构的 CPU 中,EINT 就对应着 标志寄存器 (程序状态字)efl 中的一位,用 IF 表示。
因此可以总结,当 EINT = 1 且有中断请求(INTRi = 1)时,CPU 就可以响应中断。
2.中断响应的时间
很多情况下中断请求的产生是随机的,为了不影响 CPU 的正常工作,需要周期性地在统一的时刻由 CPU 发出中断查询信号,判断当前是否有中断请求。
因此 CPU 响应中断的时间,一定是在每条指令执行阶段的结束时刻;相当于在指令周期最后又加入了一个阶段,这就是 中断周期。执行周期结束后,如果有中断请求,则 CPU 进入中断周期;如果没有则直接进入下一条指令的取指周期。
3.中断响应的过程
CPU 响应中断之后,就会进入中断周期。在中断周期 CPU 会执行一系列的操作,这些操作都是由一条 中断隐指令 完成的。所谓的隐指令,指的是指令系统中本身没有这条指令,它是由硬件自动完成的。具体操作如下:
(1)保护程序断点
将当前 PC 的内容(程序断点位置)保存到主存中。可以存入特定的某个地址(比如 0 地址),也可以存入堆栈中。
(2)寻找中断服务程序的入口地址
在中断周期内,可以用两种方法寻找中断服务程序的入口地址:硬件向量法和软件查询法,分别对应着硬件和软件实现。
(3)关中断
为了在响应中断后,不受到新的中断请求的干扰,在中断周期需要自动做 "关中断" 的操作,禁止 CPU 再次响应中断请求。关中断的具体操作就是将允许中断触发器 EINT 置 "0",一般直接由硬件电路实现。
对应的微操作如下:
四、中断服务程序
1.中断服务程序的入口地址
不同的中断请求,需要执行不同的中断服务程序。寻找中断服务程序的入口地址,通常可以采用两种方法:硬件向量法 和 软件查询法。
(1)硬件向量法
所谓硬件向量法,就是使用硬件直接产生一个 向量地址,再用这个向量地址找到中断服务程序的入口地址。向量地址由中断向量地址形成部件产生。
中断向量地址形成部件的输入,是来自排队器的输出 INTPi ,它的输出则是一个二进制的 中断向量。一般可以让一个中断源对应一个向量地址,因此这个部件本质上就是一个编码器。
通过向量地址寻找中断服务程序入口地址可以采用两种方法。
-
在向量地址对应内存单元放一条 无条件转移指令。这样 CPU 响应中断时,只要将向量地址交给 PC,然后执行这条指令,就可以跳转到中断服务程序入口地址了。
-
设置 向量地址表。向量地址表存放在主存中,向量地址就是对应存储单元的地址,而存放的内容就是中断服务程序的入口地址。
硬件向量法寻找入口地址速度快,现代计算机中普遍使用这种方法。
(2)软件查询法
用软件寻找中断服务程序入口地址的方法,就叫做软件查询法。各个中断源对应的入口地址,是由程序员(或系统)预先定好、写入程序的;可以结合软件排队的中断判优,确定要响应某个中断请求时,直接跟上一条转移指令、跳转至定义好的入口地址就可以了。
软件查询法不涉及硬件,更加容易维护和扩展,但查询的时间更长。
2.中断服务程序的流程
不同的中断请求对应的中断服务程序不同,不过它们的处理流程是类似的,一般包括 保护现场 、中断服务 、恢复现场 和 中断返回 4 个部分。
(1)保护现场
保护现场通常包含两层含义:一是保存程序的断点,这由中断隐指令完成;二是保存通用寄存器和状态寄存器的内容,这需要中断服务程序完成。
具体操作就是在中断服务程序的起始部分,安排几条存数(Store)指令,将寄存器的内容全部保存到主存中;或者直接用入栈(Push)指令将寄存器内容推入栈中。
(2)中断服务
中断服务是中断服务程序的主体部分,针对不同的中断源,需要做出对应的操作内容。
(3)恢复现场
中断服务程序的结尾部分,还需要恢复现场。对应着之前的保护现场,这一步可以用取数(Load)指令或者出栈(Pop)指令,将保存在主存中的信息恢复到寄存器中。
(4)中断返回
中断服务程序的最后一条指令,通常是一条 中断返回指令,从而返回到原程序的断点处继续执行。
如果在 CPU 执行中断服务程序时,又来了一个新的中断请求,这时有两种处理方式:一种是直接不予响应,即 CPU 在响应中断的过程中保持 "关中断" 状态,直到中断服务程序执行结束、返回之前才开中断;另一种则是 CPU 立即响应新的中断请求,这需要在中断服务程序的开始阶段 "开中断"。
五、中断屏蔽技术
1.多重中断
如果 CPU 在响应某个中断请求的时候,另一个中断源又提出了一个新的中断请求;而 CPU 立即响应这个请求,暂停正在运行的中断服务程序、转而去运行新的中断服务程序,这就是 中断嵌套 ,也称为 多重中断 。 与之对应,如果 CPU 在响应中断时不去响应新的中断请求,则称为 单重中断。
实现多重中断,需要满足两个基本条件:
- 提前设置 "开中断" 指令
由于进入中断周期后,中断隐指令会自动将 EINT 置为 0,因此默认会关中断、不再响应新的中断请求;这时如果希望处理多重中断,就必须在中断服务程序的开始阶段设置 "开中断" 指令来打开中断。
- 优先级高的中断源有权中断优先级低的中断源
只有优先级别更高的中断源,才能打断正在执行的中断服务程序、优先被响应。
例如,有 A、B、C、D 四个不同的中断源,优先级为 A > B > C > D。在 CPU 执行程序时,在某个指令周期,同时查询到了 B、C 发来的中断请求;之后在执行中断服务程序的过程中,又先后查询到了 D、A 的请求。那么如果允许多重中断,中断处理的时间顺序如下:
中断请求如果同时到来(比如上例中的 B、C),我们可以进行中断判优、利用排队器决定它们的先后顺序。但对于多重循环,还需要在中断响应过程中继续判断优先级、决定是否可以打断当前的中断服务程序。这是通过 中断屏蔽技术 来实现的。
2.中断屏蔽触发器
为 了实现对每个中断源的屏蔽,可以在中断请求触发器 INTR 之前增设一个 中断屏蔽触发器 MASK。当 MASK 为 "1" 时,表示该中断源被屏蔽,中断请求不被响应。
屏蔽触发器同样既可以设置在接口电路中、也可以直接集成在 CPU 内。以 I/O 设备作为中断源为例,I/O 设备的接口电路中会有一个 完成触发器 D,它为 "1" 则表示设备已经处于就绪状态、要向 CPU 发出中断请求了。一般情况下,D 的输出可以直接接到中断请求触发器 INTR 的输入;现在则可以与 MASK 的输出经与非门之后、再交给 INTR。
这样,当设备已经准备就绪(D = 1),且设备未被屏蔽(MASK = 0)时,来自 CPU 的中断查询信号就会将 INTR 置 "1",表示该设备发出了中断请求信号。
同样,排队器内也可以加上屏蔽条件,就组成了具有屏蔽功能的排队器。例如集成在 CPU 内的排队器如果加上屏蔽功能,只需要另外将屏蔽信号也接入与非门就可以了:
3.屏蔽字和屏蔽技术
显然,对于每个中断源,中断请求触发器 INTR 和 中断屏蔽触发器 MASK 都是成对出现的。如果将所有屏蔽触发器组合在一起,也可以构成一个 屏蔽寄存器 。屏蔽寄存器的内容就称为 屏蔽字。
屏蔽字可以在中断服务程序中进行设置,屏蔽字和中断源的优先级是一一对应的。以 16 个中断源 I1 ~ I16 的屏蔽字为例,每个屏蔽字都是 16 位:
在不同中断源的中断服务程序中,可以设置适当的屏蔽字,就能对优先级不同的中断源进行屏蔽。
例如,在 I~1~ 的服务程序中,将屏蔽字设为全 1,就表示它的优先级最高:在响应 I~1~ 中断请求的过程中,不会再去响应任何新的请求(包括 I~1~ 自己发来的);这相当于就是单重中断。而对于 I~3~ ,在服务程序中将屏蔽字前两位设为 0、后面为 1,表示 I~1~、I~2~ 优先级更高、不被屏蔽,而后面的中断源(包括自己)被屏蔽;于是开中断之后,I~1~、I~2~ 发来的新中断请求就可以打断当前 I~3~ 的中断服务程序,实现了多重中断。
4.改变处理优先级
使用屏蔽技术还可以改变中断源的优先等级。中断源的优先级,包括两层含义:响应优先级 和 处理优先级。
-
响应优先级:CPU 响应各中断源请求的先后次序,跟排队器有关,一般是硬件线路设定好的,不易改动;
-
处理优先级:CPU 实际执行中断服务程序的先后次序,可以通过屏蔽技术进行改动。
如果不采用屏蔽技术,那么处理的优先顺序就是按照响应优先级来的。例如,A、B、C、D 四个中断源,优先级别为 A > B > C > D,根据这一次序设计出排队器之后,当它们同时发来中断请求时,处理顺序就是响应顺序:
如果采用了屏蔽技术,就可以在不改变响应顺序的前提下,改变 CPU 处理中断的顺序。假如我们希望将它们的处理次序改为 A → D → C → B,那么每个中断源的中断服务程序中应该重新设置屏蔽字:
这样,同样还是 A、B、C、D 同时发出中断请求,这时的处理顺序就会变为:
显然,采用屏蔽技术改变处理优先级,需要在中断服务程序中重置屏蔽字。这样,中断服务程序的处理流程就会变为:
跟之前相比,增加了 置屏蔽字 和 恢复屏蔽字 两步操作。而为了防止在恢复阶段又出现新的中断,需要先关中断、等到恢复现场和屏蔽字之后再次开中断。