diff --git a/modules/pcjs/bin/romtests.json b/modules/pcjs/bin/romtests.json index 6dd01f4b0..744e42325 100644 --- a/modules/pcjs/bin/romtests.json +++ b/modules/pcjs/bin/romtests.json @@ -3,7 +3,8 @@ "id": "pc386.computer", "name": "Compaq DeskPro 386", "resume": 0, - "state": "" + "state": "", + "busWidth": 32 }, "ram": [ { "id": "pc386.ramLow", @@ -18,6 +19,7 @@ "name": "", "addr": 983296, "size": 65280, + "alias": 4294902016, "file": "/tests/pc/80386/tests.json", "notify": "" } diff --git a/modules/pcjs/lib/computer.js b/modules/pcjs/lib/computer.js index fc98c4680..bc58bc535 100644 --- a/modules/pcjs/lib/computer.js +++ b/modules/pcjs/lib/computer.js @@ -89,7 +89,7 @@ if (typeof module !== 'undefined') { * The Computer component has no required (parmsComputer) properties, but does * support the following: * - * buswidth: number of memory address lines (address bits) on the computer's "bus"; + * busWidth: number of memory address lines (address bits) on the computer's "bus"; * 20 is the minimum (and the default), which implies 8086/8088 real-mode addressing, * while 24 is required for 80286 protected-mode addressing. This value is passed * directly through to the Bus component; see that component for more details. @@ -125,7 +125,10 @@ function Computer(parmsComputer, parmsMachine, fSuspended) { Component.call(this, "Computer", parmsComputer, Computer, Messages.COMPUTER); this.aFlags.fPowered = false; - this.nBusWidth = parmsComputer['buswidth']; + /* + * TODO: Deprecate 'buswidth' (it should have always used camelCase) + */ + this.nBusWidth = parmsComputer['busWidth'] || parmsComputer['buswidth']; this.resume = Computer.RESUME_NONE; this.sStateData = null; this.fServerState = false; diff --git a/modules/pcjs/lib/x86cpu.js b/modules/pcjs/lib/x86cpu.js index 88a958d07..8a7d737dd 100644 --- a/modules/pcjs/lib/x86cpu.js +++ b/modules/pcjs/lib/x86cpu.js @@ -1325,14 +1325,14 @@ X86CPU.prototype.resetRegs = function() }; /** - * setAddrSize() + * updateAddrSize() * * Select the appropriate ModRM dispatch tables, 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 {X86CPU} */ -X86CPU.prototype.setAddrSize = function() +X86CPU.prototype.updateAddrSize = function() { if (!I386) { this.getAddr = this.getShort; @@ -1364,11 +1364,30 @@ X86CPU.prototype.setAddrSize = function() }; /** - * setDataSize() + * setDataSize(size) + * + * This is used by opcodes that require a particular OPERAND size, which we enforce by + * internally simulating an OPERAND size override, if needed. + * + * @this {X86CPU} + * @param {number} size (2 for 2-byte/16-bit operands, or 4 for 4-byte/32-bit operands) + */ +X86CPU.prototype.setDataSize = function(size) +{ + if (this.dataSize != size) { + this.opPrefixes |= X86.OPFLAG.DATASIZE; + this.dataSize = size; + this.dataMask = (size == 2? 0xffff : (0xffffffff|0)); + this.updateDataSize(); + } +}; + +/** + * updateDataSize() * * @this {X86CPU} */ -X86CPU.prototype.setDataSize = function() +X86CPU.prototype.updateDataSize = function() { if (this.dataSize == 2) { this.dataType = X86.RESULT.WORD; @@ -1407,7 +1426,7 @@ X86CPU.prototype.resetSizes = function() * to separate X86CPU properties, as we do for the OPERAND size and ADDRESS size properties. */ - this.setAddrSize(); + this.updateAddrSize(); /* * The following contain the (default) OPERAND size (2 for 16 bits, 4 for 32 bits), and the corresponding masks @@ -1417,7 +1436,7 @@ X86CPU.prototype.resetSizes = function() this.dataSize = this.segCS.dataSize; this.dataMask = this.segCS.dataMask; - this.setDataSize(); + this.updateDataSize(); this.opPrefixes &= ~(X86.OPFLAG.ADDRSIZE | X86.OPFLAG.DATASIZE); }; @@ -3775,11 +3794,6 @@ X86CPU.prototype.stepCPU = function(nMinCycles) if (I386 && (this.opPrefixes & (X86.OPFLAG.ADDRSIZE | X86.OPFLAG.DATASIZE))) { this.resetSizes(); - if (MAXDEBUG && DEBUGGER) { - this.println("80386 override processed"); - this.stopCPU(); - break; - } } this.opPrefixes = this.opFlags & X86.OPFLAG.REPEAT; diff --git a/modules/pcjs/lib/x86func.js b/modules/pcjs/lib/x86func.js index 41418d98f..917cd7d1f 100644 --- a/modules/pcjs/lib/x86func.js +++ b/modules/pcjs/lib/x86func.js @@ -1675,7 +1675,7 @@ X86.fnMOVn = function MOVn(dst, src) * @this {X86CPU} * @param {number} dst (current value, ignored) * @param {number} src (new value) - * @return {number} dst (src is overridden, replaced with regXX, as specified by opMOVwsr()) + * @return {number} dst (src is overridden, replaced with regXX, as specified by opMOVwsr() or opMOVrc()) */ X86.fnMOVxx = function MOVxx(dst, src) { diff --git a/modules/pcjs/lib/x86op0f.js b/modules/pcjs/lib/x86op0f.js index d8ca41f67..dd76514b5 100644 --- a/modules/pcjs/lib/x86op0f.js +++ b/modules/pcjs/lib/x86op0f.js @@ -256,7 +256,11 @@ X86.opMOVrc = function MOVrc() * however, it's moot, because we've already restricted this opcode to registers only. * * this.opFlags |= X86.OPFLAG.NOREAD; + * + * Another issue, however, is that this instruction always assumes a 32-bit OPERAND size, + * so we must call setDataSize(4) first. */ + this.setDataSize(4); this.aOpModRegWord[bModRM].call(this, X86.fnMOVxx); }; @@ -319,7 +323,13 @@ X86.opMOVcr = function MOVcr() X86.opInvalid.call(this); return; } + + /* + * This instruction always assumes a 32-bit OPERAND size, so we must call setDataSize(4) first. + */ + this.setDataSize(4); this.aOpModRegWord[bModRM].call(this, X86.fnMOV); + switch(reg) { case 0x0: reg = this.regEAX; diff --git a/modules/pcjs/lib/x86ops.js b/modules/pcjs/lib/x86ops.js index 22b7974cb..cabaae027 100644 --- a/modules/pcjs/lib/x86ops.js +++ b/modules/pcjs/lib/x86ops.js @@ -1380,7 +1380,7 @@ X86.opOS = function OS() this.opFlags |= X86.OPFLAG.DATASIZE; this.dataSize ^= 0x6; // that which is 2 shall become 4, and vice versa this.dataMask ^= (0xffff0000|0); // that which is 0x0000ffff shall become 0xffffffff, and vice versa - this.setDataSize(); + this.updateDataSize(); this.nStepCycles -= this.cycleCounts.nOpCyclesPrefix; } }; @@ -1398,7 +1398,7 @@ X86.opAS = function AS() this.opFlags |= X86.OPFLAG.ADDRSIZE; this.addrSize ^= 0x06; // that which is 2 shall become 4, and vice versa this.addrMask ^= (0xffff0000|0); // that which is 0x0000ffff shall become 0xffffffff, and vice versa - this.setAddrSize(); + this.updateAddrSize(); this.nStepCycles -= this.cycleCounts.nOpCyclesPrefix; } }; diff --git a/modules/pcjs/templates/components.xsl b/modules/pcjs/templates/components.xsl index 9f6e7682a..ed2f0f88b 100644 --- a/modules/pcjs/templates/components.xsl +++ b/modules/pcjs/templates/components.xsl @@ -974,7 +974,7 @@ - + 20 @@ -996,7 +996,7 @@ computer - ,buswidth:,resume:,state:'' + ,busWidth:,resume:,state:'' diff --git a/tests/pc/80386/tests.nasm b/tests/pc/80386/tests.nasm index 0a376d30b..035952149 100644 --- a/tests/pc/80386/tests.nasm +++ b/tests/pc/80386/tests.nasm @@ -46,11 +46,15 @@ start: mov eax,0x44332211 jnz near goProt ; apparently we have to tell NASM "near" because this is a forward reference times 32768 nop ; lots of NOPs to force a 16-bit conditional jump +addrGDT:dw romGDTEnd - romGDT - 1 ; 16-bit limit of romGDT + dw romGDT, 0xffff ; 32-bit base address of romGDT (works as long as we're aliased at 0xffff0000) + romGDT: defDesc 0 ; the first descriptor in any descriptor table is always a dud (it corresponds to the null descriptor) defDesc 0x000f0000,0x0000ffff,ACC_TYPE_CODE_READABLE defDesc 0x00000000,0x000fffff,ACC_TYPE_DATA_WRITABLE +romGDTEnd: -goProt: lgdt [cs:romGDT] +goProt: o32 lgdt [cs:addrGDT] mov eax,cr0 or eax,CR0_MSW_PE mov cr0,eax