diff --git a/modules/pcjs/lib/chipset.js b/modules/pcjs/lib/chipset.js index 626b2fbca..ee5b24262 100644 --- a/modules/pcjs/lib/chipset.js +++ b/modules/pcjs/lib/chipset.js @@ -1391,9 +1391,9 @@ ChipSet.prototype.updateRTCTime = function() if (DEBUG) { if (nCyclesUpdate - this.nRTCCyclesNextUpdate > this.nRTCCyclesPerPeriod) { if (bPrev & ChipSet.CMOS.STATUSC.PF) { - this.messageDebugger("RTC interrupt handler failed to clear STATUSC", Debugger.MESSAGE.RTC | Debugger.MESSAGE.WARN); + this.messageDebugger("RTC interrupt handler failed to clear STATUSC", Debugger.MESSAGE.RTC); } else { - this.messageDebugger("CPU took too long trigger new RTC periodic interrupt", Debugger.MESSAGE.RTC | Debugger.MESSAGE.WARN); + this.messageDebugger("CPU took too long trigger new RTC periodic interrupt", Debugger.MESSAGE.RTC); } } } @@ -2216,7 +2216,7 @@ ChipSet.prototype.dumpPIC = function() sDump += " IC" + (i + 1) + "=" + str.toHexByte(b); } sDump += " IMR=" + str.toHexByte(pic.bIMR) + " IRR=" + str.toHexByte(pic.bIRR) + " ISR=" + str.toHexByte(pic.bISR); - this.dbg.message(sDump); + this.dbg.println(sDump); } } }; @@ -2240,7 +2240,7 @@ ChipSet.prototype.dumpTimer = function() } } sDump += " mode=" + timer.mode + " bytes=" + timer.countBytes + " count=" + str.toHexWord(count); - this.dbg.message(sDump); + this.dbg.println(sDump); } } }; @@ -2259,7 +2259,7 @@ ChipSet.prototype.dumpCMOS = function() if (sDump) sDump += '\n'; sDump += "CMOS[0x" + str.toHexByte(iCMOS) + "]: 0x" + str.toHexByte(b); } - this.dbg.message(sDump); + this.dbg.println(sDump); } }; @@ -2738,7 +2738,7 @@ ChipSet.prototype.advanceDMA = function(channel, fInit) var addr = (channel.bPage << 16) | (channel.addrCurrent[1] << 8) | channel.addrCurrent[0]; if (DEBUG && DEBUGGER && channel.sAddrDebug === null) { channel.sAddrDebug = str.toHex(addr >> 4, 4) + ":" + str.toHex(addr & 0xf, 4); - if (this.dbg && this.dbg.messageEnabled(Debugger.MESSAGE.DMA | (iDMAChannel == ChipSet.DMA_FDC? Debugger.MESSAGE.FDC : (iDMAChannel == ChipSet.DMA_HDC? Debugger.MESSAGE.HDC : Debugger.MESSAGE.LOG))) && channel.xfer != ChipSet.DMA_MODE.XFER_WRITE) { + if (this.dbg && this.dbg.messageEnabled(Debugger.MESSAGE.DMA | (iDMAChannel == ChipSet.DMA_FDC? Debugger.MESSAGE.FDC : (iDMAChannel == ChipSet.DMA_HDC? Debugger.MESSAGE.HDC : 0))) && channel.xfer != ChipSet.DMA_MODE.XFER_WRITE) { this.dbg.message("advanceDMA(" + iDMAChannel + ") transferring " + channel.cbDebug + " bytes from " + channel.sAddrDebug); this.dbg.doDump("db", channel.sAddrDebug, "l" + Math.floor((channel.cbDebug + 15) / 16)); } @@ -2848,7 +2848,7 @@ ChipSet.prototype.updateDMA = function(channel) channel.component = channel.obj = null; } - if (DEBUG && DEBUGGER && this.dbg && this.dbg.messageEnabled(Debugger.MESSAGE.DMA | (iDMAChannel == ChipSet.DMA_FDC? Debugger.MESSAGE.FDC : (iDMAChannel == ChipSet.DMA_HDC? Debugger.MESSAGE.HDC : Debugger.MESSAGE.LOG))) && channel.xfer == ChipSet.DMA_MODE.XFER_WRITE && channel.sAddrDebug) { + if (DEBUG && DEBUGGER && this.dbg && this.dbg.messageEnabled(Debugger.MESSAGE.DMA | (iDMAChannel == ChipSet.DMA_FDC? Debugger.MESSAGE.FDC : (iDMAChannel == ChipSet.DMA_HDC? Debugger.MESSAGE.HDC : 0))) && channel.xfer == ChipSet.DMA_MODE.XFER_WRITE && channel.sAddrDebug) { this.dbg.message("updateDMA(" + iDMAChannel + ") transferred " + channel.cbDebug + " bytes to " + channel.sAddrDebug); this.dbg.doDump("db", channel.sAddrDebug, "l" + Math.floor((channel.cbDebug + 15) / 16)); } @@ -3721,7 +3721,7 @@ ChipSet.prototype.updateTimer = function(iTimer, fCycleReset) } } - if (DEBUG && DEBUGGER && this.dbg && this.dbg.messageEnabled(Debugger.MESSAGE.TIMER)) { + if (DEBUG && DEBUGGER && this.dbg && this.dbg.messageEnabled(Debugger.MESSAGE.TIMER | Debugger.MESSAGE.LOG)) { this.log("TIMER" + iTimer + " count: " + count + ", ticks: " + ticks + ", fired: " + (fFired? "true" : "false")); } @@ -4090,7 +4090,7 @@ ChipSet.prototype.in8042RWReg = function(port, addrFrom) * Thanks to the WAITF function, this has become a very "busy" port, so let's not generate messages * unless both MESSAGE_8042 *and* MESSAGE_LOG are set. */ - this.messagePort(port, null, addrFrom, "8042_RWREG", Debugger.MESSAGE.C8042 | Debugger.MESSAGE.LOG, b); + this.messagePort(port, null, addrFrom, "8042_RWREG", Debugger.MESSAGE.C8042, b); return b; }; @@ -4670,7 +4670,7 @@ ChipSet.prototype.messageDebugger = function(sMessage, bitsMessage, nIRQ) bitsMessage = Debugger.MESSAGE.CHIPSET; } if (nIRQ !== undefined) { - bitsMessage |= (nIRQ == ChipSet.IRQ.TIMER0? Debugger.MESSAGE.TIMER : (nIRQ == ChipSet.IRQ.KBD? Debugger.MESSAGE.KBD : (nIRQ == ChipSet.IRQ.FDC? Debugger.MESSAGE.FDC : Debugger.MESSAGE.PIC))); + bitsMessage |= (nIRQ == ChipSet.IRQ.TIMER0? Debugger.MESSAGE.TIMER : (nIRQ == ChipSet.IRQ.KBD? Debugger.MESSAGE.KBD : (nIRQ == ChipSet.IRQ.FDC? Debugger.MESSAGE.FDC : 0))) | Debugger.MESSAGE.PIC; } if (this.dbg.messageEnabled(bitsMessage)) this.dbg.message(sMessage); } diff --git a/modules/pcjs/lib/cpu.js b/modules/pcjs/lib/cpu.js index 7a6dfceaa..2c9e39950 100644 --- a/modules/pcjs/lib/cpu.js +++ b/modules/pcjs/lib/cpu.js @@ -956,7 +956,7 @@ CPU.prototype.calcRemainingTime = function() this.aCounts.nCyclesRecalc += this.aCounts.nCyclesThisRun; if (DEBUG && this.dbg && this.dbg.messageEnabled(Debugger.MESSAGE.LOG) && msRemainsThisRun) { - this.dbg.message("calcRemainingTime: " + msRemainsThisRun + "ms to sleep after " + this.aCounts.msEndThisRun + "ms"); + this.log("calcRemainingTime: " + msRemainsThisRun + "ms to sleep after " + this.aCounts.msEndThisRun + "ms"); } this.aCounts.msEndThisRun += msRemainsThisRun; diff --git a/modules/pcjs/lib/debugger.js b/modules/pcjs/lib/debugger.js index 37b74e3a3..7ef370e4c 100644 --- a/modules/pcjs/lib/debugger.js +++ b/modules/pcjs/lib/debugger.js @@ -1738,7 +1738,7 @@ if (DEBUGGER) { { if (this.sMessagePrev && sMessage == this.sMessagePrev) return; - this.println(sMessage); // + " (" + this.cpu.getCycles() + " cycles)" + if (!SAMPLER) this.println(sMessage); // + " (" + this.cpu.getCycles() + " cycles)" this.sMessagePrev = sMessage; @@ -1931,7 +1931,7 @@ if (DEBUGGER) { */ Debugger.prototype.stopCPU = function(s) { - if (s) this.message(s); + if (s) this.println(s); this.cpu.stopCPU(); }; @@ -4138,7 +4138,7 @@ if (DEBUGGER) { if (sCategory !== undefined) { var bitsMessage = 0; if (sCategory == "all") { - bitsMessage = 0xffffffff & ~Debugger.MESSAGE.HALT; + bitsMessage = 0xffffffff & ~(Debugger.MESSAGE.HALT | Debugger.MESSAGE.LOG); sCategory = null; } else if (sCategory == "on") { fCriteria = true; diff --git a/modules/pcjs/lib/defines.js b/modules/pcjs/lib/defines.js index 73f93b52c..82af1a861 100644 --- a/modules/pcjs/lib/defines.js +++ b/modules/pcjs/lib/defines.js @@ -105,6 +105,13 @@ var FATARRAYS = false; */ var TYPEDARRAYS = false; // (typeof ArrayBuffer !== 'undefined'); +/** + * @define {boolean} + * + * Enable instruction sampling (work-in-progress). + */ +var SAMPLER = false; + if (typeof module !== 'undefined') { global.PCJSCLASS = PCJSCLASS; global.DEBUGGER = DEBUGGER; diff --git a/modules/pcjs/lib/fdc.js b/modules/pcjs/lib/fdc.js index de4c79f98..93b754c44 100644 --- a/modules/pcjs/lib/fdc.js +++ b/modules/pcjs/lib/fdc.js @@ -2183,7 +2183,7 @@ FDC.prototype.doRead = function(drive) */ drive.resCode = FDC.REG_DATA.RES.NOT_READY | FDC.REG_DATA.RES.INCOMPLETE; - if (DEBUG) this.messageDebugger("FDC.doRead(" + drive.bCylinder + ":" + drive.bHead + ":" + drive.bSector + ":" + drive.nBytes + ")"); + if (DEBUG) this.messageDebugger("FDC.doRead(" + drive.bCylinder + ":" + drive.bHead + ":" + drive.bSector + ":" + drive.nBytes + ")", Debugger.MESSAGE.OTHER); if (drive.disk) { drive.sector = null; @@ -2205,7 +2205,7 @@ FDC.prototype.doWrite = function(drive) { drive.resCode = FDC.REG_DATA.RES.NOT_READY | FDC.REG_DATA.RES.INCOMPLETE; - if (DEBUG) this.messageDebugger("FDC.doWrite(" + drive.bCylinder + ":" + drive.bHead + ":" + drive.bSector + ":" + drive.nBytes + ")"); + if (DEBUG) this.messageDebugger("FDC.doWrite(" + drive.bCylinder + ":" + drive.bHead + ":" + drive.bSector + ":" + drive.nBytes + ")", Debugger.MESSAGE.OTHER); if (drive.disk) { if (drive.disk.fWriteProtected) { diff --git a/modules/pcjs/lib/video.js b/modules/pcjs/lib/video.js index 86c6db8f6..7af4504fc 100644 --- a/modules/pcjs/lib/video.js +++ b/modules/pcjs/lib/video.js @@ -1766,7 +1766,7 @@ Card.prototype.dumpCard = function() } if (this.iCard == Video.CARDS.EGA) { - this.dbg.message(" ATCDATA: " + this.fATCData); + this.dbg.println(" ATCDATA: " + this.fATCData); this.dumpRegs(" ATC", this.iATCReg, this.aATCRegs, this.asATCRegs); this.dumpRegs(" GRC", this.iGRCReg, this.aGRCRegs, this.asGRCRegs); this.dumpRegs(" SEQ", this.iSEQReg, this.aSEQRegs, this.asSEQRegs); @@ -1774,8 +1774,8 @@ Card.prototype.dumpCard = function() this.dumpRegs(" MISC", this.miscReg); this.dumpRegs(" STATUS0", this.status0); this.dumpRegs(" LATCHES", this.latches); - this.dbg.message(" ACCESS: " + str.toHexWord(this.nAccess)); - this.dbg.message("Use 'dump video buffer' to dump video memory"); + this.dbg.println(" ACCESS: " + str.toHexWord(this.nAccess)); + this.dbg.println("Use 'dump video buffer' to dump video memory"); /* * There are few more EGA regs we could dump, like GRCPos1, GRCPos2, but does anyone care? */ @@ -1793,7 +1793,7 @@ Card.prototype.dumpBuffer = function(sParm) { if (DEBUGGER) { if (!this.adwMemory) { - this.dbg.message("no buffer"); + this.dbg.println("no buffer"); return; } var idw = str.parseInt(sParm); @@ -1809,7 +1809,7 @@ Card.prototype.dumpBuffer = function(sParm) if (sDump) sDump += "\n"; sDump += sData; } - if (sDump) this.dbg.message(sDump); + if (sDump) this.dbg.println(sDump); this.prevDump = idw; } }; @@ -1830,7 +1830,7 @@ Card.prototype.dumpRegs = function(sName, iReg, aRegs, asRegs) { if (DEBUGGER) { if (!aRegs) { - this.dbg.message(sName + ": " + str.toHexByte(iReg)); + this.dbg.println(sName + ": " + str.toHexByte(iReg)); return; } var s = "", i, cchMax = 0; @@ -1842,7 +1842,7 @@ Card.prototype.dumpRegs = function(sName, iReg, aRegs, asRegs) if (s) s += '\n'; s += sName + "[" + str.toHexByte(i) + "]: " + str.pad(asRegs[i], cchMax) + str.toHexByte(aRegs[i]) + (i === iReg? "*" : ""); } - this.dbg.message(s); + this.dbg.println(s); } }; @@ -4984,14 +4984,14 @@ Video.prototype.dumpVideo = function(sParm) { if (DEBUGGER) { if (!this.cardActive) { - this.dbg.message("no active video card"); + this.dbg.println("no active video card"); return; } if (sParm) { this.cardActive.dumpBuffer(sParm); return; } - this.dbg.message("BIOSMODE: " + str.toHexByte(this.nMode)); + this.dbg.println("BIOSMODE: " + str.toHexByte(this.nMode)); this.cardActive.dumpCard(); } }; diff --git a/modules/pcjs/lib/x86cpu.js b/modules/pcjs/lib/x86cpu.js index a5006d9f1..8d1d3335b 100644 --- a/modules/pcjs/lib/x86cpu.js +++ b/modules/pcjs/lib/x86cpu.js @@ -158,6 +158,20 @@ function X86CPU(parmsCPU) { */ this.setMemoryEnabled(); + if (SAMPLER) { + /* + * For now, we're just going to sample EIP values + */ + this.nSamples = 50000; + this.nSampleFreq = 1; + this.nSampleSkip = 3183300; + this.aSamples = new Array(this.nSamples); + for (var i = 0; i < this.nSamples; i++) this.aSamples[i] = -1; + this.iSampleNext = 0; + this.iSampleFreq = 0; + this.iSampleSkip = 0; + } + /* * This initial resetRegs() call is important to create all the registers (eg, the X86Seg registers), * so that if/when we call restore(), it will have something to fill in. @@ -741,6 +755,12 @@ X86CPU.prototype.reset = function() this.resetRegs(); this.resetCycles(); this.clearError(); // clear any fatal error/exception that setError() may have flagged + + if (SAMPLER) { + this.iSampleNext = 0; + this.iSampleFreq = 0; + this.iSampleSkip = 0; + } }; /** @@ -2526,6 +2546,35 @@ X86CPU.prototype.stepCPU = function(nMinCycles) fDebugSkip = false; } + if (SAMPLER) { + if (++this.iSampleFreq >= this.nSampleFreq) { + this.iSampleFreq = 0; + if (this.iSampleSkip < this.nSampleSkip) { + this.iSampleSkip++ + } else { + if (this.iSampleNext == this.nSamples) { + this.println("sample buffer full"); + this.stopCPU(); + break; + } + var n = this.aSamples[this.iSampleNext]; + if (n !== -1) { + if (n !== this.regEIP) { + this.println("sample deviation at index " + this.iSampleNext + ": current EIP=" + str.toHex(this.regEIP) + ", target EIP=" + str.toHex(n)); + this.stopCPU(); + break; + } + } else { + this.aSamples[this.iSampleNext] = this.regEIP; + } + if (this.iSampleNext == 112) { + fDebugSkip = false; // just some no-op statement we can set a breakpoint on + } + this.iSampleNext++; + } + } + } + this.opFlags = 0; if (DEBUG || PREFETCH) {