#include "ibm.h" #include "io.h" #include "pic.h" #include "pit.h" int output; int intclear; int keywaiting=0; int pic_intpending; PIC pic, pic2; uint16_t pic_current; void pic_updatepending() { uint16_t temp_pending = 0; if (AT) { if ((pic2.pend&~pic2.mask)&~pic2.mask2) pic.pend |= (1 << 2); else pic.pend &= ~(1 << 2); } pic_intpending = (pic.pend & ~pic.mask) & ~pic.mask2; if (AT) { if (!((pic.mask | pic.mask2) & (1 << 2))) { temp_pending = ((pic2.pend&~pic2.mask)&~pic2.mask2); temp_pending <<= 8; pic_intpending |= temp_pending; } } /* pclog("pic_intpending = %i %02X %02X %02X %02X\n", pic_intpending, pic.ins, pic.pend, pic.mask, pic.mask2); pclog(" %02X %02X %02X %02X %i %i\n", pic2.ins, pic2.pend, pic2.mask, pic2.mask2, ((pic.mask | pic.mask2) & (1 << 2)), ((pic2.pend&~pic2.mask)&~pic2.mask2)); */ } void pic_reset() { pic.icw=0; pic.mask=0xFF; pic.mask2=0; pic.pend=pic.ins=0; pic.vector=8; pic.read=1; pic2.icw=0; pic2.mask=0xFF; pic.mask2=0; pic2.pend=pic2.ins=0; pic_intpending = 0; } void pic_update_mask(uint8_t *mask, uint8_t ins) { int c; *mask = 0; for (c = 0; c < 8; c++) { if (ins & (1 << c)) { *mask = 0xff << c; return; } } } static void pic_autoeoi() { int c; for (c=0;c<8;c++) { if (pic.ins&(1<0xFF) { if (!AT) { return; } pic2.pend|=(num>>8); if ((pic2.pend&~pic2.mask)&~pic2.mask2) pic.pend |= (1 << 2); } else { pic.pend|=num; } /* if (num == 0x40) { pclog("picint : PEND now %02X %02X\n", pic.pend, pic2.pend); } */ pic_updatepending(); /* if (num == 0x40) { pclog("Processing FDC interrupt, pending: %s, previously pending: %s, masked: %s, masked (2): %s, T: %s, I: %s\n", (pic_intpending & num) ? "yes" : "no", (old_pend & num) ? "yes" : "no", (pic.mask & num) ? "yes" : "no", (pic.mask2 & num) ? "yes" : "no", (flags & 0x100) ? "yes" : "no", (flags&I_FLAG) ? "yes" : "no"); } */ } void picintlevel(uint16_t num) { int c = 0; while (!(num & (1 << c))) c++; if (AT && (c == 2)) { c = 9; num = 1 << 9; } if (!(pic_current & num)) { pic_current |= num; if (num>0xFF) { if (!AT) { return; } pic2.pend|=(num>>8); } else { pic.pend|=num; } } pic_updatepending(); } void picintc(uint16_t num) { int c = 0; if (!num) return; while (!(num & (1 << c))) c++; if (AT && (c == 2)) { c = 9; num = 1 << 9; } pic_current &= ~num; if (num > 0xff) { if (!AT) { return; } pic2.pend &= ~(num >> 8); if (!((pic2.pend&~pic2.mask)&~pic2.mask2)) pic.pend &= ~(1 << 2); } else { pic.pend&=~num; } pic_updatepending(); } /* TODO: Verify this whole level-edge thing... edge/level mode is supposedly handled by bit 3 of ICW1, but the PIIX spec mandates it being able to be edge/level per IRQ... maybe the PCI-era on-board PIC ignores bit 3 of ICW1 but instead uses whatever is set in ELCR? Edit: Yes, the PIIX (and I suppose also the SIO) disables bit 3 of ICW1 and instead, uses the ELCR. Also, shouldn't there be only one picint(), and then edge/level is handled on processing? */ static uint8_t pic_process_interrupt(PIC* target_pic, int c) { uint8_t pending = target_pic->pend & ~target_pic->mask; int pic_int = c & 7; int pic_int_num = 1 << pic_int; int pic_cur_num = 1 << c; if (pending & pic_int_num) { if (!(pic_current & pic_cur_num)) { target_pic->pend &= ~pic_int_num; } target_pic->ins |= pic_int_num; pic_update_mask(&target_pic->mask2, target_pic->ins); if (c >= 8) { pic.ins |= (1 << 2); /*Cascade IRQ*/ pic_update_mask(&pic.mask2, pic.ins); } pic_updatepending(); if (target_pic->icw4 & 0x02) { (c >= 8) ? pic2_autoeoi() : pic_autoeoi(); } if (!c) { pit_set_gate(&pit2, 0, 0); } return pic_int + target_pic->vector; } else { return 0xFF; } } uint8_t picinterrupt() { int c; uint8_t ret; uint8_t irq2_pending = (pic.pend & ~pic.mask) & (1 << 2); for (c = 0; c <= 1; c++) { ret = pic_process_interrupt(&pic, c); if (ret != 0xFF) return ret; } if (irq2_pending) { if (AT) { for (c = 8; c <= 15; c++) { ret = pic_process_interrupt(&pic2, c); pclog("Processing IRQ %i: %02X\n", c, ret); if (ret != 0xFF) return ret; } } else { ret = pic_process_interrupt(&pic, 2); if (ret != 0xFF) return ret; } } for (c = 3; c <= 7; c++) { ret = pic_process_interrupt(&pic, c); if (ret != 0xFF) return ret; } return 0xFF; } void dumppic() { pclog("PIC1 : MASK %02X PEND %02X INS %02X VECTOR %02X\n",pic.mask,pic.pend,pic.ins,pic.vector); if (AT) { pclog("PIC2 : MASK %02X PEND %02X INS %02X VECTOR %02X\n",pic2.mask,pic2.pend,pic2.ins,pic2.vector); } }