import asm import t, c # PIC端口定义 PIC1_COMMAND: t.CDefine = 0x20 PIC1_DATA: t.CDefine = 0x21 PIC2_COMMAND: t.CDefine = 0xA0 PIC2_DATA: t.CDefine = 0xA1 # ICW1 - 初始化命令字1 ICW1_ICW4: t.CDefine = 0x01 # 需要ICW4 ICW1_SINGLE: t.CDefine = 0x02 # 单级模式 ICW1_INTERVAL4: t.CDefine = 0x04 # 间隔4字节 ICW1_LEVEL: t.CDefine = 0x08 # 电平触发模式 ICW1_INIT: t.CDefine = 0x10 # 初始化 # ICW4 - 初始化命令字4 ICW4_8086: t.CDefine = 0x01 # 8086/88模式 ICW4_AUTO: t.CDefine = 0x02 # 自动EOI ICW4_BUF_SLAVE: t.CDefine = 0x08 # 缓冲模式(从片) ICW4_BUF_MASTER: t.CDefine = 0x0C # 缓冲模式(主片) ICW4_SFNM: t.CDefine = 0x10 # 特殊全嵌套模式 # OCW2 - 操作命令字2 OCW2_EOI: t.CDefine = 0x20 # 结束中断 # OCW3 - 操作命令字3 OCW3_READ_ISR: t.CDefine = 0x0B # 读取中断服务寄存器(ISR) # 初始化PIC def init(): # 发送ICW1:开始初始化,需要ICW4 asm.outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4) asm.io_wait() asm.outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4) asm.io_wait() # 发送ICW2:中断向量偏移 asm.outb(PIC1_DATA, 0x20) # IRQ0-7映射到0x20-0x27 asm.io_wait() asm.outb(PIC2_DATA, 0x28) # IRQ8-15映射到0x28-0x2F asm.io_wait() # 发送ICW3:级联信息 asm.outb(PIC1_DATA, 0x04) # 主PIC的IRQ2连接从PIC asm.io_wait() asm.outb(PIC2_DATA, 0x02) # 从PIC连接到主PIC的IRQ2 asm.io_wait() # 发送ICW4:8086模式 asm.outb(PIC1_DATA, ICW4_8086) asm.io_wait() asm.outb(PIC2_DATA, ICW4_8086) asm.io_wait() # 设置初始屏蔽字:只启用IRQ0(定时器)、IRQ1(键盘)、IRQ2(级联) # 主PIC: 屏蔽所有除了IRQ0, IRQ1, IRQ2 (0xF8 = 11111000) # 从PIC: 屏蔽所有 (0xFF = 11111111),鼠标中断由驱动程序自己启用 asm.outb(PIC1_DATA, 0xF8) # 启用IRQ0, IRQ1, IRQ2 asm.io_wait() asm.outb(PIC2_DATA, 0xFF) # 屏蔽所有从PIC中断 asm.io_wait() # 发送EOI信号 def eoi(irq: t.CUInt8T): if irq >= 8: asm.outb(PIC2_COMMAND, OCW2_EOI) asm.outb(PIC1_COMMAND, OCW2_EOI) # 检查是否是虚假中断(spurious interrupt) # 返回 1 表示是虚假中断,0 表示是真实中断 def isSpurious(irq: t.CInt) -> t.CInt: # 边界检查 if irq < 0 or irq > 15: return 0 isr: t.CUInt8T if irq < 8: # 发送OCW3,读取ISR(Interrupt Service Register) asm.outb(PIC1_COMMAND, OCW3_READ_ISR) asm.io_wait() isr = asm.inb(PIC1_COMMAND) # 如果ISR中对应位为0,说明是虚假中断 return not (isr & (1 << irq)) else: # 发送OCW3,读取从PIC的ISR asm.outb(PIC2_COMMAND, OCW3_READ_ISR) asm.io_wait() isr = asm.inb(PIC2_COMMAND) # 如果ISR中对应位为0,说明是虚假中断 return not (isr & (1 << (irq - 8))) # 设置IRQ屏蔽 def setMask(irq: t.CUInt8T): # 边界检查 if irq > 15: return port: t.CUInt16T value: t.CUInt8T if irq < 8: port = PIC1_DATA else: port = PIC2_DATA irq -= 8 value = asm.inb(port) | (1 << irq) asm.outb(port, value) asm.io_wait() # 确保命令生效 # 清除IRQ屏蔽 def clearMask(irq: t.CUInt8T): # 边界检查 if irq > 15: return port: t.CUInt16T value: t.CUInt8T if irq < 8: port = PIC1_DATA else: port = PIC2_DATA irq -= 8 value = asm.inb(port) & ~(1 << irq) asm.outb(port, value) asm.io_wait() # 确保命令生效