From a2b06b76260a973f592afcd614cce14a6a84c8c1 Mon Sep 17 00:00:00 2001 From: Jeff Parsons Date: Wed, 1 Apr 2015 17:20:26 -0700 Subject: [PATCH] Simplify subclassing --- modules/c1pjs/lib/computer.js | 2 +- modules/c1pjs/lib/cpu.js | 2 +- modules/c1pjs/lib/debugger.js | 2 +- modules/c1pjs/lib/disk.js | 2 +- modules/c1pjs/lib/keyboard.js | 2 +- modules/c1pjs/lib/panel.js | 2 +- modules/c1pjs/lib/ram.js | 2 +- modules/c1pjs/lib/rom.js | 3 +- modules/c1pjs/lib/serial.js | 2 +- modules/c1pjs/lib/video.js | 2 +- modules/pcjs/lib/bus.js | 2 +- modules/pcjs/lib/chipset.js | 2 +- modules/pcjs/lib/computer.js | 2 +- modules/pcjs/lib/cpu.js | 2 +- modules/pcjs/lib/debugger.js | 2 +- modules/pcjs/lib/disk.js | 2 +- modules/pcjs/lib/fdc.js | 2 +- modules/pcjs/lib/hdc.js | 2 +- modules/pcjs/lib/keyboard.js | 2 +- modules/pcjs/lib/memory.js | 1117 +++++++++++++++---------------- modules/pcjs/lib/mouse.js | 7 +- modules/pcjs/lib/panel.js | 6 +- modules/pcjs/lib/ram.js | 2 +- modules/pcjs/lib/rom.js | 2 +- modules/pcjs/lib/serialport.js | 2 +- modules/pcjs/lib/video.js | 2 +- modules/pcjs/lib/x86cpu.js | 2 +- modules/shared/lib/component.js | 7 +- 28 files changed, 579 insertions(+), 607 deletions(-) diff --git a/modules/c1pjs/lib/computer.js b/modules/c1pjs/lib/computer.js index 6199e6933..96a08f1ba 100644 --- a/modules/c1pjs/lib/computer.js +++ b/modules/c1pjs/lib/computer.js @@ -98,7 +98,7 @@ C1PComputer.sAppName = APPNAME || "C1Pjs"; C1PComputer.sAppVer = APPVERSION; C1PComputer.sCopyright = "Copyright © 2012-2015 Jeff Parsons "; -Component.subclass(Component, C1PComputer); +Component.subclass(C1PComputer); /** * @this {C1PComputer} diff --git a/modules/c1pjs/lib/cpu.js b/modules/c1pjs/lib/cpu.js index 77b6b5b4b..d080bc116 100644 --- a/modules/c1pjs/lib/cpu.js +++ b/modules/c1pjs/lib/cpu.js @@ -469,7 +469,7 @@ function C1PCPU(parmsCPU) ]; } -Component.subclass(Component, C1PCPU); +Component.subclass(C1PCPU); /** * @this {C1PCPU} diff --git a/modules/c1pjs/lib/debugger.js b/modules/c1pjs/lib/debugger.js index 01f2c6903..442c9c97a 100644 --- a/modules/c1pjs/lib/debugger.js +++ b/modules/c1pjs/lib/debugger.js @@ -484,7 +484,7 @@ function C1PDebugger(parmsDbg) if (DEBUGGER) { - Component.subclass(Component, C1PDebugger); + Component.subclass(C1PDebugger); /** * @this {C1PDebugger} diff --git a/modules/c1pjs/lib/disk.js b/modules/c1pjs/lib/disk.js index 09cd2cdd1..342468c92 100644 --- a/modules/c1pjs/lib/disk.js +++ b/modules/c1pjs/lib/disk.js @@ -433,7 +433,7 @@ function C1PDiskController(parmsDC) this.reset(true); } -Component.subclass(Component, C1PDiskController); +Component.subclass(C1PDiskController); /** * @this {C1PDiskController} diff --git a/modules/c1pjs/lib/keyboard.js b/modules/c1pjs/lib/keyboard.js index acb820c9f..0c3ed8fea 100644 --- a/modules/c1pjs/lib/keyboard.js +++ b/modules/c1pjs/lib/keyboard.js @@ -295,7 +295,7 @@ function C1PKeyboard(parmsKbd) this.reset(); } -Component.subclass(Component, C1PKeyboard); +Component.subclass(C1PKeyboard); /** * @this {C1PKeyboard} diff --git a/modules/c1pjs/lib/panel.js b/modules/c1pjs/lib/panel.js index 5e59aa0ad..d160a2a3b 100644 --- a/modules/c1pjs/lib/panel.js +++ b/modules/c1pjs/lib/panel.js @@ -47,7 +47,7 @@ function C1PPanel(parmsPanel) this.aFlags.fPowered = false; } -Component.subclass(Component, C1PPanel); +Component.subclass(C1PPanel); /** * The Panel doesn't have any bindings of its own; it passes along all binding requests to diff --git a/modules/c1pjs/lib/ram.js b/modules/c1pjs/lib/ram.js index 5944a6863..50f5ef133 100644 --- a/modules/c1pjs/lib/ram.js +++ b/modules/c1pjs/lib/ram.js @@ -51,7 +51,7 @@ function C1PRAM(parmsRAM) Component.call(this, "C1PRAM", parmsRAM); } -Component.subclass(Component, C1PRAM); +Component.subclass(C1PRAM); /** * @this {C1PRAM} diff --git a/modules/c1pjs/lib/rom.js b/modules/c1pjs/lib/rom.js index b00c117c4..d44f96cc1 100644 --- a/modules/c1pjs/lib/rom.js +++ b/modules/c1pjs/lib/rom.js @@ -50,6 +50,7 @@ function C1PROM(parmsROM) { Component.call(this, "C1PROM", parmsROM); + this.abMem = null; this.abImage = null; this.cbROM = parmsROM['size']; @@ -70,7 +71,7 @@ function C1PROM(parmsROM) } } -Component.subclass(Component, C1PROM); +Component.subclass(C1PROM); /** * @this {C1PROM} diff --git a/modules/c1pjs/lib/serial.js b/modules/c1pjs/lib/serial.js index e391687d8..e0fedf124 100644 --- a/modules/c1pjs/lib/serial.js +++ b/modules/c1pjs/lib/serial.js @@ -53,7 +53,7 @@ function C1PSerialPort(parmsSerial) this.reset(); } -Component.subclass(Component, C1PSerialPort); +Component.subclass(C1PSerialPort); /** * @this {C1PSerialPort} diff --git a/modules/c1pjs/lib/video.js b/modules/c1pjs/lib/video.js index 0b9e4def8..5569ec162 100644 --- a/modules/c1pjs/lib/video.js +++ b/modules/c1pjs/lib/video.js @@ -152,7 +152,7 @@ function C1PVideo(parmsVideo, eCanvas, context, imgChars) this.addrVideoPort = 0xDE00; // WARNING: Hard-coded port address -JP } -Component.subclass(Component, C1PVideo); +Component.subclass(C1PVideo); /** * @this {C1PVideo} diff --git a/modules/pcjs/lib/bus.js b/modules/pcjs/lib/bus.js index c007d001c..a560ffafd 100644 --- a/modules/pcjs/lib/bus.js +++ b/modules/pcjs/lib/bus.js @@ -191,7 +191,7 @@ function Bus(parmsBus, cpu, dbg) this.setReady(); } -Component.subclass(Component, Bus); +Component.subclass(Bus); if (BACKTRACK) { /* diff --git a/modules/pcjs/lib/chipset.js b/modules/pcjs/lib/chipset.js index 75a46078c..5f74489d8 100644 --- a/modules/pcjs/lib/chipset.js +++ b/modules/pcjs/lib/chipset.js @@ -255,7 +255,7 @@ function ChipSet(parmsChipSet) this.setReady(); } -Component.subclass(Component, ChipSet); +Component.subclass(ChipSet); /* * Supported model numbers diff --git a/modules/pcjs/lib/computer.js b/modules/pcjs/lib/computer.js index 34444a2cd..fbccbe769 100644 --- a/modules/pcjs/lib/computer.js +++ b/modules/pcjs/lib/computer.js @@ -255,7 +255,7 @@ function Computer(parmsComputer, parmsMachine, fSuspended) { } } -Component.subclass(Component, Computer); +Component.subclass(Computer); /* * NOTE: 1.01 is the first version to provide limited save/restore support using localStorage. diff --git a/modules/pcjs/lib/cpu.js b/modules/pcjs/lib/cpu.js index 9d7378361..e68f58f5f 100644 --- a/modules/pcjs/lib/cpu.js +++ b/modules/pcjs/lib/cpu.js @@ -139,7 +139,7 @@ function CPU(parmsCPU, nCyclesDefault) this.setReady(); } -Component.subclass(Component, CPU); +Component.subclass(CPU); /* * Constants that control the frequency at which various updates should occur. diff --git a/modules/pcjs/lib/debugger.js b/modules/pcjs/lib/debugger.js index 77e98300f..637b01e60 100644 --- a/modules/pcjs/lib/debugger.js +++ b/modules/pcjs/lib/debugger.js @@ -192,7 +192,7 @@ function Debugger(parmsDbg) if (DEBUGGER) { - Component.subclass(Component, Debugger); + Component.subclass(Debugger); /* * Information regarding interrupts of interest (used by messageInt() and others) diff --git a/modules/pcjs/lib/disk.js b/modules/pcjs/lib/disk.js index d1700bd8c..683a8f8e3 100644 --- a/modules/pcjs/lib/disk.js +++ b/modules/pcjs/lib/disk.js @@ -305,7 +305,7 @@ Disk.REMOTE_WRITE_DELAY = 2000; // 2-second delay */ Disk.nDisks = 0; -Component.subclass(Component, Disk); +Component.subclass(Disk); /** * initBus(cmp, bus, cpu, dbg) diff --git a/modules/pcjs/lib/fdc.js b/modules/pcjs/lib/fdc.js index 345857558..f0da299a1 100644 --- a/modules/pcjs/lib/fdc.js +++ b/modules/pcjs/lib/fdc.js @@ -187,7 +187,7 @@ function FDC(parmsFDC) { */ } -Component.subclass(Component, FDC); +Component.subclass(FDC); FDC.DEFAULT_DRIVE_NAME = "Floppy Drive"; diff --git a/modules/pcjs/lib/hdc.js b/modules/pcjs/lib/hdc.js index a54c9e6f6..b0d05033c 100644 --- a/modules/pcjs/lib/hdc.js +++ b/modules/pcjs/lib/hdc.js @@ -117,7 +117,7 @@ function HDC(parmsHDC) { */ } -Component.subclass(Component, HDC); +Component.subclass(HDC); /* * HDC defaults, in case drive parameters weren't specified diff --git a/modules/pcjs/lib/keyboard.js b/modules/pcjs/lib/keyboard.js index e1416b2c6..f83c43fce 100644 --- a/modules/pcjs/lib/keyboard.js +++ b/modules/pcjs/lib/keyboard.js @@ -146,7 +146,7 @@ function Keyboard(parmsKbd) this.setReady(); } -Component.subclass(Component, Keyboard); +Component.subclass(Keyboard); /** * Alphanumeric and other common (printable) ASCII codes. diff --git a/modules/pcjs/lib/memory.js b/modules/pcjs/lib/memory.js index e84a2a6f6..66faccba9 100644 --- a/modules/pcjs/lib/memory.js +++ b/modules/pcjs/lib/memory.js @@ -126,14 +126,14 @@ function Memory(addr, used, size, type, controller) if (BACKTRACK) { if (!size || controller) { this.fModBackTrack = false; - this.readBackTrack = Memory.readBackTrackNone; - this.writeBackTrack = Memory.writeBackTrackNone; - this.modBackTrack = Memory.modBackTrackNone; + this.readBackTrack = this.readBackTrackNone; + this.writeBackTrack = this.writeBackTrackNone; + this.modBackTrack = this.modBackTrackNone; } else { this.fModBackTrack = true; - this.readBackTrack = Memory.readBackTrackIndex; - this.writeBackTrack = Memory.writeBackTrackIndex; - this.modBackTrack = Memory.modBackTrackIndex; + this.readBackTrack = this.readBackTrackIndex; + this.writeBackTrack = this.writeBackTrackIndex; + this.modBackTrack = this.modBackTrackIndex; this.abtIndexes = new Array(size); for (i = 0; i < size; i++) this.abtIndexes[i] = 0; } @@ -223,560 +223,6 @@ Memory.TYPE = { COLORS: ["black", "blue", "green", "cyan"] }; -/** - * readNone(off) - * - * @this {Memory} - * @param {number} off - * @return {number} - */ -Memory.readNone = function readNone(off) -{ - if (DEBUGGER && this.dbg.messageEnabled(Messages.MEM) /* && !off */) { - this.dbg.message("attempt to read invalid block %" + str.toHex(this.addr) + " from " + this.dbg.hexOffset(this.cpu.getIP(), this.cpu.getCS())); - } - return 0; -}; - -/** - * writeNone(off, v) - * - * @this {Memory} - * @param {number} off - * @param {number} v (could be either a byte or word value, since we use the same handler for both kinds of accesses) - */ -Memory.writeNone = function writeNone(off, v) -{ - if (DEBUGGER && this.dbg.messageEnabled(Messages.MEM) /* && !off */) { - this.dbg.message("attempt to write " + str.toHexWord(v) + " to invalid block %" + str.toHex(this.addr), true); - } -}; - -/** - * readByteMemory(off) - * - * @this {Memory} - * @param {number} off - * @return {number} - */ -Memory.readByteMemory = function readByteMemory(off) -{ - Component.assert(off >= 0 && off < this.size); - if (FATARRAYS) { - return this.ab[off]; - } - return ((this.adw[off >> 2] >>> ((off & 0x3) << 3)) & 0xff); -}; - -/** - * readShortMemory(off) - * - * @this {Memory} - * @param {number} off - * @return {number} - */ -Memory.readShortMemory = function readShortMemory(off) -{ - Component.assert(off >= 0 && off < this.size - 1); - if (FATARRAYS) { - return this.ab[off] | (this.ab[off + 1] << 8); - } - var w; - var idw = off >> 2; - var nShift = (off & 0x3) << 3; - var dw = (this.adw[idw] >> nShift); - if (nShift < 24) { - w = dw & 0xffff; - } else { - w = (dw & 0xff) | ((this.adw[idw + 1] & 0xff) << 8); - } - return w; -}; - -/** - * readLongMemory(off) - * - * @this {Memory} - * @param {number} off - * @return {number} - */ -Memory.readLongMemory = function readLongMemory(off) -{ - Component.assert(off >= 0 && off < this.size - 3); - if (FATARRAYS) { - return this.ab[off] | (this.ab[off + 1] << 8) | (this.ab[off + 2] << 16) | (this.ab[off + 3] << 24); - } - var idw = off >> 2; - var nShift = (off & 0x3) << 3; - var l = this.adw[idw]; - if (nShift) { - l >>>= nShift; - l |= this.adw[idw + 1] << (32 - nShift); - } - return l; -}; - -/** - * writeByteMemory(off, b) - * - * @this {Memory} - * @param {number} off - * @param {number} b - */ -Memory.writeByteMemory = function writeByteMemory(off, b) -{ - Component.assert(off >= 0 && off < this.size && (b & 0xff) == b); - if (FATARRAYS) { - this.ab[off] = b; - } else { - var idw = off >> 2; - var nShift = (off & 0x3) << 3; - this.adw[idw] = (this.adw[idw] & ~(0xff << nShift)) | (b << nShift); - } - this.fDirty = true; -}; - -/** - * writeShortMemory(off, w) - * - * @this {Memory} - * @param {number} off - * @param {number} w - */ -Memory.writeShortMemory = function writeShortMemory(off, w) -{ - Component.assert(off >= 0 && off < this.size - 1 && (w & 0xffff) == w); - if (FATARRAYS) { - this.ab[off] = (w & 0xff); - this.ab[off + 1] = (w >> 8); - } else { - var idw = off >> 2; - var nShift = (off & 0x3) << 3; - if (nShift < 24) { - /* - * 0: 0xffff0000 - * 8: 0xff0000ff - * 16: 0x0000ffff - */ - this.adw[idw] = (this.adw[idw] & ~(0xffff << nShift)) | (w << nShift); - } else { - this.adw[idw] = (this.adw[idw] & 0x00ffffff) | (w << 24); - idw++; - this.adw[idw] = (this.adw[idw] & (0xffffff00|0)) | (w >> 8); - } - } - this.fDirty = true; -}; - -/** - * writeLongMemory(off, l) - * - * @this {Memory} - * @param {number} off - * @param {number} l - */ -Memory.writeLongMemory = function writeLongMemory(off, l) -{ - Component.assert(off >= 0 && off < this.size - 3); - if (FATARRAYS) { - this.ab[off] = (l & 0xff); - this.ab[off + 1] = (l >> 8) & 0xff; - this.ab[off + 2] = (l >> 16) & 0xff; - this.ab[off + 3] = (l >> 24) & 0xff; - } else { - var idw = off >> 2; - var nShift = (off & 0x3) << 3; - if (!nShift) { - this.adw[idw] = l; - } else { - /* - * 8: 0xffffff00 - * 16: 0xffff0000 - * 24: 0xff000000 - */ - var mask = (0xffffffff|0) << nShift; - this.adw[idw] = (this.adw[idw] & ~mask) | (l << nShift); - idw++; - this.adw[idw] = (this.adw[idw] & mask) | (l >>> (32 - nShift)); - } - } - this.fDirty = true; -}; - -/** - * readByteChecked(off) - * - * @this {Memory} - * @param {number} off - * @return {number} - */ -Memory.readByteChecked = function readByteChecked(off) -{ - if (DEBUGGER) this.dbg.checkMemoryRead(this.addr + off); - return this.readByteDirect(off); -}; - -/** - * readShortChecked(off) - * - * @this {Memory} - * @param {number} off - * @return {number} - */ -Memory.readShortChecked = function readShortChecked(off) -{ - if (DEBUGGER) { - this.dbg.checkMemoryRead(this.addr + off) || - this.dbg.checkMemoryRead(this.addr + off + 1); - } - return this.readShortDirect(off); -}; - -/** - * readLongChecked(off) - * - * @this {Memory} - * @param {number} off - * @return {number} - */ -Memory.readLongChecked = function readLongChecked(off) -{ - if (DEBUGGER) { - this.dbg.checkMemoryRead(this.addr + off) || - this.dbg.checkMemoryRead(this.addr + off + 1) || - this.dbg.checkMemoryRead(this.addr + off + 2) || - this.dbg.checkMemoryRead(this.addr + off + 3); - } - return this.readLongDirect(off); -}; - -/** - * writeByteChecked(off, b) - * - * @this {Memory} - * @param {number} off - * @param {number} b - */ -Memory.writeByteChecked = function writeByteChecked(off, b) -{ - if (DEBUGGER) this.dbg.checkMemoryWrite(this.addr + off); - this.writeByteDirect(off, b); -}; - -/** - * writeShortChecked(off, w) - * - * @this {Memory} - * @param {number} off - * @param {number} w - */ -Memory.writeShortChecked = function writeShortChecked(off, w) -{ - if (DEBUGGER) { - this.dbg.checkMemoryWrite(this.addr + off) || - this.dbg.checkMemoryWrite(this.addr + off + 1); - } - this.writeShortDirect(off, w); -}; - -/** - * writeLongChecked(off, l) - * - * @this {Memory} - * @param {number} off - * @param {number} l - */ -Memory.writeLongChecked = function writeLongChecked(off, l) -{ - if (DEBUGGER) { - this.dbg.checkMemoryWrite(this.addr + off) || - this.dbg.checkMemoryWrite(this.addr + off + 1) || - this.dbg.checkMemoryWrite(this.addr + off + 2) || - this.dbg.checkMemoryWrite(this.addr + off + 3); - } - this.writeLongDirect(off, l); -}; - -/** - * readByteBigEndian(off) - * - * @this {Memory} - * @param {number} off - * @return {number} - */ -Memory.readByteBigEndian = function readByteBigEndian(off) -{ - Component.assert(off >= 0 && off < this.size); - return this.ab[off]; -}; - -/** - * readByteLittleEndian(off) - * - * @this {Memory} - * @param {number} off - * @return {number} - */ -Memory.readByteLittleEndian = function readByteLittleEndian(off) -{ - Component.assert(off >= 0 && off < this.size); - return this.ab[off]; -}; - -/** - * readShortBigEndian(off) - * - * @this {Memory} - * @param {number} off - * @return {number} - */ -Memory.readShortBigEndian = function readShortBigEndian(off) -{ - Component.assert(off >= 0 && off < this.size - 1); - return this.dv.getUint16(off, true); -}; - -/** - * readShortLittleEndian(off) - * - * @this {Memory} - * @param {number} off - * @return {number} - */ -Memory.readShortLittleEndian = function readShortLittleEndian(off) -{ - Component.assert(off >= 0 && off < this.size - 1); - /* - * TODO: It remains to be seen if there's any advantage to checking the offset - * for an aligned read vs. always reading the bytes separately; it seems a safe bet - * for longs, but it's less clear for shorts. - */ - return (off & 0x1)? (this.ab[off] | (this.ab[off+1] << 8)) : this.aw[off >> 1]; -}; - -/** - * readLongBigEndian(off) - * - * @this {Memory} - * @param {number} off - * @return {number} - */ -Memory.readLongBigEndian = function readLongBigEndian(off) -{ - Component.assert(off >= 0 && off < this.size - 3); - return this.dv.getInt32(off, true); -}; - -/** - * readLongLittleEndian(off) - * - * @this {Memory} - * @param {number} off - * @return {number} - */ -Memory.readLongLittleEndian = function readLongLittleEndian(off) -{ - Component.assert(off >= 0 && off < this.size - 3); - /* - * TODO: It remains to be seen if there's any advantage to checking the offset - * for an aligned read vs. always reading the bytes separately; it seems a safe bet - * for longs, but it's less clear for shorts. - */ - return (off & 0x3)? (this.ab[off] | (this.ab[off+1] << 8) | (this.ab[off+2] << 16) | (this.ab[off+3] << 24)) : this.adw[off >> 2]; -}; - -/** - * writeByteBigEndian(off, b) - * - * @this {Memory} - * @param {number} off - * @param {number} b - */ -Memory.writeByteBigEndian = function writeByteBigEndian(off, b) -{ - Component.assert(off >= 0 && off < this.size); - this.ab[off] = b; - this.fDirty = true; -}; - -/** - * writeByteLittleEndian(off, b) - * - * @this {Memory} - * @param {number} off - * @param {number} b - */ -Memory.writeByteLittleEndian = function writeByteLittleEndian(off, b) -{ - Component.assert(off >= 0 && off < this.size); - this.ab[off] = b; - this.fDirty = true; -}; - -/** - * writeShortBigEndian(off, w) - * - * @this {Memory} - * @param {number} off - * @param {number} w - */ -Memory.writeShortBigEndian = function writeShortBigEndian(off, w) -{ - Component.assert(off >= 0 && off < this.size - 1); - this.dv.setUint16(off, w, true); - this.fDirty = true; -}; - -/** - * writeShortLittleEndian(off, w) - * - * @this {Memory} - * @param {number} off - * @param {number} w - */ -Memory.writeShortLittleEndian = function writeShortLittleEndian(off, w) -{ - Component.assert(off >= 0 && off < this.size - 1); - /* - * TODO: It remains to be seen if there's any advantage to checking the offset - * for an aligned write vs. always writing the bytes separately; it seems a safe bet - * for longs, but it's less clear for shorts. - */ - if (off & 0x1) { - this.ab[off] = w; - this.ab[off+1] = w >> 8; - } else { - this.aw[off >> 1] = w; - } - this.fDirty = true; -}; - -/** - * writeLongBigEndian(off, l) - * - * @this {Memory} - * @param {number} off - * @param {number} l - */ -Memory.writeLongBigEndian = function writeLongBigEndian(off, l) -{ - Component.assert(off >= 0 && off < this.size - 3); - this.dv.setInt32(off, l, true); - this.fDirty = true; -}; - -/** - * writeLongLittleEndian(off, l) - * - * @this {Memory} - * @param {number} off - * @param {number} l - */ -Memory.writeLongLittleEndian = function writeLongLittleEndian(off, l) -{ - Component.assert(off >= 0 && off < this.size - 3); - /* - * TODO: It remains to be seen if there's any advantage to checking the offset - * for an aligned write vs. always writing the bytes separately; it seems a safe bet - * for longs, but it's less clear for shorts. - */ - if (off & 0x3) { - this.ab[off] = l; - this.ab[off+1] = (l >> 8); - this.ab[off+2] = (l >> 16); - this.ab[off+3] = (l >> 24); - } else { - this.adw[off >> 2] = l; - } - this.fDirty = true; -}; - -/** - * readBackTrackNone(off) - * - * @this {Memory} - * @param {number} off - * @return {number} - */ -Memory.readBackTrackNone = function readBackTrackNone(off) -{ - return 0; -}; - -/** - * writeBackTrackNone(off, bti) - * - * @this {Memory} - * @param {number} off - * @param {number} bti - */ -Memory.writeBackTrackNone = function writeBackTrackNone(off, bti) -{ -}; - -/** - * modBackTrackNone(fMod) - * - * @this {Memory} - * @param {boolean} fMod - */ -Memory.modBackTrackNone = function modBackTrackNone(fMod) -{ - return false; -}; - -/** - * readBackTrackIndex(off) - * - * @this {Memory} - * @param {number} off - * @return {number} - */ -Memory.readBackTrackIndex = function readBackTrackIndex(off) -{ - Component.assert(off >= 0 && off < this.size); - return this.abtIndexes[off]; -}; - -/** - * writeBackTrackIndex(off, bti) - * - * @this {Memory} - * @param {number} off - * @param {number} bti - * @return {number} previous bti (0 if none) - */ -Memory.writeBackTrackIndex = function writeBackTrackIndex(off, bti) -{ - var btiPrev; - Component.assert(off >= 0 && off < this.size); - btiPrev = this.abtIndexes[off]; - this.abtIndexes[off] = bti; - return btiPrev; -}; - -/** - * modBackTrackIndex(fMod) - * - * @this {Memory} - * @param {boolean} fMod - * @return {boolean} previous value - */ -Memory.modBackTrackIndex = function modBackTrackIndex(fMod) -{ - var fModPrev = this.fModBackTrack; - this.fModBackTrack = fMod; - return fModPrev; -}; - -Memory.afnMemory = [Memory.readByteMemory, Memory.readShortMemory, Memory.readLongMemory, Memory.writeByteMemory, Memory.writeShortMemory, Memory.writeLongMemory]; -Memory.afnChecked = [Memory.readByteChecked, Memory.readShortChecked, Memory.readLongChecked, Memory.writeByteChecked, Memory.writeShortChecked, Memory.writeLongChecked]; - -if (TYPEDARRAYS) { - Memory.afnBigEndian = [Memory.readByteBigEndian, Memory.readShortBigEndian, Memory.readLongBigEndian, Memory.writeByteBigEndian, Memory.writeShortBigEndian, Memory.writeLongBigEndian]; - Memory.afnLittleEndian = [Memory.readByteLittleEndian, Memory.readShortLittleEndian, Memory.readLongLittleEndian, Memory.writeByteLittleEndian, Memory.writeShortLittleEndian, Memory.writeLongLittleEndian]; -} - Memory.prototype = { constructor: Memory, parent: null, @@ -926,13 +372,13 @@ Memory.prototype = { * @param {boolean} [fDirect] */ setReadAccess: function(afn, fDirect) { - this.readByte = afn[0] || Memory.readNone; - this.readShort = afn[1] || Memory.readNone; - this.readLong = afn[2] || Memory.readNone; + this.readByte = afn[0] || this.readNone; + this.readShort = afn[1] || this.readNone; + this.readLong = afn[2] || this.readNone; if (fDirect) { - this.readByteDirect = afn[0] || Memory.readNone; - this.readShortDirect = afn[1] || Memory.readNone; - this.readLongDirect = afn[2] || Memory.readNone; + this.readByteDirect = afn[0] || this.readNone; + this.readShortDirect = afn[1] || this.readNone; + this.readLongDirect = afn[2] || this.readNone; } }, /** @@ -943,13 +389,13 @@ Memory.prototype = { * @param {boolean} [fDirect] */ setWriteAccess: function(afn, fDirect) { - this.writeByte = !this.fReadOnly && afn[3] || Memory.writeNone; - this.writeShort = !this.fReadOnly && afn[4] || Memory.writeNone; - this.writeLong = !this.fReadOnly && afn[5] || Memory.writeNone; + this.writeByte = !this.fReadOnly && afn[3] || this.writeNone; + this.writeShort = !this.fReadOnly && afn[4] || this.writeNone; + this.writeLong = !this.fReadOnly && afn[5] || this.writeNone; if (fDirect) { - this.writeByteDirect = afn[3] || Memory.writeNone; - this.writeShortDirect = afn[4] || Memory.writeNone; - this.writeLongDirect = afn[5] || Memory.writeNone; + this.writeByteDirect = afn[3] || this.writeNone; + this.writeShortDirect = afn[4] || this.writeNone; + this.writeLongDirect = afn[5] || this.writeNone; } }, /** @@ -968,9 +414,9 @@ Memory.prototype = { * @this {Memory} */ resetWriteAccess: function() { - this.writeByte = this.fReadOnly? Memory.writeNone : this.writeByteDirect; - this.writeShort = this.fReadOnly? Memory.writeNone : this.writeShortDirect; - this.writeLong = this.fReadOnly? Memory.writeNone : this.writeLongDirect; + this.writeByte = this.fReadOnly? this.writeNone : this.writeByteDirect; + this.writeShort = this.fReadOnly? this.writeNone : this.writeShortDirect; + this.writeLong = this.fReadOnly? this.writeNone : this.writeLongDirect; }, /** * setDebugInfo(cpu, dbg, size) @@ -1035,7 +481,528 @@ Memory.prototype = { this.dbg.assert(this.cWriteBreakpoints >= 0); } } + }, + /** + * readNone(off) + * + * @this {Memory} + * @param {number} off + * @return {number} + */ + readNone: function readNone(off) { + if (DEBUGGER && this.dbg.messageEnabled(Messages.MEM) /* && !off */) { + this.dbg.message("attempt to read invalid block %" + str.toHex(this.addr) + " from " + this.dbg.hexOffset(this.cpu.getIP(), this.cpu.getCS())); + } + return 0; + }, + /** + * writeNone(off, v) + * + * @this {Memory} + * @param {number} off + * @param {number} v (could be either a byte or word value, since we use the same handler for both kinds of accesses) + */ + writeNone: function writeNone(off, v) + { + if (DEBUGGER && this.dbg.messageEnabled(Messages.MEM) /* && !off */) { + this.dbg.message("attempt to write " + str.toHexWord(v) + " to invalid block %" + str.toHex(this.addr), true); + } + }, + /** + * readByteMemory(off) + * + * @this {Memory} + * @param {number} off + * @return {number} + */ + readByteMemory: function readByteMemory(off) + { + Component.assert(off >= 0 && off < this.size); + if (FATARRAYS) { + return this.ab[off]; + } + return ((this.adw[off >> 2] >>> ((off & 0x3) << 3)) & 0xff); + }, + /** + * readShortMemory(off) + * + * @this {Memory} + * @param {number} off + * @return {number} + */ + readShortMemory: function readShortMemory(off) + { + Component.assert(off >= 0 && off < this.size - 1); + if (FATARRAYS) { + return this.ab[off] | (this.ab[off + 1] << 8); + } + var w; + var idw = off >> 2; + var nShift = (off & 0x3) << 3; + var dw = (this.adw[idw] >> nShift); + if (nShift < 24) { + w = dw & 0xffff; + } else { + w = (dw & 0xff) | ((this.adw[idw + 1] & 0xff) << 8); + } + return w; + }, + /** + * readLongMemory(off) + * + * @this {Memory} + * @param {number} off + * @return {number} + */ + readLongMemory: function readLongMemory(off) + { + Component.assert(off >= 0 && off < this.size - 3); + if (FATARRAYS) { + return this.ab[off] | (this.ab[off + 1] << 8) | (this.ab[off + 2] << 16) | (this.ab[off + 3] << 24); + } + var idw = off >> 2; + var nShift = (off & 0x3) << 3; + var l = this.adw[idw]; + if (nShift) { + l >>>= nShift; + l |= this.adw[idw + 1] << (32 - nShift); + } + return l; + }, + /** + * writeByteMemory(off, b) + * + * @this {Memory} + * @param {number} off + * @param {number} b + */ + writeByteMemory: function writeByteMemory(off, b) + { + Component.assert(off >= 0 && off < this.size && (b & 0xff) == b); + if (FATARRAYS) { + this.ab[off] = b; + } else { + var idw = off >> 2; + var nShift = (off & 0x3) << 3; + this.adw[idw] = (this.adw[idw] & ~(0xff << nShift)) | (b << nShift); + } + this.fDirty = true; + }, + /** + * writeShortMemory(off, w) + * + * @this {Memory} + * @param {number} off + * @param {number} w + */ + writeShortMemory: function writeShortMemory(off, w) + { + Component.assert(off >= 0 && off < this.size - 1 && (w & 0xffff) == w); + if (FATARRAYS) { + this.ab[off] = (w & 0xff); + this.ab[off + 1] = (w >> 8); + } else { + var idw = off >> 2; + var nShift = (off & 0x3) << 3; + if (nShift < 24) { + /* + * 0: 0xffff0000 + * 8: 0xff0000ff + * 16: 0x0000ffff + */ + this.adw[idw] = (this.adw[idw] & ~(0xffff << nShift)) | (w << nShift); + } else { + this.adw[idw] = (this.adw[idw] & 0x00ffffff) | (w << 24); + idw++; + this.adw[idw] = (this.adw[idw] & (0xffffff00|0)) | (w >> 8); + } + } + this.fDirty = true; + }, + /** + * writeLongMemory(off, l) + * + * @this {Memory} + * @param {number} off + * @param {number} l + */ + writeLongMemory: function writeLongMemory(off, l) + { + Component.assert(off >= 0 && off < this.size - 3); + if (FATARRAYS) { + this.ab[off] = (l & 0xff); + this.ab[off + 1] = (l >> 8) & 0xff; + this.ab[off + 2] = (l >> 16) & 0xff; + this.ab[off + 3] = (l >> 24) & 0xff; + } else { + var idw = off >> 2; + var nShift = (off & 0x3) << 3; + if (!nShift) { + this.adw[idw] = l; + } else { + /* + * 8: 0xffffff00 + * 16: 0xffff0000 + * 24: 0xff000000 + */ + var mask = (0xffffffff|0) << nShift; + this.adw[idw] = (this.adw[idw] & ~mask) | (l << nShift); + idw++; + this.adw[idw] = (this.adw[idw] & mask) | (l >>> (32 - nShift)); + } + } + this.fDirty = true; + }, + /** + * readByteChecked(off) + * + * @this {Memory} + * @param {number} off + * @return {number} + */ + readByteChecked: function readByteChecked(off) + { + if (DEBUGGER) this.dbg.checkMemoryRead(this.addr + off); + return this.readByteDirect(off); + }, + /** + * readShortChecked(off) + * + * @this {Memory} + * @param {number} off + * @return {number} + */ + readShortChecked: function readShortChecked(off) + { + if (DEBUGGER) { + this.dbg.checkMemoryRead(this.addr + off) || + this.dbg.checkMemoryRead(this.addr + off + 1); + } + return this.readShortDirect(off); + }, + /** + * readLongChecked(off) + * + * @this {Memory} + * @param {number} off + * @return {number} + */ + readLongChecked: function readLongChecked(off) + { + if (DEBUGGER) { + this.dbg.checkMemoryRead(this.addr + off) || + this.dbg.checkMemoryRead(this.addr + off + 1) || + this.dbg.checkMemoryRead(this.addr + off + 2) || + this.dbg.checkMemoryRead(this.addr + off + 3); + } + return this.readLongDirect(off); + }, + /** + * writeByteChecked(off, b) + * + * @this {Memory} + * @param {number} off + * @param {number} b + */ + writeByteChecked: function writeByteChecked(off, b) + { + if (DEBUGGER) this.dbg.checkMemoryWrite(this.addr + off); + this.writeByteDirect(off, b); + }, + /** + * writeShortChecked(off, w) + * + * @this {Memory} + * @param {number} off + * @param {number} w + */ + writeShortChecked: function writeShortChecked(off, w) + { + if (DEBUGGER) { + this.dbg.checkMemoryWrite(this.addr + off) || + this.dbg.checkMemoryWrite(this.addr + off + 1); + } + this.writeShortDirect(off, w); + }, + /** + * writeLongChecked(off, l) + * + * @this {Memory} + * @param {number} off + * @param {number} l + */ + writeLongChecked: function writeLongChecked(off, l) + { + if (DEBUGGER) { + this.dbg.checkMemoryWrite(this.addr + off) || + this.dbg.checkMemoryWrite(this.addr + off + 1) || + this.dbg.checkMemoryWrite(this.addr + off + 2) || + this.dbg.checkMemoryWrite(this.addr + off + 3); + } + this.writeLongDirect(off, l); + }, + /** + * readByteBigEndian(off) + * + * @this {Memory} + * @param {number} off + * @return {number} + */ + readByteBigEndian: function readByteBigEndian(off) + { + Component.assert(off >= 0 && off < this.size); + return this.ab[off]; + }, + /** + * readByteLittleEndian(off) + * + * @this {Memory} + * @param {number} off + * @return {number} + */ + readByteLittleEndian: function readByteLittleEndian(off) + { + Component.assert(off >= 0 && off < this.size); + return this.ab[off]; + }, + /** + * readShortBigEndian(off) + * + * @this {Memory} + * @param {number} off + * @return {number} + */ + readShortBigEndian: function readShortBigEndian(off) + { + Component.assert(off >= 0 && off < this.size - 1); + return this.dv.getUint16(off, true); + }, + /** + * readShortLittleEndian(off) + * + * @this {Memory} + * @param {number} off + * @return {number} + */ + readShortLittleEndian: function readShortLittleEndian(off) + { + Component.assert(off >= 0 && off < this.size - 1); + /* + * TODO: It remains to be seen if there's any advantage to checking the offset + * for an aligned read vs. always reading the bytes separately; it seems a safe bet + * for longs, but it's less clear for shorts. + */ + return (off & 0x1)? (this.ab[off] | (this.ab[off+1] << 8)) : this.aw[off >> 1]; + }, + /** + * readLongBigEndian(off) + * + * @this {Memory} + * @param {number} off + * @return {number} + */ + readLongBigEndian: function readLongBigEndian(off) + { + Component.assert(off >= 0 && off < this.size - 3); + return this.dv.getInt32(off, true); + }, + /** + * readLongLittleEndian(off) + * + * @this {Memory} + * @param {number} off + * @return {number} + */ + readLongLittleEndian: function readLongLittleEndian(off) + { + Component.assert(off >= 0 && off < this.size - 3); + /* + * TODO: It remains to be seen if there's any advantage to checking the offset + * for an aligned read vs. always reading the bytes separately; it seems a safe bet + * for longs, but it's less clear for shorts. + */ + return (off & 0x3)? (this.ab[off] | (this.ab[off+1] << 8) | (this.ab[off+2] << 16) | (this.ab[off+3] << 24)) : this.adw[off >> 2]; + }, + /** + * writeByteBigEndian(off, b) + * + * @this {Memory} + * @param {number} off + * @param {number} b + */ + writeByteBigEndian: function writeByteBigEndian(off, b) + { + Component.assert(off >= 0 && off < this.size); + this.ab[off] = b; + this.fDirty = true; + }, + /** + * writeByteLittleEndian(off, b) + * + * @this {Memory} + * @param {number} off + * @param {number} b + */ + writeByteLittleEndian: function writeByteLittleEndian(off, b) + { + Component.assert(off >= 0 && off < this.size); + this.ab[off] = b; + this.fDirty = true; + }, + /** + * writeShortBigEndian(off, w) + * + * @this {Memory} + * @param {number} off + * @param {number} w + */ + writeShortBigEndian: function writeShortBigEndian(off, w) + { + Component.assert(off >= 0 && off < this.size - 1); + this.dv.setUint16(off, w, true); + this.fDirty = true; + }, + /** + * writeShortLittleEndian(off, w) + * + * @this {Memory} + * @param {number} off + * @param {number} w + */ + writeShortLittleEndian: function writeShortLittleEndian(off, w) + { + Component.assert(off >= 0 && off < this.size - 1); + /* + * TODO: It remains to be seen if there's any advantage to checking the offset + * for an aligned write vs. always writing the bytes separately; it seems a safe bet + * for longs, but it's less clear for shorts. + */ + if (off & 0x1) { + this.ab[off] = w; + this.ab[off+1] = w >> 8; + } else { + this.aw[off >> 1] = w; + } + this.fDirty = true; + }, + /** + * writeLongBigEndian(off, l) + * + * @this {Memory} + * @param {number} off + * @param {number} l + */ + writeLongBigEndian: function writeLongBigEndian(off, l) + { + Component.assert(off >= 0 && off < this.size - 3); + this.dv.setInt32(off, l, true); + this.fDirty = true; + }, + /** + * writeLongLittleEndian(off, l) + * + * @this {Memory} + * @param {number} off + * @param {number} l + */ + writeLongLittleEndian: function writeLongLittleEndian(off, l) + { + Component.assert(off >= 0 && off < this.size - 3); + /* + * TODO: It remains to be seen if there's any advantage to checking the offset + * for an aligned write vs. always writing the bytes separately; it seems a safe bet + * for longs, but it's less clear for shorts. + */ + if (off & 0x3) { + this.ab[off] = l; + this.ab[off+1] = (l >> 8); + this.ab[off+2] = (l >> 16); + this.ab[off+3] = (l >> 24); + } else { + this.adw[off >> 2] = l; + } + this.fDirty = true; + }, + /** + * readBackTrackNone(off) + * + * @this {Memory} + * @param {number} off + * @return {number} + */ + readBackTrackNone: function readBackTrackNone(off) + { + return 0; + }, + /** + * writeBackTrackNone(off, bti) + * + * @this {Memory} + * @param {number} off + * @param {number} bti + */ + writeBackTrackNone: function writeBackTrackNone(off, bti) + { + }, + /** + * modBackTrackNone(fMod) + * + * @this {Memory} + * @param {boolean} fMod + */ + modBackTrackNone: function modBackTrackNone(fMod) + { + return false; + }, + /** + * readBackTrackIndex(off) + * + * @this {Memory} + * @param {number} off + * @return {number} + */ + readBackTrackIndex: function readBackTrackIndex(off) + { + Component.assert(off >= 0 && off < this.size); + return this.abtIndexes[off]; + }, + /** + * writeBackTrackIndex(off, bti) + * + * @this {Memory} + * @param {number} off + * @param {number} bti + * @return {number} previous bti (0 if none) + */ + writeBackTrackIndex: function writeBackTrackIndex(off, bti) + { + var btiPrev; + Component.assert(off >= 0 && off < this.size); + btiPrev = this.abtIndexes[off]; + this.abtIndexes[off] = bti; + return btiPrev; + }, + /** + * modBackTrackIndex(fMod) + * + * @this {Memory} + * @param {boolean} fMod + * @return {boolean} previous value + */ + modBackTrackIndex: function modBackTrackIndex(fMod) + { + var fModPrev = this.fModBackTrack; + this.fModBackTrack = fMod; + return fModPrev; } }; +Memory.afnMemory = [Memory.prototype.readByteMemory, Memory.prototype.readShortMemory, Memory.prototype.readLongMemory, Memory.prototype.writeByteMemory, Memory.prototype.writeShortMemory, Memory.prototype.writeLongMemory]; +Memory.afnChecked = [Memory.prototype.readByteChecked, Memory.prototype.readShortChecked, Memory.prototype.readLongChecked, Memory.prototype.writeByteChecked, Memory.prototype.writeShortChecked, Memory.prototype.writeLongChecked]; + +if (TYPEDARRAYS) { + Memory.afnBigEndian = [Memory.prototype.readByteBigEndian, Memory.prototype.readShortBigEndian, Memory.prototype.readLongBigEndian, Memory.prototype.writeByteBigEndian, Memory.prototype.writeShortBigEndian, Memory.prototype.writeLongBigEndian]; + Memory.afnLittleEndian = [Memory.prototype.readByteLittleEndian, Memory.prototype.readShortLittleEndian, Memory.prototype.readLongLittleEndian, Memory.prototype.writeByteLittleEndian, Memory.prototype.writeShortLittleEndian, Memory.prototype.writeLongLittleEndian]; +} + if (typeof module !== 'undefined') module.exports = Memory; diff --git a/modules/pcjs/lib/mouse.js b/modules/pcjs/lib/mouse.js index 2ae92bdd3..c27b8647d 100644 --- a/modules/pcjs/lib/mouse.js +++ b/modules/pcjs/lib/mouse.js @@ -158,7 +158,7 @@ function Mouse(parmsMouse) * synchronize with the mouse. */ -Component.subclass(Component, Mouse); +Component.subclass(Mouse); Mouse.ID_SERIAL = 0x4D; @@ -267,9 +267,10 @@ Mouse.prototype.powerUp = function(data, fRepower) * * @this {Mouse} * @param {boolean} fSave - * @return {Object|boolean} + * @param {boolean} [fShutdown] + * @return {Object|boolean} component state if fSave; otherwise, true if successful, false if failure */ -Mouse.prototype.powerDown = function(fSave) +Mouse.prototype.powerDown = function(fSave, fShutdown) { return fSave && this.save? this.save() : true; }; diff --git a/modules/pcjs/lib/panel.js b/modules/pcjs/lib/panel.js index 1af77b81b..b3ca2d2bf 100644 --- a/modules/pcjs/lib/panel.js +++ b/modules/pcjs/lib/panel.js @@ -49,8 +49,10 @@ if (typeof module !== 'undefined') { * @extends Component * @param {Object} parmsPanel */ -function Panel(parmsPanel) { +function Panel(parmsPanel) +{ Component.call(this, "Panel", parmsPanel, Panel); + this.canvas = null; this.lockMouse = -1; this.fMouseDown = false; @@ -61,7 +63,7 @@ function Panel(parmsPanel) { } } -Component.subclass(Component, Panel); +Component.subclass(Panel); /* * The "Live" canvases that we create internally have the following fixed dimensions, to make drawing diff --git a/modules/pcjs/lib/ram.js b/modules/pcjs/lib/ram.js index 2a3b416de..5e99da428 100644 --- a/modules/pcjs/lib/ram.js +++ b/modules/pcjs/lib/ram.js @@ -65,7 +65,7 @@ function RAM(parmsRAM) this.fAllocated = false; } -Component.subclass(Component, RAM); +Component.subclass(RAM); /** * initBus(cmp, bus, cpu, dbg) diff --git a/modules/pcjs/lib/rom.js b/modules/pcjs/lib/rom.js index 0d2050866..11470df58 100644 --- a/modules/pcjs/lib/rom.js +++ b/modules/pcjs/lib/rom.js @@ -101,7 +101,7 @@ function ROM(parmsROM) } } -Component.subclass(Component, ROM); +Component.subclass(ROM); /* * ROM BIOS Data Area (RBDA) definitions, in physical address form, using the same ALL-CAPS names diff --git a/modules/pcjs/lib/serialport.js b/modules/pcjs/lib/serialport.js index c0c06be6b..78ca438b1 100644 --- a/modules/pcjs/lib/serialport.js +++ b/modules/pcjs/lib/serialport.js @@ -109,7 +109,7 @@ function SerialPort(parmsSerial) { * for third-party apps. */ -Component.subclass(Component, SerialPort); +Component.subclass(SerialPort); /* * Internal name used for the I/O buffer control, if any, that we bind to the SerialPort. diff --git a/modules/pcjs/lib/video.js b/modules/pcjs/lib/video.js index d6523cc45..c141c0768 100644 --- a/modules/pcjs/lib/video.js +++ b/modules/pcjs/lib/video.js @@ -269,7 +269,7 @@ function Video(parmsVideo, canvas, context, textarea, container) } } -Component.subclass(Component, Video); +Component.subclass(Video); Video.TRAPALL = true; // monitor all I/O by default (not just deltas) diff --git a/modules/pcjs/lib/x86cpu.js b/modules/pcjs/lib/x86cpu.js index 6b6bac433..bd92fc0c7 100644 --- a/modules/pcjs/lib/x86cpu.js +++ b/modules/pcjs/lib/x86cpu.js @@ -188,7 +188,7 @@ function X86CPU(parmsCPU) { this.resetRegs(); } -Component.subclass(CPU, X86CPU); +Component.subclass(X86CPU, CPU); X86CPU.CYCLES_8088 = { nWordCyclePenalty: 4, // NOTE: accurate for the 8088/80188 only (on the 8086/80186, it applies to odd addresses only) diff --git a/modules/shared/lib/component.js b/modules/shared/lib/component.js index b8302bbee..50551d380 100644 --- a/modules/shared/lib/component.js +++ b/modules/shared/lib/component.js @@ -185,17 +185,18 @@ Component.extend = function(o, p) }; /** - * Component.subclass(superclass, subclass, methods, statics) + * Component.subclass(subclass, superclass, methods, statics) * * See: Flanagan, David (2011-04-18). JavaScript: The Definitive Guide: The Definitive Guide (Kindle Locations 9854-9903). OReilly Media - A. Kindle Edition (Example 9-11) * - * @param {Object} superclass is the constructor of the superclass * @param {Object} subclass is the constructor for the new subclass + * @param {Object} [superclass] is the constructor of the superclass (default is Component) * @param {Object} [methods] contains all instance methods * @param {Object} [statics] contains all class properties and methods */ -Component.subclass = function(superclass, subclass, methods, statics) +Component.subclass = function(subclass, superclass, methods, statics) { + if (!superclass) superclass = Component; subclass.prototype = Component.inherit(superclass.prototype); subclass.prototype.constructor = subclass; subclass.prototype.parent = superclass.prototype;