From e2ddc497c3a3bcdaaf77780699be465ce7fe4286 Mon Sep 17 00:00:00 2001 From: Jeff Parsons Date: Fri, 30 Jan 2015 12:00:12 -0800 Subject: [PATCH] dataSize and addrSize tweaks --- modules/pcjs/lib/defines.js | 9 +-- modules/pcjs/lib/x86cpu.js | 116 +++++++++++++++++++++++++--------- modules/pcjs/lib/x86opxx.js | 24 +++---- modules/pcjs/lib/x86seg.js | 8 +-- modules/shared/lib/nodebug.js | 2 +- 5 files changed, 105 insertions(+), 54 deletions(-) diff --git a/modules/pcjs/lib/defines.js b/modules/pcjs/lib/defines.js index b953afb26..d30b5424e 100644 --- a/modules/pcjs/lib/defines.js +++ b/modules/pcjs/lib/defines.js @@ -80,17 +80,12 @@ var PREFETCH = false; var FATARRAYS = false; /** - * @define {boolean} - * * TYPEDARRAYS enables use of typed arrays for Memory blocks. This used to be a compile-time-only option, but I've * added Memory access functions for typed arrays (see Memory.afnTypedArray), so support can be enabled dynamically. * - * However, TYPEDARRAYS has always been slightly slower than the original LONGARRAYS implementation (which uses an - * Array of numbers that stores 32 bits -- 4 consecutive bytes -- per number), so TYPEDARRAYS is completely disabled. - * * See the Memory component for details. */ -var TYPEDARRAYS = false; // (typeof ArrayBuffer !== 'undefined'); +var TYPEDARRAYS = (typeof ArrayBuffer !== 'undefined'); /** * @define {boolean} @@ -98,7 +93,7 @@ var TYPEDARRAYS = false; // (typeof ArrayBuffer !== 'undefined'); * Enables backtracking (disabled in compiled versions). Backtracking is a mechanism that allows us to tag * every byte of incoming data and follow the flow of that data. */ -var BACKTRACK = true; +var BACKTRACK = DEBUG; /** * @define {boolean} diff --git a/modules/pcjs/lib/x86cpu.js b/modules/pcjs/lib/x86cpu.js index c5779bb10..36ee41a87 100644 --- a/modules/pcjs/lib/x86cpu.js +++ b/modules/pcjs/lib/x86cpu.js @@ -956,7 +956,7 @@ X86CPU.prototype.resetRegs = function() this.opFlags = this.opPrefixes = 0; /* - * The following contain the (default) OPERAND size (0 for 16 bits, 1 for 32 bits), and the corresponding masks + * The following contain the (default) OPERAND size (2 for 16 bits, 4 for 32 bits), and the corresponding masks * for isolating the (src) bits of an OPERAND and clearing the (dst) bits of an OPERAND. These are reset to * their segCS counterparts at the start of every new instruction, but are also set here for documentation purposes. */ @@ -964,7 +964,7 @@ X86CPU.prototype.resetRegs = function() this.dataMask = this.segCS.dataMask; /* - * Similarly, the following contain the (default) ADDRESS size (0 for 16 bits, 1 for 32 bits), and the corresponding + * Similarly, the following contain the (default) ADDRESS size (2 for 16 bits, 4 for 32 bits), and the corresponding * masks for isolating the (src) bits of an address and clearing the (dst) bits of an address. Like the OPERAND size * properties, these are reset to their segCS counterparts at the start of every new instruction. */ @@ -975,7 +975,7 @@ X86CPU.prototype.resetRegs = function() * It's also worth noting that instructions that implicitly use the stack also rely on something called STACK size, * which is based on the BIG bit of the last descriptor loaded into SS; use the following segSS properties: * - * segSS.addrSize (0 or 1) + * segSS.addrSize (2 or 4) * segSS.addrMask (0xffff or 0xffffffff) * * As there is no STACK size instruction prefix override, there's no need to propagate these segSS properties @@ -986,18 +986,14 @@ X86CPU.prototype.resetRegs = function() * The memory dispatch tables; opMem refers to the active set, based on the current OPERAND size (dataSize), * which is based foremost on segCS.dataSize, but can also be overridden by an OPERAND size instruction prefix. */ - this.aaOpMem = new Array(2); - this.aaOpMem[0] = { - getByte: this.getByte.bind(this), + this.aaOpMem = new Array(5); + this.aaOpMem[2] = { getWord: this.getShort.bind(this), - setByte: this.setByte.bind(this), setWord: this.setShort.bind(this) }; if (I386) { - this.aaOpMem[1] = { - getByte: this.getByte.bind(this), + this.aaOpMem[4] = { getWord: this.getLong.bind(this), - setByte: this.setByte.bind(this), setWord: this.setLong.bind(this) }; } @@ -1007,8 +1003,8 @@ X86CPU.prototype.resetRegs = function() * The ModRM dispatch tables; opMod refers to the active set, based on the current ADDRESS size (addrSize), * which is based foremost on segCS.addrSize, but can also be overridden by an ADDRESS size instruction prefix. */ - this.aaOpMod = new Array(2); - this.aaOpMod[0] = { + this.aaOpMod = new Array(5); + this.aaOpMod[2] = { aOpModRegByte: X86ModB.aOpModReg, aOpModMemByte: X86ModB.aOpModMem, aOpModGrpByte: X86ModB.aOpModGrp, @@ -1017,7 +1013,7 @@ X86CPU.prototype.resetRegs = function() aOpModGrpWord: X86ModW.aOpModGrp }; if (I386) { - this.aaOpMod[1] = { + this.aaOpMod[4] = { aOpModRegByte: X86ModB32.aOpModReg, aOpModMemByte: X86ModB32.aOpModMem, aOpModGrpByte: X86ModB32.aOpModGrp, @@ -2030,7 +2026,7 @@ X86CPU.prototype.getEAByte = function(seg, off) X86CPU.prototype.getEAWord = function(seg, off) { this.segEA = seg; - this.regEA = seg.checkRead(this.offEA = off, 1 + this.dataSize + this.dataSize); + this.regEA = seg.checkRead(this.offEA = off, this.dataSize-1); if (this.opFlags & X86.OPFLAG.NOREAD) return 0; var w = this.opMem.getWord(this.regEA); if (BACKTRACK) { @@ -2069,7 +2065,7 @@ X86CPU.prototype.modEAByte = function(seg, off) X86CPU.prototype.modEAWord = function(seg, off) { this.segEA = seg; - this.regEAWrite = this.regEA = seg.checkRead(this.offEA = off, 1 + this.dataSize + this.dataSize); + this.regEAWrite = this.regEA = seg.checkRead(this.offEA = off, this.dataSize-1); if (this.opFlags & X86.OPFLAG.NOREAD) return 0; var w = this.opMem.getWord(this.regEA); if (BACKTRACK) { @@ -2088,7 +2084,13 @@ X86CPU.prototype.modEAWord = function(seg, off) */ X86CPU.prototype.getEAByteData = function(off) { - return this.getEAByte(this.segData, off & this.addrMask); + // return this.getEAByte(this.segData, off & this.addrMask); + this.segEA = this.segData; + this.regEA = this.segData.checkRead(this.offEA = off & this.addrMask, 0); + if (this.opFlags & X86.OPFLAG.NOREAD) return 0; + var b = this.getByte(this.regEA); + if (BACKTRACK) this.backTrack.btiEALo = this.backTrack.btiMemLo; + return b; }; /** @@ -2100,7 +2102,13 @@ X86CPU.prototype.getEAByteData = function(off) */ X86CPU.prototype.getEAByteStack = function(off) { - return this.getEAByte(this.segStack, off & this.addrMask); + // return this.getEAByte(this.segStack, off & this.addrMask); + this.segEA = this.segStack; + this.regEA = this.segStack.checkRead(this.offEA = off & this.addrMask, 0); + if (this.opFlags & X86.OPFLAG.NOREAD) return 0; + var b = this.getByte(this.regEA); + if (BACKTRACK) this.backTrack.btiEALo = this.backTrack.btiMemLo; + return b; }; /** @@ -2112,7 +2120,16 @@ X86CPU.prototype.getEAByteStack = function(off) */ X86CPU.prototype.getEAWordData = function(off) { - return this.getEAWord(this.segData, off & this.addrMask); + // return this.getEAWord(this.segData, off & this.addrMask); + this.segEA = this.segData; + this.regEA = this.segData.checkRead(this.offEA = off & this.addrMask, this.dataSize-1); + if (this.opFlags & X86.OPFLAG.NOREAD) return 0; + var w = this.opMem.getWord(this.regEA); + if (BACKTRACK) { + this.backTrack.btiEALo = this.backTrack.btiMemLo; + this.backTrack.btiEAHi = this.backTrack.btiMemHi; + } + return w; }; /** @@ -2124,7 +2141,16 @@ X86CPU.prototype.getEAWordData = function(off) */ X86CPU.prototype.getEAWordStack = function(off) { - return this.getEAWord(this.segStack, off & this.addrMask); + // return this.getEAWord(this.segStack, off & this.addrMask); + this.segEA = this.segStack; + this.regEA = this.segStack.checkRead(this.offEA = off & this.addrMask, this.dataSize-1); + if (this.opFlags & X86.OPFLAG.NOREAD) return 0; + var w = this.opMem.getWord(this.regEA); + if (BACKTRACK) { + this.backTrack.btiEALo = this.backTrack.btiMemLo; + this.backTrack.btiEAHi = this.backTrack.btiMemHi; + } + return w; }; /** @@ -2136,7 +2162,13 @@ X86CPU.prototype.getEAWordStack = function(off) */ X86CPU.prototype.modEAByteData = function(off) { - return this.modEAByte(this.segData, off & this.addrMask); + // return this.modEAByte(this.segData, off & this.addrMask); + this.segEA = this.segData; + this.regEAWrite = this.regEA = this.segData.checkRead(this.offEA = off & this.addrMask, 0); + if (this.opFlags & X86.OPFLAG.NOREAD) return 0; + var b = this.getByte(this.regEA); + if (BACKTRACK) this.backTrack.btiEALo = this.backTrack.btiMemLo; + return b; }; /** @@ -2148,7 +2180,13 @@ X86CPU.prototype.modEAByteData = function(off) */ X86CPU.prototype.modEAByteStack = function(off) { - return this.modEAByte(this.segStack, off & this.addrMask); + // return this.modEAByte(this.segStack, off & this.addrMask); + this.segEA = this.segStack; + this.regEAWrite = this.regEA = this.segStack.checkRead(this.offEA = off & this.addrMask, 0); + if (this.opFlags & X86.OPFLAG.NOREAD) return 0; + var b = this.getByte(this.regEA); + if (BACKTRACK) this.backTrack.btiEALo = this.backTrack.btiMemLo; + return b; }; /** @@ -2160,7 +2198,16 @@ X86CPU.prototype.modEAByteStack = function(off) */ X86CPU.prototype.modEAWordData = function(off) { - return this.modEAWord(this.segData, off & this.addrMask); + // return this.modEAWord(this.segData, off & this.addrMask); + this.segEA = this.segData; + this.regEAWrite = this.regEA = this.segData.checkRead(this.offEA = off & this.addrMask, this.dataSize-1); + if (this.opFlags & X86.OPFLAG.NOREAD) return 0; + var w = this.opMem.getWord(this.regEA); + if (BACKTRACK) { + this.backTrack.btiEALo = this.backTrack.btiMemLo; + this.backTrack.btiEAHi = this.backTrack.btiMemHi; + } + return w; }; /** @@ -2172,7 +2219,16 @@ X86CPU.prototype.modEAWordData = function(off) */ X86CPU.prototype.modEAWordStack = function(off) { - return this.modEAWord(this.segStack, off & this.addrMask); + // return this.modEAWord(this.segStack, off & this.addrMask); + this.segEA = this.segStack; + this.regEAWrite = this.regEA = this.segStack.checkRead(this.offEA = off & this.addrMask, this.dataSize-1); + if (this.opFlags & X86.OPFLAG.NOREAD) return 0; + var w = this.opMem.getWord(this.regEA); + if (BACKTRACK) { + this.backTrack.btiEALo = this.backTrack.btiMemLo; + this.backTrack.btiEAHi = this.backTrack.btiMemHi; + } + return w; }; /** @@ -2201,7 +2257,7 @@ X86CPU.prototype.setEAWord = function(w) this.backTrack.btiMemLo = this.backTrack.btiEALo; this.backTrack.btiMemHi = this.backTrack.btiEAHi; } - this.opMem.setWord(this.segEA.checkWrite(this.offEA, 1), w); + this.opMem.setWord(this.segEA.checkWrite(this.offEA, this.dataSize-1), w); }; /** @@ -2231,7 +2287,7 @@ X86CPU.prototype.getSOByte = function(seg, off) */ X86CPU.prototype.getSOWord = function(seg, off) { - return this.opMem.getWord(seg.checkRead(off, 1 + this.dataSize + this.dataSize)); + return this.opMem.getWord(seg.checkRead(off, this.dataSize-1)); }; /** @@ -2261,7 +2317,7 @@ X86CPU.prototype.setSOByte = function(seg, off, b) */ X86CPU.prototype.setSOWord = function(seg, off, w) { - this.opMem.setWord(seg.checkWrite(off, 1), w); + this.opMem.setWord(seg.checkWrite(off, this.dataSize-1), w); }; /** @@ -2426,7 +2482,7 @@ X86CPU.prototype.getIPDisp = function() * getIPWord() * * @this {X86CPU} - * @return {number} word at the current IP; IP advanced by 2 + * @return {number} word at the current IP; IP advanced by 2 or 4 */ X86CPU.prototype.getIPWord = function() { @@ -2435,7 +2491,7 @@ X86CPU.prototype.getIPWord = function() this.bus.updateBackTrackCode(this.regLIP, this.backTrack.btiMemLo); this.bus.updateBackTrackCode(this.regLIP + 1, this.backTrack.btiMemHi); } - this.regLIP = this.segCS.base + (this.regEIP = (this.regEIP + (2 << this.dataSize)) & this.addrMask); + this.regLIP = this.segCS.base + (this.regEIP = (this.regEIP + this.dataSize) & this.addrMask); return w; }; @@ -2462,7 +2518,7 @@ X86CPU.prototype.getSIBAddr = function(mod) X86CPU.prototype.popWord = function() { var regESP = this.regESP; - this.regESP = (this.regESP + (2 << this.dataSize)) & this.addrMask; + this.regESP = (this.regESP + this.dataSize) & this.addrMask; return this.getSOWord(this.segSS, regESP); }; @@ -2475,7 +2531,7 @@ X86CPU.prototype.popWord = function() X86CPU.prototype.pushWord = function(w) { this.assert((w & this.dataMask) == w); - this.setSOWord(this.segSS, (this.regESP = (this.regESP - (2 << this.dataSize)) & this.addrMask), w); + this.setSOWord(this.segSS, (this.regESP = (this.regESP - this.dataSize) & this.addrMask), w); }; /** diff --git a/modules/pcjs/lib/x86opxx.js b/modules/pcjs/lib/x86opxx.js index a371c95ad..1417b33b8 100644 --- a/modules/pcjs/lib/x86opxx.js +++ b/modules/pcjs/lib/x86opxx.js @@ -1026,7 +1026,7 @@ var X86OpXX = { * @this {X86CPU} */ opPUSHSP8086: function() { - var w = (this.regESP - (2 << this.dataSize)) & this.dataMask; + var w = (this.regESP - this.dataSize) & this.dataMask; this.pushWord(w); this.nStepCycles -= this.CYCLES.nOpCyclesPushReg; }, @@ -1224,7 +1224,7 @@ var X86OpXX = { if (BACKTRACK) { this.backTrack.btiBPLo = this.backTrack.btiMemLo; this.backTrack.btiBPHi = this.backTrack.btiMemHi; } - this.regESP += (2 << this.dataSize); + this.regESP += this.dataSize; this.regEBX = (this.regEBX & ~this.dataMask) | this.popWord(); if (BACKTRACK) { this.backTrack.btiBL = this.backTrack.btiMemLo; this.backTrack.btiBH = this.backTrack.btiMemHi; @@ -1268,7 +1268,7 @@ var X86OpXX = { */ opOS: function() { this.opFlags |= X86.OPFLAG.SEG; - this.dataSize ^= 1; // that which is 0 shall become 1, and vice versa + this.dataSize ^= 0x6; // that which is 2 shall become 4, and vice versa this.dataMask ^= 0xffff0000; // that which is 0x0000ffff shall become 0xffffffff, and vice versa this.opMem = this.aaOpMem[this.dataSize]; this.nStepCycles -= this.CYCLES.nOpCyclesPrefix; @@ -1282,7 +1282,7 @@ var X86OpXX = { */ opAS: function() { this.opFlags |= X86.OPFLAG.SEG; - this.addrSize ^= 1; // that which is 0 shall become 1, and vice versa + this.addrSize ^= 0x06; // that which is 2 shall become 4, and vice versa this.addrMask ^= 0xffff0000; // that which is 0x0000ffff shall become 0xffffffff, and vice versa this.opMod = this.aaOpMod[this.addrSize]; this.nStepCycles -= this.CYCLES.nOpCyclesPrefix; @@ -2123,7 +2123,7 @@ var X86OpXX = { * @this {X86CPU} */ opCBW: function() { - if (!this.dataSize) { + if (this.dataSize == 2) { /* * CBW */ @@ -2146,7 +2146,7 @@ var X86OpXX = { * @this {X86CPU} */ opCWD: function() { - if (!this.dataSize) { + if (this.dataSize == 2) { /* * CWD */ @@ -2910,7 +2910,7 @@ var X86OpXX = { opRETn: function() { var n = this.getIPWord(); this.setIP(this.popWord()); - this.regESP = (this.regESP & ~this.addrMask) | ((this.regESP + (n << this.dataSize)) & this.addrMask); + this.regESP = (this.regESP & ~this.addrMask) | ((this.regESP + (n << (this.dataSize >> 2))) & this.addrMask); this.nStepCycles -= this.CYCLES.nOpCyclesRetn; }, /** @@ -3004,7 +3004,7 @@ var X86OpXX = { if (bLevel > 0) { this.nStepCycles -= (bLevel << 2) + (bLevel > 1? 1 : 0); while (--bLevel) { - this.regEBP = (this.regEBP & ~this.segSS.addrMask) | ((this.regEBP - (2 << this.dataSize)) & this.segSS.addrMask); + this.regEBP = (this.regEBP & ~this.segSS.addrMask) | ((this.regEBP - this.dataSize) & this.segSS.addrMask); this.pushWord(this.getSOWord(this.segSS, this.regEBP & this.segSS.addrMask)); } this.pushWord(wFrame); @@ -3206,7 +3206,7 @@ var X86OpXX = { */ opLOOPNZ: function() { var disp = this.getIPDisp(); - if ((this.regECX = (this.regECX - 1) & 0xffff) && (this.resultValue & (this.resultSize - 1))) { + if ((this.regECX = (this.regECX - 1) & this.addrMask) && (this.resultValue & (this.resultSize - 1))) { this.setIP(this.regEIP + disp); this.nStepCycles -= this.CYCLES.nOpCyclesLoopNZ; return; @@ -3220,7 +3220,7 @@ var X86OpXX = { */ opLOOPZ: function() { var disp = this.getIPDisp(); - if ((this.regECX = (this.regECX - 1) & 0xffff) && !(this.resultValue & (this.resultSize - 1))) { + if ((this.regECX = (this.regECX - 1) & this.addrMask) && !(this.resultValue & (this.resultSize - 1))) { this.setIP(this.regEIP + disp); this.nStepCycles -= this.CYCLES.nOpCyclesLoopZ; return; @@ -3234,7 +3234,7 @@ var X86OpXX = { */ opLOOP: function() { var disp = this.getIPDisp(); - if ((this.regECX = (this.regECX - 1) & 0xffff)) { + if ((this.regECX = (this.regECX - 1) & this.addrMask)) { this.setIP(this.regEIP + disp); this.nStepCycles -= this.CYCLES.nOpCyclesLoop; return; @@ -3551,7 +3551,7 @@ var X86OpXX = { */ opCLI: function() { this.clearIF(); - this.nStepCycles -= this.CYCLES.nOpCyclesCLI; // CLI takes LONGER on an 80286 + this.nStepCycles -= this.CYCLES.nOpCyclesCLI; // CLI takes LONGER on an 80286 }, /** * op=0xFB (STI) diff --git a/modules/pcjs/lib/x86seg.js b/modules/pcjs/lib/x86seg.js index d4fff7fc7..31bbe835e 100644 --- a/modules/pcjs/lib/x86seg.js +++ b/modules/pcjs/lib/x86seg.js @@ -118,7 +118,7 @@ X86Seg.ID = { X86Seg.loadReal = function loadReal(sel, fSuppress) { this.sel = sel; - this.dataSize = this.addrSize = 0; + this.dataSize = this.addrSize = 2; this.dataMask = this.addrMask = 0xffff; return this.base = sel << 4; }; @@ -848,10 +848,10 @@ X86Seg.prototype.updateMode = function(fProt) this.cpl = this.sel & X86.SEL.RPL; this.dpl = (this.acc & X86.DESC.ACC.DPL.MASK) >> X86.DESC.ACC.DPL.SHIFT; if (this.cpu.model < X86.MODEL_80386 || !(this.ext & X86.DESC.EXT.BIG)) { - this.dataSize = 0; + this.dataSize = 2; this.dataMask = 0xffff; } else { - this.dataSize = 1; + this.dataSize = 4; this.dataMask = 0xffffffff; } } else { @@ -862,7 +862,7 @@ X86Seg.prototype.updateMode = function(fProt) this.limit = 0xffff; this.cpl = this.dpl = 0; this.addrDesc = X86.ADDR_INVALID; - this.dataSize = 0; + this.dataSize = 2; this.dataMask = 0xffff; } this.addrSize = this.dataSize; diff --git a/modules/shared/lib/nodebug.js b/modules/shared/lib/nodebug.js index 95a5fd3fb..d4248c738 100644 --- a/modules/shared/lib/nodebug.js +++ b/modules/shared/lib/nodebug.js @@ -37,7 +37,7 @@ /* * In the compiled case, we rely on the Closure Compiler to override DEBUG, setting it to false, * so that all DEBUG-only code will be removed by the compiler. - * + * * However, when we're in "development mode" and want to run uncompiled code without any DEBUG-only * code, we must arrange for this additional file, nodebug.js, to be loaded as early as possible, * which will then set DEBUG to false at runtime.