i8259.cpp
1 /* i8259.c - emulation code for the Intel 8259 controller. 2 Note: This is not a very complete i8259 interrupt controller 3 implementation, but for the purposes of a PC, it's all we need. */ 4 5 #include <stdint.h> 6 #include <string.h> 7 8 struct structpic { 9 uint8_t imr; //mask register 10 uint8_t irr; //request register 11 uint8_t isr; //service register 12 uint8_t icwstep; //used during initialization to keep track of which ICW we're at 13 uint8_t icw[5]; 14 uint8_t intoffset; //interrupt vector offset 15 uint8_t priority; //which IRQ has highest priority 16 uint8_t autoeoi; //automatic EOI mode 17 uint8_t readmode; //remember what to return on read register from OCW3 18 uint8_t enabled; 19 } i8259; 20 21 22 void init8259() { 23 memset((void *)&i8259, 0, sizeof(i8259)); 24 } 25 26 uint8_t in8259(uint16_t portnum) { 27 switch (portnum & 1) { 28 case 0: 29 if (i8259.readmode==0) return(i8259.irr); else return(i8259.isr); 30 case 1: //read mask register 31 return(i8259.imr); 32 } 33 return(0); //can't get here, but the compiler bitches 34 } 35 36 extern uint32_t makeupticks; 37 void out8259(uint16_t portnum, uint8_t value) { 38 uint8_t i; 39 switch (portnum & 1) { 40 case 0: 41 if (value & 0x10) { //begin initialization sequence 42 i8259.icwstep = 1; 43 i8259.imr = 0; //clear interrupt mask register 44 i8259.icw[i8259.icwstep++] = value; 45 return; 46 } 47 if ((value & 0x98)==8) { //it's an OCW3 48 if (value & 2) i8259.readmode = value & 2; 49 } 50 if (value & 0x20) { //EOI command 51 for (i=0; i<8; i++) 52 if ((i8259.isr >> i) & 1) { 53 i8259.isr ^= (1 << i); 54 if ((i==0) && (makeupticks>0)) { makeupticks = 0; i8259.irr |= 1; } 55 return; 56 } 57 } 58 break; 59 case 1: 60 if ((i8259.icwstep==3) && (i8259.icw[1] & 2)) i8259.icwstep = 4; //single mode, so don't read ICW3 61 if (i8259.icwstep<5) { i8259.icw[i8259.icwstep++] = value; return; } 62 //if we get to this point, this is just a new IMR value 63 i8259.imr = value; 64 break; 65 } 66 } 67 68 uint8_t nextintr() { 69 uint8_t i, tmpirr; 70 tmpirr = i8259.irr & (~i8259.imr); //XOR request register with inverted mask register 71 for (i=0; i<8; i++) 72 if ((tmpirr >> i) & 1) { 73 i8259.irr ^= (1 << i); 74 i8259.isr |= (1 << i); 75 return(i8259.icw[2] + i); 76 } 77 return(0); //can't get here, but the compiler bitches 78 } 79 80 void doirq(uint8_t irqnum) { 81 i8259.irr |= (1 << irqnum); 82 } 83