diff --git a/src/browser/lib.js b/src/browser/lib.js index 5d5236ad..72d0e90a 100644 --- a/src/browser/lib.js +++ b/src/browser/lib.js @@ -301,14 +301,8 @@ var v86util = v86util || {}; { this.onload && this.onload({}); }; - - this._state_skip = [ - "file", - "block_count", - "byteLength", - "block_size", - ]; } + AsyncFileBuffer.prototype.get = function(offset, len, fn) { console.assert(offset % this.block_size === 0); diff --git a/src/cpu.macro.js b/src/cpu.macro.js index 0f741f49..3b92cb9d 100644 --- a/src/cpu.macro.js +++ b/src/cpu.macro.js @@ -12,25 +12,28 @@ function CPU() this.segment_limits = []; //this.segment_infos = []; - /* + /** * Translation Lookaside Buffer + * @const */ - this.tlb_data = []; + this.tlb_data = new Int32Array(1 << 20); - /* + /** * Information about which pages are cached in the tlb. * By bit: * 0 system, read * 1 system, write * 2 user, read * 3 user, write + * @const */ - this.tlb_info = []; + this.tlb_info = new Uint8Array(1 << 20); - /* + /** * Same as tlb_info, except it only contains global pages + * @const */ - this.tlb_info_global = []; + this.tlb_info_global = new Uint8Array(1 << 20); /** * Wheter or not in protected mode @@ -180,8 +183,14 @@ function CPU() /** @type {number} */ this.previous_ip = 0; - /** @type {!Object} */ - this.bios = {}; + /** + * @const + * @type {{main: ArrayBuffer, vga: ArrayBuffer}} + */ + this.bios = { + main: null, + vga: null, + }; /** * @type {number} @@ -229,23 +238,10 @@ function CPU() // Closure Compiler is able to remove unused functions #include "debug.macro.js" - /** @const */ - this._state_skip = [ - "bios", - "debug", - "regv", - "table", "table0F", - "table16", "table32", - "table0F_16", "table0F_32", - "reg8", "reg8s", - "reg16", "reg16s", "reg32", + dbg_assert(this.table16 && this.table32); + dbg_assert(this.table0F_16 && this.table0F_32); - "tlb_data", - "tlb_info", - "tlb_info_global", - - "timestamp_counter", - ]; + this._state_restore(); } CPU.prototype._state_restore = function() @@ -271,6 +267,21 @@ CPU.prototype._state_restore = function() this.full_clear_tlb(); this.timestamp_counter = 0; this.tsc_offset = v86.microtick(); + + /** @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, + ]; }; #include "translate.macro.js" @@ -348,11 +359,7 @@ CPU.prototype.reset = function() //this.segment_infos = new Uint32Array(8); this.segment_offsets = new Int32Array(8); - // 16 MB in total - this.tlb_data = new Int32Array(1 << 20); - this.tlb_info = new Uint8Array(1 << 20); - this.tlb_info_global = new Uint8Array(1 << 20); - + this.full_clear_tlb(); this.reg32s = new Int32Array(8); this.reg32 = new Uint32Array(this.reg32s.buffer); @@ -437,10 +444,8 @@ CPU.prototype.init = function(settings, device_bus) var io = new IO(this.memory); this.io = io; - this.bios = { - main: settings.bios, - vga: settings.vga_bios, - }; + this.bios.main = settings.bios; + this.bios.vga = settings.vga_bios; this.load_bios(); diff --git a/src/dma.js b/src/dma.js index ef25b3a8..541dd59f 100644 --- a/src/dma.js +++ b/src/dma.js @@ -5,7 +5,7 @@ */ function DMA(dev) { - this.io = dev.io; + /** @const */ this.memory = dev.memory; this.channels = [ @@ -17,15 +17,18 @@ function DMA(dev) this.lsb_msb_flipflop = 0; - this.io.register_write(0x04, this, this.port_write.bind(this, 0x04)); - this.io.register_write(0x05, this, this.port_write.bind(this, 0x05)); - this.io.register_write(0x0A, this, this.portA_write); - this.io.register_write(0x0B, this, this.portB_write); - this.io.register_write(0x0C, this, this.portC_write); - this.io.register_write(0x81, this, this.port81_write); + var io = dev.io; + io.register_write(0x04, this, this.port_write.bind(this, 0x04)); + io.register_write(0x05, this, this.port_write.bind(this, 0x05)); + io.register_write(0x0A, this, this.portA_write); + 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 = ["io", "memory"]; + this._state_skip = [ + this.memory, + ]; }; DMA.prototype.port_write = function(port, data_byte) diff --git a/src/floppy.js b/src/floppy.js index c5c58f9b..c21a2852 100644 --- a/src/floppy.js +++ b/src/floppy.js @@ -3,8 +3,13 @@ /** @constructor */ function FloppyController(cpu, fda_image, fdb_image) { + /** @const */ this.io = cpu.io; + + /** @const */ this.pic = cpu.devices.pic; + + /** @const */ this.dma = cpu.devices.dma; this.bytes_expecting = 0; @@ -18,9 +23,13 @@ function FloppyController(cpu, fda_image, fdb_image) this.floppy_size = 0; + /** @const */ this.fda_image = fda_image; + + /** @const */ this.fdb_image = fdb_image; + this.status_reg0 = 0; this.status_reg1 = 0; this.status_reg2 = 0; @@ -30,8 +39,17 @@ function FloppyController(cpu, fda_image, fdb_image) this.last_head = 0; this.last_sector = 1; + /** @const */ + this._state_skip = [ + this.io, + this.pic, + this.dma, + ]; - this._state_skip = ["io", "pic", "dma", "fda_image", "fdb_image"]; + if(this.fdb_image) + { + this._state_skip.push(this.fdb_image); + } if(!fda_image) { @@ -39,6 +57,8 @@ function FloppyController(cpu, fda_image, fdb_image) return; } + this._state_skip.push(this.fda_image); + this.floppy_size = fda_image.byteLength; var floppy_types = { diff --git a/src/fpu.js b/src/fpu.js index 9e0d49d3..369826cf 100644 --- a/src/fpu.js +++ b/src/fpu.js @@ -63,8 +63,8 @@ function FPU(cpu) // Why no Float80Array :-( this._st = new Float64Array(8); - this._st8 = new Uint8Array(this._st.buffer); - this._st32 = new Int32Array(this._st.buffer); + + this._state_restore(); // bitmap of which stack registers are empty this._stack_empty = 0xff; @@ -78,16 +78,6 @@ function FPU(cpu) this._fpu_dp = 0; this._fpu_dp_selector = 0; - /* - * used for conversion - */ - this.float32 = new Float32Array(1); - this.float32_byte = new Uint8Array(this.float32.buffer); - this.float32_int = new Int32Array(this.float32.buffer); - this.float64 = new Float64Array(1); - this.float64_byte = new Uint8Array(this.float64.buffer); - this.float64_int = new Int32Array(this.float64.buffer); - /** @const */ this.indefinite_nan = NaN; @@ -97,32 +87,35 @@ function FPU(cpu) Math.log(2) / Math.LN10, Math.LN2, 0 ]); - /** @const */ - this._state_skip = [ - "cpu", - "float32", - "float32_byte", - "float32_int", - "float64", - "float64_byte", - "float64_int", - "_st8", - "_st32", - ]; } FPU.prototype._state_restore = function() { - this.float32 = new Float32Array(1); - this.float32_byte = new Uint8Array(this.float32.buffer); - this.float32_int = new Int32Array(this.float32.buffer); + // 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); - this.float64 = new Float64Array(1); - this.float64_byte = new Uint8Array(this.float64.buffer); - this.float64_int = new Int32Array(this.float64.buffer); + /** @const */ this._st8 = new Uint8Array(this._st.buffer); + /** @const */ this._st32 = new Int32Array(this._st.buffer); - this._st8 = new Uint8Array(this._st.buffer); - this._st32 = new Int32Array(this._st.buffer); + /** @const */ + this._state_skip = [ + this.cpu, + + this.float32, + this.float32_byte, + this.float32_int, + this.float64, + this.float64_byte, + this.float64_int, + + this._st8, + this._st32, + ]; }; FPU.prototype._fpu_unimpl = function() diff --git a/src/ide.js b/src/ide.js index d658a747..44a48281 100644 --- a/src/ide.js +++ b/src/ide.js @@ -41,7 +41,10 @@ function IDEDevice(cpu, buffer, is_cd, nr) /** @type {number} */ this.master_port = 0xC000; + /** @const */ this.pic = cpu.devices.pic; + + /** @const */ this.memory = cpu.memory; this.buffer = buffer; @@ -94,6 +97,7 @@ function IDEDevice(cpu, buffer, is_cd, nr) } } + /** @const */ this.stats = { sectors_read: 0, sectors_written: 0, @@ -275,9 +279,10 @@ function IDEDevice(cpu, buffer, is_cd, nr) /** @const */ this._state_skip = [ - "memory", - "pic", - "stats", + this.memory, + this.pic, + this.stats, + this.buffer, ]; } diff --git a/src/io.js b/src/io.js index 1758c977..90629ba0 100644 --- a/src/io.js +++ b/src/io.js @@ -10,8 +10,6 @@ function IO(memory) { var memory_size = memory.size; - this._state_skip = ["devices", "ports",]; - function get_port_description(addr) { // via seabios ioport.h @@ -100,9 +98,18 @@ function IO(memory) { } + /** @const */ this.ports = []; + + /** @const */ this.devices = Array(0x10000); + this._state_skip = [ + this.ports, + this.devices, + ]; + + for(var i = 0; i < 0x10000; i++) { this.ports[i] = { diff --git a/src/memory.js b/src/memory.js index 244bf5b4..d05524c4 100644 --- a/src/memory.js +++ b/src/memory.js @@ -5,14 +5,6 @@ */ function Memory(memory_size) { - var buffer = new ArrayBuffer(memory_size); - - this.mem8 = new Uint8Array(buffer); - this.mem16 = new Uint16Array(buffer); - this.mem32s = new Int32Array(buffer); - - this.buffer = buffer; - this.size = memory_size; // this only supports a 32 bit address space @@ -20,38 +12,44 @@ function Memory(memory_size) var memory_map_registered = new Uint8Array(size); // managed by IO() in io.js - this.memory_map_registered = memory_map_registered; - this.memory_map_read8 = []; - this.memory_map_write8 = []; - this.memory_map_read32 = []; - this.memory_map_write32 = []; + /** @const */ this.memory_map_registered = memory_map_registered; + /** @const */ this.memory_map_read8 = []; + /** @const */ this.memory_map_write8 = []; + /** @const */ this.memory_map_read32 = []; + /** @const */ this.memory_map_write32 = []; // use by dynamic translator if(OP_TRANSLATION) this.mem_page_infos = new Uint8Array(1 << 20); dbg_assert((memory_size & MMAP_BLOCK_SIZE - 1) === 0); - /** @const */ - this._state_skip = [ - "mem8", - "mem16", - "mem32s", - "memory_map_registered", - "memory_map_read8", - "memory_map_read32", - "memory_map_write8", - "memory_map_write32", - ]; + this.buffer = new ArrayBuffer(memory_size);; + this._state_restore(); }; Memory.prototype._state_restore = function() { - //this.mem8 = new Uint8Array(this.mem32s.buffer, this.mem32s.byteOffset, this.mem32s.byteLength); - //this.mem16 = new Uint16Array(this.mem32s.buffer, this.mem32s.byteOffset, this.mem32s.byteLength >> 1); - + /** @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, + ]; }; // called by all memory reads and writes diff --git a/src/ne2k.js b/src/ne2k.js index d38b32a2..2946aec6 100644 --- a/src/ne2k.js +++ b/src/ne2k.js @@ -55,8 +55,10 @@ /** @constructor */ function Ne2k(cpu, bus) { + /** @const */ this.pic = cpu.devices.pic; + /** @const */ this.bus = bus; this.bus.register("net0-receive", function(data) { @@ -362,8 +364,8 @@ function Ne2k(cpu, bus) io.register_write(this.port | NE_DATAPORT | 0, this, this.data_port_write, this.data_port_write16, this.data_port_write32); this._state_skip = [ - "bus", - "pic", + this.bus, + this.pic, ]; } diff --git a/src/pit.js b/src/pit.js index d4661a63..8bce7194 100644 --- a/src/pit.js +++ b/src/pit.js @@ -14,6 +14,7 @@ var OSCILLATOR_FREQ = 1193.1816666; // 1.193182 MHz */ function PIT(cpu) { + /** @const */ this.pic = cpu.devices.pic; this.next_tick = Date.now(); @@ -54,7 +55,9 @@ function PIT(cpu) cpu.io.register_write(0x43, this, this.port43_write); /** @const */ - this._state_skip = ["pic"]; + this._state_skip = [ + this.pic, + ]; } PIT.prototype.get_timer2 = function() diff --git a/src/ps2.js b/src/ps2.js index 2e2da6af..b58c5dd9 100644 --- a/src/ps2.js +++ b/src/ps2.js @@ -5,9 +5,12 @@ */ function PS2(cpu, bus) { + /** @const */ this.pic = cpu.devices.pic; + /** @const */ this.cpu = cpu; + /** @const */ this.bus = bus; /** @type {boolean} */ @@ -107,9 +110,9 @@ function PS2(cpu, bus) /** @const */ this._state_skip = [ - "bus", - "pic", - "cpu", + this.bus, + this.pic, + this.cpu, ]; } diff --git a/src/rtc.js b/src/rtc.js index 3a01ab54..da61c07c 100644 --- a/src/rtc.js +++ b/src/rtc.js @@ -4,7 +4,10 @@ */ function RTC(cpu, diskette_type, boot_order) { + /** @const */ this.cpu = cpu; + + /** @const */ this.pic = cpu.devices.pic; this.cmos_index = 0; @@ -40,7 +43,10 @@ function RTC(cpu, diskette_type, boot_order) cpu.io.register_write(0x71, this, this.cmos_write); cpu.io.register_read(0x71, this, this.cmos_read); - this._state_skip = ["cpu", "pic"]; + this._state_skip = [ + this.cpu, + this.pic, + ]; } RTC.prototype.timer = function(time, legacy_mode) diff --git a/src/state.js b/src/state.js index dc01f793..235c947c 100644 --- a/src/state.js +++ b/src/state.js @@ -71,21 +71,21 @@ function save_object(obj, arraybuffers) }; } - var skip = Array.setify(obj._state_skip || []); - skip["_state_skip"] = true; + var skip; + + if(obj._state_skip) + { + skip = obj._state_skip.slice(); + skip.push(obj._state_skip); + } var keys = Object.keys(obj); var result = {}; + outer: for(var i = 0; i < keys.length; i++) { var key = keys[i]; - - if(skip[key]) - { - continue; - } - var value = obj[key]; if(typeof value === "function") @@ -93,6 +93,17 @@ function save_object(obj, arraybuffers) continue; } + 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); } diff --git a/src/uart.js b/src/uart.js index d61aeddd..72d03bcc 100644 --- a/src/uart.js +++ b/src/uart.js @@ -26,8 +26,10 @@ var DLAB = 0x80; */ function UART(cpu, port, bus) { + /** @const */ this.bus = bus; + /** @const */ this.pic = cpu.devices.pic; this.ints = 0; @@ -247,7 +249,8 @@ function UART(cpu, port, bus) }); this._state_skip = [ - "bus", + this.bus, + this.pic, ]; } diff --git a/src/vga.js b/src/vga.js index db4c06f4..b9c8448b 100644 --- a/src/vga.js +++ b/src/vga.js @@ -23,6 +23,7 @@ var */ function VGAScreen(cpu, bus, vga_memory_size) { + /** @const */ this.bus = bus; this.vga_memory_size = vga_memory_size; @@ -40,13 +41,13 @@ function VGAScreen(cpu, bus, vga_memory_size) * Number of columns in text mode * @type {number} */ - this.max_cols = 0; + this.max_cols = 80; /** * Number of rows in text mode * @type {number} */ - this.max_rows = 0; + this.max_rows = 25; /** * Width in pixels in graphical mode @@ -97,18 +98,6 @@ function VGAScreen(cpu, bus, vga_memory_size) /** @type {number} */ this.text_mode_width = 80; - this.plane0; - this.plane1; - this.plane2; - this.plane3; - - // 4 times 64k - this.vga_memory = null; - - this.svga_memory = null; - this.svga_memory16 = null; - this.svga_memory32 = null; - this.svga_enabled = false; /** @type {number} */ @@ -225,18 +214,8 @@ function VGAScreen(cpu, bus, vga_memory_size) } this.svga_memory = new Uint8Array(this.vga_memory_size); - 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); - - this.set_size_text(80, 25); - this.update_cursor_scanline(); + this._state_restore(); var me = this; io.mmap_register(0xA0000, 0x20000, @@ -249,31 +228,32 @@ function VGAScreen(cpu, bus, vga_memory_size) function(addr) { return me.svga_memory_read32(addr); }, function(addr, value) { me.svga_memory_write32(addr, value); } ); - - /** @const */ - this._state_skip = [ - "bus", - "svga_memory16", - "svga_memory32", - "vga_memory", - "plane0", - "plane1", - "plane2", - "plane3", - ]; }; VGAScreen.prototype._state_restore = function() { - this.svga_memory16 = new Uint16Array(this.svga_memory.buffer); - this.svga_memory32 = new Int32Array(this.svga_memory.buffer); + /** @const */ this.svga_memory16 = new Uint16Array(this.svga_memory.buffer); + /** @const */ this.svga_memory32 = new Int32Array(this.svga_memory.buffer); - this.vga_memory = new Uint8Array(this.svga_memory.buffer, 0, 4 * VGA_BANK_SIZE); + /** @const */ 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); + /** @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); + + /** @const */ + this._state_skip = [ + this.bus, + + this.svga_memory16, + this.svga_memory32, + this.vga_memory, + this.plane0, + this.plane1, + this.plane2, + this.plane3, + ]; this.bus.send("screen-set-mode", this.graphical_mode || this.svga_enabled); diff --git a/src/virtio.js b/src/virtio.js index eceedcf8..50e569a3 100644 --- a/src/virtio.js +++ b/src/virtio.js @@ -125,6 +125,8 @@ function VirtIO(cpu, filesystem) }); this.irq = 0xC; + + /** @const */ this.pic = cpu.devices.pic; this.queue_select = 0; @@ -136,7 +138,7 @@ function VirtIO(cpu, filesystem) this.queue_size = 32; this.queue_address = 0; - + /** @const */ this.memory = cpu.memory; for(var i = 0; i < 128; i++) @@ -156,10 +158,15 @@ function VirtIO(cpu, filesystem) } // should be generalized to support more devices than just the filesystem + /** @const */ this.device = new Virtio9p(filesystem); this.device.SendReply = this.device_reply.bind(this); - this._state_skip = ["memory", "pic"]; + this._state_skip = [ + this.memory, + this.pic, + this.device, + ]; this._state_restore = function() { this.device.SendReply = this.device_reply.bind(this);