From 763b02794b4feedb9081c9933e60ba4f42e6ced0 Mon Sep 17 00:00:00 2001 From: Jeff Parsons Date: Wed, 27 Jan 2016 13:04:52 -0800 Subject: [PATCH] When halting on faults in the Debugger, interrupt the instruction in the same manner as the actual fault would --- modules/pcjs/lib/x86func.js | 20 ++++---- modules/pcjs/lib/x86ops.js | 98 ++++++++++++++++--------------------- 2 files changed, 53 insertions(+), 65 deletions(-) diff --git a/modules/pcjs/lib/x86func.js b/modules/pcjs/lib/x86func.js index a3fc37bb3..fd2f2cdad 100644 --- a/modules/pcjs/lib/x86func.js +++ b/modules/pcjs/lib/x86func.js @@ -360,7 +360,6 @@ X86.fnBTMem = function(dst, src) if (this.regEA === X86.ADDR_INVALID) { return X86.fnBT.call(this, dst, src); } - /* * TODO: Consider a worker function that performs the following block of code for: BT, BTC, BTR, and BTS. * It's somewhat inconvenient, because it needs to provide two results: an updated src AND an updated dst. @@ -409,7 +408,6 @@ X86.fnBTCMem = function(dst, src) if (this.regEA === X86.ADDR_INVALID) { return X86.fnBTC.call(this, dst, src); } - /* * src is usually positive BUT can also be negative (as the IA32 spec says: "The offset operand then selects * a bit position within the range −231 to 231 − 1 for a register offset and 0 to 31 for an immediate offset.") @@ -451,7 +449,6 @@ X86.fnBTRMem = function(dst, src) if (this.regEA === X86.ADDR_INVALID) { return X86.fnBTR.call(this, dst, src); } - /* * src is usually positive BUT can also be negative (as the IA32 spec says: "The offset operand then selects * a bit position within the range −231 to 231 − 1 for a register offset and 0 to 31 for an immediate offset.") @@ -493,7 +490,6 @@ X86.fnBTSMem = function(dst, src) if (this.regEA === X86.ADDR_INVALID) { return X86.fnBTS.call(this, dst, src); } - /* * src is usually positive BUT can also be negative (as the IA32 spec says: "The offset operand then selects * a bit position within the range −231 to 231 − 1 for a register offset and 0 to 31 for an immediate offset.") @@ -3939,7 +3935,7 @@ X86.fnTrap = function(nIDT, nCycles) */ X86.fnFault = function(nFault, nError, nCycles, fHalt) { - var fDispatch = null; + var fDispatch = false; if (!this.aFlags.fComplete) { /* @@ -3950,6 +3946,9 @@ X86.fnFault = function(nFault, nError, nCycles, fHalt) this.setIP(this.opLIP - this.segCS.base); } else if (this.model >= X86.MODEL_80186) { + + fDispatch = true; + if (this.nFault < 0) { /* * Single-fault (error code is passed through, and the responsible instruction is restartable; @@ -3966,14 +3965,12 @@ X86.fnFault = function(nFault, nError, nCycles, fHalt) this.setSP((this.regESP & ~this.segSS.maskAddr) | (this.opLSP - this.segSS.base)); this.opLSP = X86.ADDR_INVALID; } - fDispatch = true; } else if (this.nFault != X86.EXCEPTION.DF_FAULT) { /* * Double-fault (error code is always zero, and the responsible instruction is not restartable) */ nError = 0; nFault = X86.EXCEPTION.DF_FAULT; - fDispatch = true; } else { /* @@ -3982,12 +3979,17 @@ X86.fnFault = function(nFault, nError, nCycles, fHalt) */ nFault = -1; nError = 0; this.resetRegs(); - fHalt = false; + fDispatch = fHalt = false; } } if (X86.fnFaultMessage.call(this, nFault, nError, fHalt)) { - fDispatch = false; + /* + * If this is a fault that would normally be dispatched BUT fnFaultMessage() wants us to halt, + * then we throw a bogus fault number (-1), simply to interrupt the current instruction in exactly + * the same way that a dispatched fault would interrupt it. + */ + if (fDispatch) throw -1; } if (fDispatch) { diff --git a/modules/pcjs/lib/x86ops.js b/modules/pcjs/lib/x86ops.js index 378a501cb..2505262e6 100644 --- a/modules/pcjs/lib/x86ops.js +++ b/modules/pcjs/lib/x86ops.js @@ -1652,12 +1652,11 @@ X86.opINSb = function() if (!this.checkIOPM(port, 1, true)) return; var b = this.bus.checkPortInputNotify(port, 1, this.regLIP - nDelta - 1); this.setSOByte(this.segES, this.regEDI & maskAddr, b); - /* - * TODO: Remove this once we've done enough testing of fnFault() throwing exceptions + * fnFault() throws exceptions now, so inline checks of X86.OPFLAG.FAULT should no longer be necessary. + * + * if (this.opFlags & X86.OPFLAG.FAULT) return; */ - if (this.opFlags & X86.OPFLAG.FAULT) return; - if (BACKTRACK) this.backTrack.btiMem0 = this.backTrack.btiIO; this.regEDI = (this.regEDI & ~maskAddr) | ((this.regEDI + ((this.regPS & X86.PS.DF)? -1 : 1)) & maskAddr); this.regECX = (this.regECX & ~maskAddr) | ((this.regECX - nDelta) & maskAddr); @@ -1706,12 +1705,11 @@ X86.opINSw = function() this.backTrack.btiMem1 = this.backTrack.btiIO; } this.setSOWord(this.segES, this.regEDI & maskAddr, w); - /* - * TODO: Remove this once we've done enough testing of fnFault() throwing exceptions + * fnFault() throws exceptions now, so inline checks of X86.OPFLAG.FAULT should no longer be necessary. + * + * if (this.opFlags & X86.OPFLAG.FAULT) return; */ - if (this.opFlags & X86.OPFLAG.FAULT) return; - this.regEDI = (this.regEDI & ~maskAddr) | ((this.regEDI + ((this.regPS & X86.PS.DF)? -this.sizeData : this.sizeData)) & maskAddr); this.regECX = (this.regECX & ~maskAddr) | ((this.regECX - nDelta) & maskAddr); this.nStepCycles -= nCycles; @@ -1753,12 +1751,11 @@ X86.opOUTSb = function() var port = this.regEDX & 0xffff; if (!this.checkIOPM(port, 1, false)) return; var b = this.getSOByte(this.segDS, this.regESI & maskAddr); - /* - * TODO: Remove this once we've done enough testing of fnFault() throwing exceptions + * fnFault() throws exceptions now, so inline checks of X86.OPFLAG.FAULT should no longer be necessary. + * + * if (this.opFlags & X86.OPFLAG.FAULT) return; */ - if (this.opFlags & X86.OPFLAG.FAULT) return; - if (BACKTRACK) this.backTrack.btiIO = this.backTrack.btiMem0; this.bus.checkPortOutputNotify(port, 1, b, this.regLIP - nDelta - 1); this.regESI = (this.regESI & ~maskAddr) | ((this.regESI + ((this.regPS & X86.PS.DF)? -1 : 1)) & maskAddr); @@ -1800,12 +1797,11 @@ X86.opOUTSw = function() } if (nReps--) { var w = this.getSOWord(this.segDS, this.regESI & maskAddr); - /* - * TODO: Remove this once we've done enough testing of fnFault() throwing exceptions + * fnFault() throws exceptions now, so inline checks of X86.OPFLAG.FAULT should no longer be necessary. + * + * if (this.opFlags & X86.OPFLAG.FAULT) return; */ - if (this.opFlags & X86.OPFLAG.FAULT) return; - var port = this.regEDX & 0xffff; if (!this.checkIOPM(port, this.sizeData, false)) return; if (BACKTRACK) { @@ -2803,12 +2799,11 @@ X86.opMOVSb = function() } if (nReps--) { this.setSOByte(this.segES, this.regEDI & maskAddr, this.getSOByte(this.segData, this.regESI & maskAddr)); - /* - * TODO: Remove this once we've done enough testing of fnFault() throwing exceptions + * fnFault() throws exceptions now, so inline checks of X86.OPFLAG.FAULT should no longer be necessary. + * + * if (this.opFlags & X86.OPFLAG.FAULT) return; */ - if (this.opFlags & X86.OPFLAG.FAULT) return; - var nInc = ((this.regPS & X86.PS.DF)? -1 : 1); this.regESI = (this.regESI & ~maskAddr) | ((this.regESI + nInc) & maskAddr); this.regEDI = (this.regEDI & ~maskAddr) | ((this.regEDI + nInc) & maskAddr); @@ -2841,12 +2836,11 @@ X86.opMOVSw = function() } if (nReps--) { this.setSOWord(this.segES, this.regEDI & maskAddr, this.getSOWord(this.segData, this.regESI & maskAddr)); - /* - * TODO: Remove this once we've done enough testing of fnFault() throwing exceptions + * fnFault() throws exceptions now, so inline checks of X86.OPFLAG.FAULT should no longer be necessary. + * + * if (this.opFlags & X86.OPFLAG.FAULT) return; */ - if (this.opFlags & X86.OPFLAG.FAULT) return; - var nInc = ((this.regPS & X86.PS.DF)? -this.sizeData : this.sizeData); this.regESI = (this.regESI & ~maskAddr) | ((this.regESI + nInc) & maskAddr); this.regEDI = (this.regEDI & ~maskAddr) | ((this.regEDI + nInc) & maskAddr); @@ -2880,12 +2874,11 @@ X86.opCMPSb = function() if (nReps--) { var bDst = this.getEAByte(this.segData, this.regESI & maskAddr); var bSrc = this.modEAByte(this.segES, this.regEDI & maskAddr); - /* - * TODO: Remove this once we've done enough testing of fnFault() throwing exceptions + * fnFault() throws exceptions now, so inline checks of X86.OPFLAG.FAULT should no longer be necessary. + * + * if (this.opFlags & X86.OPFLAG.FAULT) return; */ - if (this.opFlags & X86.OPFLAG.FAULT) return; - X86.fnCMPb.call(this, bDst, bSrc); var nInc = ((this.regPS & X86.PS.DF)? -1 : 1); this.regESI = (this.regESI & ~maskAddr) | ((this.regESI + nInc) & maskAddr); @@ -2928,12 +2921,11 @@ X86.opCMPSw = function() if (nReps--) { var wDst = this.getEAWord(this.segData, this.regESI & maskAddr); var wSrc = this.modEAWord(this.segES, this.regEDI & maskAddr); - /* - * TODO: Remove this once we've done enough testing of fnFault() throwing exceptions + * fnFault() throws exceptions now, so inline checks of X86.OPFLAG.FAULT should no longer be necessary. + * + * if (this.opFlags & X86.OPFLAG.FAULT) return; */ - if (this.opFlags & X86.OPFLAG.FAULT) return; - X86.fnCMPw.call(this, wDst, wSrc); var nInc = ((this.regPS & X86.PS.DF)? -this.sizeData : this.sizeData); this.regESI = (this.regESI & ~maskAddr) | ((this.regESI + nInc) & maskAddr); @@ -2999,12 +2991,11 @@ X86.opSTOSb = function() } if (nReps--) { this.setSOByte(this.segES, this.regEDI & maskAddr, this.regEAX); - /* - * TODO: Remove this once we've done enough testing of fnFault() throwing exceptions + * fnFault() throws exceptions now, so inline checks of X86.OPFLAG.FAULT should no longer be necessary. + * + * if (this.opFlags & X86.OPFLAG.FAULT) return; */ - if (this.opFlags & X86.OPFLAG.FAULT) return; - if (BACKTRACK) this.backTrack.btiMem0 = this.backTrack.btiAL; this.regECX = (this.regECX & ~maskAddr) | ((this.regECX - nDelta) & maskAddr); @@ -3058,12 +3049,11 @@ X86.opSTOSw = function() } if (nReps--) { this.setSOWord(this.segES, this.regEDI & maskAddr, this.regEAX); - /* - * TODO: Remove this once we've done enough testing of fnFault() throwing exceptions + * fnFault() throws exceptions now, so inline checks of X86.OPFLAG.FAULT should no longer be necessary. + * + * if (this.opFlags & X86.OPFLAG.FAULT) return; */ - if (this.opFlags & X86.OPFLAG.FAULT) return; - if (BACKTRACK) { this.backTrack.btiMem0 = this.backTrack.btiAL; this.backTrack.btiMem1 = this.backTrack.btiAH; } @@ -3097,12 +3087,11 @@ X86.opLODSb = function() } if (nReps--) { var b = this.getSOByte(this.segData, this.regESI & maskAddr); - /* - * TODO: Remove this once we've done enough testing of fnFault() throwing exceptions + * fnFault() throws exceptions now, so inline checks of X86.OPFLAG.FAULT should no longer be necessary. + * + * if (this.opFlags & X86.OPFLAG.FAULT) return; */ - if (this.opFlags & X86.OPFLAG.FAULT) return; - this.regEAX = (this.regEAX & ~0xff) | b; if (BACKTRACK) this.backTrack.btiAL = this.backTrack.btiMem0; this.regESI = (this.regESI & ~maskAddr) | ((this.regESI + ((this.regPS & X86.PS.DF)? -1 : 1)) & maskAddr); @@ -3135,12 +3124,11 @@ X86.opLODSw = function() } if (nReps--) { var w = this.getSOWord(this.segData, this.regESI & maskAddr); - /* - * TODO: Remove this once we've done enough testing of fnFault() throwing exceptions + * fnFault() throws exceptions now, so inline checks of X86.OPFLAG.FAULT should no longer be necessary. + * + * if (this.opFlags & X86.OPFLAG.FAULT) return; */ - if (this.opFlags & X86.OPFLAG.FAULT) return; - this.regEAX = (this.regEAX & ~this.maskData) | w; if (BACKTRACK) { this.backTrack.btiAL = this.backTrack.btiMem0; this.backTrack.btiAH = this.backTrack.btiMem1; @@ -3175,12 +3163,11 @@ X86.opSCASb = function() } if (nReps--) { X86.fnCMPb.call(this, this.regEAX & 0xff, this.modEAByte(this.segES, this.regEDI & maskAddr)); - /* - * TODO: Remove this once we've done enough testing of fnFault() throwing exceptions + * fnFault() throws exceptions now, so inline checks of X86.OPFLAG.FAULT should no longer be necessary. + * + * if (this.opFlags & X86.OPFLAG.FAULT) return; */ - if (this.opFlags & X86.OPFLAG.FAULT) return; - this.regEDI = (this.regEDI & ~maskAddr) | ((this.regEDI + ((this.regPS & X86.PS.DF)? -1 : 1)) & maskAddr); this.regECX = (this.regECX & ~maskAddr) | ((this.regECX - nDelta) & maskAddr); /* @@ -3219,12 +3206,11 @@ X86.opSCASw = function() } if (nReps--) { X86.fnCMPw.call(this, this.regEAX & this.maskData, this.modEAWord(this.segES, this.regEDI & maskAddr)); - /* - * TODO: Remove this once we've done enough testing of fnFault() throwing exceptions + * fnFault() throws exceptions now, so inline checks of X86.OPFLAG.FAULT should no longer be necessary. + * + * if (this.opFlags & X86.OPFLAG.FAULT) return; */ - if (this.opFlags & X86.OPFLAG.FAULT) return; - this.regEDI = (this.regEDI & ~maskAddr) | ((this.regEDI + ((this.regPS & X86.PS.DF)? -this.sizeData : this.sizeData)) & maskAddr); this.regECX = (this.regECX & ~maskAddr) | ((this.regECX - nDelta) & maskAddr); /*