From c47fba7b0cb92bfc39486c7d71db899c21017acc Mon Sep 17 00:00:00 2001 From: Jeff Parsons Date: Wed, 18 Nov 2015 17:05:16 -0800 Subject: [PATCH] Some FPU corrections (due to 8087 datasheet errors) and additions --- modules/pcjs/lib/debugger.js | 34 +++++++------- modules/pcjs/lib/x86fpu.js | 91 +++++++++++++++++++++++------------- 2 files changed, 75 insertions(+), 50 deletions(-) diff --git a/modules/pcjs/lib/debugger.js b/modules/pcjs/lib/debugger.js index 077f278ba..2bea65c13 100644 --- a/modules/pcjs/lib/debugger.js +++ b/modules/pcjs/lib/debugger.js @@ -1129,7 +1129,7 @@ if (DEBUGGER) { 0x30: [Debugger.FINS.FLD, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT], 0x31: [Debugger.FINS.FXCH, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT], 0x32: [Debugger.FINS.FNOP], - 0x33: [Debugger.FINS.FSTP, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT], // Obsolete decoding + 0x33: [Debugger.FINS.FSTP, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT], // Obsolete encoding 0x40: [Debugger.FINS.FCHS], 0x41: [Debugger.FINS.FABS], 0x44: [Debugger.FINS.FTST], @@ -1188,12 +1188,12 @@ if (DEBUGGER) { 0x07: [Debugger.FINS.FDIVR, Debugger.TYPE_MODRM | Debugger.TYPE_LREAL | Debugger.TYPE_IN], 0x30: [Debugger.FINS.FADD, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT, Debugger.TYPE_IMPREG | Debugger.TYPE_ST | Debugger.TYPE_IN], 0x31: [Debugger.FINS.FMUL, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT, Debugger.TYPE_IMPREG | Debugger.TYPE_ST | Debugger.TYPE_IN], - 0x32: [Debugger.FINS.FCOM, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_IN], // Obsolete decoding - 0x33: [Debugger.FINS.FCOMP, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_IN], // Obsolete decoding - 0x34: [Debugger.FINS.FSUB, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT, Debugger.TYPE_IMPREG | Debugger.TYPE_ST | Debugger.TYPE_IN], - 0x35: [Debugger.FINS.FSUBR, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT, Debugger.TYPE_IMPREG | Debugger.TYPE_ST | Debugger.TYPE_IN], - 0x36: [Debugger.FINS.FDIV, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT, Debugger.TYPE_IMPREG | Debugger.TYPE_ST | Debugger.TYPE_IN], - 0x37: [Debugger.FINS.FDIVR, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT, Debugger.TYPE_IMPREG | Debugger.TYPE_ST | Debugger.TYPE_IN] + 0x32: [Debugger.FINS.FCOM, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_IN], // Obsolete encoding + 0x33: [Debugger.FINS.FCOMP, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_IN], // Obsolete encoding + 0x34: [Debugger.FINS.FSUBR, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT, Debugger.TYPE_IMPREG | Debugger.TYPE_ST | Debugger.TYPE_IN], + 0x35: [Debugger.FINS.FSUB, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT, Debugger.TYPE_IMPREG | Debugger.TYPE_ST | Debugger.TYPE_IN], + 0x36: [Debugger.FINS.FDIVR, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT, Debugger.TYPE_IMPREG | Debugger.TYPE_ST | Debugger.TYPE_IN], + 0x37: [Debugger.FINS.FDIV, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT, Debugger.TYPE_IMPREG | Debugger.TYPE_ST | Debugger.TYPE_IN] }, 0xDD: { 0x00: [Debugger.FINS.FLD, Debugger.TYPE_MODRM | Debugger.TYPE_LREAL | Debugger.TYPE_IN], @@ -1203,7 +1203,7 @@ if (DEBUGGER) { 0x06: [Debugger.FINS.FSAVE, Debugger.TYPE_MODRM | Debugger.TYPE_FPU | Debugger.TYPE_OUT], 0x07: [Debugger.FINS.FSTSW, Debugger.TYPE_MODRM | Debugger.TYPE_SHORT | Debugger.TYPE_OUT], 0x30: [Debugger.FINS.FFREE, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_IN], - 0x31: [Debugger.FINS.FXCH, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT], // Obsolete decoding + 0x31: [Debugger.FINS.FXCH, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT], // Obsolete encoding 0x32: [Debugger.FINS.FST, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_IN], 0x33: [Debugger.FINS.FSTP, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_IN] }, @@ -1218,12 +1218,12 @@ if (DEBUGGER) { 0x07: [Debugger.FINS.FIDIVR, Debugger.TYPE_MODRM | Debugger.TYPE_SHORT | Debugger.TYPE_IN], 0x30: [Debugger.FINS.FADDP, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT, Debugger.TYPE_IMPREG | Debugger.TYPE_ST | Debugger.TYPE_IN], 0x31: [Debugger.FINS.FMULP, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT, Debugger.TYPE_IMPREG | Debugger.TYPE_ST | Debugger.TYPE_IN], - 0x32: [Debugger.FINS.FCOMP, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_IN], // Obsolete decoding + 0x32: [Debugger.FINS.FCOMP, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_IN], // Obsolete encoding 0x33: [Debugger.FINS.FCOMPP, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_IN], - 0x34: [Debugger.FINS.FSUBP, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT, Debugger.TYPE_IMPREG | Debugger.TYPE_ST | Debugger.TYPE_IN], - 0x35: [Debugger.FINS.FSUBRP, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT, Debugger.TYPE_IMPREG | Debugger.TYPE_ST | Debugger.TYPE_IN], - 0x36: [Debugger.FINS.FDIVP, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT, Debugger.TYPE_IMPREG | Debugger.TYPE_ST | Debugger.TYPE_IN], - 0x37: [Debugger.FINS.FDIVRP, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT, Debugger.TYPE_IMPREG | Debugger.TYPE_ST | Debugger.TYPE_IN] + 0x34: [Debugger.FINS.FSUBRP, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT, Debugger.TYPE_IMPREG | Debugger.TYPE_ST | Debugger.TYPE_IN], + 0x35: [Debugger.FINS.FSUBP, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT, Debugger.TYPE_IMPREG | Debugger.TYPE_ST | Debugger.TYPE_IN], + 0x36: [Debugger.FINS.FDIVRP, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT, Debugger.TYPE_IMPREG | Debugger.TYPE_ST | Debugger.TYPE_IN], + 0x37: [Debugger.FINS.FDIVP, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT, Debugger.TYPE_IMPREG | Debugger.TYPE_ST | Debugger.TYPE_IN] }, 0xDF: { 0x00: [Debugger.FINS.FILD, Debugger.TYPE_MODRM | Debugger.TYPE_SHORT | Debugger.TYPE_IN], @@ -1233,10 +1233,10 @@ if (DEBUGGER) { 0x05: [Debugger.FINS.FILD, Debugger.TYPE_MODRM | Debugger.TYPE_LINT | Debugger.TYPE_IN], 0x06: [Debugger.FINS.FBSTP, Debugger.TYPE_MODRM | Debugger.TYPE_DEC18 | Debugger.TYPE_OUT], 0x07: [Debugger.FINS.FISTP, Debugger.TYPE_MODRM | Debugger.TYPE_LINT | Debugger.TYPE_OUT], - 0x30: [Debugger.FINS.FFREEP, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_IN], // Obsolete decoding - 0x31: [Debugger.FINS.FXCH, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT], // Obsolete decoding - 0x32: [Debugger.FINS.FSTP, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_IN], // Obsolete decoding - 0x33: [Debugger.FINS.FSTP, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_IN], // Obsolete decoding + 0x30: [Debugger.FINS.FFREEP, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_IN], // Obsolete encoding + 0x31: [Debugger.FINS.FXCH, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT], // Obsolete encoding + 0x32: [Debugger.FINS.FSTP, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_IN], // Obsolete encoding + 0x33: [Debugger.FINS.FSTP, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_IN], // Obsolete encoding 0x34: [Debugger.FINS.FSTSWAX, Debugger.TYPE_80287] } }; diff --git a/modules/pcjs/lib/x86fpu.js b/modules/pcjs/lib/x86fpu.js index ec5891991..03c2758cd 100644 --- a/modules/pcjs/lib/x86fpu.js +++ b/modules/pcjs/lib/x86fpu.js @@ -245,7 +245,7 @@ X86FPU.FADDsti = function() */ X86FPU.FADDPsti = function() { - this.opUnimplemented(); + if (this.setST(this.iStack, this.doAdd(this.getST(this.iStack), this.getST(0)))) this.popValue(); }; /** @@ -374,9 +374,7 @@ X86FPU.FCOMPsr = function() */ X86FPU.FCOMPst = function() { - // if (this.opStop()) return; // for untested instructions: stops the CPU if it's running, but not if single-stepping - this.doCompare(this.getST(0), this.getST(this.iStack)); - this.popValue(); + if (this.doCompare(this.getST(0), this.getST(this.iStack))) this.popValue(); }; /** @@ -404,13 +402,13 @@ X86FPU.FCOMP8087 = function() }; /** - * FCOMPPsti() + * FCOMPP() * * @this {X86FPU} */ -X86FPU.FCOMPPsti = function() +X86FPU.FCOMPP = function() { - this.opUnimplemented(); + if (this.doCompare(this.getST(0), this.getST(1)) && this.popValue() != null) this.popValue(); }; /** @@ -1249,9 +1247,7 @@ X86FPU.FSTPsr = function() */ X86FPU.FSTPsti = function() { - if (this.setST(this.iStack, this.getST(0))) { - this.popValue(); - } + if (this.setST(this.iStack, this.getST(0))) this.popValue(); }; /** @@ -1322,7 +1318,7 @@ X86FPU.FSTSWAX287 = function() */ X86FPU.FSUBlr = function() { - this.opUnimplemented(); + this.setST(0, this.doSubtract(this.getST(0), this.getLRFromEA())); }; /** @@ -1332,37 +1328,43 @@ X86FPU.FSUBlr = function() */ X86FPU.FSUBsr = function() { - this.opUnimplemented(); + this.setST(0, this.doSubtract(this.getST(0), this.getSRFromEA())); }; /** * FSUBst() * + * This is for encoding 0xD8,0xE0-0xE7 ("FSUB ST,ST(i)"): ST(0) <- ST(0) - ST(i) + * * @this {X86FPU} */ X86FPU.FSUBst = function() { - this.opUnimplemented(); + this.setST(0, this.doSubtract(this.getST(0), this.getST(this.iStack))); }; /** * FSUBsti() * + * This is for encoding 0xDC,0xE8-0xEF ("FSUB ST(i),ST"): ST(i) <- ST(0) - ST(i) + * * @this {X86FPU} */ X86FPU.FSUBsti = function() { - this.opUnimplemented(); + this.setST(this.iStack, this.doSubtract(this.getST(0), this.getST(this.iStack))); }; /** * FSUBPsti() * + * This is for encoding 0xDE,0xE8-0xEF ("FSUBP ST(i),ST"): ST(i) <- ST(0) - ST(i), POP + * * @this {X86FPU} */ X86FPU.FSUBPsti = function() { - this.opUnimplemented(); + if (this.setST(this.iStack, this.doSubtract(this.getST(0), this.getST(this.iStack)))) this.popValue(); }; /** @@ -1372,7 +1374,7 @@ X86FPU.FSUBPsti = function() */ X86FPU.FSUBRlr = function() { - this.opUnimplemented(); + this.setST(0, this.doSubtract(this.getLRFromEA(), this.getST(0))); }; /** @@ -1382,22 +1384,26 @@ X86FPU.FSUBRlr = function() */ X86FPU.FSUBRsr = function() { - this.opUnimplemented(); + this.setST(0, this.doSubtract(this.getSRFromEA(), this.getST(0))); }; /** * FSUBRst() * + * This is for encoding 0xD8,0xE8-0xEF ("FSUBR ST,ST(i)"): ST(0) <- ST(i) - ST(0) + * * @this {X86FPU} */ X86FPU.FSUBRst = function() { - this.opUnimplemented(); + this.setST(0, this.doSubtract(this.getST(this.iStack), this.getST(0))); }; /** * FSUBRsti() * + * This is for encoding 0xDC,0xE0-0xE7 ("FSUBR ST(i),ST"): ST(i) <- ST(i) - ST(0) + * * @this {X86FPU} */ X86FPU.FSUBRsti = function() @@ -1408,13 +1414,13 @@ X86FPU.FSUBRsti = function() /** * FSUBRPsti() * + * This is for encoding 0xDE,0xE0-0xE7 ("FSUBRP ST(i),ST"): ST(i) <- ST(i) - ST(0), POP + * * @this {X86FPU} */ X86FPU.FSUBRPsti = function() { - if (this.setST(this.iStack, this.doSubtract(this.getST(this.iStack), this.getST(0)))) { - this.popValue(); - } + if (this.setST(this.iStack, this.doSubtract(this.getST(this.iStack), this.getST(0)))) this.popValue(); }; /** @@ -1466,7 +1472,9 @@ X86FPU.FXAM = function() */ X86FPU.FXCHsti = function() { - this.opUnimplemented(); + var tmp = this.getST(0); + this.setST(0, this.getST(this.iStack)); + this.setST(this.iStack, tmp); }; /** @@ -1708,6 +1716,12 @@ X86FPU.prototype.getRandomInt = function(min, max) /** * opStop(fError) * + * Place this inside any opcode handler to stop the CPU from running the current instruction; eg: + * + * if (this.opStop()) return; + * + * You can still use the Debugger to single-step over the instruction; opStop() will return false in that case. + * * @this {X86FPU} * @param {boolean} [fError] * @return {boolean} (true if there was an error or the CPU was running, false if not) @@ -1990,6 +2004,7 @@ X86FPU.prototype.doDivide = function(dividend, divisor) * @this {X86FPU} * @param {number|null} operand1 * @param {number|null} operand2 + * @return {boolean} */ X86FPU.prototype.doCompare = function(operand1, operand2) { @@ -2006,7 +2021,9 @@ X86FPU.prototype.doCompare = function(operand1, operand2) } } this.regStatus = (this.regStatus & ~X86.FPU.STATUS.CC) | cc; + return true; } + return false; }; /** @@ -2030,14 +2047,16 @@ X86FPU.prototype.doSquareRoot = function(operand) }; /** - * roundInteger(operand, limit) + * roundInteger(operand, max) + * + * NOTE: The max parameter is EXCLUSIVE, not inclusive (ie, the maximum positive integer is < max). * * @this {X86FPU} * @param {number|null} operand - * @param {number} limit (ie, 0x8000, 0x80000000, or 0x8000000000000000) + * @param {number} max (ie, 0x8000, 0x80000000, or 0x8000000000000000) * @return {boolean} true if intTmpLR was loaded, false if not */ -X86FPU.prototype.roundInteger = function(operand, limit) +X86FPU.prototype.roundInteger = function(operand, max) { var result; var rc = (this.regControl & X86.FPU.CONTROL.RC); @@ -2053,18 +2072,18 @@ X86FPU.prototype.roundInteger = function(operand, limit) result = Math.ceil(operand); } - if (result >= limit) { + if (result >= max) { if (this.setException(X86.FPU.STATUS.OE)) return false; - result = limit - 1; + result = max - 1; } - else if (result < -limit) { + else if (result < -max) { if (this.setException(X86.FPU.STATUS.UE)) return false; - result = -limit; + result = -max; } this.intTmpLR[0] = result|0; - if (limit > X86FPU.MAX_INT32) { + if (max > X86FPU.MAX_INT32) { this.intTmpLR[1] = (result / 0x100000000)|0; if (!this.intTmpLR[1] && result < 0) this.intTmpLR[1] = -1; } @@ -2791,7 +2810,10 @@ X86FPU.aaOps = { 0x00: X86FPU.FADDlr, 0x01: X86FPU.FMULlr, 0x02: X86FPU.FCOMlr, 0x03: X86FPU.FCOMPlr, 0x04: X86FPU.FSUBlr, 0x05: X86FPU.FSUBRlr, 0x06: X86FPU.FDIVlr, 0x07: X86FPU.FDIVRlr, 0x30: X86FPU.FADDsti, 0x31: X86FPU.FMULsti, 0x32: X86FPU.FCOM8087, 0x33: X86FPU.FCOMP8087, - 0x34: X86FPU.FSUBsti, 0x35: X86FPU.FSUBRsti, 0x36: X86FPU.FDIVsti, 0x37: X86FPU.FDIVRsti + /* + * Intel's original 8087 datasheet had these forms of SUB and SUBR (and DIV and DIVR) swapped. + */ + 0x34: X86FPU.FSUBRsti, 0x35: X86FPU.FSUBsti, 0x36: X86FPU.FDIVRsti, 0x37: X86FPU.FDIVsti }, 0xDD: { 0x00: X86FPU.FLDlr, 0x02: X86FPU.FSTlr, 0x03: X86FPU.FSTPlr, @@ -2801,8 +2823,11 @@ X86FPU.aaOps = { 0xDE: { 0x00: X86FPU.FIADD16, 0x01: X86FPU.FIMUL16, 0x02: X86FPU.FICOM16, 0x03: X86FPU.FICOMP16, 0x04: X86FPU.FISUB16, 0x05: X86FPU.FISUBR16, 0x06: X86FPU.FIDIV16, 0x07: X86FPU.FIDIVR16, - 0x30: X86FPU.FADDPsti, 0x31: X86FPU.FMULPsti, 0x32: X86FPU.FCOMP8087, 0x33: X86FPU.FCOMPPsti, - 0x34: X86FPU.FSUBPsti, 0x35: X86FPU.FSUBRPsti, 0x36: X86FPU.FDIVPsti, 0x37: X86FPU.FDIVRPsti + 0x30: X86FPU.FADDPsti, 0x31: X86FPU.FMULPsti, 0x32: X86FPU.FCOMP8087, 0x33: X86FPU.FCOMPP, + /* + * Intel's original 8087 datasheet had these forms of SUBP and SUBRP (and DIVP and DIVRP) swapped. + */ + 0x34: X86FPU.FSUBRPsti, 0x35: X86FPU.FSUBPsti, 0x36: X86FPU.FDIVRPsti, 0x37: X86FPU.FDIVPsti }, 0xDF: { 0x00: X86FPU.FILD16, 0x02: X86FPU.FIST16, 0x03: X86FPU.FISTP16,