Build state of emulator explicitly. Fixes #40
This commit is contained in:
parent
4244e295eb
commit
f82373d6b2
37
lib/9p.js
37
lib/9p.js
|
@ -65,7 +65,7 @@ function Virtio9p(filesystem, bus) {
|
|||
//this.configspace = [0x0, 0x4, 0x68, 0x6F, 0x73, 0x74]; // length of string and "host" string
|
||||
//this.configspace = [0x0, 0x9, 0x2F, 0x64, 0x65, 0x76, 0x2F, 0x72, 0x6F, 0x6F, 0x74 ]; // length of string and "/dev/root" string
|
||||
|
||||
this.configspace = [0x6, 0x0, 0x68, 0x6F, 0x73, 0x74, 0x39, 0x70]; // length of string and "host9p" string
|
||||
this.configspace = new Uint8Array([0x6, 0x0, 0x68, 0x6F, 0x73, 0x74, 0x39, 0x70]); // length of string and "host9p" string
|
||||
this.VERSION = "9P2000.L";
|
||||
this.BLOCKSIZE = 8192; // Let's define one page.
|
||||
this.msize = 8192; // maximum message size
|
||||
|
@ -73,13 +73,38 @@ function Virtio9p(filesystem, bus) {
|
|||
this.replybuffersize = 0;
|
||||
|
||||
this.fids = [];
|
||||
|
||||
this._state_skip = [
|
||||
this.fs,
|
||||
this.bus,
|
||||
];
|
||||
}
|
||||
|
||||
Virtio9p.prototype.get_state = function()
|
||||
{
|
||||
var state = [];
|
||||
|
||||
state[0] = this.deviceid;
|
||||
state[1] = this.hostfeature;
|
||||
state[2] = this.configspace;
|
||||
state[3] = this.VERSION;
|
||||
state[4] = this.BLOCKSIZE;
|
||||
state[5] = this.msize;
|
||||
state[6] = this.replybuffer;
|
||||
state[7] = this.replybuffersize;
|
||||
state[8] = this.fids.map(function(f) { return [f.inodeid, f.type, f.uid] });
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
Virtio9p.prototype.set_state = function(state)
|
||||
{
|
||||
this.deviceid = state[0];
|
||||
this.hostfeature = state[1];
|
||||
this.configspace = state[2];
|
||||
this.VERSION = state[3];
|
||||
this.BLOCKSIZE = state[4];
|
||||
this.msize = state[5];
|
||||
this.replybuffer = state[6];
|
||||
this.replybuffersize = state[7];
|
||||
this.fids = state[8].map(function(f) { return { inodeid: f[0], type: f[1], uid: f[2] } });
|
||||
};
|
||||
|
||||
Virtio9p.prototype.Createfid = function(inode, type, uid) {
|
||||
return {inodeid: inode, type: type, uid: uid};
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ var STATUS_UNLINKED = 0x4;
|
|||
|
||||
/** @constructor */
|
||||
function FS(baseurl) {
|
||||
/** @type {Array.<Inode>} */
|
||||
this.inodes = [];
|
||||
this.events = [];
|
||||
|
||||
|
@ -77,8 +78,6 @@ function FS(baseurl) {
|
|||
|
||||
// root entry
|
||||
this.CreateDirectory("", -1);
|
||||
|
||||
this._state_skip = [];
|
||||
}
|
||||
|
||||
|
||||
|
@ -90,7 +89,7 @@ FS.prototype.AddEvent = function(id, OnEvent) {
|
|||
OnEvent();
|
||||
return;
|
||||
}
|
||||
this.events.push({id: id, OnEvent: OnEvent});
|
||||
this.events.push({id: id, OnEvent: OnEvent});
|
||||
}
|
||||
|
||||
FS.prototype.HandleEvent = function(id) {
|
||||
|
@ -276,7 +275,7 @@ FS.prototype.PushInode = function(inode) {
|
|||
function Inode(qidnumber)
|
||||
{
|
||||
this.updatedir = false; // did the directory listing changed?
|
||||
this.parentid= -1;
|
||||
this.parentid = -1;
|
||||
this.firstid = -1; // first file id in directory
|
||||
this.nextid = -1; // next id in directory
|
||||
this.status = 0;
|
||||
|
|
169
src/cpu.macro.js
169
src/cpu.macro.js
|
@ -239,11 +239,6 @@ function CPU()
|
|||
dbg_assert(this.table16 && this.table32);
|
||||
dbg_assert(this.table0F_16 && this.table0F_32);
|
||||
|
||||
this._state_restore();
|
||||
}
|
||||
|
||||
CPU.prototype._state_restore = function()
|
||||
{
|
||||
this.reg32 = new Uint32Array(this.reg32s.buffer);
|
||||
this.reg16s = new Int16Array(this.reg32s.buffer);
|
||||
this.reg16 = new Uint16Array(this.reg32s.buffer);
|
||||
|
@ -253,33 +248,163 @@ CPU.prototype._state_restore = function()
|
|||
this.update_address_size();
|
||||
this.update_operand_size();
|
||||
|
||||
this.tsc_offset = v86.microtick();
|
||||
}
|
||||
|
||||
CPU.prototype.get_state = function()
|
||||
{
|
||||
var state = [];
|
||||
|
||||
state[0] = this.memory_size;
|
||||
state[1] = this.segment_is_null;
|
||||
state[2] = this.segment_offsets;
|
||||
state[3] = this.segment_limits;
|
||||
state[4] = this.protected_mode;
|
||||
state[5] = this.idtr_offset;
|
||||
state[6] = this.idtr_size;
|
||||
state[7] = this.gdtr_offset;
|
||||
state[8] = this.gdtr_size;
|
||||
state[9] = this.page_fault;
|
||||
state[10] = this.cr;
|
||||
state[11] = this.cpl;
|
||||
state[12] = this.page_size_extensions;
|
||||
state[13] = this.is_32;
|
||||
state[14] = this.operand_size_32;
|
||||
state[15] = this.address_size_32;
|
||||
state[16] = this.stack_size_32;
|
||||
state[17] = this.in_hlt;
|
||||
state[18] = this.last_virt_eip;
|
||||
state[19] = this.eip_phys;
|
||||
state[20] = this.last_virt_esp;
|
||||
state[21] = this.esp_phys;
|
||||
state[22] = this.sysenter_cs;
|
||||
state[23] = this.sysenter_eip;
|
||||
state[24] = this.sysenter_esp;
|
||||
state[25] = this.repeat_string_prefix;
|
||||
state[26] = this.flags;
|
||||
state[27] = this.flags_changed;
|
||||
state[28] = this.last_op1;
|
||||
state[29] = this.last_op2;
|
||||
state[30] = this.last_op_size;
|
||||
state[31] = this.last_add_result;
|
||||
state[32] = this.modrm_byte;
|
||||
|
||||
state[36] = this.paging;
|
||||
state[37] = this.instruction_pointer;
|
||||
state[38] = this.previous_ip;
|
||||
state[39] = this.reg32s;
|
||||
state[40] = this.sreg;
|
||||
state[41] = this.dreg;
|
||||
state[42] = this.memory;
|
||||
state[43] = this.fpu;
|
||||
|
||||
state[45] = this.devices.virtio;
|
||||
state[46] = this.devices.apic;
|
||||
state[47] = this.devices.rtc;
|
||||
state[48] = this.devices.pci;
|
||||
state[49] = this.devices.dma;
|
||||
//state[50] = this.devices.acpi;
|
||||
state[51] = this.devices.hpet;
|
||||
state[52] = this.devices.vga;
|
||||
state[53] = this.devices.ps2;
|
||||
state[54] = this.devices.uart;
|
||||
state[55] = this.devices.fdc;
|
||||
state[56] = this.devices.cdrom;
|
||||
state[57] = this.devices.hda;
|
||||
state[58] = this.devices.pit;
|
||||
state[59] = this.devices.net;
|
||||
state[60] = this.devices.pic;
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
CPU.prototype.set_state = function(state)
|
||||
{
|
||||
this.memory_size = state[0];
|
||||
this.segment_is_null = state[1];
|
||||
this.segment_offsets = state[2];
|
||||
this.segment_limits = state[3];
|
||||
this.protected_mode = state[4];
|
||||
this.idtr_offset = state[5];
|
||||
this.idtr_size = state[6];
|
||||
this.gdtr_offset = state[7];
|
||||
this.gdtr_size = state[8];
|
||||
this.page_fault = state[9];
|
||||
this.cr = state[10];
|
||||
this.cpl = state[11];
|
||||
this.page_size_extensions = state[12];
|
||||
this.is_32 = state[13];
|
||||
this.operand_size_32 = state[14];
|
||||
this.address_size_32 = state[15];
|
||||
this.stack_size_32 = state[16];
|
||||
this.in_hlt = state[17];
|
||||
this.last_virt_eip = state[18];
|
||||
this.eip_phys = state[19];
|
||||
this.last_virt_esp = state[20];
|
||||
this.esp_phys = state[21];
|
||||
this.sysenter_cs = state[22];
|
||||
this.sysenter_eip = state[23];
|
||||
this.sysenter_esp = state[24];
|
||||
this.repeat_string_prefix = state[25];
|
||||
this.flags = state[26];
|
||||
this.flags_changed = state[27];
|
||||
this.last_op2 = state[27];
|
||||
this.last_op3 = state[28];
|
||||
this.last_op_size = state[30];
|
||||
this.last_add_result = state[31];
|
||||
this.modrm_byte = state[32];
|
||||
|
||||
this.paging = state[36];
|
||||
this.instruction_pointer = state[37];
|
||||
this.previous_ip = state[38];
|
||||
this.reg33s = state[38];
|
||||
this.sreg = state[40];
|
||||
this.dreg = state[41];
|
||||
this.memory = state[42];
|
||||
this.fpu = state[43];
|
||||
|
||||
this.devices.virtio = state[45];
|
||||
this.devices.apic = state[46];
|
||||
this.devices.rtc = state[47];
|
||||
this.devices.pci = state[48];
|
||||
this.devices.dma = state[49];
|
||||
this.devices.acpi = state[50];
|
||||
this.devices.hpet = state[51];
|
||||
this.devices.vga = state[52];
|
||||
this.devices.ps5 = state[50];
|
||||
this.devices.uart = state[54];
|
||||
this.devices.fdc = state[55];
|
||||
this.devices.cdrom = state[56];
|
||||
this.devices.hda = state[57];
|
||||
this.devices.pit = state[58];
|
||||
this.devices.net = state[59];
|
||||
this.devices.pic = state[60];
|
||||
|
||||
|
||||
this.full_clear_tlb();
|
||||
// tsc_offset?
|
||||
|
||||
if(this.stack_size_32)
|
||||
{
|
||||
this.stack_reg = this.reg32s;
|
||||
this.reg_vsp = reg_esp;
|
||||
this.reg_vbp = reg_ebp;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.stack_reg = this.reg16;
|
||||
this.reg_vsp = reg_sp;
|
||||
this.reg_vbp = reg_bp;
|
||||
}
|
||||
|
||||
this.full_clear_tlb();
|
||||
this.timestamp_counter = 0;
|
||||
this.tsc_offset = v86.microtick();
|
||||
this.reg32 = new Uint32Array(this.reg32s.buffer);
|
||||
this.reg16s = new Int16Array(this.reg32s.buffer);
|
||||
this.reg16 = new Uint16Array(this.reg32s.buffer);
|
||||
this.reg8s = new Int8Array(this.reg32s.buffer);
|
||||
this.reg8 = new Uint8Array(this.reg32s.buffer);
|
||||
|
||||
/** @const */
|
||||
this._state_skip = [
|
||||
this.bios,
|
||||
this.debug,
|
||||
|
||||
this.table16,
|
||||
this.table32,
|
||||
this.table0F_16,
|
||||
this.table0F_32,
|
||||
|
||||
this.tlb_data,
|
||||
this.tlb_info,
|
||||
this.tlb_info_global,
|
||||
];
|
||||
this.update_address_size();
|
||||
this.update_operand_size();
|
||||
};
|
||||
|
||||
#include "translate.macro.js"
|
||||
|
|
17
src/dma.js
17
src/dma.js
|
@ -21,13 +21,24 @@ function DMA(dev)
|
|||
io.register_write(0x0B, this, this.portB_write);
|
||||
io.register_write(0x0C, this, this.portC_write);
|
||||
io.register_write(0x81, this, this.port81_write);
|
||||
}
|
||||
|
||||
/** @const */
|
||||
this._state_skip = [
|
||||
this.memory,
|
||||
DMA.prototype.get_state = function()
|
||||
{
|
||||
return [
|
||||
this.channel_addr,
|
||||
this.channel_count,
|
||||
this.lsb_msb_flipflop,
|
||||
];
|
||||
};
|
||||
|
||||
DMA.prototype.set_state = function(state)
|
||||
{
|
||||
this.channel_addr = state[0];
|
||||
this.channel_count = state[1];
|
||||
this.lsb_msb_flipflop = state[2];
|
||||
};
|
||||
|
||||
DMA.prototype.port_write = function(port, data_byte)
|
||||
{
|
||||
dbg_log("port " + port + " write " + data_byte, LOG_DMA);
|
||||
|
|
|
@ -46,18 +46,6 @@ function FloppyController(cpu, fda_image, fdb_image)
|
|||
// this should actually be write-only ... but people read it anyway
|
||||
this.dor = 0;
|
||||
|
||||
/** @const */
|
||||
this._state_skip = [
|
||||
this.io,
|
||||
this.cpu,
|
||||
this.dma,
|
||||
];
|
||||
|
||||
if(this.fdb_image)
|
||||
{
|
||||
this._state_skip.push(this.fdb_image);
|
||||
}
|
||||
|
||||
if(!fda_image)
|
||||
{
|
||||
// Needed for CD emulation provided by seabios
|
||||
|
@ -71,8 +59,6 @@ function FloppyController(cpu, fda_image, fdb_image)
|
|||
return;
|
||||
}
|
||||
|
||||
this._state_skip.push(this.fda_image);
|
||||
|
||||
this.floppy_size = fda_image.byteLength;
|
||||
|
||||
var floppy_types = {
|
||||
|
@ -121,6 +107,56 @@ function FloppyController(cpu, fda_image, fdb_image)
|
|||
this.io.register_write(0x3F5, this, this.port3F5_write);
|
||||
}
|
||||
|
||||
FloppyController.prototype.get_state = function()
|
||||
{
|
||||
var state = [];
|
||||
|
||||
state[0] = this.bytes_expecting;
|
||||
state[1] = this.receiving_command;
|
||||
state[2] = this.receiving_index;
|
||||
//state[3] = this.next_command;
|
||||
state[4] = this.response_data;
|
||||
state[5] = this.response_index;
|
||||
state[6] = this.response_length;
|
||||
state[7] = this.floppy_size;
|
||||
state[8] = this.status_reg0;
|
||||
state[9] = this.status_reg1;
|
||||
state[10] = this.status_reg2;
|
||||
state[11] = this.drive;
|
||||
state[12] = this.last_cylinder;
|
||||
state[13] = this.last_head;
|
||||
state[14] = this.last_sector;
|
||||
state[15] = this.dor;
|
||||
state[16] = this.sectors_per_track;
|
||||
state[17] = this.number_of_heads;
|
||||
state[18] = this.number_of_cylinders;
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
FloppyController.prototype.set_state = function(state)
|
||||
{
|
||||
this.bytes_expecting = state[0];
|
||||
this.receiving_command = state[1];
|
||||
this.receiving_index = state[2];
|
||||
this.next_command = state[3];
|
||||
this.response_data = state[4];
|
||||
this.response_index = state[5];
|
||||
this.response_length = state[6];
|
||||
this.floppy_size = state[7];
|
||||
this.status_reg0 = state[8];
|
||||
this.status_reg1 = state[9];
|
||||
this.status_reg2 = state[10];
|
||||
this.drive = state[11];
|
||||
this.last_cylinder = state[12];
|
||||
this.last_head = state[13];
|
||||
this.last_sector = state[14];
|
||||
this.dor = state[15];
|
||||
this.sectors_per_track = state[16];
|
||||
this.number_of_heads = state[17];
|
||||
this.number_of_cylinders = state[18];
|
||||
};
|
||||
|
||||
FloppyController.prototype.port3F0_read = function()
|
||||
{
|
||||
dbg_log("3F0 read", LOG_DISK);
|
||||
|
|
61
src/fpu.js
61
src/fpu.js
|
@ -63,7 +63,17 @@ function FPU(cpu)
|
|||
// Why no Float80Array :-(
|
||||
this.st = new Float64Array(8);
|
||||
|
||||
this._state_restore();
|
||||
// used for conversion
|
||||
/** @const */ this.float32 = new Float32Array(1);
|
||||
/** @const */ this.float32_byte = new Uint8Array(this.float32.buffer);
|
||||
/** @const */ this.float32_int = new Int32Array(this.float32.buffer);
|
||||
/** @const */ this.float64 = new Float64Array(1);
|
||||
/** @const */ this.float64_byte = new Uint8Array(this.float64.buffer);
|
||||
/** @const */ this.float64_int = new Int32Array(this.float64.buffer);
|
||||
|
||||
/** @const */ this.st8 = new Uint8Array(this.st.buffer);
|
||||
/** @const */ this.st32 = new Int32Array(this.st.buffer);
|
||||
|
||||
|
||||
// bitmap of which stack registers are empty
|
||||
this.stack_empty = 0xff;
|
||||
|
@ -88,33 +98,36 @@ function FPU(cpu)
|
|||
|
||||
}
|
||||
|
||||
FPU.prototype._state_restore = function()
|
||||
FPU.prototype.get_state = function()
|
||||
{
|
||||
// used for conversion
|
||||
/** @const */ this.float32 = new Float32Array(1);
|
||||
/** @const */ this.float32_byte = new Uint8Array(this.float32.buffer);
|
||||
/** @const */ this.float32_int = new Int32Array(this.float32.buffer);
|
||||
/** @const */ this.float64 = new Float64Array(1);
|
||||
/** @const */ this.float64_byte = new Uint8Array(this.float64.buffer);
|
||||
/** @const */ this.float64_int = new Int32Array(this.float64.buffer);
|
||||
var state = [];
|
||||
|
||||
/** @const */ this.st8 = new Uint8Array(this.st.buffer);
|
||||
/** @const */ this.st32 = new Int32Array(this.st.buffer);
|
||||
state[0] = this.st;
|
||||
state[1] = this.stack_empty;
|
||||
state[2] = this.stack_ptr;
|
||||
state[3] = this.control_word;
|
||||
state[4] = this.fpu_dp_selector;
|
||||
state[5] = this.fpu_ip;
|
||||
state[6] = this.fpu_ip_selector;
|
||||
state[7] = this.fpu_dp;
|
||||
state[8] = this.fpu_dp_selector;
|
||||
state[9] = this.fpu_opcode;
|
||||
|
||||
/** @const */
|
||||
this._state_skip = [
|
||||
this.cpu,
|
||||
return state;
|
||||
};
|
||||
|
||||
this.float32,
|
||||
this.float32_byte,
|
||||
this.float32_int,
|
||||
this.float64,
|
||||
this.float64_byte,
|
||||
this.float64_int,
|
||||
|
||||
this.st8,
|
||||
this.st32,
|
||||
];
|
||||
FPU.prototype.set_state = function(state)
|
||||
{
|
||||
this.st.set(state[0]);
|
||||
this.stack_empty = state[1];
|
||||
this.stack_ptr = state[2];
|
||||
this.control_word = state[3];
|
||||
this.fpu_dp_selector = state[4];
|
||||
this.fpu_ip = state[5];
|
||||
this.fpu_ip_selector = state[6];
|
||||
this.fpu_dp = state[7];
|
||||
this.fpu_dp_selector = state[8];
|
||||
this.fpu_opcode = state[9];
|
||||
};
|
||||
|
||||
FPU.prototype.fpu_unimpl = function()
|
||||
|
|
61
src/ide.js
61
src/ide.js
|
@ -299,17 +299,60 @@ function IDEDevice(cpu, buffer, is_cd, nr, bus)
|
|||
|
||||
cpu.io.register_read(this.master_port | 2, this, this.dma_read_status);
|
||||
cpu.io.register_write(this.master_port | 2, this, this.dma_write_status);
|
||||
|
||||
/** @const */
|
||||
this._state_skip = [
|
||||
this.memory,
|
||||
this.cpu,
|
||||
this.stats,
|
||||
this.buffer,
|
||||
this.bus,
|
||||
];
|
||||
}
|
||||
|
||||
IDEDevice.prototype.get_state = function()
|
||||
{
|
||||
var state = [];
|
||||
|
||||
state[0] = this.device_control;
|
||||
state[1] = this.last_drive;
|
||||
state[2] = this.data_pointer;
|
||||
state[3] = this.pio_data;
|
||||
state[4] = this.is_lba;
|
||||
state[5] = this.bytecount;
|
||||
state[6] = this.sector;
|
||||
state[7] = this.lba_count;
|
||||
state[8] = this.cylinder_low;
|
||||
state[9] = this.head;
|
||||
state[10] = this.drive_head;
|
||||
state[11] = this.status;
|
||||
state[12] = this.sectors_per_drq;
|
||||
state[13] = this.write_dest;
|
||||
state[14] = this.data_port_count;
|
||||
state[15] = this.data_port_current;
|
||||
state[16] = this.data_port_buffer;
|
||||
state[17] = this.next_status;
|
||||
state[18] = this.prdt_addr;
|
||||
state[19] = this.dma_status;
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
IDEDevice.prototype.set_state = function(state)
|
||||
{
|
||||
this.device_control = state[0];
|
||||
this.last_drive = state[1];
|
||||
this.data_pointer = state[2];
|
||||
this.pio_data = state[3];
|
||||
this.is_lba = state[4];
|
||||
this.bytecount = state[5];
|
||||
this.sector = state[6];
|
||||
this.lba_count = state[7];
|
||||
this.cylinder_low = state[8];
|
||||
this.head = state[9];
|
||||
this.drive_head = state[10];
|
||||
this.status = state[11];
|
||||
this.sectors_per_drq = state[12];
|
||||
this.write_dest = state[13];
|
||||
this.data_port_count = state[14];
|
||||
this.data_port_current = state[15];
|
||||
this.data_port_buffer = state[16];
|
||||
this.next_status = state[17];
|
||||
this.prdt_addr = state[18];
|
||||
this.dma_status = state[19];
|
||||
};
|
||||
|
||||
IDEDevice.prototype.do_callback = function()
|
||||
{
|
||||
switch(this.data_port_callback)
|
||||
|
|
|
@ -61,12 +61,6 @@ function IO(memory)
|
|||
dbg_log("Write to unmapped memory space, addr=" + h(addr >>> 0, 8) + " value=" + h(value >>> 0, 8), LOG_IO);
|
||||
}
|
||||
);
|
||||
|
||||
this._state_skip = [
|
||||
this.ports,
|
||||
this.devices,
|
||||
this.memory,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -25,32 +25,28 @@ function Memory(memory_size)
|
|||
dbg_assert((memory_size & MMAP_BLOCK_SIZE - 1) === 0);
|
||||
|
||||
this.buffer = new ArrayBuffer(memory_size);
|
||||
this._state_restore();
|
||||
|
||||
this.mem8 = new Uint8Array(this.buffer);
|
||||
this.mem16 = new Uint16Array(this.buffer);
|
||||
this.mem32s = new Int32Array(this.buffer);
|
||||
};
|
||||
|
||||
Memory.prototype._state_restore = function()
|
||||
Memory.prototype.get_state = function()
|
||||
{
|
||||
/** @const */
|
||||
this.mem8 = new Uint8Array(this.buffer);
|
||||
|
||||
/** @const */
|
||||
this.mem16 = new Uint16Array(this.buffer);
|
||||
|
||||
/** @const */
|
||||
this.mem32s = new Int32Array(this.buffer);
|
||||
|
||||
/** @const */
|
||||
this._state_skip = [
|
||||
this.mem8,
|
||||
this.mem16,
|
||||
this.mem32s,
|
||||
|
||||
this.memory_map_registered,
|
||||
this.memory_map_read8,
|
||||
this.memory_map_read32,
|
||||
this.memory_map_write8,
|
||||
this.memory_map_write32,
|
||||
return [
|
||||
this.size,
|
||||
this.buffer,
|
||||
];
|
||||
}
|
||||
|
||||
Memory.prototype.set_state = function(state)
|
||||
{
|
||||
this.size = state[0];
|
||||
this.buffer = state[1];
|
||||
|
||||
this.mem8 = new Uint8Array(this.buffer);
|
||||
this.mem16 = new Uint16Array(this.buffer);
|
||||
this.mem32s = new Int32Array(this.buffer);
|
||||
};
|
||||
|
||||
// called by all memory reads and writes
|
||||
|
|
39
src/ne2k.js
39
src/ne2k.js
|
@ -473,13 +473,42 @@ function Ne2k(cpu, bus)
|
|||
this.data_port_write16,
|
||||
this.data_port_write16,
|
||||
this.data_port_write32);
|
||||
|
||||
this._state_skip = [
|
||||
this.bus,
|
||||
this.cpu,
|
||||
];
|
||||
}
|
||||
|
||||
Ne2k.prototype.get_state = function()
|
||||
{
|
||||
var state = [];
|
||||
|
||||
state[0] = this.isr;
|
||||
state[1] = this.imr;
|
||||
state[2] = this.cr;
|
||||
state[3] = this.dcfg;
|
||||
state[4] = this.rcnt;
|
||||
state[5] = this.tcnt;
|
||||
state[6] = this.tpsr;
|
||||
state[7] = this.rsar;
|
||||
state[8] = this.pstart;
|
||||
state[9] = this.curpg;
|
||||
state[10] = this.boundary;
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
Ne2k.prototype.set_state = function(state)
|
||||
{
|
||||
this.isr = state[0];
|
||||
this.imr = state[1];
|
||||
this.cr = state[2];
|
||||
this.dcfg = state[3];
|
||||
this.rcnt = state[4];
|
||||
this.tcnt = state[5];
|
||||
this.tpsr = state[6];
|
||||
this.rsar = state[7];
|
||||
this.pstart = state[8];
|
||||
this.curpg = state[9];
|
||||
this.boundary = state[10];
|
||||
};
|
||||
|
||||
Ne2k.prototype.do_interrupt = function(ir_mask)
|
||||
{
|
||||
dbg_log("Do interrupt " + h(ir_mask, 2), LOG_NET);
|
||||
|
|
25
src/pci.js
25
src/pci.js
|
@ -178,13 +178,28 @@ function PCI(cpu)
|
|||
// 0xb0, 0xfe, 0xb0, 0xfe, 0xf1, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x02, 0x00,
|
||||
//], 0x1e << 3);
|
||||
|
||||
this._state_skip = [
|
||||
this.devices,
|
||||
this.device_spaces,
|
||||
];
|
||||
}
|
||||
|
||||
PCI.prototype.get_state = function()
|
||||
{
|
||||
var state = [];
|
||||
|
||||
state[0] = this.pci_addr;
|
||||
state[1] = this.pci_value;
|
||||
state[2] = this.pci_response;
|
||||
state[3] = this.pci_status;
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
PCI.prototype.set_state = function(state)
|
||||
{
|
||||
this.pci_addr.set(state[0]);
|
||||
this.pci_value.set(state[1]);
|
||||
this.pci_response.set(state[2]);
|
||||
this.pci_status.set(state[3]);
|
||||
};
|
||||
|
||||
PCI.prototype.pci_query = function()
|
||||
{
|
||||
var dbg_line = "PCI: ";
|
||||
|
|
35
src/pic.js
35
src/pic.js
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
function PIC(cpu, master)
|
||||
{
|
||||
/**
|
||||
/**
|
||||
* all irqs off
|
||||
* @type {number}
|
||||
*/
|
||||
|
@ -302,3 +302,36 @@ function PIC(cpu, master)
|
|||
return this.isr;
|
||||
};
|
||||
}
|
||||
|
||||
PIC.prototype.get_state = function()
|
||||
{
|
||||
var state = [];
|
||||
|
||||
state[0] = this.irq_mask;
|
||||
state[1] = this.irq_map;
|
||||
state[2] = this.isr;
|
||||
state[3] = this.irr;
|
||||
state[4] = this.is_master;
|
||||
state[5] = this.slave;
|
||||
state[6] = this.expect_icw4;
|
||||
state[7] = this.state;
|
||||
state[8] = this.read_irr;
|
||||
state[9] = this.auto_eoi;
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
PIC.prototype.set_state = function(state)
|
||||
{
|
||||
this.irq_mask = state[0];
|
||||
this.irq_map = state[1];
|
||||
this.isr = state[2];
|
||||
this.irr = state[3];
|
||||
this.is_master = state[4];
|
||||
this.slave = state[5];
|
||||
this.expect_icw4 = state[6];
|
||||
this.state = state[7];
|
||||
this.read_irr = state[8];
|
||||
this.auto_eoi = state[9];
|
||||
};
|
||||
|
||||
|
|
35
src/pit.js
35
src/pit.js
|
@ -56,13 +56,38 @@ function PIT(cpu)
|
|||
cpu.io.register_write(0x42, this, function(data) { this.counter_write(2, data); });
|
||||
|
||||
cpu.io.register_write(0x43, this, this.port43_write);
|
||||
|
||||
/** @const */
|
||||
this._state_skip = [
|
||||
this.cpu,
|
||||
];
|
||||
}
|
||||
|
||||
PIT.prototype.get_state = function()
|
||||
{
|
||||
var state = [];
|
||||
|
||||
state[0] = this.counter_next_low;
|
||||
state[1] = this.counter_enabled;
|
||||
state[2] = this.counter_mode;
|
||||
state[3] = this.counter_read_mode;
|
||||
state[4] = this.counter_latch;
|
||||
state[5] = this.counter_latch_value;
|
||||
state[6] = this.counter_reload;
|
||||
state[7] = this.counter_current;
|
||||
state[8] = this.counter2_start;
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
PIT.prototype.set_state = function(state)
|
||||
{
|
||||
this.counter_next_low = state[0];
|
||||
this.counter_enabled = state[1];
|
||||
this.counter_mode = state[2];
|
||||
this.counter_read_mode = state[3];
|
||||
this.counter_latch = state[4];
|
||||
this.counter_latch_value = state[5];
|
||||
this.counter_reload = state[6];
|
||||
this.counter_current = state[7];
|
||||
this.counter2_start = state[8];
|
||||
};
|
||||
|
||||
PIT.prototype.timer = function(time, no_irq)
|
||||
{
|
||||
dbg_assert(time >= this.next_tick);
|
||||
|
|
65
src/ps2.js
65
src/ps2.js
|
@ -107,19 +107,68 @@ function PS2(cpu, bus)
|
|||
|
||||
cpu.io.register_write(0x60, this, this.port60_write);
|
||||
cpu.io.register_write(0x64, this, this.port64_write);
|
||||
|
||||
/** @const */
|
||||
this._state_skip = [
|
||||
this.bus,
|
||||
this.cpu,
|
||||
];
|
||||
}
|
||||
|
||||
PS2.prototype._state_restore = function()
|
||||
PS2.prototype.get_state = function()
|
||||
{
|
||||
this.bus.send("mouse-enable", this.use_mouse);
|
||||
var state = [];
|
||||
|
||||
state[0] = this.enable_mouse_stream;
|
||||
state[1] = this.use_mouse;
|
||||
state[2] = this.have_mouse;
|
||||
state[3] = this.mouse_delta_x;
|
||||
state[4] = this.mouse_delta_y;
|
||||
state[5] = this.mouse_clicks;
|
||||
state[6] = this.have_keyboard;
|
||||
state[7] = this.enable_keyboard_stream;
|
||||
state[8] = this.next_is_mouse_command;
|
||||
state[9] = this.next_read_sample;
|
||||
state[10] = this.next_read_led;
|
||||
state[11] = this.next_handle_scan_code_set;
|
||||
state[12] = this.next_read_rate;
|
||||
state[13] = this.next_read_resolution;
|
||||
//state[14] = this.kbd_buffer;
|
||||
state[15] = this.last_port60_byte;
|
||||
state[16] = this.sample_rate;
|
||||
state[17] = this.resolution;
|
||||
state[18] = this.scaling2;
|
||||
//state[19] = this.mouse_buffer;
|
||||
state[20] = this.command_register;
|
||||
state[21] = this.read_output_register;
|
||||
state[22] = this.read_command_register;
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
PS2.prototype.set_state = function(state)
|
||||
{
|
||||
this.enable_mouse_stream = state[0];
|
||||
this.use_mouse = state[1];
|
||||
this.have_mouse = state[2];
|
||||
this.mouse_delta_x = state[3];
|
||||
this.mouse_delta_y = state[4];
|
||||
this.mouse_clicks = state[5];
|
||||
this.have_keyboard = state[6];
|
||||
this.enable_keyboard_stream = state[7];
|
||||
this.next_is_mouse_command = state[8];
|
||||
this.next_read_sample = state[9];
|
||||
this.next_read_led = state[10];
|
||||
this.next_handle_scan_code_set = state[11];
|
||||
this.next_read_rate = state[12];
|
||||
this.next_read_resolution = state[13];
|
||||
//this.kbd_buffer = state[14];
|
||||
this.last_port60_byte = state[15];
|
||||
this.sample_rate = state[16];
|
||||
this.resolution = state[17];
|
||||
this.scaling2 = state[18];
|
||||
//this.mouse_buffer = state[19];
|
||||
this.command_register = state[20];
|
||||
this.read_output_register = state[21];
|
||||
this.read_command_register = state[22];
|
||||
|
||||
this.bus.send("mouse-enable", this.use_mouse);
|
||||
}
|
||||
|
||||
PS2.prototype.mouse_irq = function()
|
||||
{
|
||||
if(this.command_register & 2)
|
||||
|
|
40
src/rtc.js
40
src/rtc.js
|
@ -78,12 +78,44 @@ function RTC(cpu)
|
|||
|
||||
cpu.io.register_write(0x71, this, this.cmos_port_write);
|
||||
cpu.io.register_read(0x71, this, this.cmos_port_read);
|
||||
|
||||
this._state_skip = [
|
||||
this.cpu,
|
||||
];
|
||||
}
|
||||
|
||||
RTC.prototype.get_state = function()
|
||||
{
|
||||
var state = [];
|
||||
|
||||
state[0] = this.cmos_index;
|
||||
state[1] = this.cmos_data;
|
||||
state[2] = this.rtc_time;
|
||||
state[3] = this.last_update;
|
||||
state[4] = this.next_interrupt;
|
||||
state[5] = this.cmos_c_was_read;
|
||||
state[6] = this.periodic_interrupt;
|
||||
state[7] = this.periodic_interrupt_time;
|
||||
state[8] = this.cmos_a;
|
||||
state[9] = this.cmos_b;
|
||||
state[10] = this.cmos_c;
|
||||
state[11] = this.nmi_disabled;
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
RTC.prototype.set_state = function(state)
|
||||
{
|
||||
this.cmos_index = state[0];
|
||||
this.cmos_data = state[1];
|
||||
this.rtc_time = state[2];
|
||||
this.last_update = state[3];
|
||||
this.next_interrupt = state[4];
|
||||
this.cmos_c_was_read = state[5];
|
||||
this.periodic_interrupt = state[6];
|
||||
this.periodic_interrupt_time = state[7];
|
||||
this.cmos_a = state[8];
|
||||
this.cmos_b = state[9];
|
||||
this.cmos_c = state[10];
|
||||
this.nmi_disabled = state[11];
|
||||
};
|
||||
|
||||
RTC.prototype.timer = function(time, legacy_mode)
|
||||
{
|
||||
this.rtc_time += time - this.last_update;
|
||||
|
|
133
src/state.js
133
src/state.js
|
@ -1,7 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
/** @const */
|
||||
var STATE_VERSION = 0;
|
||||
var STATE_VERSION = 1;
|
||||
|
||||
/** @const */
|
||||
var STATE_MAGIC = 0x86768676|0;
|
||||
|
@ -32,79 +32,45 @@ StateLoadError.prototype = new Error;
|
|||
|
||||
function save_object(obj, arraybuffers)
|
||||
{
|
||||
// recursively create a structure that can be json-dumped, pushing
|
||||
// arraybuffers into the second argument
|
||||
|
||||
if(typeof obj !== "object" || obj === null || obj instanceof Array)
|
||||
{
|
||||
return obj;
|
||||
}
|
||||
|
||||
if(obj.constructor === Object)
|
||||
{
|
||||
var keys = Object.keys(obj);
|
||||
var result = {};
|
||||
|
||||
for(var i = 0; i < keys.length; i++)
|
||||
{
|
||||
var key = keys[i];
|
||||
result[key] = save_object(obj[key], arraybuffers);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
dbg_assert(obj.constructor !== Object);
|
||||
|
||||
if(obj.BYTES_PER_ELEMENT)
|
||||
{
|
||||
// Uint8Array, etc.
|
||||
return {
|
||||
__state_type__: obj.constructor.name,
|
||||
buffer_id: arraybuffers.push(obj.buffer) - 1,
|
||||
"__state_type__": obj.constructor.name,
|
||||
"buffer_id": arraybuffers.push(obj.buffer) - 1,
|
||||
};
|
||||
}
|
||||
|
||||
if(obj instanceof ArrayBuffer)
|
||||
{
|
||||
return {
|
||||
__state_type__: "ArrayBuffer",
|
||||
buffer_id: arraybuffers.push(obj) - 1,
|
||||
"__state_type__": "ArrayBuffer",
|
||||
"buffer_id": arraybuffers.push(obj) - 1,
|
||||
};
|
||||
}
|
||||
|
||||
var skip;
|
||||
|
||||
if(obj._state_skip)
|
||||
if(DEBUG && !obj.get_state)
|
||||
{
|
||||
skip = obj._state_skip.slice();
|
||||
skip.push(obj._state_skip);
|
||||
console.log("Object without get_state: ", obj);
|
||||
}
|
||||
|
||||
var keys = Object.keys(obj);
|
||||
var result = {};
|
||||
var state = obj.get_state();
|
||||
var result = [];
|
||||
|
||||
outer:
|
||||
for(var i = 0; i < keys.length; i++)
|
||||
for(var i = 0; i < state.length; i++)
|
||||
{
|
||||
var key = keys[i];
|
||||
var value = obj[key];
|
||||
var value = state[i];
|
||||
|
||||
if(typeof value === "function")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
dbg_assert(typeof value !== "function");
|
||||
|
||||
if(skip && typeof value === "object" && value)
|
||||
{
|
||||
for(var j = 0; j < skip.length; j++)
|
||||
{
|
||||
if(skip[j] === value)
|
||||
{
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result[key] = save_object(value, arraybuffers);
|
||||
result[i] = save_object(value, arraybuffers);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -112,41 +78,49 @@ function save_object(obj, arraybuffers)
|
|||
|
||||
function restore_object(base, obj, buffers)
|
||||
{
|
||||
// recurisvely restore obj into base
|
||||
|
||||
if(typeof obj !== "object" || obj instanceof Array || obj === null)
|
||||
// recursively restore obj into base
|
||||
|
||||
if(typeof obj !== "object" || obj === null)
|
||||
{
|
||||
return obj;
|
||||
}
|
||||
|
||||
var type = obj.__state_type__;
|
||||
if(base instanceof Array)
|
||||
{
|
||||
return obj;
|
||||
}
|
||||
|
||||
var type = obj["__state_type__"];
|
||||
|
||||
if(type === undefined)
|
||||
{
|
||||
var keys = Object.keys(obj);
|
||||
|
||||
if(DEBUG && base === undefined)
|
||||
{
|
||||
console.log("Cannot restore (base doesn't exist)", obj);
|
||||
dbg_assert(false);
|
||||
}
|
||||
|
||||
for(var i = 0; i < keys.length; i++)
|
||||
if(DEBUG && !base.get_state)
|
||||
{
|
||||
var key = keys[i];
|
||||
base[key] = restore_object(base[key], obj[key], buffers);
|
||||
console.log("No get_state:", base);
|
||||
}
|
||||
|
||||
if(base._state_restore)
|
||||
var current = base.get_state();
|
||||
|
||||
dbg_assert(current.length === obj.length);
|
||||
|
||||
for(var i = 0; i < obj.length; i++)
|
||||
{
|
||||
base._state_restore();
|
||||
obj[i] = restore_object(current[i], obj[i], buffers);
|
||||
}
|
||||
|
||||
base.set_state(obj);
|
||||
|
||||
return base;
|
||||
}
|
||||
}
|
||||
else if(type === "ArrayBuffer")
|
||||
{
|
||||
var info = buffers.infos[obj.buffer_id];
|
||||
var info = buffers.infos[obj["buffer_id"]];
|
||||
|
||||
if(base && base.byteLength === info.length)
|
||||
{
|
||||
|
@ -176,16 +150,16 @@ function restore_object(base, obj, buffers)
|
|||
var constructor = table[type];
|
||||
dbg_assert(constructor, "Unkown type: " + type);
|
||||
|
||||
var info = buffers.infos[obj.buffer_id];
|
||||
var info = buffers.infos[obj["buffer_id"]];
|
||||
|
||||
// avoid a new allocation if possible
|
||||
if(base &&
|
||||
base.constructor === constructor &&
|
||||
if(base &&
|
||||
base.constructor === constructor &&
|
||||
base.byteOffset === 0 &&
|
||||
base.byteLength === info.length)
|
||||
{
|
||||
new Uint8Array(base.buffer).set(
|
||||
new Uint8Array(buffers.full, info.offset, info.length),
|
||||
new Uint8Array(buffers.full, info.offset, info.length),
|
||||
base.byteOffset
|
||||
);
|
||||
return base;
|
||||
|
@ -222,30 +196,30 @@ CPU.prototype.save_state = function()
|
|||
}
|
||||
|
||||
var info_object = JSON.stringify({
|
||||
buffer_infos: buffer_infos,
|
||||
state: state,
|
||||
"buffer_infos": buffer_infos,
|
||||
"state": state,
|
||||
});
|
||||
|
||||
var buffer_block_start = STATE_INFO_BLOCK_START + 2 * info_object.length;
|
||||
var total_size = buffer_block_start + total_buffer_size;
|
||||
|
||||
dbg_log("State: json_size=" + Math.ceil(buffer_block_start / 1024 / 1024) + "MB " +
|
||||
"buffer_size=" + Math.ceil(total_buffer_size / 1024 / 1024) + "MB");
|
||||
//console.log("State: json_size=" + Math.ceil(buffer_block_start / 1024 / 1024) + "MB " +
|
||||
// "buffer_size=" + Math.ceil(total_buffer_size / 1024 / 1024) + "MB");
|
||||
|
||||
var result = new ArrayBuffer(total_size);
|
||||
|
||||
var header_block = new Int32Array(
|
||||
result,
|
||||
0,
|
||||
result,
|
||||
0,
|
||||
STATE_INFO_BLOCK_START / 4
|
||||
);
|
||||
var info_block = new Uint16Array(
|
||||
result,
|
||||
STATE_INFO_BLOCK_START,
|
||||
result,
|
||||
STATE_INFO_BLOCK_START,
|
||||
info_object.length
|
||||
);
|
||||
var buffer_block = new Uint8Array(
|
||||
result,
|
||||
result,
|
||||
buffer_block_start
|
||||
);
|
||||
|
||||
|
@ -287,7 +261,7 @@ CPU.prototype.restore_state = function(state)
|
|||
if(header_block[STATE_INDEX_VERSION] !== STATE_VERSION)
|
||||
{
|
||||
throw new StateLoadError(
|
||||
"Version mismatch: dump=" + header_block[STATE_INDEX_VERSION] +
|
||||
"Version mismatch: dump=" + header_block[STATE_INDEX_VERSION] +
|
||||
" we=" + STATE_VERSION);
|
||||
}
|
||||
|
||||
|
@ -300,8 +274,8 @@ CPU.prototype.restore_state = function(state)
|
|||
|
||||
var info_block_len = header_block[STATE_INDEX_INFO_LEN];
|
||||
|
||||
if(info_block_len < 0 ||
|
||||
info_block_len + 12 >= len ||
|
||||
if(info_block_len < 0 ||
|
||||
info_block_len + 12 >= len ||
|
||||
info_block_len % 2)
|
||||
{
|
||||
throw new StateLoadError("Invalid info block length: " + info_block_len);
|
||||
|
@ -327,8 +301,9 @@ CPU.prototype.restore_state = function(state)
|
|||
}
|
||||
|
||||
var info_block_obj = JSON.parse(info_block);
|
||||
var state_object = info_block_obj["state"];
|
||||
var buffer_infos = info_block_obj["buffer_infos"];
|
||||
var buffer_block_start = STATE_INFO_BLOCK_START + info_block_len;
|
||||
var buffer_infos = info_block_obj.buffer_infos;
|
||||
|
||||
for(var i = 0; i < buffer_infos.length; i++)
|
||||
{
|
||||
|
@ -340,5 +315,5 @@ CPU.prototype.restore_state = function(state)
|
|||
infos: buffer_infos,
|
||||
};
|
||||
|
||||
restore_object(this, info_block_obj.state, buffers);
|
||||
restore_object(this, state_object, buffers);
|
||||
};
|
||||
|
|
39
src/uart.js
39
src/uart.js
|
@ -248,13 +248,42 @@ function UART(cpu, port, bus)
|
|||
{
|
||||
this.scratch_register = out_byte;
|
||||
});
|
||||
|
||||
this._state_skip = [
|
||||
this.bus,
|
||||
this.cpu,
|
||||
];
|
||||
}
|
||||
|
||||
UART.prototype.get_state = function()
|
||||
{
|
||||
var state = [];
|
||||
|
||||
state[0] = this.ints;
|
||||
state[1] = this.baud_rate;
|
||||
state[2] = this.line_control;
|
||||
state[3] = this.line_status;
|
||||
state[4] = this.fifo_control;
|
||||
state[5] = this.ier;
|
||||
state[6] = this.iir;
|
||||
state[7] = this.modem_control;
|
||||
state[8] = this.modem_status;
|
||||
state[9] = this.scratch_register;
|
||||
state[10] = this.irq;
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
UART.prototype.set_state = function(state)
|
||||
{
|
||||
this.ints = state[0];
|
||||
this.baud_rate = state[1];
|
||||
this.line_control = state[2];
|
||||
this.line_status = state[3];
|
||||
this.fifo_control = state[4];
|
||||
this.ier = state[5];
|
||||
this.iir = state[6];
|
||||
this.modem_control = state[7];
|
||||
this.modem_status = state[8];
|
||||
this.scratch_register = state[9];
|
||||
this.irq = state[10];
|
||||
};
|
||||
|
||||
UART.prototype.push_irq = function()
|
||||
{
|
||||
dbg_log("Push irq", LOG_SERIAL);
|
||||
|
|
119
src/vga.js
119
src/vga.js
|
@ -234,14 +234,21 @@ function VGAScreen(cpu, bus, vga_memory_size)
|
|||
this.screen_fill_buffer();
|
||||
}, this);
|
||||
|
||||
this._state_restore();
|
||||
|
||||
this.svga_memory16 = new Uint16Array(this.svga_memory.buffer);
|
||||
this.svga_memory32 = new Int32Array(this.svga_memory.buffer);
|
||||
this.vga_memory = new Uint8Array(this.svga_memory.buffer, 0, 4 * VGA_BANK_SIZE);
|
||||
this.plane0 = new Uint8Array(this.svga_memory.buffer, 0 * VGA_BANK_SIZE, VGA_BANK_SIZE);
|
||||
this.plane1 = new Uint8Array(this.svga_memory.buffer, 1 * VGA_BANK_SIZE, VGA_BANK_SIZE);
|
||||
this.plane2 = new Uint8Array(this.svga_memory.buffer, 2 * VGA_BANK_SIZE, VGA_BANK_SIZE);
|
||||
this.plane3 = new Uint8Array(this.svga_memory.buffer, 3 * VGA_BANK_SIZE, VGA_BANK_SIZE);
|
||||
|
||||
var me = this;
|
||||
io.mmap_register(0xA0000, 0x20000,
|
||||
io.mmap_register(0xA0000, 0x20000,
|
||||
function(addr) { return me.vga_memory_read(addr); },
|
||||
function(addr, value) { me.vga_memory_write(addr, value); }
|
||||
);
|
||||
io.mmap_register(0xE0000000, this.vga_memory_size,
|
||||
io.mmap_register(0xE0000000, this.vga_memory_size,
|
||||
function(addr) { return me.svga_memory_read8(addr); },
|
||||
function(addr, value) { me.svga_memory_write8(addr, value); },
|
||||
function(addr) { return me.svga_memory_read32(addr); },
|
||||
|
@ -249,30 +256,96 @@ function VGAScreen(cpu, bus, vga_memory_size)
|
|||
);
|
||||
};
|
||||
|
||||
VGAScreen.prototype._state_restore = function()
|
||||
VGAScreen.prototype.get_state = function()
|
||||
{
|
||||
/** @const */ this.svga_memory16 = new Uint16Array(this.svga_memory.buffer);
|
||||
/** @const */ this.svga_memory32 = new Int32Array(this.svga_memory.buffer);
|
||||
var state = [];
|
||||
|
||||
/** @const */ this.vga_memory = new Uint8Array(this.svga_memory.buffer, 0, 4 * VGA_BANK_SIZE);
|
||||
state[0] = this.vga_memory_size;
|
||||
state[1] = this.cursor_address;
|
||||
state[2] = this.cursor_scanline_start;
|
||||
state[3] = this.cursor_scanline_end;
|
||||
state[4] = this.max_cols;
|
||||
state[5] = this.max_rows;
|
||||
state[6] = this.screen_width;
|
||||
state[7] = this.screen_height;
|
||||
state[8] = this.start_address;
|
||||
state[9] = this.graphical_mode;
|
||||
state[10] = this.vga256_palette;
|
||||
state[11] = this.latch0;
|
||||
state[12] = this.latch1;
|
||||
state[13] = this.latch2;
|
||||
state[14] = this.latch3;
|
||||
state[15] = this.svga_width;
|
||||
state[16] = this.svga_height;
|
||||
state[17] = this.text_mode_width;
|
||||
state[18] = this.svga_enabled;
|
||||
state[19] = this.svga_bpp;
|
||||
state[20] = this.svga_bank_offset;
|
||||
state[21] = this.svga_offset;
|
||||
state[22] = this.index_crtc;
|
||||
state[23] = this.dac_color_index_write;
|
||||
state[24] = this.dac_color_index_read;
|
||||
state[25] = this.dac_map;
|
||||
state[26] = this.sequencer_index;
|
||||
state[27] = this.plane_write_bm;
|
||||
state[28] = this.sequencer_memory_mode;
|
||||
state[29] = this.graphics_index;
|
||||
state[30] = this.plane_read;
|
||||
state[31] = this.planar_mode;
|
||||
state[32] = this.planar_rotate_reg;
|
||||
state[33] = this.planar_bitmap;
|
||||
state[34] = this.max_scan_line;
|
||||
state[35] = this.miscellaneous_output_register;;
|
||||
state[36] = this.port_3DA_value;
|
||||
state[37] = this.dispi_index;
|
||||
state[38] = this.dispi_enable_value;
|
||||
state[39] = this.svga_memory;
|
||||
|
||||
/** @const */ this.plane0 = new Uint8Array(this.svga_memory.buffer, 0 * VGA_BANK_SIZE, VGA_BANK_SIZE);
|
||||
/** @const */ this.plane1 = new Uint8Array(this.svga_memory.buffer, 1 * VGA_BANK_SIZE, VGA_BANK_SIZE);
|
||||
/** @const */ this.plane2 = new Uint8Array(this.svga_memory.buffer, 2 * VGA_BANK_SIZE, VGA_BANK_SIZE);
|
||||
/** @const */ this.plane3 = new Uint8Array(this.svga_memory.buffer, 3 * VGA_BANK_SIZE, VGA_BANK_SIZE);
|
||||
return state;
|
||||
};
|
||||
|
||||
/** @const */
|
||||
this._state_skip = [
|
||||
this.bus,
|
||||
|
||||
this.svga_memory16,
|
||||
this.svga_memory32,
|
||||
this.vga_memory,
|
||||
this.plane0,
|
||||
this.plane1,
|
||||
this.plane2,
|
||||
this.plane3,
|
||||
];
|
||||
VGAScreen.prototype.set_state = function(state)
|
||||
{
|
||||
this.vga_memory_size = state[0];
|
||||
this.cursor_address = state[1];
|
||||
this.cursor_scanline_start = state[2];
|
||||
this.cursor_scanline_end = state[3];
|
||||
this.max_cols = state[4];
|
||||
this.max_rows = state[5];
|
||||
this.screen_width = state[6];
|
||||
this.screen_height = state[7];
|
||||
this.start_address = state[8];
|
||||
this.graphical_mode = state[9];
|
||||
this.vga256_palette = state[10];
|
||||
this.latch0 = state[11];
|
||||
this.latch1 = state[12];
|
||||
this.latch2 = state[13];
|
||||
this.latch3 = state[14];
|
||||
this.svga_width = state[15];
|
||||
this.svga_height = state[16];
|
||||
this.text_mode_width = state[17];
|
||||
this.svga_enabled = state[18];
|
||||
this.svga_bpp = state[19];
|
||||
this.svga_bank_offset = state[20];
|
||||
this.svga_offset = state[21];
|
||||
this.index_crtc = state[22];
|
||||
this.dac_color_index_write = state[23];
|
||||
this.dac_color_index_read = state[24];
|
||||
this.dac_map = state[25];
|
||||
this.sequencer_index = state[26];
|
||||
this.plane_write_bm = state[27];
|
||||
this.sequencer_memory_mode = state[28];
|
||||
this.graphics_index = state[29];
|
||||
this.plane_read = state[30];
|
||||
this.planar_mode = state[31];
|
||||
this.planar_rotate_reg = state[32];
|
||||
this.planar_bitmap = state[33];
|
||||
this.max_scan_line = state[34];
|
||||
this.miscellaneous_output_register = state[35];
|
||||
this.port_3DA_value = state[36];
|
||||
this.dispi_index = state[37];
|
||||
this.dispi_enable_value = state[38];
|
||||
this.svga_memory.set(state[39]);
|
||||
|
||||
this.bus.send("screen-set-mode", this.graphical_mode);
|
||||
|
||||
|
|
|
@ -166,21 +166,40 @@ function VirtIO(cpu, bus, filesystem)
|
|||
}
|
||||
|
||||
// should be generalized to support more devices than just the filesystem
|
||||
/** @const */
|
||||
this.device = new Virtio9p(filesystem, bus);
|
||||
this.device.SendReply = this.device_reply.bind(this);
|
||||
|
||||
this._state_skip = [
|
||||
this.memory,
|
||||
this.cpu,
|
||||
this.bus,
|
||||
];
|
||||
this._state_restore = function()
|
||||
{
|
||||
this.device.SendReply = this.device_reply.bind(this);
|
||||
};
|
||||
}
|
||||
|
||||
VirtIO.prototype.get_state = function()
|
||||
{
|
||||
var state = [];
|
||||
|
||||
state[0] = this.irq;
|
||||
state[1] = this.queue_select;
|
||||
state[2] = this.device_status;
|
||||
state[3] = this.isr;
|
||||
state[4] = this.last_idx;
|
||||
state[5] = this.queue_size;
|
||||
state[6] = this.queue_address;
|
||||
state[7] = this.device;
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
VirtIO.prototype.set_state = function(state)
|
||||
{
|
||||
this.irq = state[0];
|
||||
this.queue_select = state[1];
|
||||
this.device_status = state[2];
|
||||
this.isr = state[3];
|
||||
this.last_idx = state[4];
|
||||
this.queue_size = state[5];
|
||||
this.queue_address = state[6];
|
||||
|
||||
this.device = state[7];
|
||||
this.device.SendReply = this.device_reply.bind(this);
|
||||
};
|
||||
|
||||
VirtIO.prototype.reset = function()
|
||||
{
|
||||
this.queue_select = 0;
|
||||
|
|
Loading…
Reference in a new issue