Split massive emulator code into logical parts.
This commit is contained in:
parent
e3133b25ad
commit
480a1c2e68
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
Fabrix - An annotated version of the original JSLinux which is Copyright (c) 2011 Fabrice Bellard
|
||||
|
||||
Clock Emulator
|
||||
*/
|
||||
function Lg(a) { return ((a / 10) << 4) | (a % 10);}
|
||||
function CMOS(Ng) {
|
||||
var Og, d;
|
||||
Og = new Uint8Array(128);
|
||||
this.cmos_data = Og;
|
||||
this.cmos_index = 0;
|
||||
d = new Date();
|
||||
Og[0] = Lg(d.getUTCSeconds());
|
||||
Og[2] = Lg(d.getUTCMinutes());
|
||||
Og[4] = Lg(d.getUTCHours());
|
||||
Og[6] = Lg(d.getUTCDay());
|
||||
Og[7] = Lg(d.getUTCDate());
|
||||
Og[8] = Lg(d.getUTCMonth() + 1);
|
||||
Og[9] = Lg(d.getUTCFullYear() % 100);
|
||||
Og[10] = 0x26;
|
||||
Og[11] = 0x02;
|
||||
Og[12] = 0x00;
|
||||
Og[13] = 0x80;
|
||||
Og[0x14] = 0x02;
|
||||
Ng.register_ioport_write(0x70, 2, 1, this.ioport_write.bind(this));
|
||||
Ng.register_ioport_read(0x70, 2, 1, this.ioport_read.bind(this));
|
||||
}
|
||||
CMOS.prototype.ioport_write = function(mem8_loc, Ig) {
|
||||
if (mem8_loc == 0x70) {
|
||||
this.cmos_index = Ig & 0x7f;
|
||||
}
|
||||
};
|
||||
CMOS.prototype.ioport_read = function(mem8_loc) {
|
||||
var Pg;
|
||||
if (mem8_loc == 0x70) {
|
||||
return 0xff;
|
||||
} else {
|
||||
Pg = this.cmos_data[this.cmos_index];
|
||||
if (this.cmos_index == 10)
|
||||
this.cmos_data[10] ^= 0x80;
|
||||
else if (this.cmos_index == 12)
|
||||
this.cmos_data[12] = 0x00;
|
||||
return Pg;
|
||||
}
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
Fabrix - An annotated version of the original JSLinux which is Copyright (c) 2011 Fabrice Bellard
|
||||
|
||||
Keyboard Device Emulator
|
||||
*/
|
||||
function KBD(Ng, ph) {
|
||||
Ng.register_ioport_read(0x64, 1, 1, this.read_status.bind(this));
|
||||
Ng.register_ioport_write(0x64, 1, 1, this.write_command.bind(this));
|
||||
this.reset_request = ph;
|
||||
}
|
||||
KBD.prototype.read_status = function(mem8_loc) {
|
||||
return 0;
|
||||
};
|
||||
KBD.prototype.write_command = function(mem8_loc, x) {
|
||||
switch (x) {
|
||||
case 0xfe:
|
||||
this.reset_request();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
Fabrix - An annotated version of the original JSLinux which is Copyright (c) 2011 Fabrice Bellard
|
||||
|
||||
Main PC Emulator Routine
|
||||
*/
|
||||
|
||||
function set_hard_irq_wrapper(irq) { this.hard_irq = irq;}
|
||||
|
||||
function return_cycle_count() { return this.cycle_count; }
|
||||
|
||||
function PCEmulator(uh) {
|
||||
var cpu;
|
||||
cpu = new CPU_X86();
|
||||
this.cpu = cpu;
|
||||
cpu.phys_mem_resize(uh.mem_size);
|
||||
this.init_ioports();
|
||||
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.pit = new PIT(this, this.pic.set_irq.bind(this.pic, 0), return_cycle_count.bind(cpu));
|
||||
this.cmos = new CMOS(this);
|
||||
this.serial = new Serial(this, 0x3f8, this.pic.set_irq.bind(this.pic, 4), uh.serial_write);
|
||||
this.kbd = new KBD(this, this.reset.bind(this));
|
||||
this.reset_request = 0;
|
||||
if (uh.clipboard_get && uh.clipboard_set) {
|
||||
this.jsclipboard = new clipboard_device(this, 0x3c0, uh.clipboard_get, uh.clipboard_set, uh.get_boot_time);
|
||||
}
|
||||
cpu.ld8_port = this.ld8_port.bind(this);
|
||||
cpu.ld16_port = this.ld16_port.bind(this);
|
||||
cpu.ld32_port = this.ld32_port.bind(this);
|
||||
cpu.st8_port = this.st8_port.bind(this);
|
||||
cpu.st16_port = this.st16_port.bind(this);
|
||||
cpu.st32_port = this.st32_port.bind(this);
|
||||
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.start = function() { setTimeout(this.timer_func.bind(this), 10); };
|
||||
|
||||
PCEmulator.prototype.timer_func = function() {
|
||||
var La, vh, wh, xh, yh, Ng, cpu;
|
||||
Ng = this;
|
||||
cpu = Ng.cpu;
|
||||
wh = cpu.cycle_count + 100000;
|
||||
xh = false;
|
||||
yh = false;
|
||||
zh: while (cpu.cycle_count < wh) {
|
||||
Ng.pit.update_irq();
|
||||
La = cpu.exec(wh - cpu.cycle_count);
|
||||
if (La == 256) {
|
||||
if (Ng.reset_request) {
|
||||
xh = true;
|
||||
break;
|
||||
}
|
||||
} else if (La == 257) {
|
||||
yh = true;
|
||||
break;
|
||||
} else {
|
||||
xh = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!xh) {
|
||||
if (yh) {
|
||||
setTimeout(this.timer_func.bind(this), 10);
|
||||
} else {
|
||||
setTimeout(this.timer_func.bind(this), 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
PCEmulator.prototype.init_ioports = function() {
|
||||
var i, Ah, Bh;
|
||||
this.ioport_readb_table = new Array();
|
||||
this.ioport_writeb_table = new Array();
|
||||
this.ioport_readw_table = new Array();
|
||||
this.ioport_writew_table = new Array();
|
||||
this.ioport_readl_table = new Array();
|
||||
this.ioport_writel_table = new Array();
|
||||
Ah = this.default_ioport_readw.bind(this);
|
||||
Bh = this.default_ioport_writew.bind(this);
|
||||
for (i = 0; i < 1024; i++) {
|
||||
this.ioport_readb_table[i] = this.default_ioport_readb;
|
||||
this.ioport_writeb_table[i] = this.default_ioport_writeb;
|
||||
this.ioport_readw_table[i] = Ah;
|
||||
this.ioport_writew_table[i] = Bh;
|
||||
this.ioport_readl_table[i] = this.default_ioport_readl;
|
||||
this.ioport_writel_table[i] = this.default_ioport_writel;
|
||||
}
|
||||
};
|
||||
|
||||
PCEmulator.prototype.default_ioport_readb = function(Zf) {
|
||||
var x;
|
||||
x = 0xff;
|
||||
return x;
|
||||
};
|
||||
|
||||
PCEmulator.prototype.default_ioport_readw = function(Zf) {
|
||||
var x;
|
||||
x = this.ioport_readb_table[Zf](Zf);
|
||||
Zf = (Zf + 1) & (1024 - 1);
|
||||
x |= this.ioport_readb_table[Zf](Zf) << 8;
|
||||
return x;
|
||||
};
|
||||
|
||||
PCEmulator.prototype.default_ioport_readl = function(Zf) {
|
||||
var x;
|
||||
x = -1;
|
||||
return x;
|
||||
};
|
||||
|
||||
PCEmulator.prototype.default_ioport_writeb = function(Zf, x) {};
|
||||
|
||||
PCEmulator.prototype.default_ioport_writew = function(Zf, x) {
|
||||
this.ioport_writeb_table[Zf](Zf, x & 0xff);
|
||||
Zf = (Zf + 1) & (1024 - 1);
|
||||
this.ioport_writeb_table[Zf](Zf, (x >> 8) & 0xff);
|
||||
};
|
||||
|
||||
PCEmulator.prototype.default_ioport_writel = function(Zf, x) {};
|
||||
|
||||
PCEmulator.prototype.ld8_port = function(Zf) {
|
||||
var x;
|
||||
x = this.ioport_readb_table[Zf & (1024 - 1)](Zf);
|
||||
return x;
|
||||
};
|
||||
|
||||
PCEmulator.prototype.ld16_port = function(Zf) {
|
||||
var x;
|
||||
x = this.ioport_readw_table[Zf & (1024 - 1)](Zf);
|
||||
return x;
|
||||
};
|
||||
|
||||
PCEmulator.prototype.ld32_port = function(Zf) {
|
||||
var x;
|
||||
x = this.ioport_readl_table[Zf & (1024 - 1)](Zf);
|
||||
return x;
|
||||
};
|
||||
|
||||
PCEmulator.prototype.st8_port = function(Zf, x) { this.ioport_writeb_table[Zf & (1024 - 1)](Zf, x); };
|
||||
PCEmulator.prototype.st16_port = function(Zf, x) { this.ioport_writew_table[Zf & (1024 - 1)](Zf, x); };
|
||||
PCEmulator.prototype.st32_port = function(Zf, x) { this.ioport_writel_table[Zf & (1024 - 1)](Zf, x); };
|
||||
|
||||
PCEmulator.prototype.register_ioport_read = function(start, tg, cc, Ch) {
|
||||
var i;
|
||||
switch (cc) {
|
||||
case 1:
|
||||
for (i = start; i < start + tg; i++) {
|
||||
this.ioport_readb_table[i] = Ch;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
for (i = start; i < start + tg; i += 2) {
|
||||
this.ioport_readw_table[i] = Ch;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
for (i = start; i < start + tg; i += 4) {
|
||||
this.ioport_readl_table[i] = Ch;
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
PCEmulator.prototype.register_ioport_write = function(start, tg, cc, Ch) {
|
||||
var i;
|
||||
switch (cc) {
|
||||
case 1:
|
||||
for (i = start; i < start + tg; i++) {
|
||||
this.ioport_writeb_table[i] = Ch;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
for (i = start; i < start + tg; i += 2) {
|
||||
this.ioport_writew_table[i] = Ch;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
for (i = start; i < start + tg; i += 4) {
|
||||
this.ioport_writel_table[i] = Ch;
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
PCEmulator.prototype.ioport80_write = function(mem8_loc, Ig) {};
|
||||
PCEmulator.prototype.reset = function() { this.request_request = 1; };
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
Fabrix - An annotated version of the original JSLinux which is Copyright (c) 2011 Fabrice Bellard
|
||||
|
||||
8259 PIC (Programmable Interrupt Controller) Emulation Code
|
||||
*/
|
||||
function PIC(Ng, Zf) {
|
||||
Ng.register_ioport_write(Zf, 2, 1, this.ioport_write.bind(this));
|
||||
Ng.register_ioport_read(Zf, 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(Ng, Wg, Ug, Xg) {
|
||||
this.pics = new Array();
|
||||
this.pics[0] = new PIC(Ng, Wg);
|
||||
this.pics[1] = new PIC(Ng, 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;
|
||||
};
|
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
Fabrix - An annotated version of the original JSLinux which is Copyright (c) 2011 Fabrice Bellard
|
||||
|
||||
PIT Emulator
|
||||
*/
|
||||
function PIT(Ng, ah, bh) {
|
||||
var s, i;
|
||||
this.pit_channels = new Array();
|
||||
for (i = 0; i < 3; i++) {
|
||||
s = new IRQCH(bh);
|
||||
this.pit_channels[i] = s;
|
||||
s.mode = 3;
|
||||
s.gate = (i != 2) >> 0;
|
||||
s.pit_load_count(0);
|
||||
}
|
||||
this.speaker_data_on = 0;
|
||||
this.set_irq = ah;
|
||||
Ng.register_ioport_write(0x40, 4, 1, this.ioport_write.bind(this));
|
||||
Ng.register_ioport_read(0x40, 3, 1, this.ioport_read.bind(this));
|
||||
Ng.register_ioport_read(0x61, 1, 1, this.speaker_ioport_read.bind(this));
|
||||
Ng.register_ioport_write(0x61, 1, 1, this.speaker_ioport_write.bind(this));
|
||||
}
|
||||
|
||||
|
||||
|
||||
function IRQCH(bh) {
|
||||
this.count = 0;
|
||||
this.latched_count = 0;
|
||||
this.rw_state = 0;
|
||||
this.mode = 0;
|
||||
this.bcd = 0;
|
||||
this.gate = 0;
|
||||
this.count_load_time = 0;
|
||||
this.get_ticks = bh;
|
||||
this.pit_time_unit = 1193182 / 2000000;
|
||||
}
|
||||
IRQCH.prototype.get_time = function() {
|
||||
return Math.floor(this.get_ticks() * this.pit_time_unit);
|
||||
};
|
||||
IRQCH.prototype.pit_get_count = function() {
|
||||
var d, dh;
|
||||
d = this.get_time() - this.count_load_time;
|
||||
switch (this.mode) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 4:
|
||||
case 5:
|
||||
dh = (this.count - d) & 0xffff;
|
||||
break;
|
||||
default:
|
||||
dh = this.count - (d % this.count);
|
||||
break;
|
||||
}
|
||||
return dh;
|
||||
};
|
||||
IRQCH.prototype.pit_get_out = function() {
|
||||
var d, eh;
|
||||
d = this.get_time() - this.count_load_time;
|
||||
switch (this.mode) {
|
||||
default:
|
||||
case 0:
|
||||
eh = (d >= this.count) >> 0;
|
||||
break;
|
||||
case 1:
|
||||
eh = (d < this.count) >> 0;
|
||||
break;
|
||||
case 2:
|
||||
if ((d % this.count) == 0 && d != 0)
|
||||
eh = 1;
|
||||
else
|
||||
eh = 0;
|
||||
break;
|
||||
case 3:
|
||||
eh = ((d % this.count) < (this.count >> 1)) >> 0;
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
eh = (d == this.count) >> 0;
|
||||
break;
|
||||
}
|
||||
return eh;
|
||||
};
|
||||
IRQCH.prototype.get_next_transition_time = function() {
|
||||
var d, fh, base, gh;
|
||||
d = this.get_time() - this.count_load_time;
|
||||
switch (this.mode) {
|
||||
default:
|
||||
case 0:
|
||||
case 1:
|
||||
if (d < this.count)
|
||||
fh = this.count;
|
||||
else
|
||||
return -1;
|
||||
break;
|
||||
case 2:
|
||||
base = (d / this.count) * this.count;
|
||||
if ((d - base) == 0 && d != 0)
|
||||
fh = base + this.count;
|
||||
else
|
||||
fh = base + this.count + 1;
|
||||
break;
|
||||
case 3:
|
||||
base = (d / this.count) * this.count;
|
||||
gh = ((this.count + 1) >> 1);
|
||||
if ((d - base) < gh)
|
||||
fh = base + gh;
|
||||
else
|
||||
fh = base + this.count;
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
if (d < this.count)
|
||||
fh = this.count;
|
||||
else if (d == this.count)
|
||||
fh = this.count + 1;
|
||||
else
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
fh = this.count_load_time + fh;
|
||||
return fh;
|
||||
};
|
||||
IRQCH.prototype.pit_load_count = function(x) {
|
||||
if (x == 0)
|
||||
x = 0x10000;
|
||||
this.count_load_time = this.get_time();
|
||||
this.count = x;
|
||||
};
|
||||
|
||||
|
||||
|
||||
PIT.prototype.ioport_write = function(mem8_loc, x) {
|
||||
var hh, ih, s;
|
||||
mem8_loc &= 3;
|
||||
if (mem8_loc == 3) {
|
||||
hh = x >> 6;
|
||||
if (hh == 3)
|
||||
return;
|
||||
s = this.pit_channels[hh];
|
||||
ih = (x >> 4) & 3;
|
||||
switch (ih) {
|
||||
case 0:
|
||||
s.latched_count = s.pit_get_count();
|
||||
s.rw_state = 4;
|
||||
break;
|
||||
default:
|
||||
s.mode = (x >> 1) & 7;
|
||||
s.bcd = x & 1;
|
||||
s.rw_state = ih - 1 + 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
s = this.pit_channels[mem8_loc];
|
||||
switch (s.rw_state) {
|
||||
case 0:
|
||||
s.pit_load_count(x);
|
||||
break;
|
||||
case 1:
|
||||
s.pit_load_count(x << 8);
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
if (s.rw_state & 1) {
|
||||
s.pit_load_count((s.latched_count & 0xff) | (x << 8));
|
||||
} else {
|
||||
s.latched_count = x;
|
||||
}
|
||||
s.rw_state ^= 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
PIT.prototype.ioport_read = function(mem8_loc) {
|
||||
var Pg, ma, s;
|
||||
mem8_loc &= 3;
|
||||
s = this.pit_channels[mem8_loc];
|
||||
switch (s.rw_state) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
ma = s.pit_get_count();
|
||||
if (s.rw_state & 1)
|
||||
Pg = (ma >> 8) & 0xff;
|
||||
else
|
||||
Pg = ma & 0xff;
|
||||
if (s.rw_state & 2)
|
||||
s.rw_state ^= 1;
|
||||
break;
|
||||
default:
|
||||
case 4:
|
||||
case 5:
|
||||
if (s.rw_state & 1)
|
||||
Pg = s.latched_count >> 8;
|
||||
else
|
||||
Pg = s.latched_count & 0xff;
|
||||
s.rw_state ^= 1;
|
||||
break;
|
||||
}
|
||||
return Pg;
|
||||
};
|
||||
PIT.prototype.speaker_ioport_write = function(mem8_loc, x) {
|
||||
this.speaker_data_on = (x >> 1) & 1;
|
||||
this.pit_channels[2].gate = x & 1;
|
||||
};
|
||||
PIT.prototype.speaker_ioport_read = function(mem8_loc) {
|
||||
var eh, s, x;
|
||||
s = this.pit_channels[2];
|
||||
eh = s.pit_get_out();
|
||||
x = (this.speaker_data_on << 1) | s.gate | (eh << 5);
|
||||
return x;
|
||||
};
|
||||
PIT.prototype.update_irq = function() {
|
||||
this.set_irq(1);
|
||||
this.set_irq(0);
|
||||
};
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
Fabrix - An annotated version of the original JSLinux which is Copyright (c) 2011 Fabrice Bellard
|
||||
|
||||
Serial Controller Emulator
|
||||
*/
|
||||
|
||||
function Serial(Ng, mem8_loc, kh, lh) {
|
||||
this.divider = 0;
|
||||
this.rbr = 0;
|
||||
this.ier = 0;
|
||||
this.iir = 0x01;
|
||||
this.lcr = 0;
|
||||
this.mcr;
|
||||
this.lsr = 0x40 | 0x20;
|
||||
this.msr = 0;
|
||||
this.scr = 0;
|
||||
this.set_irq_func = kh;
|
||||
this.write_func = lh;
|
||||
this.receive_fifo = "";
|
||||
Ng.register_ioport_write(0x3f8, 8, 1, this.ioport_write.bind(this));
|
||||
Ng.register_ioport_read(0x3f8, 8, 1, this.ioport_read.bind(this));
|
||||
}
|
||||
Serial.prototype.update_irq = function() {
|
||||
if ((this.lsr & 0x01) && (this.ier & 0x01)) {
|
||||
this.iir = 0x04;
|
||||
} else if ((this.lsr & 0x20) && (this.ier & 0x02)) {
|
||||
this.iir = 0x02;
|
||||
} else {
|
||||
this.iir = 0x01;
|
||||
}
|
||||
if (this.iir != 0x01) {
|
||||
this.set_irq_func(1);
|
||||
} else {
|
||||
this.set_irq_func(0);
|
||||
}
|
||||
};
|
||||
Serial.prototype.ioport_write = function(mem8_loc, x) {
|
||||
mem8_loc &= 7;
|
||||
switch (mem8_loc) {
|
||||
default:
|
||||
case 0:
|
||||
if (this.lcr & 0x80) {
|
||||
this.divider = (this.divider & 0xff00) | x;
|
||||
} else {
|
||||
this.lsr &= ~0x20;
|
||||
this.update_irq();
|
||||
this.write_func(String.fromCharCode(x));
|
||||
this.lsr |= 0x20;
|
||||
this.lsr |= 0x40;
|
||||
this.update_irq();
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (this.lcr & 0x80) {
|
||||
this.divider = (this.divider & 0x00ff) | (x << 8);
|
||||
} else {
|
||||
this.ier = x;
|
||||
this.update_irq();
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
this.lcr = x;
|
||||
break;
|
||||
case 4:
|
||||
this.mcr = x;
|
||||
break;
|
||||
case 5:
|
||||
break;
|
||||
case 6:
|
||||
this.msr = x;
|
||||
break;
|
||||
case 7:
|
||||
this.scr = x;
|
||||
break;
|
||||
}
|
||||
};
|
||||
Serial.prototype.ioport_read = function(mem8_loc) {
|
||||
var Pg;
|
||||
mem8_loc &= 7;
|
||||
switch (mem8_loc) {
|
||||
default:
|
||||
case 0:
|
||||
if (this.lcr & 0x80) {
|
||||
Pg = this.divider & 0xff;
|
||||
} else {
|
||||
Pg = this.rbr;
|
||||
this.lsr &= ~(0x01 | 0x10);
|
||||
this.update_irq();
|
||||
this.send_char_from_fifo();
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (this.lcr & 0x80) {
|
||||
Pg = (this.divider >> 8) & 0xff;
|
||||
} else {
|
||||
Pg = this.ier;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
Pg = this.iir;
|
||||
break;
|
||||
case 3:
|
||||
Pg = this.lcr;
|
||||
break;
|
||||
case 4:
|
||||
Pg = this.mcr;
|
||||
break;
|
||||
case 5:
|
||||
Pg = this.lsr;
|
||||
break;
|
||||
case 6:
|
||||
Pg = this.msr;
|
||||
break;
|
||||
case 7:
|
||||
Pg = this.scr;
|
||||
break;
|
||||
}
|
||||
return Pg;
|
||||
};
|
||||
Serial.prototype.send_break = function() {
|
||||
this.rbr = 0;
|
||||
this.lsr |= 0x10 | 0x01;
|
||||
this.update_irq();
|
||||
};
|
||||
Serial.prototype.send_char = function(mh) {
|
||||
this.rbr = mh;
|
||||
this.lsr |= 0x01;
|
||||
this.update_irq();
|
||||
};
|
||||
Serial.prototype.send_char_from_fifo = function() {
|
||||
var nh;
|
||||
nh = this.receive_fifo;
|
||||
if (nh != "" && !(this.lsr & 0x01)) {
|
||||
this.send_char(nh.charCodeAt(0));
|
||||
this.receive_fifo = nh.substr(1, nh.length - 1);
|
||||
}
|
||||
};
|
||||
Serial.prototype.send_chars = function(na) {
|
||||
this.receive_fifo += na;
|
||||
this.send_char_from_fifo();
|
||||
};
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
Fabrix - An annotated version of the original JSLinux which is Copyright (c) 2011 Fabrice Bellard
|
||||
|
||||
Clipboard Device
|
||||
*/
|
||||
function clipboard_device(Ng, Zf, rh, lh, sh) {
|
||||
Ng.register_ioport_read(Zf, 16, 4, this.ioport_readl.bind(this));
|
||||
Ng.register_ioport_write(Zf, 16, 4, this.ioport_writel.bind(this));
|
||||
Ng.register_ioport_read(Zf + 8, 1, 1, this.ioport_readb.bind(this));
|
||||
Ng.register_ioport_write(Zf + 8, 1, 1, this.ioport_writeb.bind(this));
|
||||
this.cur_pos = 0;
|
||||
this.doc_str = "";
|
||||
this.read_func = rh;
|
||||
this.write_func = lh;
|
||||
this.get_boot_time = sh;
|
||||
}
|
||||
clipboard_device.prototype.ioport_writeb = function(mem8_loc, x) {
|
||||
this.doc_str += String.fromCharCode(x);
|
||||
};
|
||||
clipboard_device.prototype.ioport_readb = function(mem8_loc) {
|
||||
var c, na, x;
|
||||
na = this.doc_str;
|
||||
if (this.cur_pos < na.length) {
|
||||
x = na.charCodeAt(this.cur_pos) & 0xff;
|
||||
} else {
|
||||
x = 0;
|
||||
}
|
||||
this.cur_pos++;
|
||||
return x;
|
||||
};
|
||||
clipboard_device.prototype.ioport_writel = function(mem8_loc, x) {
|
||||
var na;
|
||||
mem8_loc = (mem8_loc >> 2) & 3;
|
||||
switch (mem8_loc) {
|
||||
case 0:
|
||||
this.doc_str = this.doc_str.substr(0, x >>> 0);
|
||||
break;
|
||||
case 1:
|
||||
return this.cur_pos = x >>> 0;
|
||||
case 2:
|
||||
na = String.fromCharCode(x & 0xff) + String.fromCharCode((x >> 8) & 0xff) + String.fromCharCode((x >> 16) & 0xff) + String.fromCharCode((x >> 24) & 0xff);
|
||||
this.doc_str += na;
|
||||
break;
|
||||
case 3:
|
||||
this.write_func(this.doc_str);
|
||||
}
|
||||
};
|
||||
clipboard_device.prototype.ioport_readl = function(mem8_loc) {
|
||||
var x;
|
||||
mem8_loc = (mem8_loc >> 2) & 3;
|
||||
switch (mem8_loc) {
|
||||
case 0:
|
||||
this.doc_str = this.read_func();
|
||||
return this.doc_str.length >> 0;
|
||||
case 1:
|
||||
return this.cur_pos >> 0;
|
||||
case 2:
|
||||
x = this.ioport_readb(0);
|
||||
x |= this.ioport_readb(0) << 8;
|
||||
x |= this.ioport_readb(0) << 16;
|
||||
x |= this.ioport_readb(0) << 24;
|
||||
return x;
|
||||
case 3:
|
||||
if (this.get_boot_time)
|
||||
return this.get_boot_time() >> 0;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
};
|
1035
cpux86-ta.js
1035
cpux86-ta.js
File diff suppressed because it is too large
Load Diff
32
index.html
32
index.html
|
@ -28,30 +28,18 @@
|
|||
<body onload="start()">
|
||||
<table border="0">
|
||||
<tr valign="top"><td>
|
||||
|
||||
<script type="text/javascript" src="term.js"></script>
|
||||
<script type="text/javascript">
|
||||
<!--
|
||||
function include(filename)
|
||||
{
|
||||
document.write('<script type="text/javascript" src="' + filename +
|
||||
'"><' + '/script>');
|
||||
}
|
||||
function test_typed_arrays()
|
||||
{
|
||||
return (window.Uint8Array &&
|
||||
window.Uint16Array &&
|
||||
window.Int32Array &&
|
||||
window.ArrayBuffer);
|
||||
}
|
||||
if (test_typed_arrays()) {
|
||||
include("cpux86-ta.js");
|
||||
} else {
|
||||
include("cpux86.js");
|
||||
document.write('<canvas id="dummy_canvas" width="1" height="1"></canvas>');
|
||||
}
|
||||
-->
|
||||
</script>
|
||||
<script type="text/javascript" src="cpux86-ta.js"></script>
|
||||
<script type="text/javascript" src="Serial.js"></script>
|
||||
<script type="text/javascript" src="PIT.js"></script>
|
||||
<script type="text/javascript" src="PIC.js"></script>
|
||||
<script type="text/javascript" src="CMOS.js"></script>
|
||||
<script type="text/javascript" src="KBD.js"></script>
|
||||
<script type="text/javascript" src="clipboard.js"></script>
|
||||
<script type="text/javascript" src="PCEmulator.js"></script>
|
||||
<script type="text/javascript" src="jslinux.js"></script>
|
||||
|
||||
<div id="copyright">© 2011 Fabrice Bellard - <a href="news.html">News</a> - <a href="faq.html">FAQ</a> - <a href="tech.html">Technical notes</a></div>
|
||||
<td><input type="button" value="Clear clipboard" onclick="clear_clipboard();"><br><textarea row="4" cols="16" id="text_clipboard"></textarea>
|
||||
</table>
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
De-obfuscated JSLinux
|
||||
=========================================================
|
||||
|
||||
I wanted to understand how the amazing [JsLinux][1] worked. However, Mr Bellard seems to have applied a decidedly french proclivity towards obfuscatory algorithmic prose, replete with two-letter variable names and the like... ;)
|
||||
I wanted to understand how the amazing [JsLinux][1] worked. However, Mr Bellard seems to have applied a decidedly french proclivity towards obfuscatory algorithmic prose, replete with two-letter variable names and the like... ;) I have no idea if he passed it through a minifier or if the code was generated algorithmically from stuff in the QEMU codebase. In any case, it's hard to follow the action as presented originally, let alone extend it to do new tricks.
|
||||
|
||||
So in order to better understand the code, I started transforming all the symbols and commenting it up, which isn't all that hard a thing to do given that it's been built to imitate a very well-specified piece of hardware.
|
||||
|
||||
### Stats
|
||||
It's still absolutely ungainly, but not nearly so ungainly as the original. About a third to a half of the variables/function names have been redescribed.
|
||||
### Status
|
||||
It's still absolutely ungainly, but not nearly so ungainly as the original. About a third to a half of the variables/function names have been redescribed. The names are basically long comments and will ultimately need to be redone once the whole is understood.
|
||||
|
||||
I highly recommend, by the way, the excellent [JSShaper][2] library for transforming large javascript code bases. The hacks I made from it are in this repo.
|
||||
I highly recommend, by the way, the excellent [JSShaper][2] library for transforming large javascript code bases. The hacks I made from it are in this repo: a little symbol-name-transformer node.js script and an emacs function for doing this in live buffers.
|
||||
|
||||
### Caveat Coder
|
||||
This is an artistic reinterpretation of Fabrice Bellard's original code. There's no alteration in the acutal algorithmic content. I do check that that it still runs. I can't guarantee anything else.
|
||||
|
|
Loading…
Reference in New Issue