一 8259A 结构图
I. 主片结构 (IBM PC/XT)
II. 主从结构 (IBM PC/AT)
III. 微机结构 (IBM PC/AT)
二 8259A pin脚介绍
- CS:片选信号,只有CS有效时,CPU才能进行读写操作
- WR:写信号,当WR有效且CS有效时,wr使8259A接受CPU送来的命令字
- RD:读信号,当RD有效且CS有效时,使8259A将状态信息放到数据总线供CPU检测
- D7~D0:双向数据总线,用来传送控制字、状态字和中断类型号
- IR7~IR0:外部接口电路中断请求信号
- INT:向CPU发出中断请求信号
- INTA:中断响应信号,接受CPU发来的中断响应脉冲
- A0:地址输入信号,主片(偶地址为0x20,奇地址为0x21),从片(偶地址为0xA0,奇地址为0xA1)
- CAS2~CAS0:级联线,指定从片
- SP/EN:从片/允许缓冲器 信号,作为输入时,SP=1为主片,SP=0为从片;作为输出时,EN=1可以启动数据总线收发器(8286)
三 8259A 部件作用
- IRR(Interrupt Request Register):接受并锁存来自IR0~IR7的中断请求信号
- PR(Priority Resolver):把新进入的中断请求和当前正在处理的中断请求进行比较,以决定哪一个优先级更高
- ISR(In-Service Register):保存当前正在处理的中断请求
- IMR(Interrupt Mask Register):可以屏蔽IRR中的中断请求信号
- ICWs(Initialization Command words):初始化命令字,用于8259A芯片的初始化设定
- OCWs(Operation Command words):操作命令字,在8259A工作时可以对它进行动态管理和控制
四 8259A 中断处理过程
- 向CPU发送中断请求:IR0~IR7出现中断请求信号 -> IRR对应位置位 -> IMR相应位决定是否屏蔽此信号 -> 中断请求进PR -> PR把新进入的中断请求和ISR中当前正在进行处理的中断进行优先级比较 -> 若新进入的中断优先级高,则把该中断请求发送给CPU
- CPU响应中断请求:若CPU的IF为1,则在完成当前指令后,相应中断请求,在INTA引脚上发出两个负脉冲,
1. 收到第一个脉冲后:> IRR锁存允许,禁止来自IR0~IR7的中断请求,> ISR相应位置位,> IRR相应位复位
2. 收到第二个脉冲后:> IRR锁存禁止,允许来自IR0~IR7的中断请求,> 把中断类型码寄存器(ICW2)的内容送到D7~D0数据总线上,> 若AEOI(自动结束中断)置位,则ISR中对应的位复位
五 8259A 工作方式
I. 中断优先级方式
- 全嵌套方式:固定优先级方式,IR0最高,IR7最低,禁止同级或低级的中断响应
- 特殊全嵌套方式:和全嵌套方式一样,但它允许同级的中断响应
- 优先级自动循环方式:优先级循环变化,开始时,优先级顺序为IR0 -> IR7,若此时IR3被PR选中发送了中断请求,那么优先级顺序变为IR4 -> IR7 -> IR3,即被响应的中断变成了最低级,而比它低一级的中断变成了最高级
- 优先级特殊循环方式:和优先级自动循环方式一样,但它允许设置开始时的最低优先级,如IR4被设为最低优先级,那么IR5就是最高优先级
II. 中断屏蔽方式
- 普通屏蔽方式:通过IMR来屏蔽,相应位置位则屏蔽相应的中断请求
- 特殊屏蔽方式:*
III. 中断结束方式(END OF INTERRUPT - EOI)
- 中断自动结束方式(AEOI):在INTA的第二个脉冲的后沿把对应的ISR位复位
- 常规中断结束方式:通过向8259A发送常规中断结束命令,适用于全嵌套方式,因为只需把ISR中最高优先级复位
- 特殊中断结束方式:和常规中断结束方式一样,但可以指定复位ISR中的哪一位
IV. 中断触发方式
- 电平触发方式:*
- 边沿触发方式:*
V. 连接系统总线方式
- 缓冲方式:8259A通过总线驱动器(8286)和数据总线相连,EN=1有效,由ICW4的M/S位来标识是主片还是从片
- 非缓冲方式:8259A直接与数据总线相连,SP=1为主片,SP=0为从片
六 8259A 控制字编程
I. 初始化命令字
- ICW1:A0=0,D4=1
D0. IC4:初始化时是否写入ICW4,0不写入,1写入
D1. SNGL:是否使用级联,0为级联方式同时要写入ICW3,1为单片方式不要写入ICW3
D2. ADI:*
D3. LTIM:中断触发方式,0为边沿触发,1为电平触发
D4=1
D7~D5. A5~A7:*
- ICW2:A0=1
D2~D0. :中断类型码的低3位,表示IR0~IR7
D7~D3. :中断类型码的高5为,初始时设定
- ICW3:A0=1,只在级联方式中使用
1. 对于主片:表示IR0~IR7中哪些引脚接有从片,那么相应位置位
2. 对于从片:用D2~D0位来表示接到主片的哪一根IR引脚上
- ICW4:A0=1,80x86系统中必须设定它
D0. uPM:规定是哪种系统,0为8080/8085,1为80x86系统
D1. AEOI:中断结束方式,0为非自动结束方式,1为自动结束方式
D3,D2. BUF,M/S:> BUF=1,缓冲方式,EN=1启动数据总线收发器,M/S决定使用主片还是从片,1是主片,0是从片,> BUF=0,非缓冲方式,SP=1为主片,SP=0为从片,M/S位无效
D4. SFNM:中断优先级方式,0为全嵌套方式,1为特殊全嵌套方式
D7~D5. :0
II. 操作命令字
- OCW1:A0=1
D7~D0. M7~M0:中断屏蔽码,对应IR7~IR0
- OCW2:A0=0,D4=0,D3=0
D7. R:中断优先级方式是否按循环方式设置,1为循环方式,0为非循环方式
D6. SL:表示L2~L0是否有效,1为有效,0为无效
D5. EOI:中断结束命令(中断非自动结束方式),EOI=1把ISR中对应位复位
D4=0
D3=0
D2~D0. L2~L0:选择结束哪个中断
- OCW3:A0=0,D4=0,D3=1
D7. :0
D6,D5. ESMM,SMM:ESMM特殊屏蔽方式允许位,SMM特殊屏蔽方式位
D4=0
D3=1
D2. P:查询命令,P=1读中断状态字
D1,D0. PR,RIS:11表示读ISR,10表示读IRR
III. 读取命令字
- IMR:用奇地址直接读取,比如’in $0x21,al‘读取主片的IMR
- IRR:设置OCW3中PR=1,RIS=0,在用偶地址直接读取,比如’in $0x20,al‘读取主片的IRR
- ISR:设置OCW3中PR=1,RIS=1,在用偶地址直接读取,比如'in $0x20,al'读取主片的ISR
- 中断状态字:设置OCW3中P=1,在用偶地址直接读取,比如’in $0x20,al‘读取主片的中断状态字
七 code部分
- boot/setup.S
# well, that went ok, I hope. Now we have to reprogram the interrupts :-( # we put them right after the intel-reserved hardware interrupts, at # int 0x20-0x2F. There they won't mess up anything. Sadly IBM really # messed this up with the original PC, and they haven't been able to # rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f, # which is used for the internal hardware interrupts as well. We just # have to reprogram the 8259's, and it isn't fun. # initialization start # ICW1 for master, A0=0, D4=1 # D7~D5=0 # D4=1 # D3=0, LTIM=0, edge trigger # D2=0, ADI=0 # D1=0, SNGL=0, multichip # D0=1, IC4=1, ICW4 need mov $0x11,%al # initialization sequence out %al,$0x20 # send it to 8259A-1 # 'eb 00': jmp rel8, mean that jmp to [IP+0](the next assembly instruction) .word 0x00eb,0x00eb # jmp $+2, jmp $+2 # ICW1 for slaver out %al,$0xA0 # and to 8259A-2 .word 0x00eb,0x00eb # ICW2 for master, A0=1 # D7~D3 + D2~D0 = 0x20 + IRx mov $0x20,%al # start of hardware int's (0x20) out %al,$0x21 .word 0x00eb,0x00eb # ICW2 for slaver, A0=1 # D7~D3 + D2~D0 = 0x28 + IRx mov $0x28,%al # start of hardware int's 2 (0x28) out %al,$0xA1 .word 0x00eb,0x00eb # ICW3 for master, A0=1 # D2=1, IR2 pin connects slaver mov $0x04,%al # 8259-1 is master out %al,$0x21 .word 0x00eb,0x00eb # ICW3 for slaver, A0=1 # D2~D0=2, slaver is connectted to IR2 pin of master mov $0x02,%al # 8259-2 is slave out %al,$0xA1 .word 0x00eb,0x00eb # ICW4 for master, A0=1 # D7~D5=0 # D4=0, SFNM=0, fully nested mode # D3=0, BUF=0, non-buffer mode # D2=0, M/S=0, no use because of BUF=0 # D1=0, AEOI=0, non-automatic EOI # D0=1, uPM=1, 8086 system mov $0x01,%al # 8086 mode for both out %al,$0x21 .word 0x00eb,0x00eb # ICW4 for slaver, A0=1 out %al,$0xA1 .word 0x00eb,0x00eb #initialization end # OCW1 for master, A0=1 # D7~D0=0xff, all mask for IRR mov $0xFF,%al # mask off all interrupts for now out %al,$0x21 .word 0x00eb,0x00eb # OCW1 for slaver, A0=1 out %al,$0xA1
- kernel/traps.c
void trap_init(void) { int i; set_trap_gate(0,÷_error); set_trap_gate(1,&debug); set_trap_gate(2,&nmi); set_system_gate(3,&int3); /* int3-5 can be called from all */ set_system_gate(4,&overflow); set_system_gate(5,&bounds); set_trap_gate(6,&invalid_op); set_trap_gate(7,&device_not_available); set_trap_gate(8,&double_fault); set_trap_gate(9,&coprocessor_segment_overrun); set_trap_gate(10,&invalid_TSS); set_trap_gate(11,&segment_not_present); set_trap_gate(12,&stack_segment); set_trap_gate(13,&general_protection); set_trap_gate(14,&page_fault); set_trap_gate(15,&reserved); set_trap_gate(16,&coprocessor_error); set_trap_gate(17,&alignment_check); for (i=18;i<48;i++) set_trap_gate(i,&reserved); set_trap_gate(45,&irq13); outb_p(inb_p(0x21)&0xfb,0x21); /* 0b1111 1011 unmask IR2 pin of master */ outb(inb_p(0xA1)&0xdf,0xA1); /* 0b1101 1111 unmask IR5 pin of slaver */ set_trap_gate(39,¶llel_interrupt); }