Added comments and clarification on the PIC and PIT emulation code.
This commit is contained in:
parent
0f6b11c78e
commit
541ce3c478
30
CMOS.js
30
CMOS.js
@ -4,22 +4,34 @@
|
|||||||
Original is Copyright (c) 2011-2012 Fabrice Bellard
|
Original is Copyright (c) 2011-2012 Fabrice Bellard
|
||||||
Redistribution or commercial use is prohibited without the author's permission.
|
Redistribution or commercial use is prohibited without the author's permission.
|
||||||
|
|
||||||
Clock Emulator
|
CMOS Ram Memory, actually just the RTC Clock Emulator
|
||||||
|
|
||||||
|
Useful references:
|
||||||
|
------------------
|
||||||
|
http://www.bioscentral.com/misc/cmosmap.htm
|
||||||
|
http://wiki.osdev.org/CMOS
|
||||||
*/
|
*/
|
||||||
function formatter(a) { return ((a / 10) << 4) | (a % 10);}
|
|
||||||
|
/*
|
||||||
|
In this implementation, bytes are stored in the RTC in BCD format
|
||||||
|
binary -> bcd: bcd = ((bin / 10) << 4) | (bin % 10)
|
||||||
|
bcd -> binary: bin = ((bcd / 16) * 10) + (bcd & 0xf)
|
||||||
|
*/
|
||||||
|
function bin_to_bcd(a) { return ((a / 10) << 4) | (a % 10);}
|
||||||
|
|
||||||
function CMOS(PC) {
|
function CMOS(PC) {
|
||||||
var time_array, d;
|
var time_array, d;
|
||||||
time_array = new Uint8Array(128);
|
time_array = new Uint8Array(128);
|
||||||
this.cmos_data = time_array;
|
this.cmos_data = time_array;
|
||||||
this.cmos_index = 0;
|
this.cmos_index = 0;
|
||||||
d = new Date();
|
d = new Date();
|
||||||
time_array[0] = formatter(d.getUTCSeconds());
|
time_array[0] = bin_to_bcd(d.getUTCSeconds());
|
||||||
time_array[2] = formatter(d.getUTCMinutes());
|
time_array[2] = bin_to_bcd(d.getUTCMinutes());
|
||||||
time_array[4] = formatter(d.getUTCHours());
|
time_array[4] = bin_to_bcd(d.getUTCHours());
|
||||||
time_array[6] = formatter(d.getUTCDay());
|
time_array[6] = bin_to_bcd(d.getUTCDay());
|
||||||
time_array[7] = formatter(d.getUTCDate());
|
time_array[7] = bin_to_bcd(d.getUTCDate());
|
||||||
time_array[8] = formatter(d.getUTCMonth() + 1);
|
time_array[8] = bin_to_bcd(d.getUTCMonth() + 1);
|
||||||
time_array[9] = formatter(d.getUTCFullYear() % 100);
|
time_array[9] = bin_to_bcd(d.getUTCFullYear() % 100);
|
||||||
time_array[10] = 0x26;
|
time_array[10] = 0x26;
|
||||||
time_array[11] = 0x02;
|
time_array[11] = 0x02;
|
||||||
time_array[12] = 0x00;
|
time_array[12] = 0x00;
|
||||||
|
@ -7,25 +7,25 @@ Redistribution or commercial use is prohibited without the author's permission.
|
|||||||
Main PC Emulator Routine
|
Main PC Emulator Routine
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// used as callback wrappers for emulated PIT and PIC chips
|
||||||
function set_hard_irq_wrapper(irq) { this.hard_irq = irq;}
|
function set_hard_irq_wrapper(irq) { this.hard_irq = irq;}
|
||||||
|
|
||||||
function return_cycle_count() { return this.cycle_count; }
|
function return_cycle_count() { return this.cycle_count; }
|
||||||
|
|
||||||
function PCEmulator(uh) {
|
function PCEmulator(params) {
|
||||||
var cpu;
|
var cpu;
|
||||||
cpu = new CPU_X86();
|
cpu = new CPU_X86();
|
||||||
this.cpu = cpu;
|
this.cpu = cpu;
|
||||||
cpu.phys_mem_resize(uh.mem_size);
|
cpu.phys_mem_resize(params.mem_size);
|
||||||
this.init_ioports();
|
this.init_ioports();
|
||||||
this.register_ioport_write(0x80, 1, 1, this.ioport80_write);
|
this.register_ioport_write(0x80, 1, 1, this.ioport80_write);
|
||||||
this.pic = new PIC_Controller(this, 0x20, 0xa0, set_hard_irq_wrapper.bind(cpu));
|
this.pic = new PIC_Controller(this, 0x20, 0xa0, set_hard_irq_wrapper.bind(cpu));
|
||||||
this.pit = new PIT(this, this.pic.set_irq.bind(this.pic, 0), return_cycle_count.bind(cpu));
|
this.pit = new PIT(this, this.pic.set_irq.bind(this.pic, 0), return_cycle_count.bind(cpu));
|
||||||
this.cmos = new CMOS(this);
|
this.cmos = new CMOS(this);
|
||||||
this.serial = new Serial(this, 0x3f8, this.pic.set_irq.bind(this.pic, 4), uh.serial_write);
|
this.serial = new Serial(this, 0x3f8, this.pic.set_irq.bind(this.pic, 4), params.serial_write);
|
||||||
this.kbd = new KBD(this, this.reset.bind(this));
|
this.kbd = new KBD(this, this.reset.bind(this));
|
||||||
this.reset_request = 0;
|
this.reset_request = 0;
|
||||||
if (uh.clipboard_get && uh.clipboard_set) {
|
if (params.clipboard_get && params.clipboard_set) {
|
||||||
this.jsclipboard = new clipboard_device(this, 0x3c0, uh.clipboard_get, uh.clipboard_set, uh.get_boot_time);
|
this.jsclipboard = new clipboard_device(this, 0x3c0, params.clipboard_get, params.clipboard_set, params.get_boot_time);
|
||||||
}
|
}
|
||||||
cpu.ld8_port = this.ld8_port.bind(this);
|
cpu.ld8_port = this.ld8_port.bind(this);
|
||||||
cpu.ld16_port = this.ld16_port.bind(this);
|
cpu.ld16_port = this.ld16_port.bind(this);
|
||||||
@ -36,7 +36,7 @@ function PCEmulator(uh) {
|
|||||||
cpu.get_hard_intno = this.pic.get_hard_intno.bind(this.pic);
|
cpu.get_hard_intno = this.pic.get_hard_intno.bind(this.pic);
|
||||||
}
|
}
|
||||||
|
|
||||||
PCEmulator.prototype.load_binary = function(Gg, ha) { return this.cpu.load_binary(Gg, ha); };
|
PCEmulator.prototype.load_binary = function(url, mem8_loc) { return this.cpu.load_binary(url, mem8_loc); };
|
||||||
|
|
||||||
PCEmulator.prototype.start = function() { setTimeout(this.timer_func.bind(this), 10); };
|
PCEmulator.prototype.start = function() { setTimeout(this.timer_func.bind(this), 10); };
|
||||||
|
|
||||||
|
218
PIC.js
218
PIC.js
@ -1,11 +1,71 @@
|
|||||||
/*
|
/*
|
||||||
JSLinux-deobfuscated - An annotated version of the original JSLinux.
|
JSLinux-deobfuscated - An annotated version of the original JSLinux.
|
||||||
|
|
||||||
Original is Copyright (c) 2011-2012 Fabrice Bellard
|
Original is Copyright (c) 2011-2012 Fabrice Bellard
|
||||||
Redistribution or commercial use is prohibited without the author's permission.
|
Redistribution or commercial use is prohibited without the author's permission.
|
||||||
|
|
||||||
8259 PIC (Programmable Interrupt Controller) Emulation Code
|
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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
|
||||||
function PIC(PC, port_num) {
|
function PIC(PC, port_num) {
|
||||||
PC.register_ioport_write(port_num, 2, 1, this.ioport_write.bind(this));
|
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));
|
PC.register_ioport_read(port_num, 2, 1, this.ioport_read.bind(this));
|
||||||
@ -13,9 +73,9 @@ function PIC(PC, port_num) {
|
|||||||
}
|
}
|
||||||
PIC.prototype.reset = function() {
|
PIC.prototype.reset = function() {
|
||||||
this.last_irr = 0;
|
this.last_irr = 0;
|
||||||
this.irr = 0;
|
this.irr = 0; //Interrupt Request Register
|
||||||
this.imr = 0;
|
this.imr = 0; //Interrupt Mask Register
|
||||||
this.isr = 0;
|
this.isr = 0; //In-Service Register
|
||||||
this.priority_add = 0;
|
this.priority_add = 0;
|
||||||
this.irq_base = 0;
|
this.irq_base = 0;
|
||||||
this.read_reg_select = 0;
|
this.read_reg_select = 0;
|
||||||
@ -24,54 +84,66 @@ PIC.prototype.reset = function() {
|
|||||||
this.auto_eoi = 0;
|
this.auto_eoi = 0;
|
||||||
this.rotate_on_autoeoi = 0;
|
this.rotate_on_autoeoi = 0;
|
||||||
this.init4 = 0;
|
this.init4 = 0;
|
||||||
this.elcr = 0;
|
this.elcr = 0; // Edge/Level Control Register
|
||||||
this.elcr_mask = 0;
|
this.elcr_mask = 0;
|
||||||
};
|
};
|
||||||
PIC.prototype.set_irq1 = function(Rg, Qf) {
|
PIC.prototype.set_irq1 = function(irq, Qf) {
|
||||||
var wc;
|
var ir_register;
|
||||||
wc = 1 << Rg;
|
ir_register = 1 << irq;
|
||||||
if (Qf) {
|
if (Qf) {
|
||||||
if ((this.last_irr & wc) == 0)
|
if ((this.last_irr & ir_register) == 0)
|
||||||
this.irr |= wc;
|
this.irr |= ir_register;
|
||||||
this.last_irr |= wc;
|
this.last_irr |= ir_register;
|
||||||
} else {
|
} else {
|
||||||
this.last_irr &= ~wc;
|
this.last_irr &= ~ir_register;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
PIC.prototype.get_priority = function(wc) {
|
/*
|
||||||
var Sg;
|
The priority assignments for IRQ0-7 seem to be maintained in a
|
||||||
if (wc == 0)
|
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)
|
||||||
return -1;
|
return -1;
|
||||||
Sg = 7;
|
priority = 7;
|
||||||
while ((wc & (1 << ((Sg + this.priority_add) & 7))) == 0)
|
while ((ir_register & (1 << ((priority + this.priority_add) & 7))) == 0)
|
||||||
Sg--;
|
priority--;
|
||||||
return Sg;
|
return priority;
|
||||||
};
|
};
|
||||||
PIC.prototype.get_irq = function() {
|
PIC.prototype.get_irq = function() {
|
||||||
var wc, Tg, Sg;
|
var ir_register, in_service_priority, priority;
|
||||||
wc = this.irr & ~this.imr;
|
ir_register = this.irr & ~this.imr;
|
||||||
Sg = this.get_priority(wc);
|
priority = this.get_priority(ir_register);
|
||||||
if (Sg < 0)
|
if (priority < 0)
|
||||||
return -1;
|
return -1;
|
||||||
Tg = this.get_priority(this.isr);
|
in_service_priority = this.get_priority(this.isr);
|
||||||
if (Sg > Tg) {
|
if (priority > in_service_priority) {
|
||||||
return Sg;
|
return priority;
|
||||||
} else {
|
} else {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
PIC.prototype.intack = function(Rg) {
|
PIC.prototype.intack = function(irq) {
|
||||||
if (this.auto_eoi) {
|
if (this.auto_eoi) {
|
||||||
if (this.rotate_on_auto_eoi)
|
if (this.rotate_on_auto_eoi)
|
||||||
this.priority_add = (Rg + 1) & 7;
|
this.priority_add = (irq + 1) & 7;
|
||||||
} else {
|
} else {
|
||||||
this.isr |= (1 << Rg);
|
this.isr |= (1 << irq);
|
||||||
}
|
}
|
||||||
if (!(this.elcr & (1 << Rg)))
|
if (!(this.elcr & (1 << irq)))
|
||||||
this.irr &= ~(1 << Rg);
|
this.irr &= ~(1 << irq);
|
||||||
};
|
};
|
||||||
PIC.prototype.ioport_write = function(mem8_loc, x) {
|
PIC.prototype.ioport_write = function(mem8_loc, x) {
|
||||||
var Sg;
|
var priority;
|
||||||
mem8_loc &= 1;
|
mem8_loc &= 1;
|
||||||
if (mem8_loc == 0) {
|
if (mem8_loc == 0) {
|
||||||
if (x & 0x10) {
|
if (x & 0x10) {
|
||||||
@ -105,9 +177,9 @@ PIC.prototype.ioport_write = function(mem8_loc, x) {
|
|||||||
break;
|
break;
|
||||||
case 0x20:
|
case 0x20:
|
||||||
case 0xa0:
|
case 0xa0:
|
||||||
Sg = this.get_priority(this.isr);
|
priority = this.get_priority(this.isr);
|
||||||
if (Sg >= 0) {
|
if (priority >= 0) {
|
||||||
this.isr &= ~(1 << ((Sg + this.priority_add) & 7));
|
this.isr &= ~(1 << ((priority + this.priority_add) & 7));
|
||||||
}
|
}
|
||||||
if (x == 0xa0)
|
if (x == 0xa0)
|
||||||
this.priority_add = (this.priority_add + 1) & 7;
|
this.priority_add = (this.priority_add + 1) & 7;
|
||||||
@ -120,8 +192,8 @@ PIC.prototype.ioport_write = function(mem8_loc, x) {
|
|||||||
case 0x65:
|
case 0x65:
|
||||||
case 0x66:
|
case 0x66:
|
||||||
case 0x67:
|
case 0x67:
|
||||||
Sg = x & 7;
|
priority = x & 7;
|
||||||
this.isr &= ~(1 << Sg);
|
this.isr &= ~(1 << priority);
|
||||||
break;
|
break;
|
||||||
case 0xc0:
|
case 0xc0:
|
||||||
case 0xc1:
|
case 0xc1:
|
||||||
@ -141,9 +213,9 @@ PIC.prototype.ioport_write = function(mem8_loc, x) {
|
|||||||
case 0xe5:
|
case 0xe5:
|
||||||
case 0xe6:
|
case 0xe6:
|
||||||
case 0xe7:
|
case 0xe7:
|
||||||
Sg = x & 7;
|
priority = x & 7;
|
||||||
this.isr &= ~(1 << Sg);
|
this.isr &= ~(1 << priority);
|
||||||
this.priority_add = (Sg + 1) & 7;
|
this.priority_add = (priority + 1) & 7;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -172,69 +244,69 @@ PIC.prototype.ioport_write = function(mem8_loc, x) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
PIC.prototype.ioport_read = function(Ug) {
|
PIC.prototype.ioport_read = function(Ug) {
|
||||||
var mem8_loc, Pg;
|
var mem8_loc, return_register;
|
||||||
mem8_loc = Ug & 1;
|
mem8_loc = Ug & 1;
|
||||||
if (mem8_loc == 0) {
|
if (mem8_loc == 0) {
|
||||||
if (this.read_reg_select)
|
if (this.read_reg_select)
|
||||||
Pg = this.isr;
|
return_register = this.isr;
|
||||||
else
|
else
|
||||||
Pg = this.irr;
|
return_register = this.irr;
|
||||||
} else {
|
} else {
|
||||||
Pg = this.imr;
|
return_register = this.imr;
|
||||||
}
|
}
|
||||||
return Pg;
|
return return_register;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
function PIC_Controller(PC, Wg, Ug, Xg) {
|
function PIC_Controller(PC, master_PIC_port, slave_PIC_port, cpu_set_irq_callback) {
|
||||||
this.pics = new Array();
|
this.pics = new Array();
|
||||||
this.pics[0] = new PIC(PC, Wg);
|
this.pics[0] = new PIC(PC, master_PIC_port);
|
||||||
this.pics[1] = new PIC(PC, Ug);
|
this.pics[1] = new PIC(PC, slave_PIC_port);
|
||||||
this.pics[0].elcr_mask = 0xf8;
|
this.pics[0].elcr_mask = 0xf8;
|
||||||
this.pics[1].elcr_mask = 0xde;
|
this.pics[1].elcr_mask = 0xde;
|
||||||
this.irq_requested = 0;
|
this.irq_requested = 0;
|
||||||
this.cpu_set_irq = Xg;
|
this.cpu_set_irq = cpu_set_irq_callback;
|
||||||
this.pics[0].update_irq = this.update_irq.bind(this);
|
this.pics[0].update_irq = this.update_irq.bind(this);
|
||||||
this.pics[1].update_irq = this.update_irq.bind(this);
|
this.pics[1].update_irq = this.update_irq.bind(this);
|
||||||
}
|
}
|
||||||
PIC_Controller.prototype.update_irq = function() {
|
PIC_Controller.prototype.update_irq = function() {
|
||||||
var Yg, Rg;
|
var slave_irq, irq;
|
||||||
Yg = this.pics[1].get_irq();
|
slave_irq = this.pics[1].get_irq();
|
||||||
if (Yg >= 0) {
|
if (slave_irq >= 0) {
|
||||||
this.pics[0].set_irq1(2, 1);
|
this.pics[0].set_irq1(2, 1);
|
||||||
this.pics[0].set_irq1(2, 0);
|
this.pics[0].set_irq1(2, 0);
|
||||||
}
|
}
|
||||||
Rg = this.pics[0].get_irq();
|
irq = this.pics[0].get_irq();
|
||||||
if (Rg >= 0) {
|
if (irq >= 0) {
|
||||||
this.cpu_set_irq(1);
|
this.cpu_set_irq(1);
|
||||||
} else {
|
} else {
|
||||||
this.cpu_set_irq(0);
|
this.cpu_set_irq(0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
PIC_Controller.prototype.set_irq = function(Rg, Qf) {
|
PIC_Controller.prototype.set_irq = function(irq, Qf) {
|
||||||
this.pics[Rg >> 3].set_irq1(Rg & 7, Qf);
|
this.pics[irq >> 3].set_irq1(irq & 7, Qf);
|
||||||
this.update_irq();
|
this.update_irq();
|
||||||
};
|
};
|
||||||
PIC_Controller.prototype.get_hard_intno = function() {
|
PIC_Controller.prototype.get_hard_intno = function() {
|
||||||
var Rg, Yg, intno;
|
var irq, slave_irq, intno;
|
||||||
Rg = this.pics[0].get_irq();
|
irq = this.pics[0].get_irq();
|
||||||
if (Rg >= 0) {
|
if (irq >= 0) {
|
||||||
this.pics[0].intack(Rg);
|
this.pics[0].intack(irq);
|
||||||
if (Rg == 2) {
|
if (irq == 2) { //IRQ 2 cascaded to slave 8259 INT line in PC/AT
|
||||||
Yg = this.pics[1].get_irq();
|
slave_irq = this.pics[1].get_irq();
|
||||||
if (Yg >= 0) {
|
if (slave_irq >= 0) {
|
||||||
this.pics[1].intack(Yg);
|
this.pics[1].intack(slave_irq);
|
||||||
} else {
|
} else {
|
||||||
Yg = 7;
|
slave_irq = 7;
|
||||||
}
|
}
|
||||||
intno = this.pics[1].irq_base + Yg;
|
intno = this.pics[1].irq_base + slave_irq;
|
||||||
Rg = Yg + 8;
|
irq = slave_irq + 8;
|
||||||
} else {
|
} else {
|
||||||
intno = this.pics[0].irq_base + Rg;
|
intno = this.pics[0].irq_base + irq;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Rg = 7;
|
irq = 7;
|
||||||
intno = this.pics[0].irq_base + Rg;
|
intno = this.pics[0].irq_base + irq;
|
||||||
}
|
}
|
||||||
this.update_irq();
|
this.update_irq();
|
||||||
return intno;
|
return intno;
|
||||||
|
54
PIT.js
54
PIT.js
@ -1,23 +1,27 @@
|
|||||||
/*
|
/*
|
||||||
JSLinux-deobfuscated - An annotated version of the original JSLinux.
|
JSLinux-deobfuscated - An annotated version of the original JSLinux.
|
||||||
|
|
||||||
Original is Copyright (c) 2011-2012 Fabrice Bellard
|
Original is Copyright (c) 2011-2012 Fabrice Bellard
|
||||||
Redistribution or commercial use is prohibited without the author's permission.
|
Redistribution or commercial use is prohibited without the author's permission.
|
||||||
|
|
||||||
8254 Programmble Interrupt Timer Emulator
|
8254 Programmble Interrupt Timer Emulator
|
||||||
|
|
||||||
|
Useful References
|
||||||
|
-----------------
|
||||||
|
https://en.wikipedia.org/wiki/Intel_8253
|
||||||
*/
|
*/
|
||||||
function PIT(PC, ah, bh) {
|
function PIT(PC, set_irq_callback, cycle_count_callback) {
|
||||||
var s, i;
|
var s, i;
|
||||||
this.pit_channels = new Array();
|
this.pit_channels = new Array();
|
||||||
for (i = 0; i < 3; i++) {
|
for (i = 0; i < 3; i++) {
|
||||||
s = new IRQCH(bh);
|
s = new IRQCH(cycle_count_callback);
|
||||||
this.pit_channels[i] = s;
|
this.pit_channels[i] = s;
|
||||||
s.mode = 3;
|
s.mode = 3;
|
||||||
s.gate = (i != 2) >> 0;
|
s.gate = (i != 2) >> 0;
|
||||||
s.pit_load_count(0);
|
s.pit_load_count(0);
|
||||||
}
|
}
|
||||||
this.speaker_data_on = 0;
|
this.speaker_data_on = 0;
|
||||||
this.set_irq = ah;
|
this.set_irq = set_irq_callback;
|
||||||
// Ports:
|
// Ports:
|
||||||
// 0x40: Channel 0 data port
|
// 0x40: Channel 0 data port
|
||||||
// 0x61: Control
|
// 0x61: Control
|
||||||
@ -27,9 +31,7 @@ function PIT(PC, ah, bh) {
|
|||||||
PC.register_ioport_write(0x61, 1, 1, this.speaker_ioport_write.bind(this));
|
PC.register_ioport_write(0x61, 1, 1, this.speaker_ioport_write.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function IRQCH(cycle_count_callback) {
|
||||||
|
|
||||||
function IRQCH(bh) {
|
|
||||||
this.count = 0;
|
this.count = 0;
|
||||||
this.latched_count = 0;
|
this.latched_count = 0;
|
||||||
this.rw_state = 0;
|
this.rw_state = 0;
|
||||||
@ -37,7 +39,7 @@ function IRQCH(bh) {
|
|||||||
this.bcd = 0;
|
this.bcd = 0;
|
||||||
this.gate = 0;
|
this.gate = 0;
|
||||||
this.count_load_time = 0;
|
this.count_load_time = 0;
|
||||||
this.get_ticks = bh;
|
this.get_ticks = cycle_count_callback;
|
||||||
this.pit_time_unit = 1193182 / 2000000;
|
this.pit_time_unit = 1193182 / 2000000;
|
||||||
}
|
}
|
||||||
IRQCH.prototype.get_time = function() {
|
IRQCH.prototype.get_time = function() {
|
||||||
@ -64,29 +66,23 @@ IRQCH.prototype.pit_get_out = function() {
|
|||||||
d = this.get_time() - this.count_load_time;
|
d = this.get_time() - this.count_load_time;
|
||||||
switch (this.mode) {
|
switch (this.mode) {
|
||||||
default:
|
default:
|
||||||
// Interrupt on terminal count
|
case 0: // Interrupt on terminal count
|
||||||
case 0:
|
|
||||||
eh = (d >= this.count) >> 0;
|
eh = (d >= this.count) >> 0;
|
||||||
break;
|
break;
|
||||||
// One shot
|
case 1: // One shot
|
||||||
case 1:
|
|
||||||
eh = (d < this.count) >> 0;
|
eh = (d < this.count) >> 0;
|
||||||
break;
|
break;
|
||||||
// Frequency divider
|
case 2: // Frequency divider
|
||||||
case 2:
|
|
||||||
if ((d % this.count) == 0 && d != 0)
|
if ((d % this.count) == 0 && d != 0)
|
||||||
eh = 1;
|
eh = 1;
|
||||||
else
|
else
|
||||||
eh = 0;
|
eh = 0;
|
||||||
break;
|
break;
|
||||||
// Square wave
|
case 3: // Square wave
|
||||||
case 3:
|
|
||||||
eh = ((d % this.count) < (this.count >> 1)) >> 0;
|
eh = ((d % this.count) < (this.count >> 1)) >> 0;
|
||||||
break;
|
break;
|
||||||
// SW strobe
|
case 4: // SW strobe
|
||||||
case 4:
|
case 5: // HW strobe
|
||||||
// HW strobe
|
|
||||||
case 5:
|
|
||||||
eh = (d == this.count) >> 0;
|
eh = (d == this.count) >> 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -97,21 +93,21 @@ IRQCH.prototype.get_next_transition_time = function() {
|
|||||||
d = this.get_time() - this.count_load_time;
|
d = this.get_time() - this.count_load_time;
|
||||||
switch (this.mode) {
|
switch (this.mode) {
|
||||||
default:
|
default:
|
||||||
case 0:
|
case 0: // Interrupt on terminal count
|
||||||
case 1:
|
case 1: // One shot
|
||||||
if (d < this.count)
|
if (d < this.count)
|
||||||
fh = this.count;
|
fh = this.count;
|
||||||
else
|
else
|
||||||
return -1;
|
return -1;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2: // Frequency divider
|
||||||
base = (d / this.count) * this.count;
|
base = (d / this.count) * this.count;
|
||||||
if ((d - base) == 0 && d != 0)
|
if ((d - base) == 0 && d != 0)
|
||||||
fh = base + this.count;
|
fh = base + this.count;
|
||||||
else
|
else
|
||||||
fh = base + this.count + 1;
|
fh = base + this.count + 1;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3: // Square wave
|
||||||
base = (d / this.count) * this.count;
|
base = (d / this.count) * this.count;
|
||||||
gh = ((this.count + 1) >> 1);
|
gh = ((this.count + 1) >> 1);
|
||||||
if ((d - base) < gh)
|
if ((d - base) < gh)
|
||||||
@ -119,8 +115,8 @@ IRQCH.prototype.get_next_transition_time = function() {
|
|||||||
else
|
else
|
||||||
fh = base + this.count;
|
fh = base + this.count;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4: // SW strobe
|
||||||
case 5:
|
case 5: // HW strobe
|
||||||
if (d < this.count)
|
if (d < this.count)
|
||||||
fh = this.count;
|
fh = this.count;
|
||||||
else if (d == this.count)
|
else if (d == this.count)
|
||||||
|
Loading…
Reference in New Issue
Block a user