8259A中断控制器,如名字所说,是用来处理中断的。
它有如下的特性:
1. 单片支持8个中断,可多片扩展,最多扩展到64个中断;
2. 可编程的中断模式;
3. 可配置中断屏蔽;
4. 中断分优先级;
8259A是一款非常老的芯片,适配8086/8088芯片,目前基本上不再使用。
因此本文是属于考古文,新程序员请在古董程序员陪同下阅读...
本文参考自《8259A PROGRAMMABLE INTERRUPT CONTROLLER》以及EDK代码。
下图是8259A的逻辑框图:
由于软件上不需要关注过多硬件方面的内容,所以这里只是简单介绍各个引脚以及功能模块。
1. IRQ1-IRQ7:这是中断引脚,连接外部设备;
2. D0-D7:数据传输通道,8259A会通过它与系统交换控制字,状态字,中断向量等信息;
3. CAS0-CAS2:级联额外的8259控制器以扩展中断,由于是3位,所以最多能够连接8个额外的8259A控制器;
4. CS:片选信号,低有效,此时RD/WR选通;
5. INT:与CPU的中断引脚连接,用于触发CPU中断;
6. INTA:用于通知8259A上传中断向量信息;
7. A0:跟CS/WR/RD一起使用,用来区分CPU发过来的命令的意义,它跟CPU的A0地址线相连,后续初始化8259A的时候会具体说明。
8. WR:低有效,此时CPU可以向8259A发送控制字;
9. RD:低有效,此时8259A向CPU发送状态字或中断信息。
中断请求寄存器(IRR):当中断进来之后,对应的中断请求寄存器位会被置位;
中断服务寄存器(ISR):中断寄存器中对应的置位表示当前中断正在处理;
优先级处理器:当多个中断同时触发时,判断那个中断会被优先处理;
中断掩码寄存器:用于屏蔽某些中断,使其不被触发;
1. 一个或多个中断从IRQ0-7中送入(中断线拉高),对应IRR被置位;
2. 8259A评估这些中断,如果有需要通过INT发送中断给CPU;
3. CPU收到INT之后,发送INTA给8259A;
4. 收到INTA之后,优先级最高的中断对应的ISR位被置位,对应的IRR被复位;
5. CPU再次发送INTA,8259A释放地址线并传输8位中断向量给CPU:
这里的中断向量低三位是可变的,高五位不同的片选配置不同,但是是固定的,需要通过ICW2来配置。
6. 中断结束,之后如果是在AEOI模式,ISR对应位会被复位,否者直到收到EOI命令,ISR对应位才会被复位。
8259A的编程包括两类,一种是初始化命令字(ICW),用于初始化控制器;另一种是操作命令字(OCW),用于设置模式(初始化之后配置,任何时候都可以修改)。
8259A的初始化需要使用若干个ICW,x86平台下通过特定IO口写入这些ICW来初始化8259控制器。
ICW1在A0=0,D4=1的情况下使用,它启动8259A的自动初始化。
ICW1中还包括其它的配置位,具体如下:
ICW1之后是配置ICW2:
T7-T3是8259A传输给CPU的中断向量的高5位。
之后是ICW3,它在主片和从片中的配置不同:
最后是ICW4,它需要根据ICW1中的某个位来确定是否需要配置:
之前提到的AEOI的配置就在这里。
下面是配置的流程:
对于级联的情况,我们需要配置其中的每一片。
x86模式下通常使用的是主从两片,对应的初始化代码如下:
//
// Set vector base for slave PIC
//
if (SlaveBase != mSlaveBase) {
mSlaveBase = SlaveBase;
//
// Initialization sequence is needed for setting vector base.
//
//
// Preserve interrtup mask register before initialization sequence
// because it will be cleared during initialization
//
Mask = IoRead8 (LEGACY_8259_MASK_REGISTER_SLAVE);
//
// ICW1: cascade mode, ICW4 write required
//
IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE, 0x11);
//
// ICW2: new vector base (must be multiple of 8)
//
IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, mSlaveBase);
//
// ICW3: slave indentification code must be 2
//
IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, 0x02);
//
// ICW4: fully nested mode, non-buffered mode, normal EOI, IA processor
//
IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, 0x01);
//
// Restore interrupt mask register
//
IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, Mask);
}
//
// Set vector base for master PIC
//
if (MasterBase != mMasterBase) {
mMasterBase = MasterBase;
//
// Initialization sequence is needed for setting vector base.
//
//
// Preserve interrtup mask register before initialization sequence
// because it will be cleared during initialization
//
Mask = IoRead8 (LEGACY_8259_MASK_REGISTER_MASTER);
//
// ICW1: cascade mode, ICW4 write required
//
IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER, 0x11);
//
// ICW2: new vector base (must be multiple of 8)
//
IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, mMasterBase);
//
// ICW3: slave PIC is cascaded on IRQ2
//
IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, 0x04);
//
// ICW4: fully nested mode, non-buffered mode, normal EOI, IA processor
//
IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, 0x01);
//
// Restore interrupt mask register
//
IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, Mask);
}
主片对应的IO地址是20h/21h,从片对应的地址是A0h/A1h。
这里需要一对寄存器来处理,并且只有低四字节有差(0和1),这跟前面提到的A0管脚相关。
当ICW初始化8259A控制器之后,它就可以正常接收中断。
不过此后我们还是可以通过OCW来配置8259A的模式。
OCW共有三个。
OCW1用于设置中断屏蔽:
OCW2用于设置中断模式:
OCW3用于设置屏蔽模式:
写入OCW的地址不同:
OCW需要使用x1h的地址,其它需要使用x0h的地址。
关于OCW的代码,实在在前面的代码中已经设置了OCW1,后面还会设置OCW2:
IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE, LEGACY_8259_EOI);
IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER, LEGACY_8259_EOI);
目前只设置了EOI,即需要通过CPU发送EOI命令,ISR对应位才会复位。
老的x86设备中不一般使用主从模式两片8259A控制器,组成的中断控制器中有15个中断:
这些中断的作用比较固定,在早起IBM的PC-AT设备中,中断的分配如下:
即使到现在,所以8259A不再使用,某些设备的中断还是没有改变,比如串口还是会使用到IRQ4,虽然实现的手段已经不同。
以上是对8259A中断控制器的介绍。
由于水平有限,某些说明可能存在问题,请见谅。