diff --git a/modules/c1pjs/lib/cpu.js b/modules/c1pjs/lib/cpu.js index 3923147ff..d515d4a7c 100644 --- a/modules/c1pjs/lib/cpu.js +++ b/modules/c1pjs/lib/cpu.js @@ -57,8 +57,8 @@ function C1PCPU(parmsCPU) Component.call(this, "C1PCPU", parmsCPU); this.clearRegs(); - this.aFlags.fPowered = false; - this.aFlags.fRunning = false; + this.bitField.fPowered = false; + this.bitField.fRunning = false; this.fAutoStart = parmsCPU["autoStart"]; /* @@ -482,8 +482,9 @@ Component.subclass(Component, C1PCPU); */ C1PCPU.prototype.reset = function(fPowerOn) { - if (this.aFlags.fRunning) + if (this.bitField.fRunning) { this.halt(); + } this.clearRegs(); this.regPC = this.getWord(this.VECTOR_RESET); this.clearError(); // clear any fatal error/exception @@ -515,10 +516,11 @@ C1PCPU.prototype.setBinding = function(sHTMLType, sBinding, control) this.bindings[sBinding] = control; control.onclick = function(cpu) { return function() { - if (!cpu.aFlags.fRunning) + if (!cpu.bitField.fRunning) { cpu.run(); - else + } else { cpu.halt(); + } }; }(this); fBound = true; @@ -578,7 +580,7 @@ C1PCPU.prototype.setBuffer = function(abMemory, start, end) */ C1PCPU.prototype.setPower = function(fOn, cmp) { - if (fOn && !this.aFlags.fPowered) { + if (fOn && !this.bitField.fPowered) { this.cmp = cmp; /* * Attach the Debugger, if any, to the CPU, so that the CPU can periodically @@ -606,7 +608,7 @@ C1PCPU.prototype.setPower = function(fOn, cmp) }; }(video); } - this.aFlags.fPowered = true; + this.bitField.fPowered = true; this.reset(true); this.update(); } @@ -879,7 +881,7 @@ C1PCPU.prototype.displayStatus = function() */ C1PCPU.prototype.isRunning = function() { - return this.aFlags.fRunning; + return this.bitField.fRunning; }; /** @@ -1050,7 +1052,7 @@ C1PCPU.prototype.run = function() if (this.cmp) this.cmp.stop(this.msRunStart, this.nRunCycles); return; } - if (!this.aFlags.fRunning) { + if (!this.bitField.fRunning) { /* * setSpeed() without a speed parameter leaves the selected speed in place, but also resets the * cycle counter and timestamp for the current series of run() calls, calculates the maximum number @@ -1059,7 +1061,7 @@ C1PCPU.prototype.run = function() */ this.setSpeed(); if (this.cmp) this.cmp.start(); - this.aFlags.fRunning = true; + this.bitField.fRunning = true; if (this.bindings["run"]) this.bindings["run"].innerHTML = "Halt"; this.setFocus(); } @@ -1106,7 +1108,7 @@ C1PCPU.prototype.run = function() this.nCyclesNextYield += this.nCyclesPerYield; break; } - } while (this.aFlags.fRunning); + } while (this.bitField.fRunning); } catch (e) { this.halt(); @@ -1267,8 +1269,8 @@ C1PCPU.prototype.halt = function() this.isBusy(true); this.nBurstCycles -= this.nStepCycles; this.nStepCycles = 0; - if (this.aFlags.fRunning) { - this.aFlags.fRunning = false; + if (this.bitField.fRunning) { + this.bitField.fRunning = false; if (this.bindings["run"]) this.bindings["run"].innerHTML = "Run"; } }; @@ -1302,7 +1304,7 @@ C1PCPU.prototype.update = function() */ C1PCPU.prototype.getCycles = function() { - return (this.aFlags.fRunning? this.nRunCycles + this.nBurstCycles - this.nStepCycles : 0); + return (this.bitField.fRunning? this.nRunCycles + this.nBurstCycles - this.nStepCycles : 0); }; /** diff --git a/modules/c1pjs/lib/debugger.js b/modules/c1pjs/lib/debugger.js index ca69f73ff..347dff4be 100644 --- a/modules/c1pjs/lib/debugger.js +++ b/modules/c1pjs/lib/debugger.js @@ -578,8 +578,8 @@ if (DEBUGGER) { */ C1PDebugger.prototype.setPower = function(fOn, cmp) { - if (fOn && !this.aFlags.fPowered) { - this.aFlags.fPowered = true; + if (fOn && !this.bitField.fPowered) { + this.bitField.fPowered = true; this.cpu = cmp.getComponentByType("cpu"); } }; diff --git a/modules/c1pjs/lib/disk.js b/modules/c1pjs/lib/disk.js index 31e1118f1..2d4b3ede7 100644 --- a/modules/c1pjs/lib/disk.js +++ b/modules/c1pjs/lib/disk.js @@ -217,7 +217,7 @@ function C1PDiskController(parmsDC) { Component.call(this, "C1PDiskController", parmsDC); - this.aFlags.fPowered = false; + this.bitField.fPowered = false; /* * Our DiskController simulates the combination of an MC6820 PIA and an MC6850 ACIA. @@ -735,8 +735,8 @@ C1PDiskController.prototype.setBuffer = function(abMemory, start, end, cpu) */ C1PDiskController.prototype.setPower = function(fOn, cmp) { - if (fOn && !this.aFlags.fPowered) { - this.aFlags.fPowered = true; + if (fOn && !this.bitField.fPowered) { + this.bitField.fPowered = true; if (DEBUGGER) this.dbg = cmp.getComponentByType("debugger"); } }; diff --git a/modules/c1pjs/lib/keyboard.js b/modules/c1pjs/lib/keyboard.js index f74e7d0f6..1786ad548 100644 --- a/modules/c1pjs/lib/keyboard.js +++ b/modules/c1pjs/lib/keyboard.js @@ -122,7 +122,7 @@ function C1PKeyboard(parmsKbd) { Component.call(this, "C1PKeyboard", parmsKbd); - this.aFlags.fPowered = false; + this.bitField.fPowered = false; this.nDefaultModel = parmsKbd['model']; /* @@ -515,8 +515,8 @@ C1PKeyboard.prototype.setModel = function(nModel) */ C1PKeyboard.prototype.setPower = function(fOn, cmp) { - if (fOn && !this.aFlags.fPowered) { - this.aFlags.fPowered = true; + if (fOn && !this.bitField.fPowered) { + this.bitField.fPowered = true; this.cmp = cmp; if (DEBUGGER) this.dbg = cmp.getComponentByType("debugger"); } diff --git a/modules/c1pjs/lib/panel.js b/modules/c1pjs/lib/panel.js index 8e15a0791..d087b32e2 100644 --- a/modules/c1pjs/lib/panel.js +++ b/modules/c1pjs/lib/panel.js @@ -44,7 +44,7 @@ function C1PPanel(parmsPanel) { Component.call(this, "C1PPanel", parmsPanel); - this.aFlags.fPowered = false; + this.bitField.fPowered = false; } Component.subclass(Component, C1PPanel); @@ -76,8 +76,8 @@ C1PPanel.prototype.setBinding = function(sHTMLType, sBinding, control) */ C1PPanel.prototype.setPower = function(fOn, cmp) { - if (fOn && !this.aFlags.fPowered) { - this.aFlags.fPowered = true; + if (fOn && !this.bitField.fPowered) { + this.bitField.fPowered = true; this.cmp = cmp; this.cpu = cmp.getComponentByType("cpu"); this.kbd = cmp.getComponentByType("keyboard"); diff --git a/modules/c1pjs/lib/rom.js b/modules/c1pjs/lib/rom.js index dc9fa01e0..e50e3e4d9 100644 --- a/modules/c1pjs/lib/rom.js +++ b/modules/c1pjs/lib/rom.js @@ -108,8 +108,8 @@ C1PROM.prototype.setBuffer = function(abMemory, start, end, cpu) */ C1PROM.prototype.setPower = function(fOn, cmp) { - if (fOn && !this.aFlags.fPowered) { - this.aFlags.fPowered = true; + if (fOn && !this.bitField.fPowered) { + this.bitField.fPowered = true; if (DEBUGGER) this.dbg = cmp.getComponentByType("debugger"); } }; diff --git a/modules/c1pjs/lib/serial.js b/modules/c1pjs/lib/serial.js index d7fea809b..7965aa819 100644 --- a/modules/c1pjs/lib/serial.js +++ b/modules/c1pjs/lib/serial.js @@ -44,7 +44,7 @@ function C1PSerialPort(parmsSerial) { Component.call(this, "C1PSerialPort", parmsSerial); - this.aFlags.fPowered = false; + this.bitField.fPowered = false; this.fDemo = parmsSerial['demo']; this.STATUS_NONE = 0x00; @@ -202,8 +202,8 @@ C1PSerialPort.prototype.setBuffer = function(abMemory, start, end, cpu) */ C1PSerialPort.prototype.setPower = function(fOn, cmp) { - if (fOn && !this.aFlags.fPowered) { - this.aFlags.fPowered = true; + if (fOn && !this.bitField.fPowered) { + this.bitField.fPowered = true; this.cmp = cmp; this.kbd = cmp.getComponentByType("keyboard"); if (DEBUGGER) this.dbg = cmp.getComponentByType("debugger"); diff --git a/modules/c1pjs/lib/video.js b/modules/c1pjs/lib/video.js index 9ac99ce46..0b9784e19 100644 --- a/modules/c1pjs/lib/video.js +++ b/modules/c1pjs/lib/video.js @@ -307,8 +307,8 @@ C1PVideo.prototype.setPower = function(fOn, cmp) * it ourselves, too. This also means that updateScreen() need check only fPower and not isReady(), * since we guarantee that the former implies the latter. */ - if (fOn && !this.aFlags.fPowered && this.isReady()) { - this.aFlags.fPowered = true; + if (fOn && !this.bitField.fPowered && this.isReady()) { + this.bitField.fPowered = true; if (DEBUGGER) this.dbg = cmp.getComponentByType("debugger"); /* * If we have an associated keyboard, then ensure that the keyboard will be notified whenever @@ -327,8 +327,8 @@ C1PVideo.prototype.setPower = function(fOn, cmp) } } else - if (!fOn && this.aFlags.fPowered) { - this.aFlags.fPowered = false; + if (!fOn && this.bitField.fPowered) { + this.bitField.fPowered = false; /* * This is where we would add some method of blanking the display, without the disturbing the video * buffer contents, and blocking all further updates to the display. @@ -441,7 +441,7 @@ C1PVideo.prototype.initScreen = function() C1PVideo.prototype.updateScreen = function() { var offset = 0; - if (this.aFlags.fPowered) { + if (this.bitField.fPowered) { while (offset < this.cbScreen) { var b = this.abMem[this.offVideo + offset]; if (this.abScreen[offset] != b) { diff --git a/modules/pcjs/lib/computer.js b/modules/pcjs/lib/computer.js index 50b17941c..1b2bc818e 100644 --- a/modules/pcjs/lib/computer.js +++ b/modules/pcjs/lib/computer.js @@ -124,7 +124,7 @@ function Computer(parmsComputer, parmsMachine, fSuspended) { Component.call(this, "Computer", parmsComputer, Computer); - this.aFlags.fPowered = false; + this.bitField.fPowered = false; this.nBusWidth = parmsComputer['buswidth']; this.resume = Computer.RESUME_NONE; this.sStateData = null; @@ -537,9 +537,9 @@ Computer.prototype.powerOn = function(resume) */ Computer.prototype.powerRestore = function(component, stateComputer, fRepower, fRestore) { - if (!component.aFlags.fPowered) { + if (!component.bitField.fPowered) { - component.aFlags.fPowered = true; + component.bitField.fPowered = true; if (component.powerUp) { @@ -642,9 +642,9 @@ Computer.prototype.donePowerOn = function(aParms) var fRepower = (aParms[1] < 0); var fRestore = aParms[2]; - if (DEBUG && this.aFlags.fPowered) this.messageDebugger("Computer.donePowerOn(): redundant"); + if (DEBUG && this.bitField.fPowered) this.messageDebugger("Computer.donePowerOn(): redundant"); - this.aFlags.fPowered = true; + this.bitField.fPowered = true; if (!this.fInitialized) { this.println(Computer.sAppName + " v" + Computer.sAppVer + "\n" + Computer.sCopyright + "\n" + Computer.LICENSE); @@ -747,7 +747,7 @@ Computer.prototype.powerOff = function(fSave, fShutdown) data = this.cpu.powerDown(fSave, fShutdown); if (typeof data === "object") stateComputer.set(this.cpu.id, data); if (fShutdown) { - this.cpu.aFlags.fPowered = false; + this.cpu.bitField.fPowered = false; if (data === false) sState = null; } } @@ -755,13 +755,13 @@ Computer.prototype.powerOff = function(fSave, fShutdown) var aComponents = Component.getComponents(this.id); for (var iComponent = 0; iComponent < aComponents.length; iComponent++) { var component = aComponents[iComponent]; - if (component.aFlags.fPowered) { + if (component.bitField.fPowered) { if (component.powerDown) { data = component.powerDown(fSave, fShutdown); if (typeof data === "object") stateComputer.set(component.id, data); } if (fShutdown) { - component.aFlags.fPowered = false; + component.bitField.fPowered = false; if (data === false) sState = null; } } @@ -813,7 +813,7 @@ Computer.prototype.powerOff = function(fSave, fShutdown) } } - if (fShutdown) this.aFlags.fPowered = false; + if (fShutdown) this.bitField.fPowered = false; return sState; }; @@ -1213,7 +1213,7 @@ Computer.init = function() */ var computer = new Computer(parmsComputer, parmsMachine, true); - if (DEBUG) computer.messageDebugger("onInit(" + computer.aFlags.fPowered + ")"); + if (DEBUG) computer.messageDebugger("onInit(" + computer.bitField.fPowered + ")"); /* * For now, all we support are "reset" and "save" buttons. We may eventually add a "power" @@ -1243,9 +1243,9 @@ Computer.show = function() var computer = Component.getComponentByType("Computer", parmsComputer['id']); if (computer) { - if (DEBUG) computer.messageDebugger("onShow(" + computer.fInitialized + "," + computer.aFlags.fPowered + ")"); + if (DEBUG) computer.messageDebugger("onShow(" + computer.fInitialized + "," + computer.bitField.fPowered + ")"); - if (computer.fInitialized && !computer.aFlags.fPowered) { + if (computer.fInitialized && !computer.bitField.fPowered) { /** * Repower the computer, notifying every component to continue running as-is. */ @@ -1290,9 +1290,9 @@ Computer.exit = function() var computer = Component.getComponentByType("Computer", parmsComputer['id']); if (computer) { - if (DEBUG) computer.messageDebugger("onExit(" + computer.aFlags.fPowered + ")"); + if (DEBUG) computer.messageDebugger("onExit(" + computer.bitField.fPowered + ")"); - if (computer.aFlags.fPowered) { + if (computer.bitField.fPowered) { /** * Power "down" the computer, giving every component an opportunity to save its state, * but only if 'resume' has been set AND there is no valid resume path (because if a valid resume diff --git a/modules/pcjs/lib/cpu.js b/modules/pcjs/lib/cpu.js index 0aaf03af6..5641494be 100644 --- a/modules/pcjs/lib/cpu.js +++ b/modules/pcjs/lib/cpu.js @@ -96,15 +96,15 @@ function CPU(parmsCPU, nCyclesDefault) */ this.aCounts.mhzTarget = this.aCounts.mhzDefault * this.aCounts.nCyclesMultiplier; - this.aFlags.fPowered = false; - this.aFlags.fRunning = false; - this.aFlags.fStarting = false; - this.aFlags.fAutoStart = parmsCPU['autoStart']; + this.bitField.fPowered = false; + this.bitField.fRunning = false; + this.bitField.fStarting = false; + this.bitField.fAutoStart = parmsCPU['autoStart']; /* * TODO: Add some UI for fDisplayLiveRegs (either an XML property, or a UI checkbox, or both) */ - this.aFlags.fDisplayLiveRegs = false; + this.bitField.fDisplayLiveRegs = false; /* * Provide a power-saving URL-based way of overriding the 'autostart' setting; @@ -113,7 +113,7 @@ function CPU(parmsCPU, nCyclesDefault) */ var sAutoStart = Component.parmsURL['autostart']; if (sAutoStart !== undefined) { - this.aFlags.fAutoStart = (sAutoStart == "true"? true : (sAutoStart == "false"? false : null)); + this.bitField.fAutoStart = (sAutoStart == "true"? true : (sAutoStart == "false"? false : null)); } /* @@ -125,7 +125,7 @@ function CPU(parmsCPU, nCyclesDefault) * command ("x"); for example, "x cs int 5000" will set nCyclesChecksumInterval to 5000 * and call resetChecksum(). */ - this.aFlags.fChecksum = false; + this.bitField.fChecksum = false; this.aCounts.nChecksum = this.aCounts.nCyclesChecksumNext = 0; this.aCounts.nCyclesChecksumStart = parmsCPU["csStart"]; this.aCounts.nCyclesChecksumInterval = parmsCPU["csInterval"]; @@ -272,7 +272,7 @@ CPU.prototype.powerUp = function(data, fRepower) this.println("No debugger detected"); } } - this.aFlags.fPowered = true; + this.bitField.fPowered = true; if (!this.autoStart() && this.dbg) this.dbg.updateStatus(); this.updateCPU(); return true; @@ -287,7 +287,7 @@ CPU.prototype.powerUp = function(data, fRepower) */ CPU.prototype.powerDown = function(fSave) { - this.aFlags.fPowered = false; + this.bitField.fPowered = false; return fSave && this.save ? this.save() : true; }; @@ -299,7 +299,7 @@ CPU.prototype.powerDown = function(fSave) */ CPU.prototype.autoStart = function() { - if (this.aFlags.fAutoStart === true || this.aFlags.fAutoStart === null && (!DEBUGGER || !this.dbg) && this.bindings["run"] === undefined) { + if (this.bitField.fAutoStart === true || this.bitField.fAutoStart === null && (!DEBUGGER || !this.dbg) && this.bindings["run"] === undefined) { this.runCPU(); // start running automatically on power-up, assuming there's no Debugger return true; } @@ -326,7 +326,7 @@ CPU.prototype.setFocus = function() */ CPU.prototype.isPowered = function() { - if (!this.aFlags.fPowered) { + if (!this.bitField.fPowered) { this.println(this.toString() + " not powered"); return false; } @@ -341,7 +341,7 @@ CPU.prototype.isPowered = function() */ CPU.prototype.isRunning = function() { - return this.aFlags.fRunning; + return this.bitField.fRunning; }; /** @@ -372,8 +372,8 @@ CPU.prototype.resetChecksum = function() if (this.aCounts.nCyclesChecksumStart === undefined) this.aCounts.nCyclesChecksumStart = 0; if (this.aCounts.nCyclesChecksumInterval === undefined) this.aCounts.nCyclesChecksumInterval = -1; if (this.aCounts.nCyclesChecksumStop === undefined) this.aCounts.nCyclesChecksumStop = -1; - this.aFlags.fChecksum = (this.aCounts.nCyclesChecksumStart >= 0 && this.aCounts.nCyclesChecksumInterval > 0); - if (this.aFlags.fChecksum) { + this.bitField.fChecksum = (this.aCounts.nCyclesChecksumStart >= 0 && this.aCounts.nCyclesChecksumInterval > 0); + if (this.bitField.fChecksum) { this.aCounts.nChecksum = 0; this.aCounts.nCyclesChecksumNext = this.aCounts.nCyclesChecksumStart - this.nTotalCycles; // this.aCounts.nCyclesChecksumNext = this.aCounts.nCyclesChecksumStart + this.aCounts.nCyclesChecksumInterval - (this.nTotalCycles % this.aCounts.nCyclesChecksumInterval); @@ -395,7 +395,7 @@ CPU.prototype.resetChecksum = function() */ CPU.prototype.updateChecksum = function(nCycles) { - if (this.aFlags.fChecksum) { + if (this.bitField.fChecksum) { /* * Get a 32-bit summation of the current CPU state and add it to our running 32-bit checksum */ @@ -449,7 +449,7 @@ CPU.prototype.displayReg = function(sReg, nVal, cch) this.stopCPU(); } var sVal; - if (!this.aFlags.fRunning || this.aFlags.fDisplayLiveRegs) { + if (!this.bitField.fRunning || this.bitField.fDisplayLiveRegs) { sVal = str.toHex(nVal, cch); } else { sVal = "----".substr(0, cch); @@ -505,7 +505,7 @@ CPU.prototype.setBinding = function(sHTMLType, sBinding, control) case "run": this.bindings[sBinding] = control; control.onclick = function onClickRun() { - if (!cpu.aFlags.fRunning) + if (!cpu.bitField.fRunning) cpu.runCPU(true); else cpu.stopCPU(true); @@ -559,7 +559,7 @@ CPU.prototype.setBinding = function(sHTMLType, sBinding, control) */ CPU.prototype.setBurstCycles = function(nCycles) { - if (this.aFlags.fRunning) { + if (this.bitField.fRunning) { var nDelta = this.nStepCycles - nCycles; /* * NOTE: If nDelta is negative, we will actually be increasing nStepCycles and nBurstCycles. @@ -744,7 +744,7 @@ CPU.prototype.getSpeedCurrent = function() { /* * TODO: Has toFixed() been "fixed" in all browsers (eg, IE) to return a rounded value now? */ - return ((this.aFlags.fRunning && this.aCounts.mhz)? (this.aCounts.mhz.toFixed(2) + "Mhz") : "Stopped"); + return ((this.bitField.fRunning && this.aCounts.mhz)? (this.aCounts.mhz.toFixed(2) + "Mhz") : "Stopped"); }; /** @@ -967,7 +967,7 @@ CPU.prototype.runCPU = function(fOnClick) this.calcStartTime(); try { do { - var nCyclesPerBurst = (this.aFlags.fChecksum? 1 : this.aCounts.nCyclesPerBurst); + var nCyclesPerBurst = (this.bitField.fChecksum? 1 : this.aCounts.nCyclesPerBurst); if (this.chipset) { this.chipset.updateAllTimers(); @@ -1009,7 +1009,7 @@ CPU.prototype.runCPU = function(fOnClick) this.aCounts.nCyclesNextYield += this.aCounts.nCyclesPerYield; break; } - } while (this.aFlags.fRunning); + } while (this.bitField.fRunning); } catch (e) { this.stopCPU(); @@ -1031,7 +1031,7 @@ CPU.prototype.runCPU = function(fOnClick) */ CPU.prototype.startCPU = function(fSetFocus) { - if (!this.aFlags.fRunning) { + if (!this.bitField.fRunning) { /* * setSpeed() without a speed parameter leaves the selected speed in place, but also resets the * cycle counter and timestamp for the current series of runCPU() calls, calculates the maximum number @@ -1040,8 +1040,8 @@ CPU.prototype.startCPU = function(fSetFocus) */ this.setSpeed(); if (this.cmp) this.cmp.start(this.aCounts.msStartRun, this.getCycles()); - this.aFlags.fRunning = true; - this.aFlags.fStarting = true; + this.bitField.fRunning = true; + this.bitField.fStarting = true; if (this.chipset) this.chipset.setSpeaker(); var controlRun = this.bindings["run"]; if (controlRun) controlRun.textContent = "Halt"; @@ -1082,13 +1082,13 @@ CPU.prototype.stopCPU = function(fComplete) this.nStepCycles = 0; this.addCycles(this.nRunCycles); this.nRunCycles = 0; - if (this.aFlags.fRunning) { - this.aFlags.fRunning = false; + if (this.bitField.fRunning) { + this.bitField.fRunning = false; if (this.chipset) this.chipset.setSpeaker(); var controlRun = this.bindings["run"]; if (controlRun) controlRun.textContent = "Run"; } - this.aFlags.fComplete = fComplete; + this.bitField.fComplete = fComplete; }; /** diff --git a/modules/pcjs/lib/debugger.js b/modules/pcjs/lib/debugger.js index 341d11b39..a3817040c 100644 --- a/modules/pcjs/lib/debugger.js +++ b/modules/pcjs/lib/debugger.js @@ -2051,8 +2051,8 @@ if (DEBUGGER) { * it here, so that if the CPU is reset while running, we can prevent stop() * from unnecessarily dumping the CPU state. */ - if (this.aFlags.fRunning !== undefined && !fQuiet) this.println("reset"); - this.aFlags.fRunning = false; + if (this.bitField.fRunning !== undefined && !fQuiet) this.println("reset"); + this.bitField.fRunning = false; this.clearTempBreakpoint(); if (!fQuiet) this.updateStatus(); }; @@ -2119,7 +2119,7 @@ if (DEBUGGER) { Debugger.prototype.start = function(ms, nCycles) { if (!this.fProcStep) this.println("running"); - this.aFlags.fRunning = true; + this.bitField.fRunning = true; this.msStart = ms; this.nCyclesStart = nCycles; }; @@ -2135,8 +2135,8 @@ if (DEBUGGER) { */ Debugger.prototype.stop = function(ms, nCycles) { - if (this.aFlags.fRunning) { - this.aFlags.fRunning = false; + if (this.bitField.fRunning) { + this.bitField.fRunning = false; this.nCycles = nCycles - this.nCyclesStart; if (!this.fProcStep) { var sStopped = "stopped"; @@ -2855,7 +2855,7 @@ if (DEBUGGER) { sLine += " "; sLine = sLine.substr(0, 50); sLine += ";"; - if (!this.cpu.aFlags.fChecksum) { + if (!this.cpu.bitField.fChecksum) { sLine += sComment + (nSequence != null? '=' + nSequence.toString() : ""); } else { var nCycles = this.cpu.getCycles(); @@ -3862,7 +3862,7 @@ if (DEBUGGER) { */ Debugger.prototype.doHalt = function(sCount) { - if (this.aFlags.fRunning && sCount === undefined) { + if (this.bitField.fRunning && sCount === undefined) { this.cpu.stopCPU(); return; } @@ -4262,7 +4262,7 @@ if (DEBUGGER) { if (nCycles !== undefined) { this.cpu.resetChecksum(); } - this.println("checksums " + (this.cpu.aFlags.fChecksum? "enabled" : "disabled")); + this.println("checksums " + (this.cpu.bitField.fChecksum? "enabled" : "disabled")); break; case "sp": if (asArgs[2] !== undefined) { diff --git a/modules/pcjs/lib/disk.js b/modules/pcjs/lib/disk.js index 8a7ce7c47..e9468ff6c 100644 --- a/modules/pcjs/lib/disk.js +++ b/modules/pcjs/lib/disk.js @@ -652,7 +652,7 @@ Disk.prototype.doneLoad = function(sDiskFile, sDiskData, nErrorCode, sDiskPath) { var disk = null; this.fWriteProtected = false; - var fPrintOnly = (nErrorCode < 0 && this.cmp && !this.cmp.aFlags.fPowered); + var fPrintOnly = (nErrorCode < 0 && this.cmp && !this.cmp.bitField.fPowered); if (this.fOnDemand) { if (!nErrorCode) { diff --git a/modules/pcjs/lib/video.js b/modules/pcjs/lib/video.js index 7af4504fc..4a0056641 100644 --- a/modules/pcjs/lib/video.js +++ b/modules/pcjs/lib/video.js @@ -3905,7 +3905,7 @@ Video.prototype.updateScreen = function(fForce) /* * The Computer component maintains the fPowered setting on our behalf, so we use it. */ - if (!this.aFlags.fPowered) return; + if (!this.bitField.fPowered) return; /* * If the card's video signal is disabled (eg, during a mode change), then skip the update, diff --git a/modules/pcjs/lib/x86.js b/modules/pcjs/lib/x86.js index 501c5cb4a..8730c1444 100644 --- a/modules/pcjs/lib/x86.js +++ b/modules/pcjs/lib/x86.js @@ -120,7 +120,7 @@ var X86 = { DATA_EXPDOWN_WRITABLE: 0x1600, CODE_EXECONLY: 0x1800, CODE_READABLE: 0x1a00, - CODE_CONFORMING_EXECONLY: 0x1c00, + CODE_CONFORMING: 0x1c00, CODE_CONFORMING_READABLE: 0x1e00 }, DPL: { diff --git a/modules/pcjs/lib/x86cpu.js b/modules/pcjs/lib/x86cpu.js index 6980e9704..fd48499ed 100644 --- a/modules/pcjs/lib/x86cpu.js +++ b/modules/pcjs/lib/x86cpu.js @@ -144,7 +144,7 @@ function X86CPU(parmsCPU) { * stepCPU() call, but it's good form to do so. */ this.nBurstCycles = 0; - this.aFlags.fComplete = this.aFlags.fDebugCheck = false; + this.bitField.fComplete = this.bitField.fDebugCheck = false; /* * We're just declaring aMemBlocks and associated Bus parameters here; they'll be initialized by initMemory() @@ -751,7 +751,7 @@ X86CPU.prototype.initProcessor = function() */ X86CPU.prototype.reset = function() { - if (this.aFlags.fRunning) this.stopCPU(); + if (this.bitField.fRunning) this.stopCPU(); this.resetRegs(); this.resetCycles(); this.clearError(); // clear any fatal error/exception that setError() may have flagged @@ -813,7 +813,6 @@ X86CPU.prototype.resetRegs = function() */ this.regMSW = X86.MSW.SET; this.addrIDT = 0; this.addrIDTLimit = 0x03FF; - this.descIDT = {off: 0, sel: 0, acc: 0, maskPS: 0}; this.nIOPL = 0; // this should be set before the first setPS() call /* @@ -966,7 +965,7 @@ X86CPU.prototype.checkIntNotify = function(nInt) * The enabling of MESSAGE_INT messages is one of the criteria that's also included in the Debugger's * checksEnabled() function, and therefore in fDebugCheck, so for maximum speed, we check fDebugCheck first. */ - if (DEBUGGER && this.aFlags.fDebugCheck) { + if (DEBUGGER && this.bitField.fDebugCheck) { if (this.dbg.messageEnabled(Debugger.MESSAGE.INT) && this.dbg.messageInt(nInt, this.regEIP)) { this.addIntReturn(this.regEIP, function(cpu, nCycles) { return function onIntReturn(nLevel) { @@ -1040,10 +1039,10 @@ X86CPU.prototype.setProtMode = function(fProt) fProt = !!(this.regMSW & X86.MSW.PE); } this.aOpGrp6 = (fProt? X86Op0F.aOpGrp6Prot : X86Op0F.aOpGrp6Real); - this.segCS.updateAccess(fProt); - this.segDS.updateAccess(fProt); - this.segSS.updateAccess(fProt); - this.segES.updateAccess(fProt); + this.segCS.updateMode(fProt); + this.segDS.updateMode(fProt); + this.segSS.updateMode(fProt); + this.segES.updateMode(fProt); }; /** @@ -2389,7 +2388,7 @@ X86CPU.prototype.delayINTR = function() */ X86CPU.prototype.displayStatus = function(fForce) { - if (fForce || !this.aFlags.fRunning || this.aFlags.fDisplayLiveRegs) { + if (fForce || !this.bitField.fRunning || this.bitField.fDisplayLiveRegs) { this.displayReg("AX", this.regAX); this.displayReg("BX", this.regBX); this.displayReg("CX", this.regCX); @@ -2452,12 +2451,12 @@ X86CPU.prototype.stepCPU = function(nMinCycles) * Debugger is single-stepping (even when performing multiple single-steps), fRunning is never set, * so stopCPU() would have no effect as far as the Debugger is concerned. */ - this.aFlags.fComplete = true; + this.bitField.fComplete = true; /* * fDebugCheck is true if we need to "check" every instruction with the Debugger. */ - var fDebugCheck = this.aFlags.fDebugCheck = (DEBUGGER && this.dbg && this.dbg.checksEnabled()); + var fDebugCheck = this.bitField.fDebugCheck = (DEBUGGER && this.dbg && this.dbg.checksEnabled()); /* * fDebugSkip is checked only when fDebugCheck is true, and its sole purpose is to tell the first call @@ -2467,8 +2466,8 @@ X86CPU.prototype.stepCPU = function(nMinCycles) * Once we snap fStarting, we clear it, because technically, we've moved beyond "starting" and have officially * "started" now. */ - var fDebugSkip = this.aFlags.fStarting || !nMinCycles; - this.aFlags.fStarting = false; + var fDebugSkip = this.bitField.fStarting || !nMinCycles; + this.bitField.fStarting = false; /* * We move the minimum cycle count to nStepCycles (the number of cycles left to step), so that other @@ -2609,7 +2608,7 @@ X86CPU.prototype.stepCPU = function(nMinCycles) /* * Make sure that every instruction is assessing a cycle cost, and that the cost is a net positive. */ - if (this.aFlags.fComplete && this.nStepCycles >= this.nSnapCycles && !(this.opFlags & X86.OPFLAG.PREFIXES)) { + if (this.bitField.fComplete && this.nStepCycles >= this.nSnapCycles && !(this.opFlags & X86.OPFLAG.PREFIXES)) { this.println("cycle miscount: " + (this.nSnapCycles - this.nStepCycles)); this.setIP(this.opEA - this.segCS.base); this.stopCPU(); @@ -2619,7 +2618,7 @@ X86CPU.prototype.stepCPU = function(nMinCycles) } while (this.nStepCycles > 0); - return (this.aFlags.fComplete? this.nBurstCycles - this.nStepCycles : (this.aFlags.fComplete === undefined? 0 : -1)); + return (this.bitField.fComplete? this.nBurstCycles - this.nStepCycles : (this.bitField.fComplete === undefined? 0 : -1)); }; /** diff --git a/modules/pcjs/lib/x86help.js b/modules/pcjs/lib/x86help.js index 511fe560b..d79470551 100644 --- a/modules/pcjs/lib/x86help.js +++ b/modules/pcjs/lib/x86help.js @@ -305,7 +305,7 @@ var X86Help = { * are there any other instructions that were, um, less explicit but also require a non-null selector? */ if ((src & X86.SEL.MASK) && this.segVER.load(src, true) != null) { - var fConforming = ((this.segVER.acc & X86.DESC.ACC.TYPE.CODE_CONFORMING_EXECONLY) == X86.DESC.ACC.TYPE.CODE_CONFORMING_EXECONLY); + var fConforming = ((this.segVER.acc & X86.DESC.ACC.TYPE.CODE_CONFORMING) == X86.DESC.ACC.TYPE.CODE_CONFORMING); if ((fConforming || this.segVER.dpl >= this.segCS.cpl) && this.segVER.dpl >= (src & X86.SEL.RPL)) { this.setZF(); return this.segVER.limit; @@ -453,18 +453,6 @@ var X86Help = { this.pushWord(regIP); } }, - /** - * opHelpDIVOverflow() - * - * @this {X86CPU} - */ - opHelpDIVOverflow: function() { - this.setIP(this.opEA - this.segCS.base); - /* - * TODO: Determine the proper cycle cost. - */ - X86Help.opHelpINT.call(this, X86.EXCEPTION.DIV_ERR, null, 2); - }, /** * opHelpINT(nIDT, nError, nCycles) * @@ -478,6 +466,7 @@ var X86Help = { * TODO: We assess the cycle cost up front, because otherwise, if loadIDT() fails, no cost may be assessed. */ this.nStepCycles -= this.CYCLES.nOpCyclesInt + nCycles; + this.segCS.fCall = true; var regPS = this.getPS(); var regCS = this.segCS.sel; var regIP = this.regIP; @@ -490,17 +479,6 @@ var X86Help = { if (nError != null) this.pushWord(nError); this.nFault = -1; } - /* - if (X86Help.opHelpLoadIDT.call(this, nIDT)) { - if (this.descIDT.maskPS) { - X86Help.opHelpPushPS.call(this, nError); - } else { - X86Help.opHelpSwitchTSS.call(this, this.descIDT.sel, true); - } - return; - } - X86Help.opHelpFault.call(this, X86.EXCEPTION.GP_FAULT, (nIDT << 3) | X86.ERRCODE.IDT | X86.ERRCODE.EXT, true); - */ }, /** * opHelpIRET() @@ -516,7 +494,7 @@ var X86Help = { if (this.regPS & X86.PS.NT) { var addrNew = this.segTSS.base; var sel = this.getWord(addrNew + X86.TSS.PREV_TSS); - X86Help.opHelpSwitchTSS.call(this, sel, false); + X86Seg.switchTSS.call(this.segCS, sel, false); return; } } @@ -529,137 +507,16 @@ var X86Help = { } }, /** - * opHelpLoadIDT(nIDT) - * - * Updates descIDT as follows: - * - * descIDT.off 0x0-0x1 offset of interrupt handler - * descIDT.sel 0x2-0x3 selector of interrupt handler - * descIDT.acc 0x4-0x5 access word (protected-mode only) - * descIDT.maskPS mask to apply PS after saving current PS (0 if none; ie, task switch) + * opHelpDIVOverflow() * * @this {X86CPU} - * @param {number} nIDT - * @return {boolean} true if successful, false if not (all failure cases currently limited to protected mode) */ - opHelpLoadIDT: function(nIDT) { - var offIDT; - - if (DEBUG) this.assert(nIDT >= 0 && nIDT < 256); - - if (this.regMSW & X86.MSW.PE) { - offIDT = this.addrIDT + (nIDT << 3); - if (offIDT + 7 > this.addrIDTLimit) { - return false; - } - this.descIDT.off = this.getWord(offIDT); - this.descIDT.sel = this.getWord(offIDT + 2); - this.descIDT.acc = this.getWord(offIDT + 4); - this.descIDT.maskPS = 0; - - switch (this.descIDT.acc & X86.DESC.ACC.TYPE.MASK) { - case X86.DESC.ACC.TYPE.GATE_INT: - this.descIDT.maskPS = ~(X86.PS.NT | X86.PS.TF | X86.PS.IF); - break; - case X86.DESC.ACC.TYPE.GATE_TRAP: - this.descIDT.maskPS = ~(X86.PS.NT | X86.PS.TF); - break; - case X86.DESC.ACC.TYPE.GATE_TASK: - break; - default: - if (DEBUG) this.assert(false, "INT 0x" + str.toHexByte(nIDT) + ": unrecognized IDT entry"); - return false; - } - return true; - } - if (DEBUG) this.assert(!this.addrIDT && this.addrIDTLimit == 0x03FF); + opHelpDIVOverflow: function() { + this.setIP(this.opEA - this.segCS.base); /* - * Intel documentation for INT/INTO under "REAL ADDRESS MODE EXCEPTIONS" says: - * - * "[T]he 80286 will shut down if the SP = 1, 3, or 5 before executing the INT or INTO instruction--due to lack of stack space" - * - * TODO: Verify that 80286 real-mode actually enforces the above. See http://localhost:8088/pubs/pc/reference/intel/80286/progref/#page-260 + * TODO: Determine the proper cycle cost. */ - offIDT = this.addrIDT + (nIDT << 2); - this.descIDT.off = this.getWord(offIDT); - this.descIDT.sel = this.getWord(offIDT + 2); - this.descIDT.maskPS = ~(X86.PS.TF | X86.PS.IF); - return true; - }, - /** - * opHelpSwitchTSS(selNew, fNest) - * - * Helper implementing TSS (Task State Segment) task switching. - * - * @this {X86CPU} - * @param {number} selNew - * @param {boolean} fNest is true if nesting, false if un-nesting - * @return {boolean} true if successful, false if error - */ - opHelpSwitchTSS: function(selNew, fNest) { - var addrOld = this.segTSS.base; - var cplOld = this.segCS.cpl; - var selOld = this.segTSS.sel; - if (!fNest) { - if (this.segTSS.type != X86.DESC.ACC.TYPE.TSS_BUSY) { - X86Help.opHelpFault.call(this, X86.EXCEPTION.TS_FAULT, selNew, true); - return false; - } - this.setWord(this.segTSS.addrDesc + X86.DESC.ACC.OFFSET, (this.segTSS.acc & ~X86.DESC.ACC.TYPE.TSS_BUSY) | X86.DESC.ACC.TYPE.TSS); - } - if (this.segTSS.load(selNew) == null) { - return false; - } - var addrNew = this.segTSS.base; - if (DEBUG) { - this.messageDebugger((fNest? "Task switch" : "Task return") + ": TR " + str.toHexWord(selOld) + " (%" + str.toHex(addrOld, 6) + "), new TR " + str.toHexWord(selNew) + " (%" + str.toHex(addrNew, 6) + ")", Debugger.MESSAGE.TSS); - } - if (fNest) { - if (this.segTSS.type == X86.DESC.ACC.TYPE.TSS_BUSY) { - X86Help.opHelpFault.call(this, X86.EXCEPTION.GP_FAULT, selNew, true); - return false; - } - this.setWord(this.segTSS.addrDesc + X86.DESC.ACC.OFFSET, this.segTSS.acc |= X86.DESC.ACC.TYPE.TSS_BUSY); - this.segTSS.type = X86.DESC.ACC.TYPE.TSS_BUSY; - } - this.setWord(addrOld + X86.TSS.TASK_IP, this.regIP); - this.setWord(addrOld + X86.TSS.TASK_PS, this.getPS()); - this.setWord(addrOld + X86.TSS.TASK_AX, this.regAX); - this.setWord(addrOld + X86.TSS.TASK_CX, this.regCX); - this.setWord(addrOld + X86.TSS.TASK_DX, this.regDX); - this.setWord(addrOld + X86.TSS.TASK_BX, this.regBX); - this.setWord(addrOld + X86.TSS.TASK_SP, this.regSP); - this.setWord(addrOld + X86.TSS.TASK_BP, this.regBP); - this.setWord(addrOld + X86.TSS.TASK_SI, this.regSI); - this.setWord(addrOld + X86.TSS.TASK_DI, this.regDI); - this.setWord(addrOld + X86.TSS.TASK_ES, this.segES.sel); - this.setWord(addrOld + X86.TSS.TASK_CS, this.segCS.sel); - this.setWord(addrOld + X86.TSS.TASK_SS, this.segSS.sel); - this.setWord(addrOld + X86.TSS.TASK_DS, this.segDS.sel); - var offSS = X86.TSS.TASK_SS; - var offSP = X86.TSS.TASK_SP; - this.setPS(this.getWord(addrNew + X86.TSS.TASK_PS) | (fNest? X86.PS.NT : 0)); - if (DEBUG) this.assert(!fNest || !!(this.regPS & X86.PS.NT)); - this.regAX = this.getWord(addrNew + X86.TSS.TASK_AX); - this.regCX = this.getWord(addrNew + X86.TSS.TASK_CX); - this.regDX = this.getWord(addrNew + X86.TSS.TASK_DX); - this.regBX = this.getWord(addrNew + X86.TSS.TASK_BX); - this.regBP = this.getWord(addrNew + X86.TSS.TASK_BP); - this.regSI = this.getWord(addrNew + X86.TSS.TASK_SI); - this.regDI = this.getWord(addrNew + X86.TSS.TASK_DI); - this.segES.load(this.getWord(addrNew + X86.TSS.TASK_ES)); - this.segDS.load(this.getWord(addrNew + X86.TSS.TASK_DS)); - this.setCSIP(this.getWord(addrNew + X86.TSS.TASK_IP), this.getWord(addrNew + X86.TSS.TASK_CS)); - if (this.segCS.cpl < cplOld) { - offSP = (this.segCS.cpl << 2) + X86.TSS.CPL0_SP; - offSS = offSP + 2; - } - this.regSP = this.getWord(addrNew + offSP); - this.segSS.load(this.getWord(addrNew + offSS)); - this.segLDT.load(this.getWord(addrNew + X86.TSS.TASK_LDT)); - if (fNest) this.setWord(addrNew + X86.TSS.PREV_TSS, selOld); - this.regMSW |= X86.MSW.TS; - return true; + X86Help.opHelpINT.call(this, X86.EXCEPTION.DIV_ERR, null, 2); }, /** * opHelpFault(nFault, nError, fHalt) @@ -671,27 +528,28 @@ var X86Help = { * @param {number} [nError] * @param {boolean} [fHalt] will halt the CPU if true *and* a Debugger is loaded */ - opHelpFault: function(nFault, nError, fHalt) { - if (!this.aFlags.fComplete) { - // this.messageDebugger("Fault " + str.toHexByte(nFault) + " blocked by Debugger", Debugger.MESSAGE.WARN); + opHelpFault: function(nFault, nError, fHalt) + { + if (!this.bitField.fComplete) { + this.messageDebugger("Fault " + str.toHexByte(nFault) + " blocked by Debugger", Debugger.MESSAGE.WARN); this.setIP(this.opEA - this.segCS.base); return; } - var fFault = false; + var fDispatch = false; if (this.model >= X86.MODEL_80186) { if (this.nFault < 0) { /* * Single-fault (error code is passed through, and the responsible instruction is restartable) */ this.setIP(this.opEA - this.segCS.base); - fFault = true; + 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; - fFault = true; + fDispatch = true; } else { /* * Triple-fault (usually referred to in Intel literature as a "shutdown", but at least on the 80286, @@ -703,9 +561,24 @@ var X86Help = { } } if (X86Help.opHelpFaultMessage.call(this, nFault, nError, fHalt)) { - fFault = false; + fDispatch = false; + } + if (fDispatch) X86Help.opHelpINT.call(this, this.nFault = nFault, nError, 0); + + /* + * Since this fault is likely being issued in the context of an instruction that hasn't finished + * executing, and since we currently don't do anything to interrupt that execution (eg, throw a + * JavaScript exception), and since we don't want that instruction to perform any writes that might + * be destructive, we should shut off all further reads/writes for the current instruction. + * + * As long as we're not using EAFUNCS, this is easy for any EA-based memory accesses: simply set + * the NOREAD and NOWRITE flags. However, there may still be direct, non-EA-based memory accesses that + * could cause us grief. TODO: Implement the ultimate solution, which will involve setting a special + * flag and throwing an exception that the CPU must intercept and then quietly ignore. + */ + if (!EAFUNCS) { + this.opFlags &= ~(X86.OPFLAG.NOREAD | X86.OPFLAG.NOWRITE); } - if (fFault) X86Help.opHelpINT.call(this, this.nFault = nFault, nError, 0); }, /** * opHelpFaultMessage() @@ -714,22 +587,26 @@ var X86Help = { * halt exception processing in tracks: return true to prevent the fault handler from being dispatched. * * TODO: Provide the Debugger with some UI to control its "interference" with fault dispatching, and to - * continue the dispatch after it has interfered. + * continue the dispatch after it has interfered. At the moment, your only option is to single-step over + * the offending instruction to allow the fault to be dispatched. * * @this {X86CPU} * @param {number} nFault * @param {number} [nError] * @param {boolean} [fHalt] will halt the CPU if true *and* a Debugger is loaded - * @return {boolean} true to halt the CPU, false if not + * @return {boolean|undefined} true to block the fault, otherwise dispatch it */ - opHelpFaultMessage: function(nFault, nError, fHalt) { - /* - * TODO: When we're done examining all GP faults, change the following to "fHalt || false" - */ - fHalt = fHalt || (nFault == X86.EXCEPTION.GP_FAULT); - + opHelpFaultMessage: function(nFault, nError, fHalt) + { var bitsMessage = Debugger.MESSAGE.FAULT; var bOpcode = this.bus.getByteDirect(this.regEIP); + + var fDebugger = false; + if (DEBUGGER && this.dbg) { + fDebugger = true; + if (nFault == X86.EXCEPTION.GP_FAULT) fHalt = true; + } + /* * OS/2 1.0 uses an INT3 (0xCC) opcode in conjunction with an invalid IDT to trigger a triple-fault * reset and return to real-mode, and these resets happen quite frequently during boot; for example, @@ -755,14 +632,19 @@ var X86Help = { if (this.regEIP >= 0x0F0000 && this.regEIP <= 0x0FFFFF) { fHalt = false; } - var sMessage = "Fault " + str.toHexByte(nFault) + (nError != null? " (" + str.toHexWord(nError) + ")" : "") + " on opcode 0x" + str.toHexByte(bOpcode) + " at " + str.toHexAddr(this.regIP, this.segCS.sel) + " (%" + str.toHex(this.regEIP, 6) + ")"; - if (DEBUGGER && this.dbg) { - this.messageDebugger(sMessage, bitsMessage); - if (fHalt) this.dbg.stopCPU(); - } else if (fHalt) { - this.notice(sMessage); - this.stopCPU(); + if (fDebugger && this.dbg.messageEnabled(bitsMessage) || !fDebugger && fHalt) { + var sMessage = "Fault " + str.toHexByte(nFault) + (nError != null? " (" + str.toHexWord(nError) + ")" : "") + " on opcode 0x" + str.toHexByte(bOpcode) + " at " + str.toHexAddr(this.regIP, this.segCS.sel) + " (%" + str.toHex(this.regEIP, 6) + ")"; + if (fDebugger) { + this.messageDebugger(sMessage, bitsMessage); + if (fHalt) { + fHalt = this.bitField.fRunning; + this.dbg.stopCPU(); + } + } else if (fHalt) { + this.notice(sMessage); + this.stopCPU(); + } } return fHalt; } diff --git a/modules/pcjs/lib/x86op0f.js b/modules/pcjs/lib/x86op0f.js index 01c6d1a08..3d58c7e9a 100644 --- a/modules/pcjs/lib/x86op0f.js +++ b/modules/pcjs/lib/x86op0f.js @@ -138,10 +138,10 @@ var X86Op0F = { this.regDX = this.getWord(0x830); this.regCX = this.getWord(0x832); this.regAX = this.getWord(0x834); - this.segES.loadDesc6(this.getWord(0x824), 0x836); - this.segCS.loadDesc6(this.getWord(0x822), 0x83C); - this.segSS.loadDesc6(this.getWord(0x820), 0x842); - this.segDS.loadDesc6(this.getWord(0x81E), 0x848); + this.segES.loadDesc6(0x836, this.getWord(0x824)); + this.segCS.loadDesc6(0x83C, this.getWord(0x822)); + this.segSS.loadDesc6(0x842, this.getWord(0x820)); + this.segDS.loadDesc6(0x848, this.getWord(0x81E)); this.setPS(this.getWord(0x818)); this.setIP(this.getWord(0x81A)); /* @@ -149,10 +149,10 @@ var X86Op0F = { */ this.addrGDT = this.getWord(0x84E) | (this.getWord(0x850) << 16); this.addrGDTLimit = this.addrGDT + this.getWord(0x852); - this.segLDT.loadDesc6(this.getWord(0x81C), 0x854); + this.segLDT.loadDesc6(0x854, this.getWord(0x81C)); this.addrIDT = this.getWord(0x85A) | (this.getWord(0x85C) << 16); this.addrIDTLimit = this.addrIDT + this.getWord(0x85E); - this.segTSS.loadDesc6(this.getWord(0x816), 0x860); + this.segTSS.loadDesc6(0x860, this.getWord(0x816)); this.nStepCycles -= 195; /* * TODO: LOADALL operation still needs to be verified in protected mode.... @@ -246,7 +246,7 @@ var X86Op0F = { * current privilege level and the selector's RPL. */ if (this.segVER.dpl >= this.segCS.cpl && this.segVER.dpl >= (dst & X86.SEL.RPL) || - (this.segVER.acc & X86.DESC.ACC.TYPE.CODE_CONFORMING_EXECONLY) == X86.DESC.ACC.TYPE.CODE_CONFORMING_EXECONLY) { + (this.segVER.acc & X86.DESC.ACC.TYPE.CODE_CONFORMING) == X86.DESC.ACC.TYPE.CODE_CONFORMING) { this.setZF(); return dst; } diff --git a/modules/pcjs/lib/x86seg.js b/modules/pcjs/lib/x86seg.js index c0495869f..1bee46e66 100644 --- a/modules/pcjs/lib/x86seg.js +++ b/modules/pcjs/lib/x86seg.js @@ -84,7 +84,7 @@ function X86Seg(cpu, id, sName, fProt) this.awScratch = (this.id == X86Seg.ID.CODE? new Array(32) : []); this.fCall = null; this.fStackSwitch = false; - this.updateAccess(fProt); + this.updateMode(fProt); } X86Seg.ID = { @@ -121,7 +121,7 @@ X86Seg.loadReal = function loadReal(sel, fSuppress) /** * loadProt(sel, fSuppress) * - * This replaces the segment's default load() function whenever the segment is notified via updateAccess() by the + * This replaces the segment's default load() function whenever the segment is notified via updateMode() by the * CPU's setProtMode() that the processor is now in protected-mode. * * Segments in protected-mode are referenced by selectors, which are indexes into descriptor tables (GDT or LDT) @@ -145,12 +145,14 @@ X86Seg.loadProt = function loadProt(sel, fSuppress) { var addrDT; var addrDTLimit; + var cpu = this.cpu; + if (!(sel & X86.SEL.LDT)) { - addrDT = this.cpu.addrGDT; - addrDTLimit = this.cpu.addrGDTLimit; + addrDT = cpu.addrGDT; + addrDTLimit = cpu.addrGDTLimit; } else { - addrDT = this.cpu.segLDT.base; - addrDTLimit = addrDT + this.cpu.segLDT.limit; + addrDT = cpu.segLDT.base; + addrDTLimit = addrDT + cpu.segLDT.limit; } var addrDesc = addrDT + (sel & X86.SEL.MASK); if (addrDesc + 7 <= addrDTLimit) { @@ -159,8 +161,8 @@ X86Seg.loadProt = function loadProt(sel, fSuppress) * I simply noted that "POP segreg" takes 5 cycles in real mode and 20 in protected mode, so I'm * starting with a 15-cycle difference. Obviously the difference will be much greater when the load fails. */ - if (!fSuppress) this.cpu.nStepCycles -= 15; - return this.loadDesc8(sel, addrDesc); + if (!fSuppress) cpu.nStepCycles -= 15; + return this.loadDesc8(addrDesc, sel); } if (!fSuppress) { X86Help.opHelpFault.call(this.cpu, X86.EXCEPTION.GP_FAULT, sel); @@ -177,8 +179,9 @@ X86Seg.loadProt = function loadProt(sel, fSuppress) */ X86Seg.loadRealIDT = function loadRealIDT(nIDT) { + var cpu = this.cpu; if (DEBUG) { - this.cpu.assert(nIDT >= 0 && nIDT < 256 && !this.cpu.addrIDT && this.cpu.addrIDTLimit == 0x03FF); + cpu.assert(nIDT >= 0 && nIDT < 256 && !cpu.addrIDT && cpu.addrIDTLimit == 0x03FF); } /* * Intel documentation for INT/INTO under "REAL ADDRESS MODE EXCEPTIONS" says: @@ -187,10 +190,10 @@ X86Seg.loadRealIDT = function loadRealIDT(nIDT) * * TODO: Verify that 80286 real-mode actually enforces the above. See http://localhost:8088/pubs/pc/reference/intel/80286/progref/#page-260 */ - var offIDT = this.cpu.addrIDT + (nIDT << 2); - this.cpu.regIP = this.cpu.getWord(offIDT); - this.sel = this.cpu.getWord(offIDT + 2); - this.cpu.regPS &= ~(X86.PS.TF | X86.PS.IF); + var offIDT = cpu.addrIDT + (nIDT << 2); + cpu.regIP = cpu.getWord(offIDT); + this.sel = cpu.getWord(offIDT + 2); + cpu.regPS &= ~(X86.PS.TF | X86.PS.IF); return this.base = this.sel << 4; }; @@ -203,12 +206,13 @@ X86Seg.loadRealIDT = function loadRealIDT(nIDT) */ X86Seg.loadProtIDT = function loadProtIDT(nIDT) { - if (DEBUG) this.cpu.assert(nIDT >= 0 && nIDT < 256); + var cpu = this.cpu; + if (DEBUG) cpu.assert(nIDT >= 0 && nIDT < 256); nIDT <<= 3; - var addrDesc = this.cpu.addrIDT + nIDT; - if (addrDesc + 7 <= this.cpu.addrIDTLimit) { - return this.loadDesc8(nIDT, addrDesc); + var addrDesc = cpu.addrIDT + nIDT; + if (addrDesc + 7 <= cpu.addrIDTLimit) { + return this.loadDesc8(addrDesc, nIDT); } X86Help.opHelpFault.call(this.cpu, X86.EXCEPTION.GP_FAULT, nIDT | X86.ERRCODE.IDT | X86.ERRCODE.EXT, true); return null; @@ -350,12 +354,123 @@ X86Seg.checkWriteProtDisallowed = function checkWriteProtDisallowed(off, cb, fSu return null; }; +/** + * switchTSS(selNew, fNest) + * + * Implements TSS (Task State Segment) task switching. + * + * @this {X86Seg} + * @param {number} selNew + * @param {boolean} fNest is true if nesting, false if un-nesting + * @return {boolean} true if successful, false if error + */ +X86Seg.switchTSS = function switchTSS(selNew, fNest) +{ + var cpu = this.cpu; + if (DEBUG) cpu.assert(this === cpu.segCS); + + var addrOld = cpu.segTSS.base; + var cplOld = this.cpl; + var selOld = cpu.segTSS.sel; + if (!fNest) { + if (cpu.segTSS.type != X86.DESC.ACC.TYPE.TSS_BUSY) { + X86Help.opHelpFault.call(cpu, X86.EXCEPTION.TS_FAULT, selNew, true); + return false; + } + cpu.setWord(cpu.segTSS.addrDesc + X86.DESC.ACC.OFFSET, (cpu.segTSS.acc & ~X86.DESC.ACC.TYPE.TSS_BUSY) | X86.DESC.ACC.TYPE.TSS); + } + if (cpu.segTSS.load(selNew) == null) { + return false; + } + var addrNew = cpu.segTSS.base; + if (DEBUG) { + cpu.messageDebugger((fNest? "Task switch" : "Task return") + ": TR " + str.toHexWord(selOld) + " (%" + str.toHex(addrOld, 6) + "), new TR " + str.toHexWord(selNew) + " (%" + str.toHex(addrNew, 6) + ")", Debugger.MESSAGE.TSS); + } + if (fNest) { + if (cpu.segTSS.type == X86.DESC.ACC.TYPE.TSS_BUSY) { + X86Help.opHelpFault.call(cpu, X86.EXCEPTION.GP_FAULT, selNew, true); + return false; + } + cpu.setWord(cpu.segTSS.addrDesc + X86.DESC.ACC.OFFSET, cpu.segTSS.acc |= X86.DESC.ACC.TYPE.TSS_BUSY); + cpu.segTSS.type = X86.DESC.ACC.TYPE.TSS_BUSY; + } + cpu.setWord(addrOld + X86.TSS.TASK_IP, cpu.regIP); + cpu.setWord(addrOld + X86.TSS.TASK_PS, cpu.getPS()); + cpu.setWord(addrOld + X86.TSS.TASK_AX, cpu.regAX); + cpu.setWord(addrOld + X86.TSS.TASK_CX, cpu.regCX); + cpu.setWord(addrOld + X86.TSS.TASK_DX, cpu.regDX); + cpu.setWord(addrOld + X86.TSS.TASK_BX, cpu.regBX); + cpu.setWord(addrOld + X86.TSS.TASK_SP, cpu.regSP); + cpu.setWord(addrOld + X86.TSS.TASK_BP, cpu.regBP); + cpu.setWord(addrOld + X86.TSS.TASK_SI, cpu.regSI); + cpu.setWord(addrOld + X86.TSS.TASK_DI, cpu.regDI); + cpu.setWord(addrOld + X86.TSS.TASK_ES, cpu.segES.sel); + cpu.setWord(addrOld + X86.TSS.TASK_CS, cpu.segCS.sel); + cpu.setWord(addrOld + X86.TSS.TASK_SS, cpu.segSS.sel); + cpu.setWord(addrOld + X86.TSS.TASK_DS, cpu.segDS.sel); + var offSS = X86.TSS.TASK_SS; + var offSP = X86.TSS.TASK_SP; + cpu.setPS(cpu.getWord(addrNew + X86.TSS.TASK_PS) | (fNest? X86.PS.NT : 0)); + if (DEBUG) cpu.assert(!fNest || !!(cpu.regPS & X86.PS.NT)); + cpu.regAX = cpu.getWord(addrNew + X86.TSS.TASK_AX); + cpu.regCX = cpu.getWord(addrNew + X86.TSS.TASK_CX); + cpu.regDX = cpu.getWord(addrNew + X86.TSS.TASK_DX); + cpu.regBX = cpu.getWord(addrNew + X86.TSS.TASK_BX); + cpu.regBP = cpu.getWord(addrNew + X86.TSS.TASK_BP); + cpu.regSI = cpu.getWord(addrNew + X86.TSS.TASK_SI); + cpu.regDI = cpu.getWord(addrNew + X86.TSS.TASK_DI); + cpu.segES.load(cpu.getWord(addrNew + X86.TSS.TASK_ES)); + cpu.segDS.load(cpu.getWord(addrNew + X86.TSS.TASK_DS)); + cpu.setCSIP(cpu.getWord(addrNew + X86.TSS.TASK_IP), cpu.getWord(addrNew + X86.TSS.TASK_CS)); + if (this.cpl < cplOld) { + offSP = (this.cpl << 2) + X86.TSS.CPL0_SP; + offSS = offSP + 2; + } + cpu.regSP = cpu.getWord(addrNew + offSP); + cpu.segSS.load(cpu.getWord(addrNew + offSS)); + cpu.segLDT.load(cpu.getWord(addrNew + X86.TSS.TASK_LDT)); + if (fNest) cpu.setWord(addrNew + X86.TSS.PREV_TSS, selOld); + cpu.regMSW |= X86.MSW.TS; + return true; +}; + /* * Object methods */ /** - * loadDesc6(sel, addrDesc) + * loadAcc(sel, fGDT) + * + * @this {X86Seg} + * @param {number} sel (protected-mode only) + * @param {boolean} [fGDT] is true if sel must be in the GDT + * @return {number|null} acc field from descriptor, or null if error + */ +X86Seg.prototype.loadAcc = function(sel, fGDT) +{ + var addrDT; + var addrDTLimit; + var cpu = this.cpu; + + if (!(sel & X86.SEL.LDT)) { + addrDT = cpu.addrGDT; + addrDTLimit = cpu.addrGDTLimit; + } else if (!fGDT) { + addrDT = cpu.segLDT.base; + addrDTLimit = addrDT + cpu.segLDT.limit; + } + if (addrDT !== undefined) { + var addrDesc = addrDT + (sel & X86.SEL.MASK); + if (addrDesc + 7 <= addrDTLimit) { + return cpu.getWord(addrDesc + X86.DESC.ACC.OFFSET); + } + } + X86Help.opHelpFault.call(cpu, X86.EXCEPTION.GP_FAULT, sel); + return null; +}; + +/** + * loadDesc6(addrDesc, sel) * * Used to load a protected-mode selector that refers to a 6-byte "descriptor cache" (aka LOADALL) entry: * @@ -364,22 +479,23 @@ X86Seg.checkWriteProtDisallowed = function checkWriteProtDisallowed(off, cb, fSu * word 2: segment limit (0-15) * * @this {X86Seg} - * @param {number} sel is the selector - * @param {number} addrDesc is the offset + * @param {number} addrDesc is the descriptor address + * @param {number} sel is the associated selector * @return {number} base address of selected segment */ -X86Seg.prototype.loadDesc6 = function(sel, addrDesc) +X86Seg.prototype.loadDesc6 = function(addrDesc, sel) { - var acc = this.cpu.getWord(addrDesc + 2); - var base = this.cpu.getWord(addrDesc + 0) | ((acc & 0xff) << 16); - var limit = this.cpu.getWord(addrDesc + 4); + var cpu = this.cpu; + var acc = cpu.getWord(addrDesc + 2); + var base = cpu.getWord(addrDesc + 0) | ((acc & 0xff) << 16); + var limit = cpu.getWord(addrDesc + 4); this.sel = sel; this.base = base; this.limit = limit; this.acc = acc & X86.DESC.ACC.MASK; this.addrDesc = addrDesc; - this.updateAccess(); + this.updateMode(); this.messageDebugger(sel, base, limit, acc); @@ -387,7 +503,7 @@ X86Seg.prototype.loadDesc6 = function(sel, addrDesc) }; /** - * loadDesc8(sel, addrDesc) + * loadDesc8(addrDesc, sel) * * Used to load a protected-mode selector that refers to an 8-byte "descriptor table" (GDT, LDT, IDT) entry: * @@ -399,22 +515,23 @@ X86Seg.prototype.loadDesc6 = function(sel, addrDesc) * See X86.DESC for offset and bit definitions. * * @this {X86Seg} - * @param {number} sel is the selector - * @param {number} addrDesc is the offset + * @param {number} addrDesc is the descriptor address + * @param {number} sel is the associated selector * @return {number|null} base address of selected segment, or null if error */ -X86Seg.prototype.loadDesc8 = function(sel, addrDesc) +X86Seg.prototype.loadDesc8 = function(addrDesc, sel) { - var limit = this.cpu.getWord(addrDesc + X86.DESC.LIMIT.OFFSET); - var acc = this.cpu.getWord(addrDesc + X86.DESC.ACC.OFFSET); + var cpu = this.cpu; + var limit = cpu.getWord(addrDesc + X86.DESC.LIMIT.OFFSET); + var acc = cpu.getWord(addrDesc + X86.DESC.ACC.OFFSET); var type = (acc & X86.DESC.ACC.TYPE.MASK); - var base = this.cpu.getWord(addrDesc + X86.DESC.BASE.OFFSET) | ((acc & X86.DESC.ACC.BASE1623) << 16); - var ext = (DEBUG? this.cpu.getWord(addrDesc + X86.DESC.EXT.OFFSET) : 0); + var base = cpu.getWord(addrDesc + X86.DESC.BASE.OFFSET) | ((acc & X86.DESC.ACC.BASE1623) << 16); + var ext = (DEBUG? cpu.getWord(addrDesc + X86.DESC.EXT.OFFSET) : 0); var selMasked = sel & X86.SEL.MASK; while (true) { - var cplPrev, addrTSS, offSP, offSS, regSPPrev, regSSPrev; + var accCode, selCode, cplPrev, addrTSS, offSP, offSS, regSPPrev, regSSPrev; if (this.id == X86Seg.ID.CODE) { this.fStackSwitch = false; @@ -422,93 +539,128 @@ X86Seg.prototype.loadDesc8 = function(sel, addrDesc) var rpl = sel & X86.SEL.RPL; var dpl = (acc & X86.DESC.ACC.DPL.MASK) >> X86.DESC.ACC.DPL.SHIFT; var regSP; - if (type == X86.DESC.ACC.TYPE.GATE_CALL) { - /* - * Since we are X86Seg.ID.CODE, we can use this.cpl instead of the more generic this.cpu.segCS.cpl - */ - if (rpl < this.cpl) rpl = this.cpl; - if (rpl <= dpl) { - cplPrev = this.cpl; - if (this.load(base & 0xffff, true) != null) { - this.cpu.regIP = limit; - if (this.cpl < cplPrev) { - if (fCall !== true) { - base = null; - break; - } - regSP = this.cpu.regSP; - var i = 0, nWords = (acc & 0x1f); - while (nWords--) { - this.awScratch[i++] = this.cpu.getSOWord(this.cpu.segSS, regSP); - regSP += 2; - } - addrTSS = this.cpu.segTSS.base; - offSP = (this.cpl << 2) + X86.TSS.CPL0_SP; - offSS = offSP + 2; - regSPPrev = this.cpu.regSP; - regSSPrev = this.cpu.segSS.sel; - this.cpu.regSP = this.cpu.getWord(addrTSS + offSP); - this.cpu.segSS.load(this.cpu.getWord(addrTSS + offSS)); - this.cpu.pushWord(regSSPrev); - this.cpu.pushWord(regSPPrev); - while (i) this.cpu.pushWord(this.awScratch[--i]); - this.fStackSwitch = true; - } - return this.base; - } - } - } - else if (type == X86.DESC.ACC.TYPE.GATE_INT || type == X86.DESC.ACC.TYPE.GATE_TRAP) { - if (rpl < this.cpl) rpl = this.cpl; - if (rpl <= dpl) { - cplPrev = this.cpl; - if (this.load(base & 0xffff, true) != null) { - this.cpu.regIP = limit; - if (this.cpl < cplPrev) { - if (fCall !== true) { - base = null; - break; - } - regSP = this.cpu.regSP; - addrTSS = this.cpu.segTSS.base; - offSP = (this.cpl << 2) + X86.TSS.CPL0_SP; - offSS = offSP + 2; - regSPPrev = this.cpu.regSP; - regSSPrev = this.cpu.segSS.sel; - this.cpu.regSP = this.cpu.getWord(addrTSS + offSP); - this.cpu.segSS.load(this.cpu.getWord(addrTSS + offSS)); - this.cpu.pushWord(regSSPrev); - this.cpu.pushWord(regSPPrev); - this.fStackSwitch = true; - } - if (type == X86.DESC.ACC.TYPE.GATE_INT) { - this.cpu.regPS &= ~(X86.PS.NT | X86.PS.TF | X86.PS.IF); - } else { - this.cpu.regPS &= ~(X86.PS.NT | X86.PS.TF); - } - return this.base; - } - } - } - else if (type >= X86.DESC.ACC.TYPE.CODE_EXECONLY /* || dpl > this.cpu.segCS.cpl */) { + if (type >= X86.DESC.ACC.TYPE.CODE_EXECONLY /* || dpl > cpu.segCS.cpl */) { rpl = sel & X86.SEL.RPL; if (rpl > this.cpl) { if (fCall !== false) { base = null; break; } - regSP = this.cpu.popWord(); - this.cpu.segSS.load(this.cpu.popWord()); - this.cpu.regSP = regSP; + regSP = cpu.popWord(); + cpu.segSS.load(cpu.popWord()); + cpu.regSP = regSP; this.fStackSwitch = true; } } + else if (type == X86.DESC.ACC.TYPE.GATE_CALL) { + /* + * Since we are X86Seg.ID.CODE, we can use this.cpl instead of the more generic cpu.segCS.cpl + */ + selCode = base & 0xffff; + if (rpl < this.cpl) rpl = this.cpl; + if (rpl > dpl) { + accCode = this.loadAcc(selCode, true); + if (accCode != null && (accCode & X86.DESC.ACC.TYPE.CODE_CONFORMING) == X86.DESC.ACC.TYPE.CODE_CONFORMING) { + rpl = dpl; + } + } + if (rpl <= dpl) { + cplPrev = this.cpl; + if (this.load(selCode, true) == null) { + if (DEBUG) cpu.assert(false); + base = null; + break; + } + cpu.regIP = limit; + if (this.cpl < cplPrev) { + if (fCall !== true) { + if (DEBUG) cpu.assert(false); + base = null; + break; + } + regSP = cpu.regSP; + var i = 0, nWords = (acc & 0x1f); + while (nWords--) { + this.awScratch[i++] = cpu.getSOWord(cpu.segSS, regSP); + regSP += 2; + } + addrTSS = cpu.segTSS.base; + offSP = (this.cpl << 2) + X86.TSS.CPL0_SP; + offSS = offSP + 2; + regSPPrev = cpu.regSP; + regSSPrev = cpu.segSS.sel; + cpu.regSP = cpu.getWord(addrTSS + offSP); + cpu.segSS.load(cpu.getWord(addrTSS + offSS)); + cpu.pushWord(regSSPrev); + cpu.pushWord(regSPPrev); + while (i) cpu.pushWord(this.awScratch[--i]); + this.fStackSwitch = true; + } + return this.base; + } + if (DEBUG) cpu.assert(false); + X86Help.opHelpFault.call(cpu, X86.EXCEPTION.GP_FAULT, sel, true); + base = null; + break; + } + else if (type == X86.DESC.ACC.TYPE.GATE_INT || type == X86.DESC.ACC.TYPE.GATE_TRAP) { + selCode = base & 0xffff; + if (dpl > this.cpl) { + accCode = this.loadAcc(selCode, true); + if (accCode != null && (accCode & X86.DESC.ACC.TYPE.CODE_CONFORMING) == X86.DESC.ACC.TYPE.CODE_CONFORMING) { + dpl = this.cpl; + } + } + if (dpl <= this.cpl) { + cplPrev = this.cpl; + if (this.load(selCode, true) == null) { + if (DEBUG) cpu.assert(false); + base = null; + break; + } + cpu.regIP = limit; + if (this.cpl < cplPrev) { + if (fCall !== true) { + base = null; + break; + } + regSP = cpu.regSP; + addrTSS = cpu.segTSS.base; + offSP = (this.cpl << 2) + X86.TSS.CPL0_SP; + offSS = offSP + 2; + regSPPrev = cpu.regSP; + regSSPrev = cpu.segSS.sel; + cpu.regSP = cpu.getWord(addrTSS + offSP); + cpu.segSS.load(cpu.getWord(addrTSS + offSS)); + cpu.pushWord(regSSPrev); + cpu.pushWord(regSPPrev); + this.fStackSwitch = true; + } + if (type == X86.DESC.ACC.TYPE.GATE_INT) { + cpu.regPS &= ~(X86.PS.NT | X86.PS.TF | X86.PS.IF); + } else { + cpu.regPS &= ~(X86.PS.NT | X86.PS.TF); + } + return this.base; + } + if (DEBUG) cpu.assert(false); + X86Help.opHelpFault.call(cpu, X86.EXCEPTION.GP_FAULT, sel | X86.ERRCODE.EXT, true); + base = null; + break; + } + else if (type == X86.DESC.ACC.TYPE.GATE_TASK) { + if (!X86Seg.switchTSS.call(this, base & 0xffff, true)) { + base = null; + break; + } + return this.base; + } else { X86Help.opHelpFault.call(this.cpu, X86.EXCEPTION.GP_FAULT, sel, true); base = null; break; } - if (DEBUG) this.cpu.assert(!!selMasked); // a null CS selector should be caught by the final preceding check + if (DEBUG) cpu.assert(!!selMasked); // a null CS selector should be caught by the final preceding check } else if (this.id == X86Seg.ID.DATA) { if (selMasked) { @@ -548,7 +700,7 @@ X86Seg.prototype.loadDesc8 = function(sel, addrDesc) this.acc = acc; this.type = type; this.addrDesc = addrDesc; - this.updateAccess(); + this.updateMode(); break; } this.messageDebugger(sel, base, limit, acc, ext); @@ -612,7 +764,7 @@ X86Seg.prototype.restore = function(a) }; /** - * updateAccess(fProt) + * updateMode(fProt) * * Ensures that the segment register's access (ie, load and check methods) matches the specified (or current) * operating mode (real or protected). @@ -621,7 +773,7 @@ X86Seg.prototype.restore = function(a) * @param {boolean} [fProt] true for protected-mode access, false for real-mode access, undefined for current mode * @return {boolean} */ -X86Seg.prototype.updateAccess = function(fProt) +X86Seg.prototype.updateMode = function(fProt) { if (fProt === undefined) { fProt = !!(this.cpu.regMSW & X86.MSW.PE); @@ -684,7 +836,7 @@ X86Seg.prototype.messageDebugger = function(sel, base, limit, acc, ext) if (this.id == X86Seg.ID.CODE) sDPL += " cpl=" + this.cpl; this.cpu.messageDebugger("loadSeg(" + this.sName + "):" + ch + "sel=" + str.toHexWord(sel) + " base=" + str.toHex(base) + " limit=" + str.toHexWord(limit) + " acc=" + str.toHexWord(acc) + sDPL, Debugger.MESSAGE.SEG); } - this.cpu.assert(base != null && (!ext || ext == X86.DESC.EXT.AVAIL)); + this.cpu.assert(/* base != null && */ (!ext || ext == X86.DESC.EXT.AVAIL)); } }; diff --git a/modules/shared/lib/component.js b/modules/shared/lib/component.js index 45b980781..392136f90 100644 --- a/modules/shared/lib/component.js +++ b/modules/shared/lib/component.js @@ -113,7 +113,7 @@ function Component(type, parms, constructor) * Gather all the various component flags (booleans) into a single "flags" object, and encourage * subclasses to do the same, to reduce the property clutter we have to wade through while debugging. */ - this.aFlags = { + this.bitField = { fReady: false, fBusy: false, fBusyCancel: false, @@ -784,7 +784,7 @@ Component.prototype = { * @param {string} s describes a fatal error condition */ setError: function(s) { - this.aFlags.fError = true; + this.bitField.fError = true; this.notice("Fatal error: " + s); }, /** @@ -795,7 +795,7 @@ Component.prototype = { * @this {Component} */ clearError: function() { - this.aFlags.fError = false; + this.bitField.fError = false; }, /** * isError() @@ -806,7 +806,7 @@ Component.prototype = { * @return {boolean} true if a fatal error condition exists, false if not */ isError: function() { - if (this.aFlags.fError) { + if (this.bitField.fError) { this.println(this.toString() + " error"); return true; } @@ -827,14 +827,14 @@ Component.prototype = { */ isReady: function(fnReady) { if (fnReady) { - if (this.aFlags.fReady) { + if (this.bitField.fReady) { fnReady(); } else { if (DEBUG) this.log("NOT ready"); this.fnReady = fnReady; } } - return this.aFlags.fReady; + return this.bitField.fReady; }, /** * setReady(fReady) @@ -845,9 +845,9 @@ Component.prototype = { * @param {boolean} [fReady] is assumed to indicate "ready" unless EXPLICITLY set to false */ setReady: function(fReady) { - if (!this.aFlags.fError) { - this.aFlags.fReady = (fReady !== false); - if (this.aFlags.fReady) { + if (!this.bitField.fError) { + this.bitField.fReady = (fReady !== false); + if (this.bitField.fReady) { if (DEBUG || this.name) this.log("ready"); var fnReady = this.fnReady; this.fnReady = null; @@ -865,14 +865,14 @@ Component.prototype = { * @return {boolean} true if "busy", false if not */ isBusy: function(fCancel) { - if (this.aFlags.fBusy) { + if (this.bitField.fBusy) { if (fCancel) { - this.aFlags.fBusyCancel = true; + this.bitField.fBusyCancel = true; } else if (fCancel === undefined) { this.println(this.toString() + " busy"); } } - return this.aFlags.fBusy; + return this.bitField.fBusy; }, /** * setBusy(fBusy) @@ -884,19 +884,19 @@ Component.prototype = { * @return {boolean} */ setBusy: function(fBusy) { - if (this.aFlags.fBusyCancel) { - if (this.aFlags.fBusy) { - this.aFlags.fBusy = false; + if (this.bitField.fBusyCancel) { + if (this.bitField.fBusy) { + this.bitField.fBusy = false; } - this.aFlags.fBusyCancel = false; + this.bitField.fBusyCancel = false; return false; } - if (this.aFlags.fError) { + if (this.bitField.fError) { this.println(this.toString() + " error"); return false; } - this.aFlags.fBusy = fBusy; - return this.aFlags.fBusy; + this.bitField.fBusy = fBusy; + return this.bitField.fBusy; }, /** * powerUp(fSave) @@ -907,7 +907,7 @@ Component.prototype = { * @return {boolean} true if successful, false if failure */ powerUp: function(data, fRepower) { - this.aFlags.fPowered = true; + this.bitField.fPowered = true; return true; }, /** @@ -919,7 +919,7 @@ Component.prototype = { * @return {Object|boolean} component state if fSave; otherwise, true if successful, false if failure */ powerDown: function(fSave, fShutdown) { - if (fShutdown) this.aFlags.fPowered = false; + if (fShutdown) this.bitField.fPowered = false; return true; } };