231 lines
6.1 KiB
JavaScript
231 lines
6.1 KiB
JavaScript
/*
|
|
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;
|
|
};
|
|
|
|
|