/* Fabrix - An annotated version of the original JSLinux which is Copyright (c) 2011 Fabrice Bellard 8259 PIC (Programmable Interrupt Controller) Emulation Code */ function PIC(PC, port_num) { PC.register_ioport_write(port_num, 2, 1, this.ioport_write.bind(this)); PC.register_ioport_read(port_num, 2, 1, this.ioport_read.bind(this)); this.reset(); } PIC.prototype.reset = function() { this.last_irr = 0; this.irr = 0; this.imr = 0; this.isr = 0; this.priority_add = 0; this.irq_base = 0; this.read_reg_select = 0; this.special_mask = 0; this.init_state = 0; this.auto_eoi = 0; this.rotate_on_autoeoi = 0; this.init4 = 0; this.elcr = 0; this.elcr_mask = 0; }; PIC.prototype.set_irq1 = function(Rg, Qf) { var wc; wc = 1 << Rg; if (Qf) { if ((this.last_irr & wc) == 0) this.irr |= wc; this.last_irr |= wc; } else { this.last_irr &= ~wc; } }; PIC.prototype.get_priority = function(wc) { var Sg; if (wc == 0) return -1; Sg = 7; while ((wc & (1 << ((Sg + this.priority_add) & 7))) == 0) Sg--; return Sg; }; PIC.prototype.get_irq = function() { var wc, Tg, Sg; wc = this.irr & ~this.imr; Sg = this.get_priority(wc); if (Sg < 0) return -1; Tg = this.get_priority(this.isr); if (Sg > Tg) { return Sg; } else { return -1; } }; PIC.prototype.intack = function(Rg) { if (this.auto_eoi) { if (this.rotate_on_auto_eoi) this.priority_add = (Rg + 1) & 7; } else { this.isr |= (1 << Rg); } if (!(this.elcr & (1 << Rg))) this.irr &= ~(1 << Rg); }; PIC.prototype.ioport_write = function(mem8_loc, x) { var Sg; mem8_loc &= 1; if (mem8_loc == 0) { if (x & 0x10) { this.reset(); this.init_state = 1; this.init4 = x & 1; if (x & 0x02) throw "single mode not supported"; if (x & 0x08) throw "level sensitive irq not supported"; } else if (x & 0x08) { if (x & 0x02) this.read_reg_select = x & 1; if (x & 0x40) this.special_mask = (x >> 5) & 1; } else { switch (x) { case 0x00: case 0x80: this.rotate_on_autoeoi = x >> 7; break; case 0x20: case 0xa0: Sg = this.get_priority(this.isr); if (Sg >= 0) { this.isr &= ~(1 << ((Sg + this.priority_add) & 7)); } if (x == 0xa0) this.priority_add = (this.priority_add + 1) & 7; break; case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: Sg = x & 7; this.isr &= ~(1 << Sg); break; case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: this.priority_add = (x + 1) & 7; break; case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7: Sg = x & 7; this.isr &= ~(1 << Sg); this.priority_add = (Sg + 1) & 7; break; } } } else { switch (this.init_state) { case 0: this.imr = x; this.update_irq(); break; case 1: this.irq_base = x & 0xf8; this.init_state = 2; break; case 2: if (this.init4) { this.init_state = 3; } else { this.init_state = 0; } break; case 3: this.auto_eoi = (x >> 1) & 1; this.init_state = 0; break; } } }; PIC.prototype.ioport_read = function(Ug) { var mem8_loc, Pg; mem8_loc = Ug & 1; if (mem8_loc == 0) { if (this.read_reg_select) Pg = this.isr; else Pg = this.irr; } else { Pg = this.imr; } return Pg; }; function PIC_Controller(PC, Wg, Ug, Xg) { this.pics = new Array(); this.pics[0] = new PIC(PC, Wg); this.pics[1] = new PIC(PC, Ug); this.pics[0].elcr_mask = 0xf8; this.pics[1].elcr_mask = 0xde; this.irq_requested = 0; this.cpu_set_irq = Xg; this.pics[0].update_irq = this.update_irq.bind(this); this.pics[1].update_irq = this.update_irq.bind(this); } PIC_Controller.prototype.update_irq = function() { var Yg, Rg; Yg = this.pics[1].get_irq(); if (Yg >= 0) { this.pics[0].set_irq1(2, 1); this.pics[0].set_irq1(2, 0); } Rg = this.pics[0].get_irq(); if (Rg >= 0) { this.cpu_set_irq(1); } else { this.cpu_set_irq(0); } }; PIC_Controller.prototype.set_irq = function(Rg, Qf) { this.pics[Rg >> 3].set_irq1(Rg & 7, Qf); this.update_irq(); }; PIC_Controller.prototype.get_hard_intno = function() { var Rg, Yg, intno; Rg = this.pics[0].get_irq(); if (Rg >= 0) { this.pics[0].intack(Rg); if (Rg == 2) { Yg = this.pics[1].get_irq(); if (Yg >= 0) { this.pics[1].intack(Yg); } else { Yg = 7; } intno = this.pics[1].irq_base + Yg; Rg = Yg + 8; } else { intno = this.pics[0].irq_base + Rg; } } else { Rg = 7; intno = this.pics[0].irq_base + Rg; } this.update_irq(); return intno; };