diff --git a/src/hardware/pic.cpp b/src/hardware/pic.cpp index 98ec2f3d..814d3bfe 100644 --- a/src/hardware/pic.cpp +++ b/src/hardware/pic.cpp @@ -28,31 +28,36 @@ struct IRQ_Block { bool masked; bool active; bool inservice; - Bit8u vector; + Bitu vector; char * name; PIC_EOIHandler * handler; }; -Bitu PIC_Ticks=0; +struct PIC_Controller { + Bitu icw_words; + Bitu icw_index; + Bitu masked; + Bitu active; + Bitu inservice; + bool auto_eoi; + bool request_issr; + Bit8u vector_base; +}; + +Bitu PIC_Ticks=0; Bitu PIC_IRQCheck; Bitu PIC_IRQActive; + static IRQ_Block irqs[16]; -static Bit8u pic0_icws=0; -static Bit8u pic1_icws=0; -static Bit8u pic0_icw_state=0; -static Bit8u pic1_icw_state=0; -static bool pic0_request_iisr=0; -static bool pic1_request_iisr=0; +static PIC_Controller pics[2]; + enum QUEUE_TYPE { IRQ,EVENT }; - - - struct PICEntry { QUEUE_TYPE type; Bitu irq; @@ -61,240 +66,125 @@ struct PICEntry { PICEntry * next; }; - static struct { PICEntry entries[PIC_QUEUESIZE]; PICEntry * free_entry; PICEntry * next_entry; } pic; -static void write_p20(Bit32u port,Bit8u val) { +static void write_command(Bit32u port,Bit8u val) { + PIC_Controller * pic=&pics[port==0x20 ? 0 : 1]; + Bitu irq_base=port==0x20 ? 0 : 8; switch (val) { case 0x0A: /* select read interrupt request register */ - pic0_request_iisr=false; + pic->request_issr=false; break; case 0x0B: /* select read interrupt in-service register */ - pic0_request_iisr=true; + pic->request_issr=true; break; case 0x10: /* ICW1 */ - pic0_icws=2; - pic0_icw_state=1; + pic->icw_index=1; + pic->icw_words=2; break; case 0x11: /* ICW1 + need for ICW4 */ - pic0_icws=3; - pic0_icw_state=1; + pic->icw_index=1; + pic->icw_words=3; break; - case 0x20: /* end of interrupt command */ - case 0x21: /* end of interrupt command */ - case 0x22: /* end of interrupt command */ - case 0x23: /* end of interrupt command */ - case 0x24: /* end of interrupt command */ - case 0x25: /* end of interrupt command */ - case 0x26: /* end of interrupt command */ - case 0x27: /* end of interrupt command */ - /* clear highest current in service bit */ - if (PIC_IRQActive<8) { + case 0x20:case 0x21:case 0x22:case 0x23:case 0x24:case 0x25:case 0x26:case 0x27: + if (PIC_IRQActive<(irq_base+8)) { irqs[PIC_IRQActive].inservice=false; if (irqs[PIC_IRQActive].handler!=0) irqs[PIC_IRQActive].handler(); PIC_IRQActive=PIC_NOIRQ; - } + }//TODO Warnings? break; - case 0x60: /* specific EOI 0 */ - case 0x61: /* specific EOI 1 */ - case 0x62: /* specific EOI 2 */ - case 0x63: /* specific EOI 3 */ - case 0x64: /* specific EOI 4 */ - case 0x65: /* specific EOI 5 */ - case 0x66: /* specific EOI 6 */ - case 0x67: /* specific EOI 7 */ - if (PIC_IRQActive==(val-0x60U)) { + case 0x60:case 0x61:case 0x62:case 0x63:case 0x64:case 0x65:case 0x66:case 0x67: + /* Spefific EOI 0-7 */ + if (PIC_IRQActive==(irq_base+val-0x60U)) { irqs[PIC_IRQActive].inservice=false; if (irqs[PIC_IRQActive].handler!=0) irqs[PIC_IRQActive].handler(); PIC_IRQActive=PIC_NOIRQ; - } + }//TODO Warnings? break; - // IRQ lowest priority commands - case 0xC0: // 0 7 6 5 4 3 2 1 - case 0xC1: // 1 0 7 6 5 4 3 2 - case 0xC2: // 2 1 0 7 6 5 4 3 - case 0xC3: // 3 2 1 0 7 6 5 4 - case 0xC4: // 4 3 2 1 0 7 6 5 - case 0xC5: // 5 4 3 2 1 0 7 6 - case 0xC6: // 6 5 4 3 2 1 0 7 - case 0xC7: // 7 6 5 4 3 2 1 0 - // ignore for now TODO + case 0xC0:case 0xC1:case 0xC2:case 0xC3:case 0xC4:case 0xC5:case 0xC6:case 0xC7: + /* Priority order, no need for it */ break; default: - E_Exit("PIC0:Unhandled command %02X",val); + E_Exit("PIC:Unhandled command %02X",val); } } -//Pic 0 Interrupt mask -static void write_p21(Bit32u port,Bit8u val) { - Bit8u i; - switch(pic0_icw_state) { +static void write_data(Bit32u port,Bit8u val) { + PIC_Controller * pic=&pics[port==0x21 ? 0 : 1]; + Bitu irq_base=(port==0x21) ? 0 : 8; + Bitu i; + switch(pic->icw_index) { case 0: /* mask register */ for (i=0;i<=7;i++) { - irqs[i].masked=(val&(1<0; - if (irqs[i].active && !irqs[i].masked) PIC_IRQCheck|=(1 << 1); - else PIC_IRQCheck&=~(1 << i); + irqs[i+irq_base].masked=(val&(1<0; + if (irqs[i+irq_base].active && !irqs[i+irq_base].masked) PIC_IRQCheck|=(1 << (i+irq_base)); + else PIC_IRQCheck&=~(1 << (i+irq_base)); }; break; case 1: /* icw2 */ - LOG(LOG_PIC,"PIC0:Base vector %X",val); + LOG(LOG_PIC,"%d:Base vector %X",port==0x21 ? 0 : 1,val); for (i=0;i<=7;i++) { - irqs[i].vector=(val&0xf8)+i; + irqs[i+irq_base].vector=(val&0xf8)+i; }; - default: /* icw2, 3, and 4*/ - if(pic0_icw_state++ >= pic0_icws) pic0_icw_state=0; + if(pic->icw_index++ >= pic->icw_words) pic->icw_index=0; + break; + case 2: /* icw 3 */ + LOG(LOG_PIC,"%d:ICW 3 %X",port==0x21 ? 0 : 1,val); + if(pic->icw_index++ >= pic->icw_words) pic->icw_index=0; + break; + case 3: /* icw 4 */ + /* + 0 1 8086/8080 0 mcs-8085 mode + 1 1 Auto EOI 1 Normal EOI + 2-3 0x Non buffer Mode + 10 Buffer Mode Slave + 11 Buffer mode Master + 4 Special/Not Special nested mode + */ + pic->auto_eoi=(val & 0x2)>0; + + LOG(LOG_PIC,"%d:ICW 4 %X",port==0x21 ? 0 : 1,val); + if(pic->icw_index++ >= pic->icw_words) pic->icw_index=0; + break; + default: /* icw 3, and 4*/ + LOG(LOG_PIC,"ICW HUH? %X",val); } } -static Bit8u read_p20(Bit32u port) { - Bit8u ret=0; - Bit32u i; - Bit8u b=1; - if (pic0_request_iisr) { - for (i=0;i<=7;i++) { + +static Bit8u read_command(Bit32u port) { + PIC_Controller * pic=&pics[port==0x20 ? 0 : 1]; + Bitu irq_base=(port==0x20) ? 0 : 8; + Bitu i;Bit8u ret=0;Bit8u b=1; + if (pic->request_issr) { + for (i=irq_base;i7 && PIC_IRQActive <16) { - irqs[PIC_IRQActive].inservice=false; - if (irqs[PIC_IRQActive].handler!=0) irqs[PIC_IRQActive].handler(); - PIC_IRQActive=PIC_NOIRQ; - } - break; - case 0x60: /* specific EOI 0 */ - case 0x61: /* specific EOI 1 */ - case 0x62: /* specific EOI 2 */ - case 0x63: /* specific EOI 3 */ - case 0x64: /* specific EOI 4 */ - case 0x65: /* specific EOI 5 */ - case 0x66: /* specific EOI 6 */ - case 0x67: /* specific EOI 7 */ - if (PIC_IRQActive==(8+val-0x60U)) { - irqs[PIC_IRQActive].inservice=false; - if (irqs[PIC_IRQActive].handler!=0) irqs[PIC_IRQActive].handler(); - PIC_IRQActive=PIC_NOIRQ; - }; - break; - // IRQ lowest priority commands - case 0xC0: // 0 7 6 5 4 3 2 1 - case 0xC1: // 1 0 7 6 5 4 3 2 - case 0xC2: // 2 1 0 7 6 5 4 3 - case 0xC3: // 3 2 1 0 7 6 5 4 - case 0xC4: // 4 3 2 1 0 7 6 5 - case 0xC5: // 5 4 3 2 1 0 7 6 - case 0xC6: // 6 5 4 3 2 1 0 7 - case 0xC7: // 7 6 5 4 3 2 1 0 - //TODO Maybe does it even matter? - break; - default: - E_Exit("Unhandled command %04X sent to port A0",val); - } -} - - -static void write_pa1(Bit32u port,Bit8u val) { - Bit8u i; - switch(pic1_icw_state) { - case 0: /* mask register */ - for (i=0;i<=7;i++) { - irqs[i+8].masked=(val&1 <0; - }; - break; - case 1: /* icw2 */ - for (i=0;i<=7;i++) { - irqs[i+8].vector=(val&0xf8)+i; - }; - default: /* icw2, 3, and 4*/ - if(pic1_icw_state++ >= pic1_icws) pic1_icw_state=0; - } -} - -static Bit8u read_pa0(Bit32u port) { - Bit8u ret=0; - Bit32u i; - Bit8u b=1; - if (pic1_request_iisr) { - for (i=0;i<=7;i++) { - if (irqs[i+8].inservice) ret|=b; - b <<= 1; - } - } else { - for (i=0;i<=7;i++) { - if (irqs[i+8].active) ret|=b; - b <<= 1; - } - } - return ret; -} - - -static Bit8u read_pa1(Bit32u port) { - Bit8u ret=0; - Bit32u i; - Bit8u b=1; - for (i=0;i<=7;i++) { - if (irqs[i+8].masked) ret|=b; - b <<= 1; - } - return ret; -} - void PIC_RegisterIRQ(Bit32u irq,PIC_EOIHandler handler,char * name) { if (irq>15) E_Exit("PIC:Illegal IRQ"); irqs[irq].name=name; @@ -328,17 +218,19 @@ void PIC_DeActivateIRQ(Bit32u irq) { void PIC_runIRQs(void) { Bitu i; - if (!flags.intf) return; + if (!GETFLAG(IF)) return; if (PIC_IRQActive!=PIC_NOIRQ) return; if (!PIC_IRQCheck) return; for (i=0;i<=15;i++) { if (i!=2) { if (!irqs[i].masked && irqs[i].active) { - irqs[i].inservice=true; irqs[i].active=false; PIC_IRQCheck&=~(1 << i); Interrupt(irqs[i].vector); - PIC_IRQActive=i; + if (!pics[0].auto_eoi) { + PIC_IRQActive=i; + irqs[i].inservice=true; + } return; } } @@ -498,6 +390,16 @@ void PIC_Init(Section* sec) { PIC_IRQActive=PIC_NOIRQ; PIC_Ticks=0; Bitu i; + for (i=0;i<2;i++) { + pics[i].masked=0xff; + pics[i].active=0; + pics[i].inservice=0; + pics[i].auto_eoi=false; + pics[i].auto_eoi=false; + pics[i].request_issr=false; + pics[i].icw_index=0; + pics[i].icw_words=0; + } for (i=0;i<=7;i++) { irqs[i].active=false; irqs[i].masked=true; @@ -511,14 +413,14 @@ void PIC_Init(Section* sec) { irqs[0].masked=false; /* Enable system timer */ irqs[1].masked=false; /* Enable Keyboard IRQ */ irqs[12].masked=false; /* Enable Mouse IRQ */ - IO_RegisterReadHandler(0x20,read_p20,"Master PIC Command"); - IO_RegisterReadHandler(0x21,read_p21,"Master PIC Data"); - IO_RegisterWriteHandler(0x20,write_p20,"Master PIC Command"); - IO_RegisterWriteHandler(0x21,write_p21,"Master PIC Data"); - IO_RegisterReadHandler(0xa0,read_pa0,"Slave PIC Command"); - IO_RegisterReadHandler(0xa1,read_pa1,"Slave PIC Data"); - IO_RegisterWriteHandler(0xa0,write_pa0,"Slave PIC Command"); - IO_RegisterWriteHandler(0xa1,write_pa1,"Slave PIC Data"); + IO_RegisterReadHandler(0x20,read_command,"Master PIC Command"); + IO_RegisterReadHandler(0x21,read_data,"Master PIC Data"); + IO_RegisterWriteHandler(0x20,write_command,"Master PIC Command"); + IO_RegisterWriteHandler(0x21,write_data,"Master PIC Data"); + IO_RegisterReadHandler(0xa0,read_command,"Slave PIC Command"); + IO_RegisterReadHandler(0xa1,read_data,"Slave PIC Data"); + IO_RegisterWriteHandler(0xa0,write_command,"Slave PIC Command"); + IO_RegisterWriteHandler(0xa1,write_data,"Slave PIC Data"); /* Initialize the pic queue */ for (i=0;i