2011-12-21 13:34:38 +08:00
|
|
|
|
/*
|
2013-09-16 11:17:04 +08:00
|
|
|
|
JSLinux-deobfuscated - An annotated version of the original JSLinux.
|
2013-03-29 10:43:44 +08:00
|
|
|
|
|
2013-09-16 11:17:04 +08:00
|
|
|
|
Original is Copyright (c) 2011-2012 Fabrice Bellard
|
|
|
|
|
Redistribution or commercial use is prohibited without the author's permission.
|
2011-12-21 13:34:38 +08:00
|
|
|
|
|
2013-09-16 11:17:04 +08:00
|
|
|
|
8259A PIC (Programmable Interrupt Controller) Emulation Code
|
|
|
|
|
|
|
|
|
|
The 8259 combines multiple interrupt input sources into a single
|
|
|
|
|
interrupt output to the host microprocessor, extending the interrupt
|
|
|
|
|
levels available in a system beyond the one or two levels found on the
|
|
|
|
|
processor chip.
|
|
|
|
|
|
|
|
|
|
There are three registers, an Interrupt Mask Register (IMR), an
|
|
|
|
|
Interrupt Request Register (IRR), and an In-Service Register
|
|
|
|
|
(ISR):
|
|
|
|
|
IRR - a mask of the current interrupts that are pending acknowledgement
|
|
|
|
|
ISR - a mask of the interrupts that are pending an EOI
|
|
|
|
|
IMR - a mask of interrupts that should not be sent an acknowledgement
|
|
|
|
|
|
|
|
|
|
End Of Interrupt (EOI) operations support specific EOI, non-specific
|
|
|
|
|
EOI, and auto-EOI. A specific EOI specifies the IRQ level it is
|
|
|
|
|
acknowledging in the ISR. A non-specific EOI resets the IRQ level in
|
|
|
|
|
the ISR. Auto-EOI resets the IRQ level in the ISR immediately after
|
|
|
|
|
the interrupt is acknowledged.
|
|
|
|
|
|
|
|
|
|
After the IBM XT, it was decided that 8 IRQs was not enough.
|
|
|
|
|
The backwards-compatible solution was simply to chain two 8259As together,
|
|
|
|
|
the master and slave PIC.
|
|
|
|
|
|
|
|
|
|
Useful References
|
|
|
|
|
-----------------
|
|
|
|
|
https://en.wikipedia.org/wiki/Programmable_Interrupt_Controller
|
|
|
|
|
https://en.wikipedia.org/wiki/Intel_8259
|
|
|
|
|
http://www.thesatya.com/8259.html
|
2011-12-21 13:34:38 +08:00
|
|
|
|
*/
|
2013-09-16 11:17:04 +08:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Common PC arrangements of IRQ lines:
|
|
|
|
|
------------------------------------
|
|
|
|
|
|
|
|
|
|
PC/AT and later systems had two 8259 controllers, master and
|
|
|
|
|
slave. IRQ0 through IRQ7 are the master 8259's interrupt lines, while
|
|
|
|
|
IRQ8 through IRQ15 are the slave 8259's interrupt lines. The labels on
|
|
|
|
|
the pins on an 8259 are IR0 through IR7. IRQ0 through IRQ15 are the
|
|
|
|
|
names of the ISA bus's lines to which the 8259s are attached.
|
|
|
|
|
|
|
|
|
|
Master 8259
|
|
|
|
|
IRQ0 – Intel 8253 or Intel 8254 Programmable Interval Timer, aka the system timer
|
|
|
|
|
IRQ1 – Intel 8042 keyboard controller
|
|
|
|
|
IRQ2 – not assigned in PC/XT; cascaded to slave 8259 INT line in PC/AT
|
|
|
|
|
IRQ3 – 8250 UART serial ports 2 and 4
|
|
|
|
|
IRQ4 – 8250 UART serial ports 1 and 3
|
|
|
|
|
IRQ5 – hard disk controller in PC/XT; Intel 8255 parallel ports 2 and 3 in PC/AT
|
|
|
|
|
IRQ6 – Intel 82072A floppy disk controller
|
|
|
|
|
IRQ7 – Intel 8255 parallel port 1 / spurious interrupt
|
|
|
|
|
|
|
|
|
|
Slave 8259 (PC/AT and later only)
|
|
|
|
|
IRQ8 – real-time clock (RTC)
|
|
|
|
|
IRQ9 – no common assignment, but 8-bit cards' IRQ2 line is routed to this interrupt.
|
|
|
|
|
IRQ10 – no common assignment
|
|
|
|
|
IRQ11 – no common assignment
|
|
|
|
|
IRQ12 – Intel 8042 PS/2 mouse controller
|
|
|
|
|
IRQ13 – math coprocessor
|
|
|
|
|
IRQ14 – hard disk controller 1
|
|
|
|
|
IRQ15 – hard disk controller 2
|
|
|
|
|
*/
|
|
|
|
|
|
2011-12-24 11:28:34 +08:00
|
|
|
|
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));
|
2011-12-21 13:34:38 +08:00
|
|
|
|
this.reset();
|
|
|
|
|
}
|
|
|
|
|
PIC.prototype.reset = function() {
|
|
|
|
|
this.last_irr = 0;
|
2013-09-16 11:17:04 +08:00
|
|
|
|
this.irr = 0; //Interrupt Request Register
|
|
|
|
|
this.imr = 0; //Interrupt Mask Register
|
|
|
|
|
this.isr = 0; //In-Service Register
|
2011-12-21 13:34:38 +08:00
|
|
|
|
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;
|
2013-09-16 11:17:04 +08:00
|
|
|
|
this.elcr = 0; // Edge/Level Control Register
|
2011-12-21 13:34:38 +08:00
|
|
|
|
this.elcr_mask = 0;
|
|
|
|
|
};
|
2013-09-16 11:17:04 +08:00
|
|
|
|
PIC.prototype.set_irq1 = function(irq, Qf) {
|
|
|
|
|
var ir_register;
|
|
|
|
|
ir_register = 1 << irq;
|
2011-12-21 13:34:38 +08:00
|
|
|
|
if (Qf) {
|
2013-09-16 11:17:04 +08:00
|
|
|
|
if ((this.last_irr & ir_register) == 0)
|
|
|
|
|
this.irr |= ir_register;
|
|
|
|
|
this.last_irr |= ir_register;
|
2011-12-21 13:34:38 +08:00
|
|
|
|
} else {
|
2013-09-16 11:17:04 +08:00
|
|
|
|
this.last_irr &= ~ir_register;
|
2011-12-21 13:34:38 +08:00
|
|
|
|
}
|
|
|
|
|
};
|
2013-09-16 11:17:04 +08:00
|
|
|
|
/*
|
|
|
|
|
The priority assignments for IRQ0-7 seem to be maintained in a
|
|
|
|
|
cyclic order modulo 8 by the 8259A. On bootup, it default to:
|
|
|
|
|
|
|
|
|
|
Priority: 0 1 2 3 4 5 6 7
|
|
|
|
|
IRQ: 7 6 5 4 3 2 1 0
|
|
|
|
|
|
|
|
|
|
but can be rotated automatically or programmatically to a state e.g.:
|
|
|
|
|
|
|
|
|
|
Priority: 5 6 7 0 1 2 3 4
|
|
|
|
|
IRQ: 7 6 5 4 3 2 1 0
|
|
|
|
|
*/
|
|
|
|
|
PIC.prototype.get_priority = function(ir_register) {
|
|
|
|
|
var priority;
|
|
|
|
|
if (ir_register == 0)
|
2011-12-21 13:34:38 +08:00
|
|
|
|
return -1;
|
2013-09-16 11:17:04 +08:00
|
|
|
|
priority = 7;
|
|
|
|
|
while ((ir_register & (1 << ((priority + this.priority_add) & 7))) == 0)
|
|
|
|
|
priority--;
|
|
|
|
|
return priority;
|
2011-12-21 13:34:38 +08:00
|
|
|
|
};
|
|
|
|
|
PIC.prototype.get_irq = function() {
|
2013-09-16 11:17:04 +08:00
|
|
|
|
var ir_register, in_service_priority, priority;
|
|
|
|
|
ir_register = this.irr & ~this.imr;
|
|
|
|
|
priority = this.get_priority(ir_register);
|
|
|
|
|
if (priority < 0)
|
2011-12-21 13:34:38 +08:00
|
|
|
|
return -1;
|
2013-09-16 11:17:04 +08:00
|
|
|
|
in_service_priority = this.get_priority(this.isr);
|
|
|
|
|
if (priority > in_service_priority) {
|
|
|
|
|
return priority;
|
2011-12-21 13:34:38 +08:00
|
|
|
|
} else {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
};
|
2013-09-16 11:17:04 +08:00
|
|
|
|
PIC.prototype.intack = function(irq) {
|
2011-12-21 13:34:38 +08:00
|
|
|
|
if (this.auto_eoi) {
|
|
|
|
|
if (this.rotate_on_auto_eoi)
|
2013-09-16 11:17:04 +08:00
|
|
|
|
this.priority_add = (irq + 1) & 7;
|
2011-12-21 13:34:38 +08:00
|
|
|
|
} else {
|
2013-09-16 11:17:04 +08:00
|
|
|
|
this.isr |= (1 << irq);
|
2011-12-21 13:34:38 +08:00
|
|
|
|
}
|
2013-09-16 11:17:04 +08:00
|
|
|
|
if (!(this.elcr & (1 << irq)))
|
|
|
|
|
this.irr &= ~(1 << irq);
|
2011-12-21 13:34:38 +08:00
|
|
|
|
};
|
|
|
|
|
PIC.prototype.ioport_write = function(mem8_loc, x) {
|
2013-09-16 11:17:04 +08:00
|
|
|
|
var priority;
|
2011-12-21 13:34:38 +08:00
|
|
|
|
mem8_loc &= 1;
|
|
|
|
|
if (mem8_loc == 0) {
|
|
|
|
|
if (x & 0x10) {
|
2013-03-23 12:12:08 +08:00
|
|
|
|
/*
|
|
|
|
|
ICW1
|
|
|
|
|
// 7:5 = address (if MCS-80/85 mode)
|
|
|
|
|
// 4 == 1
|
|
|
|
|
// 3: 1 == level triggered, 0 == edge triggered
|
|
|
|
|
// 2: 1 == call interval 4, 0 == call interval 8
|
|
|
|
|
// 1: 1 == single PIC, 0 == cascaded PICs
|
|
|
|
|
// 0: 1 == send ICW4
|
|
|
|
|
|
|
|
|
|
*/
|
2011-12-21 13:34:38 +08:00
|
|
|
|
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:
|
2013-09-16 11:17:04 +08:00
|
|
|
|
priority = this.get_priority(this.isr);
|
|
|
|
|
if (priority >= 0) {
|
|
|
|
|
this.isr &= ~(1 << ((priority + this.priority_add) & 7));
|
2011-12-21 13:34:38 +08:00
|
|
|
|
}
|
|
|
|
|
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:
|
2013-09-16 11:17:04 +08:00
|
|
|
|
priority = x & 7;
|
|
|
|
|
this.isr &= ~(1 << priority);
|
2011-12-21 13:34:38 +08:00
|
|
|
|
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:
|
2013-09-16 11:17:04 +08:00
|
|
|
|
priority = x & 7;
|
|
|
|
|
this.isr &= ~(1 << priority);
|
|
|
|
|
this.priority_add = (priority + 1) & 7;
|
2011-12-21 13:34:38 +08:00
|
|
|
|
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) {
|
2013-09-16 11:17:04 +08:00
|
|
|
|
var mem8_loc, return_register;
|
2011-12-21 13:34:38 +08:00
|
|
|
|
mem8_loc = Ug & 1;
|
|
|
|
|
if (mem8_loc == 0) {
|
|
|
|
|
if (this.read_reg_select)
|
2013-09-16 11:17:04 +08:00
|
|
|
|
return_register = this.isr;
|
2011-12-21 13:34:38 +08:00
|
|
|
|
else
|
2013-09-16 11:17:04 +08:00
|
|
|
|
return_register = this.irr;
|
2011-12-21 13:34:38 +08:00
|
|
|
|
} else {
|
2013-09-16 11:17:04 +08:00
|
|
|
|
return_register = this.imr;
|
2011-12-21 13:34:38 +08:00
|
|
|
|
}
|
2013-09-16 11:17:04 +08:00
|
|
|
|
return return_register;
|
2011-12-21 13:34:38 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2013-09-16 11:17:04 +08:00
|
|
|
|
function PIC_Controller(PC, master_PIC_port, slave_PIC_port, cpu_set_irq_callback) {
|
2011-12-21 13:34:38 +08:00
|
|
|
|
this.pics = new Array();
|
2013-09-16 11:17:04 +08:00
|
|
|
|
this.pics[0] = new PIC(PC, master_PIC_port);
|
|
|
|
|
this.pics[1] = new PIC(PC, slave_PIC_port);
|
2011-12-21 13:34:38 +08:00
|
|
|
|
this.pics[0].elcr_mask = 0xf8;
|
|
|
|
|
this.pics[1].elcr_mask = 0xde;
|
|
|
|
|
this.irq_requested = 0;
|
2013-09-16 11:17:04 +08:00
|
|
|
|
this.cpu_set_irq = cpu_set_irq_callback;
|
2011-12-21 13:34:38 +08:00
|
|
|
|
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() {
|
2013-09-16 11:17:04 +08:00
|
|
|
|
var slave_irq, irq;
|
|
|
|
|
slave_irq = this.pics[1].get_irq();
|
|
|
|
|
if (slave_irq >= 0) {
|
2011-12-21 13:34:38 +08:00
|
|
|
|
this.pics[0].set_irq1(2, 1);
|
|
|
|
|
this.pics[0].set_irq1(2, 0);
|
|
|
|
|
}
|
2013-09-16 11:17:04 +08:00
|
|
|
|
irq = this.pics[0].get_irq();
|
|
|
|
|
if (irq >= 0) {
|
2011-12-21 13:34:38 +08:00
|
|
|
|
this.cpu_set_irq(1);
|
|
|
|
|
} else {
|
|
|
|
|
this.cpu_set_irq(0);
|
|
|
|
|
}
|
|
|
|
|
};
|
2013-09-16 11:17:04 +08:00
|
|
|
|
PIC_Controller.prototype.set_irq = function(irq, Qf) {
|
|
|
|
|
this.pics[irq >> 3].set_irq1(irq & 7, Qf);
|
2011-12-21 13:34:38 +08:00
|
|
|
|
this.update_irq();
|
|
|
|
|
};
|
|
|
|
|
PIC_Controller.prototype.get_hard_intno = function() {
|
2013-09-16 11:17:04 +08:00
|
|
|
|
var irq, slave_irq, intno;
|
|
|
|
|
irq = this.pics[0].get_irq();
|
|
|
|
|
if (irq >= 0) {
|
|
|
|
|
this.pics[0].intack(irq);
|
|
|
|
|
if (irq == 2) { //IRQ 2 cascaded to slave 8259 INT line in PC/AT
|
|
|
|
|
slave_irq = this.pics[1].get_irq();
|
|
|
|
|
if (slave_irq >= 0) {
|
|
|
|
|
this.pics[1].intack(slave_irq);
|
2011-12-21 13:34:38 +08:00
|
|
|
|
} else {
|
2013-09-16 11:17:04 +08:00
|
|
|
|
slave_irq = 7;
|
2011-12-21 13:34:38 +08:00
|
|
|
|
}
|
2013-09-16 11:17:04 +08:00
|
|
|
|
intno = this.pics[1].irq_base + slave_irq;
|
|
|
|
|
irq = slave_irq + 8;
|
2011-12-21 13:34:38 +08:00
|
|
|
|
} else {
|
2013-09-16 11:17:04 +08:00
|
|
|
|
intno = this.pics[0].irq_base + irq;
|
2011-12-21 13:34:38 +08:00
|
|
|
|
}
|
|
|
|
|
} else {
|
2013-09-16 11:17:04 +08:00
|
|
|
|
irq = 7;
|
|
|
|
|
intno = this.pics[0].irq_base + irq;
|
2011-12-21 13:34:38 +08:00
|
|
|
|
}
|
|
|
|
|
this.update_irq();
|
|
|
|
|
return intno;
|
|
|
|
|
};
|
2011-12-24 11:28:34 +08:00
|
|
|
|
|
|
|
|
|
|