Implemented 80286 LOADALL

This commit is contained in:
Jeff Parsons 2014-11-01 17:12:20 -07:00 committed by jeffpar
commit 5dce2a1a23
31 changed files with 1831 additions and 1765 deletions

View file

@ -57,8 +57,8 @@ function C1PCPU(parmsCPU)
Component.call(this, "C1PCPU", parmsCPU);
this.clearRegs();
this.fPower = false;
this.fRunning = false;
this.aFlags.fPowered = false;
this.aFlags.fRunning = false;
this.fAutoStart = parmsCPU["autoStart"];
/*
@ -482,7 +482,7 @@ Component.subclass(Component, C1PCPU);
*/
C1PCPU.prototype.reset = function(fPowerOn)
{
if (this.fRunning)
if (this.aFlags.fRunning)
this.halt();
this.clearRegs();
this.regPC = this.getWord(this.VECTOR_RESET);
@ -516,7 +516,7 @@ C1PCPU.prototype.setBinding = function(c, t, s, e)
this.bindings[s] = e;
e.onclick = function(cpu) {
return function() {
if (!cpu.fRunning)
if (!cpu.aFlags.fRunning)
cpu.run();
else
cpu.halt();
@ -579,7 +579,7 @@ C1PCPU.prototype.setBuffer = function(abMemory, start, end)
*/
C1PCPU.prototype.setPower = function(fOn, cmp)
{
if (fOn && !this.fPower) {
if (fOn && !this.aFlags.fPowered) {
this.cmp = cmp;
/*
* Attach the Debugger, if any, to the CPU, so that the CPU can periodically
@ -607,7 +607,7 @@ C1PCPU.prototype.setPower = function(fOn, cmp)
};
}(video);
}
this.fPower = true;
this.aFlags.fPowered = true;
this.reset(true);
this.update();
}
@ -880,7 +880,7 @@ C1PCPU.prototype.displayStatus = function()
*/
C1PCPU.prototype.isRunning = function()
{
return this.fRunning;
return this.aFlags.fRunning;
};
/**
@ -1051,7 +1051,7 @@ C1PCPU.prototype.run = function()
if (this.cmp) this.cmp.stop(this.msRunStart, this.nRunCycles);
return;
}
if (!this.fRunning) {
if (!this.aFlags.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
@ -1060,7 +1060,7 @@ C1PCPU.prototype.run = function()
*/
this.setSpeed();
if (this.cmp) this.cmp.start();
this.fRunning = true;
this.aFlags.fRunning = true;
if (this.bindings["run"]) this.bindings["run"].innerHTML = "Halt";
this.setFocus();
}
@ -1107,7 +1107,7 @@ C1PCPU.prototype.run = function()
this.nCyclesNextYield += this.nCyclesPerYield;
break;
}
} while (this.fRunning);
} while (this.aFlags.fRunning);
}
catch (e) {
this.halt();
@ -1268,8 +1268,8 @@ C1PCPU.prototype.halt = function()
this.isBusy(true);
this.nBurstCycles -= this.nStepCycles;
this.nStepCycles = 0;
if (this.fRunning) {
this.fRunning = false;
if (this.aFlags.fRunning) {
this.aFlags.fRunning = false;
if (this.bindings["run"]) this.bindings["run"].innerHTML = "Run";
}
};
@ -1303,7 +1303,7 @@ C1PCPU.prototype.update = function()
*/
C1PCPU.prototype.getCycles = function()
{
return (this.fRunning? this.nRunCycles + this.nBurstCycles - this.nStepCycles : 0);
return (this.aFlags.fRunning? this.nRunCycles + this.nBurstCycles - this.nStepCycles : 0);
};
/**

View file

@ -579,8 +579,8 @@ if (DEBUGGER) {
*/
C1PDebugger.prototype.setPower = function(fOn, cmp)
{
if (fOn && !this.fPower) {
this.fPower = true;
if (fOn && !this.aFlags.fPowered) {
this.aFlags.fPowered = true;
this.cpu = cmp.getComponentByType("cpu");
}
};

View file

@ -217,7 +217,7 @@ function C1PDiskController(parmsDC)
{
Component.call(this, "C1PDiskController", parmsDC);
this.fPower = false;
this.aFlags.fPowered = false;
/*
* Our DiskController simulates the combination of an MC6820 PIA and an MC6850 ACIA.
@ -733,8 +733,8 @@ C1PDiskController.prototype.setBuffer = function(abMemory, start, end, cpu)
*/
C1PDiskController.prototype.setPower = function(fOn, cmp)
{
if (fOn && !this.fPower) {
this.fPower = true;
if (fOn && !this.aFlags.fPowered) {
this.aFlags.fPowered = true;
if (DEBUGGER) this.dbg = cmp.getComponentByType("debugger");
}
};

View file

@ -122,7 +122,7 @@ function C1PKeyboard(parmsKbd)
{
Component.call(this, "C1PKeyboard", parmsKbd);
this.fPower = false;
this.aFlags.fPowered = false;
this.nDefaultModel = parmsKbd['model'];
/*
@ -516,8 +516,8 @@ C1PKeyboard.prototype.setModel = function(nModel)
*/
C1PKeyboard.prototype.setPower = function(fOn, cmp)
{
if (fOn && !this.fPower) {
this.fPower = true;
if (fOn && !this.aFlags.fPowered) {
this.aFlags.fPowered = true;
this.cmp = cmp;
if (DEBUGGER) this.dbg = cmp.getComponentByType("debugger");
}

View file

@ -44,7 +44,7 @@ function C1PPanel(parmsPanel)
{
Component.call(this, "C1PPanel", parmsPanel);
this.fPower = false;
this.aFlags.fPowered = false;
}
Component.subclass(Component, C1PPanel);
@ -77,8 +77,8 @@ C1PPanel.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, contro
*/
C1PPanel.prototype.setPower = function(fOn, cmp)
{
if (fOn && !this.fPower) {
this.fPower = true;
if (fOn && !this.aFlags.fPowered) {
this.aFlags.fPowered = true;
this.cmp = cmp;
this.cpu = cmp.getComponentByType("cpu");
this.kbd = cmp.getComponentByType("keyboard");

View file

@ -115,8 +115,8 @@ C1PROM.prototype.setBuffer = function(abMemory, start, end, cpu)
*/
C1PROM.prototype.setPower = function(fOn, cmp)
{
if (fOn && !this.fPower) {
this.fPower = true;
if (fOn && !this.aFlags.fPowered) {
this.aFlags.fPowered = true;
if (DEBUGGER) this.dbg = cmp.getComponentByType("debugger");
}
};

View file

@ -44,7 +44,7 @@ function C1PSerialPort(parmsSerial)
{
Component.call(this, "C1PSerialPort", parmsSerial);
this.fPower = false;
this.aFlags.fPowered = false;
this.fDemo = parmsSerial['demo'];
this.STATUS_NONE = 0x00;
@ -160,8 +160,8 @@ C1PSerialPort.prototype.setBuffer = function(abMemory, start, end, cpu)
*/
C1PSerialPort.prototype.setPower = function(fOn, cmp)
{
if (fOn && !this.fPower) {
this.fPower = true;
if (fOn && !this.aFlags.fPowered) {
this.aFlags.fPowered = true;
this.cmp = cmp;
this.kbd = cmp.getComponentByType("keyboard");
if (DEBUGGER) this.dbg = cmp.getComponentByType("debugger");

View file

@ -308,8 +308,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.fPower && this.isReady()) {
this.fPower = true;
if (fOn && !this.aFlags.fPowered && this.isReady()) {
this.aFlags.fPowered = true;
if (DEBUGGER) this.dbg = cmp.getComponentByType("debugger");
/*
* If we have an associated keyboard, then ensure that the keyboard will be notified whenever
@ -328,8 +328,8 @@ C1PVideo.prototype.setPower = function(fOn, cmp)
}
}
else
if (!fOn && this.fPower) {
this.fPower = false;
if (!fOn && this.aFlags.fPowered) {
this.aFlags.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.
@ -442,7 +442,7 @@ C1PVideo.prototype.initScreen = function()
C1PVideo.prototype.updateScreen = function()
{
var offset = 0;
if (this.fPower) {
if (this.aFlags.fPowered) {
while (offset < this.cbScreen) {
var b = this.abMem[this.offVideo + offset];
if (this.abScreen[offset] != b) {

View file

@ -9,7 +9,7 @@
<xsl:variable name="MACHINECLASS">c1p</xsl:variable>
<xsl:variable name="APPCLASS">c1pjs</xsl:variable>
<xsl:variable name="APPVERSION">1.0.0</xsl:variable>
<xsl:variable name="APPVERSION">1.x.x</xsl:variable>
<xsl:variable name="SITEHOST">www.pcjs.org</xsl:variable>
<xsl:template name="componentStyles">

View file

@ -15,7 +15,7 @@
"PCJSCLASS": true,
"DEBUGGER": true,
"PREFETCH": true,
"FASTDISABLE": true,
"EAFUNCS": true,
"FATARRAYS": true,
"TYPEDARRAYS": true,
"Component": true,

View file

@ -123,11 +123,11 @@ function Computer(parmsComputer, parmsMachine, fSuspended) {
Component.call(this, "Computer", parmsComputer, Computer);
this.fPowered = false;
this.aFlags.fPowered = false;
this.nBusWidth = parmsComputer['buswidth'];
this.resume = Computer.RESUME_NONE;
this.sStateData = null;
this.fServerState = this.fSave = false;
this.fServerState = false;
this.url = parmsMachine? parmsMachine['url'] : null;
/*
@ -544,9 +544,9 @@ Computer.prototype.powerOn = function(resume)
*/
Computer.prototype.powerRestore = function(component, stateComputer, fRepower, fRestore)
{
if (!component.fPowered) {
if (!component.aFlags.fPowered) {
component.fPowered = true;
component.aFlags.fPowered = true;
if (component.powerUp) {
@ -649,9 +649,9 @@ Computer.prototype.donePowerOn = function(aParms)
var fRepower = (aParms[1] < 0);
var fRestore = aParms[2];
if (DEBUG && this.fPowered) this.messageDebugger("Computer.donePowerOn(): redundant");
if (DEBUG && this.aFlags.fPowered) this.messageDebugger("Computer.donePowerOn(): redundant");
this.fPowered = true;
this.aFlags.fPowered = true;
if (!this.fInitialized) {
this.println(Computer.sAppName + " v" + Computer.sAppVer + "\n" + Computer.sCopyright + "\n" + Computer.LICENSE);
@ -754,7 +754,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.fPowered = false;
this.cpu.aFlags.fPowered = false;
if (data === false) sState = null;
}
}
@ -762,13 +762,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.fPowered) {
if (component.aFlags.fPowered) {
if (component.powerDown) {
data = component.powerDown(fSave, fShutdown);
if (typeof data === "object") stateComputer.set(component.id, data);
}
if (fShutdown) {
component.fPowered = false;
component.aFlags.fPowered = false;
if (data === false) sState = null;
}
}
@ -820,7 +820,7 @@ Computer.prototype.powerOff = function(fSave, fShutdown)
}
}
if (fShutdown) this.fPowered = false;
if (fShutdown) this.aFlags.fPowered = false;
return sState;
};
@ -1221,7 +1221,7 @@ Computer.init = function()
*/
var computer = new Computer(parmsComputer, parmsMachine, true);
if (DEBUG) computer.messageDebugger("onInit(" + computer.fPowered + ")");
if (DEBUG) computer.messageDebugger("onInit(" + computer.aFlags.fPowered + ")");
/*
* For now, all we support are "reset" and "save" buttons. We may eventually add a "power"
@ -1251,9 +1251,9 @@ Computer.show = function()
var computer = Component.getComponentByType("Computer", parmsComputer['id']);
if (computer) {
if (DEBUG) computer.messageDebugger("onShow(" + computer.fInitialized + "," + computer.fPowered + ")");
if (DEBUG) computer.messageDebugger("onShow(" + computer.fInitialized + "," + computer.aFlags.fPowered + ")");
if (computer.fInitialized && !computer.fPowered) {
if (computer.fInitialized && !computer.aFlags.fPowered) {
/**
* Repower the computer, notifying every component to continue running as-is.
*/
@ -1298,9 +1298,9 @@ Computer.exit = function()
var computer = Component.getComponentByType("Computer", parmsComputer['id']);
if (computer) {
if (DEBUG) computer.messageDebugger("onExit(" + computer.fPowered + ")");
if (DEBUG) computer.messageDebugger("onExit(" + computer.aFlags.fPowered + ")");
if (computer.fPowered) {
if (computer.aFlags.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

View file

@ -80,23 +80,24 @@ function CPU(parmsCPU, nCyclesDefault)
var nMultiplier = parmsCPU['multiplier'] || 1;
this.nCyclesPerSecond = nCycles;
this.aCounts = {};
this.aCounts.nCyclesPerSecond = nCycles;
/*
* nCyclesMultiplier replaces the old "speed" variable (0, 1, 2) and eliminates the need for
* the constants (SPEED_SLOW, SPEED_FAST and SPEED_MAX). The UI simply doubles the multiplier
* until we've exceeded the host's speed limit and then starts the multiplier over at 1.
*/
this.nCyclesMultiplier = nMultiplier;
this.mhzDefault = Math.round(this.nCyclesPerSecond / 10000) / 100;
this.aCounts.nCyclesMultiplier = nMultiplier;
this.aCounts.mhzDefault = Math.round(this.aCounts.nCyclesPerSecond / 10000) / 100;
/*
* TODO: Take care of this with an initial setSpeed() call instead?
*/
this.mhzTarget = this.mhzDefault * this.nCyclesMultiplier;
this.aCounts.mhzTarget = this.aCounts.mhzDefault * this.aCounts.nCyclesMultiplier;
this.fPowered = false;
this.fRunning = false;
this.fAutoStart = parmsCPU['autoStart'];
this.aFlags.fPowered = false;
this.aFlags.fRunning = false;
this.aFlags.fAutoStart = parmsCPU['autoStart'];
/*
* Provide a power-saving URL-based way of overriding the 'autostart' setting;
@ -105,7 +106,7 @@ function CPU(parmsCPU, nCyclesDefault)
*/
var sAutoStart = Component.parmsURL['autostart'];
if (sAutoStart !== undefined) {
this.fAutoStart = (sAutoStart == "true"? true : (sAutoStart == "false"? false : null));
this.aFlags.fAutoStart = (sAutoStart == "true"? true : (sAutoStart == "false"? false : null));
}
/*
@ -117,11 +118,11 @@ function CPU(parmsCPU, nCyclesDefault)
* command ("x"); for example, "x cs int 5000" will set nCyclesChecksumInterval to 5000
* and call resetChecksum().
*/
this.fChecksum = false;
this.nChecksum = this.nCyclesChecksumNext = 0;
this.nCyclesChecksumStart = parmsCPU["csStart"];
this.nCyclesChecksumInterval = parmsCPU["csInterval"];
this.nCyclesChecksumStop = parmsCPU["csStop"];
this.aFlags.fChecksum = false;
this.aCounts.nChecksum = this.aCounts.nCyclesChecksumNext = 0;
this.aCounts.nCyclesChecksumStart = parmsCPU["csStart"];
this.aCounts.nCyclesChecksumInterval = parmsCPU["csInterval"];
this.aCounts.nCyclesChecksumStop = parmsCPU["csStop"];
var cpu = this;
this.onRunTimeout = function() { cpu.runCPU(); };
@ -138,16 +139,16 @@ Component.subclass(Component, CPU);
* calcCycles(), which uses the nCyclesPerSecond passed to the constructor as a starting
* point and computes the following variables:
*
* this.nCyclesPerYield (this.nCyclesPerSecond / CPU.YIELDS_PER_SECOND)
* this.nCyclesPerVideoUpdate (this.nCyclesPerSecond / CPU.VIDEO_UPDATES_PER_SECOND)
* this.nCyclesPerStatusUpdate (this.nCyclesPerSecond / CPU.STATUS_UPDATES_PER_SECOND)
* this.aCounts.nCyclesPerYield (this.aCounts.nCyclesPerSecond / CPU.YIELDS_PER_SECOND)
* this.aCounts.nCyclesPerVideoUpdate (this.aCounts.nCyclesPerSecond / CPU.VIDEO_UPDATES_PER_SECOND)
* this.aCounts.nCyclesPerStatusUpdate (this.aCounts.nCyclesPerSecond / CPU.STATUS_UPDATES_PER_SECOND)
*
* The above variables are also multiplied by any cycle multiplier in effect, via setSpeed(),
* and then they're used to initialize another set of variables for each runCPU() iteration:
*
* this.nCyclesNextYield <= this.nCyclesPerYield
* this.nCyclesNextVideoUpdate <= this.nCyclesPerVideoUpdate
* this.nCyclesNextStatusUpdate <= this.nCyclesPerStatusUpdate
* this.aCounts.nCyclesNextYield <= this.aCounts.nCyclesPerYield
* this.aCounts.nCyclesNextVideoUpdate <= this.aCounts.nCyclesPerVideoUpdate
* this.aCounts.nCyclesNextStatusUpdate <= this.aCounts.nCyclesPerStatusUpdate
*/
CPU.YIELDS_PER_SECOND = 30;
CPU.VIDEO_UPDATES_PER_SECOND = 60; // WARNING: if you change this, beware of side-effects in the Video component
@ -264,7 +265,7 @@ CPU.prototype.powerUp = function(data, fRepower)
this.println("No debugger detected");
}
}
this.fPowered = true;
this.aFlags.fPowered = true;
if (!this.autoStart() && this.dbg) this.dbg.updateStatus();
this.updateCPU();
return true;
@ -279,7 +280,7 @@ CPU.prototype.powerUp = function(data, fRepower)
*/
CPU.prototype.powerDown = function(fSave)
{
this.fPowered = false;
this.aFlags.fPowered = false;
return fSave && this.save ? this.save() : true;
};
@ -291,7 +292,7 @@ CPU.prototype.powerDown = function(fSave)
*/
CPU.prototype.autoStart = function()
{
if (this.fAutoStart === true || this.fAutoStart === null && (!DEBUGGER || !this.dbg) && this.bindings["run"] === undefined) {
if (this.aFlags.fAutoStart === true || this.aFlags.fAutoStart === null && (!DEBUGGER || !this.dbg) && this.bindings["run"] === undefined) {
this.runCPU(); // start running automatically on power-up, assuming there's no Debugger
return true;
}
@ -318,7 +319,7 @@ CPU.prototype.setFocus = function()
*/
CPU.prototype.isPowered = function()
{
if (!this.fPowered) {
if (!this.aFlags.fPowered) {
this.println(this.toString() + " not powered");
return false;
}
@ -333,7 +334,7 @@ CPU.prototype.isPowered = function()
*/
CPU.prototype.isRunning = function()
{
return this.fRunning;
return this.aFlags.fRunning;
};
/**
@ -361,14 +362,14 @@ CPU.prototype.getChecksum = function()
*/
CPU.prototype.resetChecksum = function()
{
if (this.nCyclesChecksumStart === undefined) this.nCyclesChecksumStart = 0;
if (this.nCyclesChecksumInterval === undefined) this.nCyclesChecksumInterval = -1;
if (this.nCyclesChecksumStop === undefined) this.nCyclesChecksumStop = -1;
this.fChecksum = (this.nCyclesChecksumStart >= 0 && this.nCyclesChecksumInterval > 0);
if (this.fChecksum) {
this.nChecksum = 0;
this.nCyclesChecksumNext = this.nCyclesChecksumStart - this.nTotalCycles;
// this.nCyclesChecksumNext = this.nCyclesChecksumStart + this.nCyclesChecksumInterval - (this.nTotalCycles % this.nCyclesChecksumInterval);
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.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);
return true;
}
return false;
@ -387,20 +388,20 @@ CPU.prototype.resetChecksum = function()
*/
CPU.prototype.updateChecksum = function(nCycles)
{
if (this.fChecksum) {
if (this.aFlags.fChecksum) {
/*
* Get a 32-bit summation of the current CPU state and add it to our running 32-bit checksum
*/
var fDisplay = false;
this.nChecksum = (this.nChecksum + this.getChecksum()) | 0;
this.nCyclesChecksumNext -= nCycles;
if (this.nCyclesChecksumNext <= 0) {
this.nCyclesChecksumNext += this.nCyclesChecksumInterval;
this.aCounts.nChecksum = (this.aCounts.nChecksum + this.getChecksum()) | 0;
this.aCounts.nCyclesChecksumNext -= nCycles;
if (this.aCounts.nCyclesChecksumNext <= 0) {
this.aCounts.nCyclesChecksumNext += this.aCounts.nCyclesChecksumInterval;
fDisplay = true;
}
if (this.nCyclesChecksumStop >= 0) {
if (this.nCyclesChecksumStop <= this.getCycles()) {
this.nCyclesChecksumInterval = this.nCyclesChecksumStop = -1;
if (this.aCounts.nCyclesChecksumStop >= 0) {
if (this.aCounts.nCyclesChecksumStop <= this.getCycles()) {
this.aCounts.nCyclesChecksumInterval = this.aCounts.nCyclesChecksumStop = -1;
this.resetChecksum();
this.haltCPU();
fDisplay = true;
@ -421,7 +422,7 @@ CPU.prototype.updateChecksum = function(nCycles)
*/
CPU.prototype.displayChecksum = function()
{
this.println(this.getCycles() + " cycles: " + "checksum=" + str.toHex(this.nChecksum));
this.println(this.getCycles() + " cycles: " + "checksum=" + str.toHex(this.aCounts.nChecksum));
};
/**
@ -492,7 +493,7 @@ CPU.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, control)
case "run":
this.bindings[sBinding] = control;
control.onclick = function onClickRun() {
if (!cpu.fRunning)
if (!cpu.aFlags.fRunning)
cpu.runCPU(true);
else
cpu.haltCPU(true);
@ -521,7 +522,7 @@ CPU.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, control)
case "setSpeed":
this.bindings[sBinding] = control;
control.onclick = function onClickSetSpeed() {
cpu.setSpeed(cpu.nCyclesMultiplier << 1, true);
cpu.setSpeed(cpu.aCounts.nCyclesMultiplier << 1, true);
};
control.innerHTML = this.getSpeedTarget();
fBound = true;
@ -605,26 +606,26 @@ CPU.prototype.calcCycles = function(fRecalc)
*/
var vMultiplier = 1;
if (fRecalc) {
if (this.nCyclesMultiplier > 1 && this.mhz) {
vMultiplier = (this.mhz / this.mhzDefault);
if (this.aCounts.nCyclesMultiplier > 1 && this.aCounts.mhz) {
vMultiplier = (this.aCounts.mhz / this.aCounts.mhzDefault);
}
}
this.msPerYield = Math.round(1000 / CPU.YIELDS_PER_SECOND);
this.nCyclesPerBurst = Math.floor(this.nCyclesPerSecond / nMostUpdatesPerSecond * vMultiplier);
this.nCyclesPerYield = Math.floor(this.nCyclesPerSecond / CPU.YIELDS_PER_SECOND * vMultiplier);
this.nCyclesPerVideoUpdate = Math.floor(this.nCyclesPerSecond / CPU.VIDEO_UPDATES_PER_SECOND * vMultiplier);
this.nCyclesPerStatusUpdate = Math.floor(this.nCyclesPerSecond / CPU.STATUS_UPDATES_PER_SECOND * vMultiplier);
this.aCounts.msPerYield = Math.round(1000 / CPU.YIELDS_PER_SECOND);
this.aCounts.nCyclesPerBurst = Math.floor(this.aCounts.nCyclesPerSecond / nMostUpdatesPerSecond * vMultiplier);
this.aCounts.nCyclesPerYield = Math.floor(this.aCounts.nCyclesPerSecond / CPU.YIELDS_PER_SECOND * vMultiplier);
this.aCounts.nCyclesPerVideoUpdate = Math.floor(this.aCounts.nCyclesPerSecond / CPU.VIDEO_UPDATES_PER_SECOND * vMultiplier);
this.aCounts.nCyclesPerStatusUpdate = Math.floor(this.aCounts.nCyclesPerSecond / CPU.STATUS_UPDATES_PER_SECOND * vMultiplier);
/*
* And initialize "next" yield, video update, and status update cycle "threshold" counters to those "per" values
*/
if (!fRecalc) {
this.nCyclesNextYield = this.nCyclesPerYield;
this.nCyclesNextVideoUpdate = this.nCyclesPerVideoUpdate;
this.nCyclesNextStatusUpdate = this.nCyclesPerStatusUpdate;
this.aCounts.nCyclesNextYield = this.aCounts.nCyclesPerYield;
this.aCounts.nCyclesNextVideoUpdate = this.aCounts.nCyclesPerVideoUpdate;
this.aCounts.nCyclesNextStatusUpdate = this.aCounts.nCyclesPerStatusUpdate;
}
this.nRecalcCycles = 0;
this.aCounts.nCyclesRecalc = 0;
};
/**
@ -647,11 +648,11 @@ CPU.prototype.calcCycles = function(fRecalc)
CPU.prototype.getCycles = function(fScaled)
{
var nCycles = this.nTotalCycles + this.nRunCycles + this.nBurstCycles - this.nStepCycles;
if (fScaled && this.nCyclesMultiplier > 1 && this.mhz > this.mhzDefault) {
if (fScaled && this.aCounts.nCyclesMultiplier > 1 && this.aCounts.mhz > this.aCounts.mhzDefault) {
/*
* We could scale the current cycle count by the current effective speed (this.mhz); eg:
* We could scale the current cycle count by the current effective speed (this.aCounts.mhz); eg:
*
* nCycles = Math.round(nCycles / (this.mhz / this.mhzDefault));
* nCycles = Math.round(nCycles / (this.aCounts.mhz / this.aCounts.mhzDefault));
*
* but that speed will fluctuate somewhat: large fluctuations at first, but increasingly smaller
* fluctuations after each burst of instructions that runCPU() executes.
@ -666,7 +667,7 @@ CPU.prototype.getCycles = function(fScaled)
* interface allows any value, as does the CPU "multiplier" parmsCPU property (from the machine's
* XML file).
*/
nCycles = Math.round(nCycles / this.nCyclesMultiplier);
nCycles = Math.round(nCycles / this.aCounts.nCyclesMultiplier);
}
return nCycles;
};
@ -681,7 +682,7 @@ CPU.prototype.getCycles = function(fScaled)
*/
CPU.prototype.getCyclesPerSecond = function()
{
return this.nCyclesPerSecond;
return this.aCounts.nCyclesPerSecond;
};
/**
@ -695,7 +696,7 @@ CPU.prototype.getCyclesPerSecond = function()
*/
CPU.prototype.resetCycles = function()
{
this.mhz = 0;
this.aCounts.mhz = 0;
this.setBurstDivisor(1);
this.nTotalCycles = this.nRunCycles = this.nBurstCycles = this.nStepCycles = 0;
this.resetChecksum();
@ -709,7 +710,7 @@ CPU.prototype.resetCycles = function()
* @return {number} the current speed multiplier
*/
CPU.prototype.getSpeed = function() {
return this.nCyclesMultiplier;
return this.aCounts.nCyclesMultiplier;
};
/**
@ -722,7 +723,7 @@ CPU.prototype.getSpeedCurrent = function() {
/*
* TODO: Has toFixed() been "fixed" in all browsers (eg, IE) to return a rounded value now?
*/
return ((this.fRunning && this.mhz)? (this.mhz.toFixed(2) + "Mhz") : "Stopped");
return ((this.aFlags.fRunning && this.aCounts.mhz)? (this.aCounts.mhz.toFixed(2) + "Mhz") : "Stopped");
};
/**
@ -735,7 +736,7 @@ CPU.prototype.getSpeedTarget = function() {
/*
* TODO: Has toFixed() been "fixed" in all browsers (eg, IE) to return a rounded value now?
*/
return this.mhzTarget.toFixed(2) + "Mhz";
return this.aCounts.mhzTarget.toFixed(2) + "Mhz";
};
/**
@ -756,11 +757,11 @@ CPU.prototype.setSpeed = function(nMultiplier, fOnClick)
* If we couldn't reach at least 80% (0.8) of the current target speed,
* then revert the multiplier back to one.
*/
if (this.mhz/this.mhzTarget < 0.8) nMultiplier = 1;
this.nCyclesMultiplier = nMultiplier;
var mhz = this.mhzDefault * this.nCyclesMultiplier;
if (this.mhzTarget != mhz) {
this.mhzTarget = mhz;
if (this.aCounts.mhz / this.aCounts.mhzTarget < 0.8) nMultiplier = 1;
this.aCounts.nCyclesMultiplier = nMultiplier;
var mhz = this.aCounts.mhzDefault * this.aCounts.nCyclesMultiplier;
if (this.aCounts.mhzTarget != mhz) {
this.aCounts.mhzTarget = mhz;
var sSpeed = this.getSpeedTarget();
if (this.bindings["setSpeed"]) this.bindings["setSpeed"].innerHTML = sSpeed;
this.println("target speed: " + sSpeed);
@ -769,10 +770,10 @@ CPU.prototype.setSpeed = function(nMultiplier, fOnClick)
}
this.addCycles(this.nRunCycles);
this.nRunCycles = 0;
this.msRunStart = usr.getTime();
this.msEndThisRun = 0;
this.aCounts.msStartRun = usr.getTime();
this.aCounts.msEndThisRun = 0;
this.calcCycles();
return this.mhzTarget;
return this.aCounts.mhzTarget;
};
/**
@ -785,7 +786,7 @@ CPU.prototype.setSpeed = function(nMultiplier, fOnClick)
CPU.prototype.calcSpeed = function(nCycles, msElapsed)
{
if (msElapsed) {
this.mhz = Math.round(nCycles / (msElapsed * 10)) / 100;
this.aCounts.mhz = Math.round(nCycles / (msElapsed * 10)) / 100;
if (msElapsed >= 86400000) {
this.nTotalCycles = 0;
if (this.chipset) this.chipset.updateAllTimers(true);
@ -801,11 +802,11 @@ CPU.prototype.calcSpeed = function(nCycles, msElapsed)
*/
CPU.prototype.calcStartTime = function()
{
if (this.nRecalcCycles >= this.nCyclesPerSecond) {
if (this.aCounts.nCyclesRecalc >= this.aCounts.nCyclesPerSecond) {
this.calcCycles(true);
}
this.nCyclesThisRun = 0;
this.msStartThisRun = usr.getTime();
this.aCounts.nCyclesThisRun = 0;
this.aCounts.msStartThisRun = usr.getTime();
/*
* Try to detect situations where the browser may have throttled us, such as when the user switches
@ -818,7 +819,7 @@ CPU.prototype.calcStartTime = function()
*
* We can detect throttling/lagging by verifying that msEndThisRun (which was set at the end of the
* previous run and includes any requested sleep time) is comparable to the current msStartThisRun;
* if the delta is significant, we compensate by bumping msRunStart forward by that delta.
* if the delta is significant, we compensate by bumping msStartRun forward by that delta.
*
* This shouldn't be triggered when the Debugger halts the CPU, because setSpeed() -- which is called
* whenever the CPU starts running again -- zeroes msEndThisRun.
@ -832,19 +833,19 @@ CPU.prototype.calcStartTime = function()
* to hit its target speed, since you would expect any instruction that displays a message to be an
* EXTREMELY slow instruction.
*/
if (this.msEndThisRun) {
var msDelta = this.msStartThisRun - this.msEndThisRun;
if (msDelta > this.msPerYield) {
if (this.aCounts.msEndThisRun) {
var msDelta = this.aCounts.msStartThisRun - this.aCounts.msEndThisRun;
if (msDelta > this.aCounts.msPerYield) {
if (MAXDEBUG) this.println("large time delay: " + msDelta + "ms");
this.msRunStart += msDelta;
this.aCounts.msStartRun += msDelta;
/*
* Bumping msRunStart forward should NEVER cause it to exceed msStartThisRun; however, just
* Bumping msStartRun forward should NEVER cause it to exceed msStartThisRun; however, just
* in case, I make absolutely sure it cannot happen, since doing so could result in negative
* speed calculations.
*/
Component.assert(this.msRunStart <= this.msStartThisRun);
if (this.msRunStart > this.msStartThisRun) {
this.msRunStart = this.msStartThisRun;
Component.assert(this.aCounts.msStartRun <= this.aCounts.msStartThisRun);
if (this.aCounts.msStartRun > this.aCounts.msStartThisRun) {
this.aCounts.msStartRun = this.aCounts.msStartThisRun;
}
}
}
@ -858,47 +859,47 @@ CPU.prototype.calcStartTime = function()
*/
CPU.prototype.calcRemainingTime = function()
{
this.msEndThisRun = usr.getTime();
this.aCounts.msEndThisRun = usr.getTime();
var msYield = this.msPerYield;
if (this.nCyclesThisRun) {
var msYield = this.aCounts.msPerYield;
if (this.aCounts.nCyclesThisRun) {
/*
* Normally, we would assume we executed a full quota of work over msPerYield, but since the CPU
* now has the option of calling yieldCPU(), that might not be true. If nCyclesThisRun is correct, then
* the ratio of nCyclesThisRun/nCyclesPerYield should represent the percentage of work we performed,
* and so applying that percentage to msPerYield should give us a better estimate of work vs. time.
*/
msYield = Math.round(msYield * this.nCyclesThisRun / this.nCyclesPerYield);
msYield = Math.round(msYield * this.aCounts.nCyclesThisRun / this.aCounts.nCyclesPerYield);
}
var msElapsedThisRun = this.msEndThisRun - this.msStartThisRun;
var msElapsedThisRun = this.aCounts.msEndThisRun - this.aCounts.msStartThisRun;
var msRemainsThisRun = msYield - msElapsedThisRun;
/*
* We could pass only "this run" results to calcSpeed():
*
* nCycles = this.nCyclesThisRun;
* nCycles = this.aCounts.nCyclesThisRun;
* msElapsed = msElapsedThisRun;
*
* but it seems preferable to use longer time periods and hopefully get a more accurate speed.
*
* Also, if msRemainsThisRun >= 0 && this.nCyclesMultiplier == 1, we could pass these results instead:
* Also, if msRemainsThisRun >= 0 && this.aCounts.nCyclesMultiplier == 1, we could pass these results instead:
*
* nCycles = this.nCyclesThisRun;
* msElapsed = this.msPerYield;
* nCycles = this.aCounts.nCyclesThisRun;
* msElapsed = this.aCounts.msPerYield;
*
* to insure that we display a smooth, constant N Mhz. But for now, I prefer seeing any fluctuations.
*/
var nCycles = this.nRunCycles;
var msElapsed = this.msEndThisRun - this.msRunStart;
var msElapsed = this.aCounts.msEndThisRun - this.aCounts.msStartRun;
if (MAXDEBUG && msRemainsThisRun < 0 && this.nCyclesMultiplier > 1) {
if (MAXDEBUG && msRemainsThisRun < 0 && this.aCounts.nCyclesMultiplier > 1) {
this.println("warning: updates @" + msElapsedThisRun + "ms (prefer " + Math.round(msYield) + "ms)");
}
this.calcSpeed(nCycles, msElapsed);
if (msRemainsThisRun < 0 || this.mhz < this.mhzTarget) {
if (msRemainsThisRun < 0 || this.aCounts.mhz < this.aCounts.mhzTarget) {
/*
* If the last burst took MORE time than we allotted (ie, it's taking more than 1 second to simulate
* nCyclesPerSecond), all we can do is yield for as little time as possible (ie, 0ms) and hope that the
@ -908,16 +909,16 @@ CPU.prototype.calcRemainingTime = function()
}
/*
* Last but not least, update nRecalcCycles, so that when runCPU() starts up again and calls calcStartTime(),
* Last but not least, update nCyclesRecalc, so that when runCPU() starts up again and calls calcStartTime(),
* it'll be ready to decide if calcCycles() should be called again.
*/
this.nRecalcCycles += this.nCyclesThisRun;
this.aCounts.nCyclesRecalc += this.aCounts.nCyclesThisRun;
if (DEBUG && this.dbg && this.dbg.messageEnabled(Debugger.MESSAGE_LOG) && msRemainsThisRun) {
this.dbg.message("at " + this.msEndThisRun + "ms, calcRemainingTime returned " + msRemainsThisRun + "ms to sleep");
this.dbg.message("at " + this.aCounts.msEndThisRun + "ms, calcRemainingTime returned " + msRemainsThisRun + "ms to sleep");
}
this.msEndThisRun += msRemainsThisRun;
this.aCounts.msEndThisRun += msRemainsThisRun;
return msRemainsThisRun;
};
@ -934,28 +935,28 @@ CPU.prototype.runCPU = function(fOnClick)
if (this.cmp) this.cmp.stop(usr.getTime(), this.getCycles());
return;
}
if (!this.fRunning) {
if (!this.aFlags.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
* of cycles for each burst based on the last known effective CPU speed, and resets the nRecalcCycles
* of cycles for each burst based on the last known effective CPU speed, and resets the nCyclesRecalc
* threshold counter.
*/
this.setSpeed();
if (this.cmp) this.cmp.start(this.msRunStart, this.getCycles());
this.fRunning = true;
if (this.cmp) this.cmp.start(this.aCounts.msStartRun, this.getCycles());
this.aFlags.fRunning = true;
if (this.chipset) this.chipset.setSpeaker();
if (this.bindings["run"]) this.bindings["run"].innerHTML = "Halt";
if (fOnClick) this.setFocus();
}
/*
* calcStartTime() initializes the cycle counter and timestamp for this runCPU() invocation, and optionally
* recalculates the the maximum number of cycles for each burst if the nRecalcCycles threshold has been reached.
* recalculates the the maximum number of cycles for each burst if the nCyclesRecalc threshold has been reached.
*/
this.calcStartTime();
try {
do {
var nCyclesPerBurst = this.fChecksum? 1 : Math.round(this.nCyclesPerBurst / this.nBurstDivisor);
var nCyclesPerBurst = this.aFlags.fChecksum? 1 : Math.round(this.aCounts.nCyclesPerBurst / this.nBurstDivisor);
/*
* This is an alternative to ChipSet calling setBurstDivisor(). Unfortunately, this doesn't seem
@ -982,28 +983,28 @@ CPU.prototype.runCPU = function(fOnClick)
*/
var nCycles = this.nBurstCycles - this.nStepCycles;
this.nRunCycles += nCycles;
this.nCyclesThisRun += nCycles;
this.aCounts.nCyclesThisRun += nCycles;
this.addCycles(0, true);
this.updateChecksum(nCycles);
this.nCyclesNextVideoUpdate -= nCycles;
if (this.nCyclesNextVideoUpdate <= 0) {
this.nCyclesNextVideoUpdate += this.nCyclesPerVideoUpdate;
this.aCounts.nCyclesNextVideoUpdate -= nCycles;
if (this.aCounts.nCyclesNextVideoUpdate <= 0) {
this.aCounts.nCyclesNextVideoUpdate += this.aCounts.nCyclesPerVideoUpdate;
this.displayVideo();
}
this.nCyclesNextStatusUpdate -= nCycles;
if (this.nCyclesNextStatusUpdate <= 0) {
this.nCyclesNextStatusUpdate += this.nCyclesPerStatusUpdate;
this.aCounts.nCyclesNextStatusUpdate -= nCycles;
if (this.aCounts.nCyclesNextStatusUpdate <= 0) {
this.aCounts.nCyclesNextStatusUpdate += this.aCounts.nCyclesPerStatusUpdate;
this.displayStatus();
}
this.nCyclesNextYield -= nCycles;
if (this.nCyclesNextYield <= 0) {
this.nCyclesNextYield += this.nCyclesPerYield;
this.aCounts.nCyclesNextYield -= nCycles;
if (this.aCounts.nCyclesNextYield <= 0) {
this.aCounts.nCyclesNextYield += this.aCounts.nCyclesPerYield;
break;
}
} while (this.fRunning);
} while (this.aFlags.fRunning);
}
catch (e) {
this.haltCPU();
@ -1029,7 +1030,7 @@ CPU.prototype.runCPU = function(fOnClick)
*/
CPU.prototype.setBurstCycles = function(nCycles)
{
if (this.fRunning) {
if (this.aFlags.fRunning) {
var nDelta = this.nStepCycles - nCycles;
/*
* NOTE: If nDelta is negative, we will actually be increasing nStepCycles and nBurstCycles.
@ -1060,12 +1061,12 @@ CPU.prototype.haltCPU = function(fComplete)
this.nStepCycles = 0;
this.addCycles(this.nRunCycles);
this.nRunCycles = 0;
if (this.fRunning) {
this.fRunning = false;
if (this.aFlags.fRunning) {
this.aFlags.fRunning = false;
if (this.chipset) this.chipset.setSpeaker();
if (this.bindings["run"]) this.bindings["run"].innerHTML = "Run";
}
this.fComplete = fComplete;
this.aFlags.fComplete = fComplete;
};
/**
@ -1108,7 +1109,7 @@ CPU.prototype.updateCPU = function()
*/
CPU.prototype.yieldCPU = function()
{
this.nCyclesNextYield = 0; // this will break us out of runCPU(), once we break out of stepCPU()
this.aCounts.nCyclesNextYield = 0; // this will break us out of runCPU(), once we break out of stepCPU()
this.nBurstCycles -= this.nStepCycles;
this.nStepCycles = 0; // this will break us out of stepCPU()
/*

View file

@ -235,62 +235,62 @@ if (DEBUGGER) {
* 286 or 386, then I might as well leave some of that support in place, since the impact is minimal).
*/
Debugger.INS = {
NONE: 0, AAA: 1, AAD: 2, AAM: 3, AAS: 4, ADC: 5, ADD: 6, AND: 7,
ARPL: 8, ASIZE: 9, BOUND: 10, BSF: 11, BSR: 12, BT: 13, BTC: 14, BTR: 15,
BTS: 16, CALL: 17, CBW: 18, CLC: 19, CLD: 20, CLI: 21, CLTS: 22, CMC: 23,
CMP: 24, CMPSB: 25, CMPSW: 26, CS: 27, CWD: 28, DAA: 29, DAS: 30, DEC: 31,
DIV: 32, DS: 33, ENTER: 34, ES: 35, ESC: 36, FADD: 37, FBLD: 38, FBSTP: 39,
FCOM: 40, FCOMP: 41, FDIV: 42, FDIVR: 43, FIADD: 44, FICOM: 45, FICOMP: 46, FIDIV: 47,
FIDIVR: 48, FILD: 49, FIMUL: 50, FIST: 51, FISTP: 52, FISUB: 53, FISUBR: 54, FLD: 55,
FLDCW: 56, FLDENV: 57, FMUL: 58, FNSAVE: 59, FNSTCW: 60, FNSTENV: 61, FNSTSW: 62, FRSTOR: 63,
FS: 64, FST: 65, FSTP: 66, FSUB: 67, FSUBR: 68, GBP: 69, GS: 70, HLT: 71,
IDIV: 72, IMUL: 73, IN: 74, INC: 75, INS: 76, INT: 77, INT3: 78, INTO: 79,
IRET: 80, JBE: 81, JC: 82, JCXZ: 83, JG: 84, JGE: 85, JL: 86, JLE: 87,
JMP: 88, JNBE: 89, JNC: 90, JNO: 91, JNP: 92, JNS: 93, JNZ: 94, JO: 95,
JP: 96, JS: 97, JZ: 98, LAHF: 99, LAR: 100, LDS: 101, LEA: 102, LEAVE: 103,
LES: 104, LFS: 105, LGDT: 106, LGS: 107, LIDT: 108, LLDT: 109, LMSW: 110, LOCK: 111,
LODSB: 112, LODSW: 113, LOOP: 114, LOOPNZ: 115, LOOPZ: 116, LSL: 117, LSS: 118, LTR: 119,
MOV: 120, MOVSB: 121, MOVSW: 122, MOVSX: 123, MOVZX: 124, MUL: 125, NEG: 126, NOP: 127,
NOT: 128, OR: 129, OSIZE: 130, OUT: 131, OUTS: 132, POP: 133, POPA: 134, POPF: 135,
PUSH: 136, PUSHA: 137, PUSHF: 138, RCL: 139, RCR: 140, REPNZ: 141, REPZ: 142, RET: 143,
RETF: 144, ROL: 145, ROR: 146, SAHF: 147, SAR: 148, SBB: 149, SCASB: 150, SCASW: 151,
SETBE: 152, SETC: 153, SETG: 154, SETGE: 155, SETL: 156, SETLE: 157, SETNBE: 158, SETNC: 159,
SETNO: 160, SETNP: 161, SETNS: 162, SETNZ: 163, SETO: 164, SETP: 165, SETS: 166, SETZ: 167,
SGDT: 168, SHL: 169, SHLD: 170, SHR: 171, SHRD: 172, SIDT: 173, SLDT: 174, SMSW: 175,
SS: 176, STC: 177, STD: 178, STI: 179, STOSB: 180, STOSW: 181, STR: 182, SUB: 183,
TEST: 184, VERR: 185, VERW: 186, WAIT: 187, XCHG: 188, XLAT: 189, XOR: 190, GRP1B: 191,
GRP1W: 192, GRP1SW: 193, GRP2B: 194, GRP2W: 195, GRP2B1: 196, GRP2W1: 197, GRP2BC: 198, GRP2WC: 199,
GRP3B: 200, GRP3W: 201, GRP4B: 202, GRP4W: 203, OP0F: 204, GRP6: 205, GRP7: 206
NONE: 0, AAA: 1, AAD: 2, AAM: 3, AAS: 4, ADC: 5, ADD: 6, AND: 7,
ARPL: 8, ASIZE: 9, BOUND: 10, BSF: 11, BSR: 12, BT: 13, BTC: 14, BTR: 15,
BTS: 16, CALL: 17, CBW: 18, CLC: 19, CLD: 20, CLI: 21, CLTS: 22, CMC: 23,
CMP: 24, CMPSB: 25, CMPSW: 26, CS: 27, CWD: 28, DAA: 29, DAS: 30, DEC: 31,
DIV: 32, DS: 33, ENTER: 34, ES: 35, ESC: 36, FADD: 37, FBLD: 38, FBSTP: 39,
FCOM: 40, FCOMP: 41, FDIV: 42, FDIVR: 43, FIADD: 44, FICOM: 45, FICOMP: 46, FIDIV: 47,
FIDIVR: 48, FILD: 49, FIMUL: 50, FIST: 51, FISTP: 52, FISUB: 53, FISUBR: 54, FLD: 55,
FLDCW: 56, FLDENV: 57, FMUL: 58, FNSAVE: 59, FNSTCW: 60, FNSTENV:61, FNSTSW: 62, FRSTOR: 63,
FS: 64, FST: 65, FSTP: 66, FSUB: 67, FSUBR: 68, GBP: 69, GS: 70, HLT: 71,
IDIV: 72, IMUL: 73, IN: 74, INC: 75, INS: 76, INT: 77, INT3: 78, INTO: 79,
IRET: 80, JBE: 81, JC: 82, JCXZ: 83, JG: 84, JGE: 85, JL: 86, JLE: 87,
JMP: 88, JNBE: 89, JNC: 90, JNO: 91, JNP: 92, JNS: 93, JNZ: 94, JO: 95,
JP: 96, JS: 97, JZ: 98, LAHF: 99, LAR: 100, LDS: 101, LEA: 102, LEAVE: 103,
LES: 104, LFS: 105, LGDT: 106, LGS: 107, LIDT: 108, LLDT: 109, LMSW: 110, LOADALL:111,
LOCK: 112, LODSB: 113, LODSW: 114, LOOP: 115, LOOPNZ: 116, LOOPZ: 117, LSL: 118, LSS: 119,
LTR: 120, MOV: 121, MOVSB: 122, MOVSW: 123, MOVSX: 124, MOVZX: 125, MUL: 126, NEG: 127,
NOP: 128, NOT: 129, OR: 130, OSIZE: 131, OUT: 132, OUTS: 133, POP: 134, POPA: 135,
POPF: 136, PUSH: 137, PUSHA: 138, PUSHF: 139, RCL: 140, RCR: 141, REPNZ: 142, REPZ: 143,
RET: 144, RETF: 145, ROL: 146, ROR: 147, SAHF: 148, SAR: 149, SBB: 150, SCASB: 151,
SCASW: 152, SETBE: 153, SETC: 154, SETG: 155, SETGE: 156, SETL: 157, SETLE: 158, SETNBE: 159,
SETNC: 160, SETNO: 161, SETNP: 162, SETNS: 163, SETNZ: 164, SETO: 165, SETP: 166, SETS: 167,
SETZ: 168, SGDT: 169, SHL: 170, SHLD: 171, SHR: 172, SHRD: 173, SIDT: 174, SLDT: 175,
SMSW: 176, SS: 177, STC: 178, STD: 179, STI: 180, STOSB: 181, STOSW: 182, STR: 183,
SUB: 184, TEST: 185, VERR: 186, VERW: 187, WAIT: 188, XCHG: 189, XLAT: 190, XOR: 191,
GRP1B: 192, GRP1W: 193, GRP1SW: 194, GRP2B: 195, GRP2W: 196, GRP2B1: 197, GRP2W1: 198, GRP2BC: 199,
GRP2WC: 200, GRP3B: 201, GRP3W: 202, GRP4B: 203, GRP4W: 204, OP0F: 205, GRP6: 206, GRP7: 207
};
/*
* Instruction names, indexed by instruction ordinal (above)
*/
Debugger.asIns = [
"DB", "AAA", "AAD", "AAM", "AAS", "ADC", "ADD", "AND",
"ARPL", "AS:", "BOUND", "BSF", "BSR", "BT", "BTC", "BTR",
"BTS", "CALL", "CBW", "CLC", "CLD", "CLI", "CLTS", "CMC",
"CMP", "CMPSB", "CMPSW", "CS:", "CWD", "DAA", "DAS", "DEC",
"DIV", "DS:", "ENTER", "ES:", "ESC", "FADD", "FBLD", "FBSTP",
"FCOM", "FCOMP", "FDIV", "FDIVR", "FIADD", "FICOM", "FICOMP", "FIDIV",
"FIDIVR", "FILD", "FIMUL", "FIST", "FISTP", "FISUB", "FISUBR", "FLD",
"FLDCW", "FLDENV", "FMUL", "FNSAVE", "FNSTCW", "FNSTENV", "FNSTSW", "FRSTOR",
"FS:", "FST", "FSTP", "FSUB", "FSUBR", "GBP", "GS:", "HLT",
"IDIV", "IMUL", "IN", "INC", "INS", "INT", "INT3", "INTO",
"IRET", "JBE", "JC", "JCXZ", "JG", "JGE", "JL", "JLE",
"JMP", "JNBE", "JNC", "JNO", "JNP", "JNS", "JNZ", "JO",
"JP", "JS", "JZ", "LAHF", "LAR", "LDS", "LEA", "LEAVE",
"LES", "LFS", "LGDT", "LGS", "LIDT", "LLDT", "LMSW", "LOCK",
"LODSB", "LODSW", "LOOP", "LOOPNZ", "LOOPZ", "LSL", "LSS", "LTR",
"MOV", "MOVSB", "MOVSW", "MOVSX", "MOVZX", "MUL", "NEG", "NOP",
"NOT", "OR", "OS:", "OUT", "OUTS", "POP", "POPA", "POPF",
"PUSH", "PUSHA", "PUSHF", "RCL", "RCR", "REPNZ", "REPZ", "RET",
"RETF", "ROL", "ROR", "SAHF", "SAR", "SBB", "SCASB", "SCASW",
"SETBE", "SETC", "SETG", "SETGE", "SETL", "SETLE", "SETNBE", "SETNC",
"SETNO", "SETNP", "SETNS", "SETNZ", "SETO", "SETP", "SETS", "SETZ",
"SGDT", "SHL", "SHLD", "SHR", "SHRD", "SIDT", "SLDT", "SMSW",
"SS:", "STC", "STD", "STI", "STOSB", "STOSW", "STR", "SUB",
"TEST", "VERR", "VERW", "WAIT", "XCHG", "XLAT", "XOR"
"DB", "AAA", "AAD", "AAM", "AAS", "ADC", "ADD", "AND",
"ARPL", "AS:", "BOUND", "BSF", "BSR", "BT", "BTC", "BTR",
"BTS", "CALL", "CBW", "CLC", "CLD", "CLI", "CLTS", "CMC",
"CMP", "CMPSB", "CMPSW", "CS:", "CWD", "DAA", "DAS", "DEC",
"DIV", "DS:", "ENTER", "ES:", "ESC", "FADD", "FBLD", "FBSTP",
"FCOM", "FCOMP", "FDIV", "FDIVR", "FIADD", "FICOM", "FICOMP", "FIDIV",
"FIDIVR", "FILD", "FIMUL", "FIST", "FISTP", "FISUB", "FISUBR", "FLD",
"FLDCW", "FLDENV", "FMUL", "FNSAVE", "FNSTCW", "FNSTENV","FNSTSW", "FRSTOR",
"FS:", "FST", "FSTP", "FSUB", "FSUBR", "GBP", "GS:", "HLT",
"IDIV", "IMUL", "IN", "INC", "INS", "INT", "INT3", "INTO",
"IRET", "JBE", "JC", "JCXZ", "JG", "JGE", "JL", "JLE",
"JMP", "JNBE", "JNC", "JNO", "JNP", "JNS", "JNZ", "JO",
"JP", "JS", "JZ", "LAHF", "LAR", "LDS", "LEA", "LEAVE",
"LES", "LFS", "LGDT", "LGS", "LIDT", "LLDT", "LMSW", "LOADALL",
"LOCK", "LODSB", "LODSW", "LOOP", "LOOPNZ", "LOOPZ", "LSL", "LSS",
"LTR", "MOV", "MOVSB", "MOVSW", "MOVSX", "MOVZX", "MUL", "NEG",
"NOP", "NOT", "OR", "OS:", "OUT", "OUTS", "POP", "POPA",
"POPF", "PUSH", "PUSHA", "PUSHF", "RCL", "RCR", "REPNZ", "REPZ",
"RET", "RETF", "ROL", "ROR", "SAHF", "SAR", "SBB", "SCASB",
"SCASW", "SETBE", "SETC", "SETG", "SETGE", "SETL", "SETLE", "SETNBE",
"SETNC", "SETNO", "SETNP", "SETNS", "SETNZ", "SETO", "SETP", "SETS",
"SETZ", "SGDT", "SHL", "SHLD", "SHR", "SHRD", "SIDT", "SLDT",
"SMSW", "SS:", "STC", "STD", "STI", "STOSB", "STOSW", "STR",
"SUB", "TEST", "VERR", "VERW", "WAIT", "XCHG", "XLAT", "XOR"
];
Debugger.CPU_86 = 0;
@ -524,7 +524,7 @@ if (DEBUGGER) {
*
* On the 8086, it functioned as POP CS
* On the 80186, it generated an illegal opcode (UD_FAULT) exception
* On the 80286, it introduced a series of new (and growing) two-byte opcodes
* On the 80286, it introduced a new (and growing) series of two-byte opcodes
*
* Based on the active CPU model, we make every effort to execute and disassemble this (and every other)
* opcode appropriately, by setting the opcode's entry in aaOpDescs accordingly. 0x0F defaults to the 8086
@ -840,10 +840,11 @@ if (DEBUGGER) {
];
Debugger.aaOp0FDescs = {
0x00: [Debugger.INS.GRP6, Debugger.TYPE_MODRM | Debugger.TYPE_WORD | Debugger.TYPE_BOTH],
0x01: [Debugger.INS.GRP7, Debugger.TYPE_MODRM | Debugger.TYPE_WORD | Debugger.TYPE_BOTH],
0x02: [Debugger.INS.LAR, Debugger.TYPE_REG | Debugger.TYPE_WORD | Debugger.TYPE_IN | Debugger.TYPE_286, Debugger.TYPE_MEM | Debugger.TYPE_WORD | Debugger.TYPE_IN],
0x03: [Debugger.INS.LSL, Debugger.TYPE_REG | Debugger.TYPE_WORD | Debugger.TYPE_IN | Debugger.TYPE_286, Debugger.TYPE_MEM | Debugger.TYPE_WORD | Debugger.TYPE_IN]
0x00: [Debugger.INS.GRP6, Debugger.TYPE_MODRM | Debugger.TYPE_WORD | Debugger.TYPE_BOTH],
0x01: [Debugger.INS.GRP7, Debugger.TYPE_MODRM | Debugger.TYPE_WORD | Debugger.TYPE_BOTH],
0x02: [Debugger.INS.LAR, Debugger.TYPE_REG | Debugger.TYPE_WORD | Debugger.TYPE_IN | Debugger.TYPE_286, Debugger.TYPE_MEM | Debugger.TYPE_WORD | Debugger.TYPE_IN],
0x03: [Debugger.INS.LSL, Debugger.TYPE_REG | Debugger.TYPE_WORD | Debugger.TYPE_IN | Debugger.TYPE_286, Debugger.TYPE_MEM | Debugger.TYPE_WORD | Debugger.TYPE_IN],
0x05: [Debugger.INS.LOADALL, Debugger.TYPE_286]
};
Debugger.aaGrpDescs = [
@ -1778,8 +1779,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.fRunning !== undefined && !fQuiet) this.println("reset");
this.fRunning = false;
if (this.aFlags.fRunning !== undefined && !fQuiet) this.println("reset");
this.aFlags.fRunning = false;
this.clearTempBreakpoint();
if (!fQuiet) this.updateStatus();
};
@ -1845,7 +1846,7 @@ if (DEBUGGER) {
Debugger.prototype.start = function(ms, nCycles)
{
if (!this.fProcStep) this.println("running");
this.fRunning = true;
this.aFlags.fRunning = true;
this.msStart = ms;
this.nCyclesStart = nCycles;
};
@ -1861,8 +1862,8 @@ if (DEBUGGER) {
*/
Debugger.prototype.stop = function(ms, nCycles)
{
if (this.fRunning) {
this.fRunning = false;
if (this.aFlags.fRunning) {
this.aFlags.fRunning = false;
this.nCycles = nCycles - this.nCyclesStart;
if (!this.fProcStep) {
var sStopped = "stopped";
@ -2565,11 +2566,11 @@ if (DEBUGGER) {
sLine += " ";
sLine = sLine.substr(0, 50);
sLine += ";";
if (!this.cpu.fChecksum) {
if (!this.cpu.aFlags.fChecksum) {
sLine += sComment + (nSequence != null? '=' + nSequence.toString() : "");
} else {
var nCycles = this.cpu.getCycles();
sLine += "cycles=" + nCycles.toString() + " cs=" + str.toHex(this.cpu.nChecksum);
sLine += "cycles=" + nCycles.toString() + " cs=" + str.toHex(this.cpu.aCounts.nChecksum);
}
}
return sLine;
@ -3495,7 +3496,7 @@ if (DEBUGGER) {
break;
}
}
s += ",dpl" + ((seg.acc >> X86.DESC.ACC.LEVEL.SHIFT) & X86.DESC.ACC.LEVEL.MASK);
s += ",dpl" + ((seg.acc >> X86.DESC.ACC.DPL.SHIFT) & X86.DESC.ACC.DPL.MASK);
s += (seg.acc & X86.DESC.ACC.PRESENT)? ",present" : ",not present";
} else {
// We must be in real-mode, where selectors have no access bytes
@ -3618,7 +3619,7 @@ if (DEBUGGER) {
*/
Debugger.prototype.doHalt = function(sCount)
{
if (this.fRunning && sCount === undefined) {
if (this.aFlags.fRunning && sCount === undefined) {
this.haltCPU();
return;
}
@ -3713,11 +3714,11 @@ if (DEBUGGER) {
} while (cLines && i != this.iTraceBuffer);
if (!sDump) sDump = "nothing to dump";
this.println(sDump);
this.println("msPerYield: " + this.cpu.msPerYield);
this.println("nCyclesPerBurst: " + this.cpu.nCyclesPerBurst);
this.println("nCyclesPerYield: " + this.cpu.nCyclesPerYield);
this.println("nCyclesPerVideoUpdate: " + this.cpu.nCyclesPerVideoUpdate);
this.println("nCyclesPerStatusUpdate: " + this.cpu.nCyclesPerStatusUpdate);
this.println("msPerYield: " + this.cpu.aCounts.msPerYield);
this.println("nCyclesPerBurst: " + this.cpu.aCounts.nCyclesPerBurst);
this.println("nCyclesPerYield: " + this.cpu.aCounts.nCyclesPerYield);
this.println("nCyclesPerVideoUpdate: " + this.cpu.aCounts.nCyclesPerVideoUpdate);
this.println("nCyclesPerStatusUpdate: " + this.cpu.aCounts.nCyclesPerStatusUpdate);
} else {
var fEnable = (sEnable == "on");
for (var prop in this.traceEnabled) {
@ -3980,13 +3981,13 @@ if (DEBUGGER) {
}
switch (asArgs[2]) {
case "int":
this.cpu.nCyclesChecksumInterval = nCycles;
this.cpu.aCounts.nCyclesChecksumInterval = nCycles;
break;
case "start":
this.cpu.nCyclesChecksumStart = nCycles;
this.cpu.aCounts.nCyclesChecksumStart = nCycles;
break;
case "stop":
this.cpu.nCyclesChecksumStop = nCycles;
this.cpu.aCounts.nCyclesChecksumStop = nCycles;
break;
default:
this.println("unknown cs option");
@ -3995,7 +3996,7 @@ if (DEBUGGER) {
if (nCycles !== undefined) {
this.cpu.resetChecksum();
}
this.println("checksums " + (this.cpu.fChecksum? "enabled" : "disabled"));
this.println("checksums " + (this.cpu.aFlags.fChecksum? "enabled" : "disabled"));
break;
case "sp":
if (asArgs[2] !== undefined) {
@ -4533,7 +4534,7 @@ if (DEBUGGER) {
if (this.cmp) this.cmp.reset();
return true;
case "ver":
this.println((APPNAME || "PCjs") + " version " + APPVERSION + " (" + (COMPILED? "release" : (DEBUG? "debug" : "nodebug")) + (PREFETCH? ",prefetch" : "") + (TYPEDARRAYS? ",typedarrays" : (FATARRAYS? ",fatarrays" : "")) + ")");
this.println((APPNAME || "PCjs") + " version " + APPVERSION + " (" + (COMPILED? "release" : (DEBUG? "debug" : "nodebug")) + (PREFETCH? ",prefetch" : ",noprefetch") + (EAFUNCS? "eafuncs" : ",eatests") + (TYPEDARRAYS? ",typedarrays" : (FATARRAYS? ",fatarrays" : ",dwords")) + ")");
return true;
default:
ch0 = sCmd.charAt(0);

View file

@ -64,7 +64,7 @@ var DEBUGGER = true; // this @define is overridden by the Closure Com
* @define {boolean}
*
* PREFETCH enables the use of a prefetch queue.
*
*
* See the Bus component for details.
*/
var PREFETCH = false;
@ -72,27 +72,21 @@ var PREFETCH = false;
/**
* @define {boolean}
*
* FASTDISABLE turns on memory-function switching to dynamically disable memory accesses whenever the CPU wants
* to disable spurious memory reads (which are mostly harmless) or stale memory writes (which tend to be destructive
* and are NOT mostly harmless).
*
* If FASTDISABLE is false, then the code falls back to setting/testing internal OP_NOREAD and OP_NOWRITE opFlags
* as needed.
*
* At the moment, it seems that FASTDISABLE is a bit slower than relying on the OP_NOREAD/OP_NOWRITE flags, so it's
* turned off; apparently, I was a bit too optimistic calling it "FAST". But your mileage may vary, depending on the
* browser and its version.
* EAFUNCS enables dynamic function switching whenever the CPU needs to disable one or both EA (Effective Address)
* memory functions for an instruction that doesn't observe the normal "read/modify/write" behavior. The goal is to
* avoid useless memory reads (which are mostly harmless) and stale memory writes (which are mostly destructive).
*
* See the X86CPU component for details, since it is the CPU, not the underlying Bus or Memory components, that needs
* to be able to do this.
* If EAFUNCS is false, then the CPU falls back to setting/testing internal OP_NOREAD and OP_NOWRITE opFlags
* as needed. At the moment, it seems that "EAFUNCS mode" is a bit slower than "EATESTS mode", which relies on the
* bits in opFlags, so EAFUNCS is turned off; however, your mileage may vary, depending on the browser and its vintage.
*/
var FASTDISABLE = false;
var EAFUNCS = false;
/**
* @define {boolean}
*
* FATARRAYS is a Closure Compiler compile-time option that allocates 1 number per byte for Memory blocks;
* wasteful, but potentially slightly faster.
* FATARRAYS is a Closure Compiler compile-time option that allocates a normal Array of numbers for each Memory block,
* where each a number represents ONE byte; very wasteful, but potentially slightly faster.
*
* See the Memory component for details.
*/
@ -100,16 +94,14 @@ var FATARRAYS = false;
/**
* @define {boolean}
*
* TYPEDARRAYS enables use of typed arrays for Memory blocks. This used to be a compile-time-only option, but since I've
* added memory access functions for typed arrays (see Memory.afnTypedArray), I can turn the support on dynamically now.
* Originally, I didn't see much of a speed increase over the original (non-typed) implementation, but that will probably
* change over time.
*
* TYPEDARRAYS enables use of typed arrays for Memory blocks. This used to be a compile-time-only option, but I've
* added memory access functions for typed arrays (see Memory.afnTypedArray), so the support CAN be enabled dynamically.
*
* However, TYPEDARRAYS has always been slightly slower than the original DWORDS implementation (which uses a normal Array
* of numbers that stores 32 bits, or 4 consecutive bytes, per number), so TYPEDARRAYS is completely disabled for now.
*
* See the Memory component for details.
*
* UPDATE (Oct 2014): Time has passed, and TypedArray support is still measurably slower than the default Memory implementation,
* so it's turned off by default for now.
*/
var TYPEDARRAYS = false; // (typeof ArrayBuffer !== 'undefined');
@ -117,7 +109,7 @@ if (typeof module !== 'undefined') {
global.PCJSCLASS = PCJSCLASS;
global.DEBUGGER = DEBUGGER;
global.PREFETCH = PREFETCH;
global.FASTDISABLE = FASTDISABLE;
global.EAFUNCS = EAFUNCS;
global.FATARRAYS = FATARRAYS;
global.TYPEDARRAYS = TYPEDARRAYS;
/*

View file

@ -578,7 +578,7 @@ Disk.prototype.doneLoad = function(sDiskFile, sDiskData, nErrorCode, sDiskPath)
{
var disk = null;
this.fWriteProtected = false;
var fPrintOnly = (nErrorCode < 0 && this.cmp && !this.cmp.fPowered);
var fPrintOnly = (nErrorCode < 0 && this.cmp && !this.cmp.aFlags.fPowered);
if (this.fOnDemand) {
if (!nErrorCode) {

View file

@ -939,8 +939,8 @@ Keyboard.prototype.calcReleaseDelay = function(fRepeat)
* handler, otherwise doing things like pressing ENTER repeatedly will result in sluggish behavior
* (because you can generally press/release/repress keys faster than they will auto-repeat).
*/
var msDelay = (fRepeat ? this.msReleaseRepeat : this.msReleaseDelay);
if (this.cpu && this.cpu.mhz) msDelay /= this.cpu.mhz;
var msDelay = (fRepeat? this.msReleaseRepeat : this.msReleaseDelay);
if (this.cpu && this.cpu.aCounts.mhz) msDelay /= this.cpu.aCounts.mhz;
return msDelay;
};

View file

@ -38,9 +38,14 @@
* nearly all of debugger.js will be conditionally removed by the compiler, reducing it to little more than a
* "type skeleton", which also solves some type-related warnings we would otherwise have if we tried to remove
* debugger.js from the compilation process altogether.
*
*
* However, when we're in "development mode" and running uncompiled code in debugger-less configurations,
* I would still like to skip loading debugger.js altogether. To do that, we must arrange for an additional file,
* nodebugger.js, to be loaded as early as possible, which must explicitly UPDATE the value of DEBUGGER to *false*.
*/
DEBUGGER = false;
/*
* We still need a Debugger "stub" object, so that attempts to reference Debugger constants won't trigger exceptions.
*/
var Debugger = {};

View file

@ -3820,9 +3820,9 @@ Video.prototype.updateChar = function(col, row, data, context)
Video.prototype.updateScreen = function(fForce)
{
/*
* The Computer component maintains an fPowered setting on our behalf, so we use it.
* The Computer component maintains the fPowered setting on our behalf, so we use it.
*/
if (!this.fPowered) return;
if (!this.aFlags.fPowered) return;
/*
* If the card's video signal is disabled (eg, during a mode change), then skip the update,

View file

@ -75,7 +75,7 @@ var X86 = {
SET: 0xfff0 // on the 80286, these are always set (TODO: Verify)
},
SEL: {
LEVEL: 0x0003, // selector privilege level (0-3)
RPL: 0x0003, // requested privilege level (0-3)
LDT: 0x0004, // table indicator (0: GDT, 1: LDT)
MASK: 0xfff8 // table index
},
@ -91,37 +91,48 @@ var X86 = {
BASE1623: 0x00ff,
MASK: 0xff00,
TYPE: {
MASK: 0x1f00,
SEG: 0x1000,
MASK: 0x1f00,
SEG: 0x1000,
NONSEG: 0x0f00,
/*
* The rest of these apply only when SEG is set
* The following bits apply only when SEG is set
*/
ACCESSED: 0x0100,
READABLE: 0x0200, // CODE: set if readable, clear if execute-only
WRITEABLE: 0x0200, // DATA: set if writable, clear if read-only
CONFORMING: 0x0400, // CODE: set if conforming, clear if not
EXPDOWN: 0x0400, // DATA: set if expand-down, clear if not
CODE: 0x0800, // set for CODE, clear for DATA
CODE_READABLE: 0x0A00, // both CODE and READABLE
CODE_CONFORMING: 0x0C00, // both CODE and CONFORMING
CODE_CONFORMING_READABLE: 0x0E00, // all of CODE and CONFORMING and READABLE
CODE: 0x0800, // set for CODE, clear for DATA
ACCESSED: 0x0100, // set if accessed, clear if not accessed
READABLE: 0x0200, // CODE: set if readable, clear if exec-only
WRITEABLE: 0x0200, // DATA: set if writable, clear if read-only
CONFORMING: 0x0400, // CODE: set if conforming, clear if not
EXPDOWN: 0x0400, // DATA: set if expand-down, clear if not
/*
* The rest of these apply only when SEG is clear
* The following are all the possible (valid) types (well, except for the variations
* of DATA and CODE where the ACCESSED bit (0x0100) may also be set)
*/
TSS: 0x0100,
LDT: 0x0200,
TSS_LDT: 0x0300,
TSS_BUSY: 0x0300,
GATE_CALL: 0x0400,
GATE_TASK: 0x0500,
GATE_INT: 0x0600,
GATE_TRAP: 0x0700
TSS: 0x0100,
LDT: 0x0200,
TSS_LDT: 0x0300,
TSS_BUSY: 0x0300,
GATE_CALL: 0x0400,
GATE_TASK: 0x0500,
GATE_INT: 0x0600,
GATE_TRAP: 0x0700,
DATA_READONLY: 0x1000,
DATA_WRITEABLE: 0x1200,
DATA_EXPDOWN_READONLY: 0x1400,
DATA_EXPDOWN_WRITEABLE: 0x1600,
CODE_EXECONLY: 0x1800,
CODE_READABLE: 0x1a00,
CODE_CONFORMING_EXECONLY: 0x1c00,
CODE_CONFORMING_READABLE: 0x1e00
},
LEVEL: {
DPL: {
MASK: 0x6000,
SHIFT: 13
},
PRESENT: 0x8000
},
EXT: { // descriptor extension word (reserved on the 80286; "must be zero")
OFFSET: 0x6,
MASK: 0xffff
}
},
/*

View file

@ -143,14 +143,14 @@ function X86CPU(parmsCPU) {
* stepCPU() call, but it's good form to do so.
*/
this.nBurstCycles = 0;
this.fComplete = this.fDebugCheck = false;
this.aFlags.fComplete = this.aFlags.fDebugCheck = false;
/*
* We're just declaring aMemBlocks and associated Bus parameters here; they'll be initialized by initMemory()
* when the Bus is initialized.
*/
this.aMemBlocks = [];
this.addrLimit = this.addrMask = this.blockShift = this.blockLimit = this.blockMask = 0;
this.addrMemMask = this.blockShift = this.blockLimit = this.blockMask = 0;
/*
* Establish all the default get/set functions for accessing memory; see this function for details.
@ -467,7 +467,7 @@ X86CPU.PREFETCH.MASK = 0x7; // (X86CPU.PREFETCH.ARRAY - 1)
X86CPU.prototype.initMemory = function(aMemBlocks, addrLimit, blockShift, blockLimit, blockMask)
{
this.aMemBlocks = aMemBlocks;
this.addrLimit = this.addrMask = addrLimit;
this.addrMemMask = addrLimit;
this.blockShift = blockShift;
this.blockLimit = blockLimit;
this.blockMask = blockMask;
@ -491,7 +491,7 @@ X86CPU.prototype.initMemory = function(aMemBlocks, addrLimit, blockShift, blockL
*/
X86CPU.prototype.setAddressMask = function(addrMask)
{
this.addrMask = addrMask;
this.addrMemMask = addrMask;
};
/**
@ -727,7 +727,7 @@ X86CPU.prototype.initProcessor = function()
*/
X86CPU.prototype.reset = function()
{
if (this.fRunning) this.haltCPU();
if (this.aFlags.fRunning) this.haltCPU();
this.resetRegs();
this.resetCycles();
this.clearError(); // clear any fatal error/exception that setError() may have flagged
@ -760,9 +760,6 @@ X86CPU.prototype.reset = function()
* which takes both an offset and a segment, or setIP(), whichever is appropriate; in unusual cases where only
* segCS is changing (eg, undocumented 8086 opcodes), use setCS().
*
* On the 80286, another "register" that mirrors segCS is nCPL: whenever CS is updated, nCPL is updated
* with the CS selector's access level.
*
* The other segment registers (DS, SS and ES) have similar setters (for segDS, segSS and segES), but those
* functions do not mirror any special segment:offset values in the same way that regEIP mirrors CS:IP.
*
@ -827,7 +824,7 @@ X86CPU.prototype.resetRegs = function()
/*
* This resets the Processor Status flags (regPS), along with all the internal "result registers";
* we've taken care to ensure that both nCPL and nIOPL are initialized before this first setPS() call.
* we've taken care to ensure that both segCS.cpl and nIOPL are initialized before this first setPS() call.
*/
this.setPS(0);
@ -924,7 +921,7 @@ X86CPU.prototype.checkIntNotify = function(nInt)
}
}
}
else if (DEBUGGER && this.fDebugCheck) {
else if (DEBUGGER && this.aFlags.fDebugCheck) {
/*
* Enabling MESSAGE_INT messages is one of the criteria that's also included in fDebugCheck, so for maximum
* speed, we check fDebugCheck first.
@ -1007,10 +1004,10 @@ X86CPU.prototype.setProtMode = function(fProt)
} else {
X86Op0F.aOpGRP6 = X86Op0F.aOpGRP6Real;
}
this.segCS.setProt(fProt);
this.segDS.setProt(fProt);
this.segSS.setProt(fProt);
this.segES.setProt(fProt);
this.segCS.updateAccess(fProt);
this.segDS.updateAccess(fProt);
this.segSS.updateAccess(fProt);
this.segES.updateAccess(fProt);
};
/**
@ -1048,7 +1045,6 @@ X86CPU.prototype.restoreProtMode = function(a)
this.segLDT.restore(a[5]);
this.segTSS.restore(a[6]);
this.nIOPL = a[7];
this.nCPL = this.segCS.level;
this.setProtMode();
}
};
@ -1122,7 +1118,7 @@ X86CPU.prototype.restore = function(data)
/**
* setMemoryEnabled()
*
* Set the default EA memory access functions (enabled vs. disabled). When FASTDISABLE is true, assorted
* Set the default EA memory access functions (enabled vs. disabled). When EAFUNCS is true, assorted
* CPU opcode functions override the default functions whenever a CPU operation needs to temporarily disable the
* "get" of a source operand (or the "set" of a destination operand, as in the case of a CMP instruction).
*
@ -1248,7 +1244,6 @@ X86CPU.prototype.loadIDTEntry = function(nIDT)
X86CPU.prototype.setCS = function(sel)
{
this.regEIP = this.segCS.load(sel) + this.regIP;
this.nCPL = this.segCS.level;
this.opFlags |= this.OPFLAG_NOINTR8086;
if (PREFETCH) this.flushPrefetch(this.regEIP);
};
@ -1330,7 +1325,6 @@ X86CPU.prototype.setCSIP = function(off, sel)
{
Component.assert((off & 0xffff) == off);
this.regEIP = this.segCS.load(sel) + (this.regIP = off);
this.nCPL = this.segCS.level;
if (PREFETCH) this.flushPrefetch(this.regEIP);
};
@ -1646,13 +1640,13 @@ X86CPU.prototype.setPS = function(regPS)
* Since PS.IOPL and PS.IF are part of PS.DIRECT, we need to take care of any 80286-specific checks before
* setting the PS.DIRECT bits. Specifically, PS.IOPL is unchanged if CPL > 0, and PS.IF is unchanged if CPL > IOPL.
*/
if (!this.nCPL) {
if (!this.segCS.cpl) {
this.nIOPL = (regPS & X86.PS.IOPL.MASK) >> X86.PS.IOPL.SHIFT; // IOPL allowed to change
if (this.nIOPL && !(this.regMSW & X86.MSW.PE)) this.nIOPL = 0; // effective IOPL remains 0
} else {
regPS = (regPS & ~X86.PS.IOPL.MASK) | (this.regPS & X86.PS.IOPL.MASK); // IOPL not allowed to change
}
if (this.nCPL > this.nIOPL) {
if (this.segCS.cpl > this.nIOPL) {
regPS = (regPS & ~X86.PS.IF) | (this.regPS & X86.PS.IF); // IF not allowed to change
}
@ -1744,7 +1738,7 @@ X86CPU.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, control)
*/
X86CPU.prototype.getByte = function(addr)
{
return this.aMemBlocks[(addr & this.addrMask) >> this.blockShift].readByte(addr & this.blockLimit);
return this.aMemBlocks[(addr & this.addrMemMask) >> this.blockShift].readByte(addr & this.blockLimit);
};
/**
@ -1757,7 +1751,7 @@ X86CPU.prototype.getByte = function(addr)
X86CPU.prototype.getWord = function(addr)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.addrMask) >> this.blockShift;
var iBlock = (addr & this.addrMemMask) >> this.blockShift;
/*
* On the 8088, it takes 4 cycles to read the additional byte REGARDLESS whether the address is odd or even.
*
@ -1779,7 +1773,7 @@ X86CPU.prototype.getWord = function(addr)
*/
X86CPU.prototype.setByte = function(addr, b)
{
this.aMemBlocks[(addr & this.addrMask) >> this.blockShift].writeByte(addr & this.blockLimit, b & 0xff);
this.aMemBlocks[(addr & this.addrMemMask) >> this.blockShift].writeByte(addr & this.blockLimit, b & 0xff);
};
/**
@ -1792,7 +1786,7 @@ X86CPU.prototype.setByte = function(addr, b)
X86CPU.prototype.setWord = function(addr, w)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.addrMask) >> this.blockShift;
var iBlock = (addr & this.addrMemMask) >> this.blockShift;
/*
* On the 8088, it takes 4 cycles to write the additional byte REGARDLESS whether the address is odd or even.
*
@ -1815,7 +1809,7 @@ X86CPU.prototype.setWord = function(addr, w)
* @param {number} off is a segment-relative offset
* @return {number}
*
X86CPU.prototype.getEAByteDisabled = function(seg, off)
X86CPU.prototype.getEAByteDisabled = function getEAByteDisabled(seg, off)
{
this.segEA = seg;
this.offEA = off;
@ -1836,7 +1830,7 @@ X86CPU.prototype.getEAByteDisabled = function(seg, off)
* @param {number} off is a segment-relative offset
* @return {number}
*/
X86CPU.prototype.getEAWordDisabled = function(seg, off)
X86CPU.prototype.getEAWordDisabled = function getEAWordDisabled(seg, off)
{
this.segEA = seg;
this.offEA = off;
@ -1855,7 +1849,7 @@ X86CPU.prototype.getEAWordDisabled = function(seg, off)
* @param {number} off is a segment-relative offset
* @return {number}
*/
X86CPU.prototype.modEAByteDisabled = function(seg, off)
X86CPU.prototype.modEAByteDisabled = function modEADisabled(seg, off)
{
this.segEA = seg;
this.offEA = off;
@ -1874,7 +1868,7 @@ X86CPU.prototype.modEAWordDisabled = X86CPU.prototype.modEAByteDisabled;
* @this {X86CPU}
* @param {number} w is the word (16-bit) value to write (ignored)
*/
X86CPU.prototype.setEAByteDisabled = function(w)
X86CPU.prototype.setEAByteDisabled = function setEAByteDisabled(w)
{
};
@ -1884,7 +1878,7 @@ X86CPU.prototype.setEAByteDisabled = function(w)
* @this {X86CPU}
* @param {number} w is the word (16-bit) value to write (ignored)
*/
X86CPU.prototype.setEAWordDisabled = function(w)
X86CPU.prototype.setEAWordDisabled = function setEAWordDisabled(w)
{
};
@ -1896,11 +1890,11 @@ X86CPU.prototype.setEAWordDisabled = function(w)
* @param {number} off is a segment-relative offset
* @return {number} byte (8-bit) value at that address
*/
X86CPU.prototype.getEAByteEnabled = function(seg, off)
X86CPU.prototype.getEAByteEnabled = function getEAByteEnabled(seg, off)
{
this.segEA = seg;
this.regEA = seg.checkRead(this.offEA = off, 0);
if (!FASTDISABLE && (this.opFlags & X86.OPFLAG.NOREAD)) return 0;
if (!EAFUNCS && (this.opFlags & X86.OPFLAG.NOREAD)) return 0;
return this.getByte(this.regEA);
};
@ -1912,11 +1906,11 @@ X86CPU.prototype.getEAByteEnabled = function(seg, off)
* @param {number} off is a segment-relative offset
* @return {number} word (16-bit) value at that address
*/
X86CPU.prototype.getEAWordEnabled = function(seg, off)
X86CPU.prototype.getEAWordEnabled = function getEAWordEnabled(seg, off)
{
this.segEA = seg;
this.regEA = seg.checkRead(this.offEA = off, 1);
if (!FASTDISABLE && (this.opFlags & X86.OPFLAG.NOREAD)) return 0;
if (!EAFUNCS && (this.opFlags & X86.OPFLAG.NOREAD)) return 0;
return this.getWord(this.regEA);
};
@ -1928,11 +1922,11 @@ X86CPU.prototype.getEAWordEnabled = function(seg, off)
* @param {number} off is a segment-relative offset
* @return {number} byte (8-bit) value at that address
*/
X86CPU.prototype.modEAByteEnabled = function(seg, off)
X86CPU.prototype.modEAByteEnabled = function modEAByteEnabled(seg, off)
{
this.segEA = seg;
this.regEAWrite = this.regEA = seg.checkRead(this.offEA = off, 0);
if (!FASTDISABLE && (this.opFlags & X86.OPFLAG.NOREAD)) return 0;
if (!EAFUNCS && (this.opFlags & X86.OPFLAG.NOREAD)) return 0;
return this.getByte(this.regEA);
};
@ -1944,11 +1938,11 @@ X86CPU.prototype.modEAByteEnabled = function(seg, off)
* @param {number} off is a segment-relative offset
* @return {number} word (16-bit) value at that address
*/
X86CPU.prototype.modEAWordEnabled = function(seg, off)
X86CPU.prototype.modEAWordEnabled = function modEAWordEnabled(seg, off)
{
this.segEA = seg;
this.regEAWrite = this.regEA = seg.checkRead(this.offEA = off, 1);
if (!FASTDISABLE && (this.opFlags & X86.OPFLAG.NOREAD)) return 0;
if (!EAFUNCS && (this.opFlags & X86.OPFLAG.NOREAD)) return 0;
return this.getWord(this.regEA);
};
@ -1958,9 +1952,9 @@ X86CPU.prototype.modEAWordEnabled = function(seg, off)
* @this {X86CPU}
* @param {number} b is the byte (8-bit) value to write
*/
X86CPU.prototype.setEAByteEnabled = function(b)
X86CPU.prototype.setEAByteEnabled = function setEAByteEnabled(b)
{
if (!FASTDISABLE && (this.opFlags & X86.OPFLAG.NOWRITE)) return;
if (!EAFUNCS && (this.opFlags & X86.OPFLAG.NOWRITE)) return;
this.setByte(this.segEA.checkWrite(this.offEA, 1), b);
};
@ -1970,9 +1964,9 @@ X86CPU.prototype.setEAByteEnabled = function(b)
* @this {X86CPU}
* @param {number} w is the word (16-bit) value to write
*/
X86CPU.prototype.setEAWordEnabled = function(w)
X86CPU.prototype.setEAWordEnabled = function setEAWordEnabled(w)
{
if (!FASTDISABLE && (this.opFlags & X86.OPFLAG.NOWRITE)) return;
if (!EAFUNCS && (this.opFlags & X86.OPFLAG.NOWRITE)) return;
this.setWord(this.segEA.checkWrite(this.offEA, 2), w);
};
@ -2047,7 +2041,7 @@ X86CPU.prototype.setSOWord = function(seg, off, w)
*/
X86CPU.prototype.getBytePrefetch = function(addr)
{
if (!FASTDISABLE && (this.opFlags & X86.OPFLAG.NOREAD)) return 0;
if (!EAFUNCS && (this.opFlags & X86.OPFLAG.NOREAD)) return 0;
var b;
if (!this.cbPrefetchQueued) {
if (MAXDEBUG) Component.assert(addr == this.addrPrefetchHead, "X86CPU.getBytePrefetch(" + str.toHex(addr) + "): invalid head address (" + str.toHex(this.addrPrefetchHead) + ")");
@ -2059,10 +2053,10 @@ X86CPU.prototype.getBytePrefetch = function(addr)
* with side-effects we may not want, and in any case, while it seemed to improve Safari's performance slightly,
* it did nothing for the oddball Chrome performance I'm seeing with PREFETCH enabled.
*
* b = this.aMemBlocks[(addr & this.addrMask) >> this.blockShift].readByte(addr & this.blockLimit);
* b = this.aMemBlocks[(addr & this.addrMemMask) >> this.blockShift].readByte(addr & this.blockLimit);
* this.nBusCycles += 4;
* this.cbPrefetchValid = 0;
* this.addrPrefetchHead = (addr + 1) & this.addrMask;
* this.addrPrefetchHead = (addr + 1) & this.addrMemMask;
* return b;
*/
}
@ -2107,10 +2101,10 @@ X86CPU.prototype.fillPrefetch = function(n)
{
while (n-- > 0 && this.cbPrefetchQueued < X86CPU.PREFETCH.QUEUE) {
var addr = this.addrPrefetchHead;
var b = this.aMemBlocks[(addr & this.addrMask) >> this.blockShift].readByte(addr & this.blockLimit);
var b = this.aMemBlocks[(addr & this.addrMemMask) >> this.blockShift].readByte(addr & this.blockLimit);
this.aPrefetch[this.iPrefetchHead] = b | (addr << 8);
if (MAXDEBUG) this.messageDebugger(" fillPrefetch[" + this.iPrefetchHead + "]: " + str.toHex(addr) + ":" + str.toHexByte(b));
this.addrPrefetchHead = (addr + 1) & this.addrMask;
this.addrPrefetchHead = (addr + 1) & this.addrMemMask;
this.iPrefetchHead = (this.iPrefetchHead + 1) & X86CPU.PREFETCH.MASK;
this.cbPrefetchQueued++;
/*
@ -2443,7 +2437,7 @@ X86CPU.prototype.stepCPU = function(nMinCycles)
* Debugger is single-stepping (even when performing multiple single-steps), fRunning is never set,
* so haltCPU() would have no effect as far as the Debugger is concerned.
*/
this.fComplete = true;
this.aFlags.fComplete = true;
/*
* fDebugCheck is true if we need to "check" every instruction with the Debugger. The Debugger will
@ -2460,7 +2454,7 @@ X86CPU.prototype.stepCPU = function(nMinCycles)
* minimum number of cycles to process: one and only one instruction will execute, since every (valid)
* instruction consumes at least 1 cycle.
*/
this.fDebugCheck = (DEBUGGER && nMinCycles && this.dbg && this.dbg.checksEnabled());
var fDebugCheck = this.aFlags.fDebugCheck = (DEBUGGER && nMinCycles && this.dbg && this.dbg.checksEnabled());
/*
* We move the minimum cycle count to nStepCycles (the number of cycles left to step), so that other
@ -2542,7 +2536,7 @@ X86CPU.prototype.stepCPU = function(nMinCycles)
}
}
if (DEBUGGER && this.fDebugCheck && this.dbg.checkInstruction(this.regEIP)) {
if (DEBUGGER && fDebugCheck && this.dbg.checkInstruction(this.regEIP)) {
this.haltCPU();
break;
}
@ -2589,7 +2583,7 @@ X86CPU.prototype.stepCPU = function(nMinCycles)
} while (this.nStepCycles > 0);
return (this.fComplete? this.nBurstCycles - this.nStepCycles : (this.fComplete === undefined? 0 : -1));
return (this.aFlags.fComplete? this.nBurstCycles - this.nStepCycles : (this.aFlags.fComplete === undefined? 0 : -1));
};
/**
@ -2603,7 +2597,7 @@ X86CPU.prototype.stepCPU = function(nMinCycles)
X86CPU.prototype.messageDebugger = function(sMessage)
{
if (DEBUGGER && this.dbg) {
if (this.dbg.messageEnabled(Debugger.MESSAGE_MEM)) {
if (this.dbg.messageEnabled(Debugger.MESSAGE_CPU)) {
this.dbg.message(sMessage);
}
}

View file

@ -139,7 +139,7 @@ var X86Grps = {
this.resultSize = X86.RESULT.SIZE_BYTE;
this.resultValue = this.resultParitySign = dst - src;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesCompareRM) : this.CYCLES.nOpCyclesArithRM);
if (FASTDISABLE) this.setEAByte = this.setEAByteDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
if (EAFUNCS) this.setEAByte = this.setEAByteDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
},
/**
@ -242,7 +242,7 @@ var X86Grps = {
this.resultSize = X86.RESULT.SIZE_WORD;
this.resultValue = this.resultParitySign = dst - src;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesArithRR : this.CYCLES.nOpCyclesCompareRM) : this.CYCLES.nOpCyclesArithRM);
if (FASTDISABLE) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
if (EAFUNCS) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
},
/**
@ -654,7 +654,7 @@ var X86Grps = {
this.resultValue = this.resultParitySign = this.resultAuxOverflow = dst & src;
this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesTestRI : this.CYCLES.nOpCyclesTestMI);
if (FASTDISABLE) this.setEAByte = this.setEAByteDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
if (EAFUNCS) this.setEAByte = this.setEAByteDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
},
/**
@ -668,7 +668,7 @@ var X86Grps = {
this.resultValue = this.resultParitySign = this.resultAuxOverflow = dst & src;
this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesTestRI : this.CYCLES.nOpCyclesTestMI);
if (FASTDISABLE) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
if (EAFUNCS) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
},
/**
@ -744,7 +744,7 @@ var X86Grps = {
*/
if (DEBUG && DEBUGGER) this.traceLog('MULB', src, dst, null, this.getPS(), this.regMD16);
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesMulBR : this.CYCLES.nOpCyclesMulBM);
if (FASTDISABLE) this.setEAByte = this.setEAByteDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
if (EAFUNCS) this.setEAByte = this.setEAByteDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
},
/**
@ -788,7 +788,7 @@ var X86Grps = {
*/
if (DEBUG && DEBUGGER) this.traceLog('IMULB', src, dst, null, this.getPS(), this.regMD16);
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesIMulBR : this.CYCLES.nOpCyclesIMulBM);
if (FASTDISABLE) this.setEAByte = this.setEAByteDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
if (EAFUNCS) this.setEAByte = this.setEAByteDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
},
/**
@ -827,7 +827,7 @@ var X86Grps = {
*/
if (DEBUG && DEBUGGER) this.traceLog('DIVB', src, dst, null, this.getPS(), this.regMD16);
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesDivBR : this.CYCLES.nOpCyclesDivBM);
if (FASTDISABLE) this.setEAByte = this.setEAByteDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
if (EAFUNCS) this.setEAByte = this.setEAByteDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
},
/**
@ -874,7 +874,7 @@ var X86Grps = {
*/
if (DEBUG && DEBUGGER) this.traceLog('IDIVB', src, dst, null, this.getPS(), this.regMD16);
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesIDivBR : this.CYCLES.nOpCyclesIDivBM);
if (FASTDISABLE) this.setEAByte = this.setEAByteDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
if (EAFUNCS) this.setEAByte = this.setEAByteDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
},
/**
@ -905,7 +905,7 @@ var X86Grps = {
*/
if (DEBUG && DEBUGGER) this.traceLog('MULW', src, dst, null, this.getPS(), this.regMD16 | (this.regMD32 << 16));
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesMulWR : this.CYCLES.nOpCyclesMulWM);
if (FASTDISABLE) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
if (EAFUNCS) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
},
/**
@ -950,7 +950,7 @@ var X86Grps = {
*/
if (DEBUG && DEBUGGER) this.traceLog('IMULW', src, dst, null, this.getPS(), this.regMD16 | (this.regMD32 << 16));
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesIMulWR : this.CYCLES.nOpCyclesIMulWM);
if (FASTDISABLE) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
if (EAFUNCS) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
},
/**
@ -995,7 +995,7 @@ var X86Grps = {
*/
if (DEBUG && DEBUGGER) this.traceLog('DIVW', src, dst, null, this.getPS(), this.regMD16 | (this.regMD32 << 16));
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesDivWR : this.CYCLES.nOpCyclesDivWM);
if (FASTDISABLE) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
if (EAFUNCS) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
},
/**
@ -1045,7 +1045,7 @@ var X86Grps = {
*/
if (DEBUG && DEBUGGER) this.traceLog('IDIVW', src, dst, null, this.getPS(), this.regMD16 | (this.regMD32 << 16));
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesIDivWR : this.CYCLES.nOpCyclesIDivWM);
if (FASTDISABLE) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
if (EAFUNCS) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
},
/**
@ -1114,7 +1114,7 @@ var X86Grps = {
this.pushWord(this.regIP);
this.setIP(dst);
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesCallWR : this.CYCLES.nOpCyclesCallWM);
if (FASTDISABLE) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
if (EAFUNCS) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
},
/**
@ -1131,7 +1131,7 @@ var X86Grps = {
this.pushWord(this.regIP);
this.setCSIP(dst, this.getWord(this.regEA + 2));
this.nStepCycles -= this.CYCLES.nOpCyclesCallDM;
if (FASTDISABLE) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
if (EAFUNCS) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
},
/**
@ -1143,7 +1143,7 @@ var X86Grps = {
opGrpJMPw: function(dst, src) {
this.setIP(dst);
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesJmpWR : this.CYCLES.nOpCyclesJmpWM);
if (FASTDISABLE) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
if (EAFUNCS) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
},
/**
@ -1158,7 +1158,7 @@ var X86Grps = {
}
this.setCSIP(dst, this.getWord(this.regEA + 2));
this.nStepCycles -= this.CYCLES.nOpCyclesJmpDM;
if (FASTDISABLE) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
if (EAFUNCS) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
},
/**
@ -1186,7 +1186,7 @@ var X86Grps = {
/*
* The PUSH is the only write that needs to occur; dst was the source operand and does not need to be rewritten.
*/
if (FASTDISABLE) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
if (EAFUNCS) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
},
/**

View file

@ -67,7 +67,7 @@ var X86Help = {
this.resultValue = this.resultParitySign = this.resultAuxOverflow = dst & src;
this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesTestRR : this.CYCLES.nOpCyclesTestRM) : this.CYCLES.nOpCyclesTestRM);
if (FASTDISABLE) this.setEAByte = this.setEAByteDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
if (EAFUNCS) this.setEAByte = this.setEAByteDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
},
/**
@ -80,7 +80,7 @@ var X86Help = {
this.resultValue = this.resultParitySign = this.resultAuxOverflow = dst & src;
this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesTestRR : this.CYCLES.nOpCyclesTestRM) : this.CYCLES.nOpCyclesTestRM);
if (FASTDISABLE) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
if (EAFUNCS) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
},
/**
@ -242,7 +242,7 @@ var X86Help = {
this.setIP(this.opEA - this.segCS.base);
X86Help.opHelpINT.call(this, X86.EXCEPTION.BOUND_ERR, null, 0);
}
if (FASTDISABLE) this.setEAByte = this.setEAByteDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
if (EAFUNCS) this.setEAByte = this.setEAByteDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
},
/**
@ -253,8 +253,8 @@ var X86Help = {
*/
opHelpARPL: function(dst, src) {
this.nStepCycles -= (10 + (this.regEA < 0? 0 : 1));
if ((dst & X86.SEL.LEVEL) < (src & X86.SEL.LEVEL)) {
dst = (dst & ~X86.SEL.LEVEL) | (src & X86.SEL.LEVEL);
if ((dst & X86.SEL.RPL) < (src & X86.SEL.RPL)) {
dst = (dst & ~X86.SEL.RPL) | (src & X86.SEL.RPL);
this.setZF();
return dst;
}
@ -277,7 +277,7 @@ var X86Help = {
* if we need a special check for them.
*/
if (this.segVER.load(src, true) >= 0) {
if (this.segVER.level >= (this.segCS.sel & X86.SEL.LEVEL) && this.segVER.level >= (src & X86.SEL.LEVEL)) {
if (this.segVER.dpl >= this.segCS.cpl && this.segVER.dpl >= (src & X86.SEL.RPL)) {
this.setZF();
return this.segVER.acc & X86.DESC.ACC.MASK;
}
@ -288,10 +288,13 @@ var X86Help = {
/**
* @this {X86CPU}
* @param {number} dst
* @param {number} src
* @param {number} src (the selector)
* @return {number}
*/
opHelpLSL: function(dst, src) {
/*
* TODO: Is this an invalid operation if regEAWrite is set? dst is required to be a register.
*/
this.nStepCycles -= (14 + (this.regEA < 0? 0 : 2));
/*
* Currently, segVER.load() will return an error only if the selector is beyond the bounds of the
@ -301,8 +304,8 @@ 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) >= 0) {
var fConforming = ((this.segVER.acc & X86.DESC.ACC.TYPE.CODE_CONFORMING) == X86.DESC.ACC.TYPE.CODE_CONFORMING);
if ((fConforming || this.segVER.level >= (this.segCS.sel & X86.SEL.LEVEL)) && this.segVER.level >= (src & X86.SEL.LEVEL)) {
var fConforming = ((this.segVER.acc & X86.DESC.ACC.TYPE.CODE_CONFORMING_EXECONLY) == X86.DESC.ACC.TYPE.CODE_CONFORMING_EXECONLY);
if ((fConforming || this.segVER.dpl >= this.segCS.cpl) && this.segVER.dpl >= (src & X86.SEL.RPL)) {
this.setZF();
return this.segVER.limit;
}
@ -465,8 +468,9 @@ var X86Help = {
* @this {X86CPU}
* @param {number} nFault
* @param {number} [nError]
* @param {boolean} [fHalt] will halt the CPU if true *and* a Debugger is loaded
*/
opHelpFault: function(nFault, nError) {
opHelpFault: function(nFault, nError, fHalt) {
if (DEBUGGER && this.dbg) {
/*
* NOTE: By using Debugger.message(), we have the option of setting "m halt on" and halting on messages like this.
@ -474,6 +478,7 @@ var X86Help = {
if (this.dbg.messageEnabled(Debugger.MESSAGE_CPU)) {
this.dbg.message("Fault 0x" + str.toHexByte(nFault) + (nError != null? " (0x" + str.toHexWord(nError) + ")" : "") + " on opcode 0x" + str.toHexByte(this.bus.getByteDirect(this.regEIP)) + " at " + str.toHexAddr(this.regIP, this.segCS.sel));
}
if (fHalt) this.haltCPU();
}
if (this.model >= X86.MODEL_80186) {
this.setIP(this.opEA - this.segCS.base);

View file

@ -48,10 +48,10 @@ var X86Op0F = {
opGRP6: function() {
var bModRM = this.getIPByte();
if ((bModRM & 0x38) < 0x10) { // possible reg values: 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38
if (FASTDISABLE) this.modEAWord = this.modEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOREAD;
if (EAFUNCS) this.modEAWord = this.modEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOREAD;
}
X86Mods.aOpModsGrpWord[bModRM].call(this, X86Op0F.aOpGRP6, X86Grps.opGrpNoSrc);
if (FASTDISABLE) { this.modEAWord = this.modEAWordEnabled; this.setEAWord = this.setEAWordEnabled; }
if (EAFUNCS) { this.modEAWord = this.modEAWordEnabled; this.setEAWord = this.setEAWordEnabled; }
},
/**
* @this {X86CPU}
@ -61,10 +61,10 @@ var X86Op0F = {
opGRP7: function() {
var bModRM = this.getIPByte();
if (!(bModRM & 0x10)) {
if (FASTDISABLE) this.modEAWord = this.modEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOREAD;
if (EAFUNCS) this.modEAWord = this.modEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOREAD;
}
X86Mods.aOpModsGrpWord[bModRM].call(this, X86Op0F.aOpGRP7, X86Grps.opGrpNoSrc);
if (FASTDISABLE) { this.modEAWord = this.modEAWordEnabled; this.setEAWord = this.setEAWordEnabled; }
if (EAFUNCS) { this.modEAWord = this.modEAWordEnabled; this.setEAWord = this.setEAWordEnabled; }
},
/**
* @this {X86CPU}
@ -124,6 +124,10 @@ var X86Op0F = {
* op=0x0F,0x05 (loadall)
*/
opLOADALL: function() {
if (this.segCS.cpl) {
X86Help.opHelpFault.call(this, X86.EXCEPTION.GP_FAULT, 0, true);
return;
}
X86Help.opHelpLMSW.call(this, this.getWord(0x806));
this.regDI = this.getWord(0x826);
this.regSI = this.getWord(0x828);
@ -133,26 +137,21 @@ var X86Op0F = {
this.regDX = this.getWord(0x830);
this.regCX = this.getWord(0x832);
this.regAX = this.getWord(0x834);
/*
* loadDesc() is an X86Seg class method that we must use to force the specified descriptor to be loaded;
* since the processor might still be in real-mode, we can't use normal segment register instance methods.
*/
X86Seg.loadDesc.call(this.segES, this.getWord(0x824), 0x836);
X86Seg.loadDesc.call(this.segCS, this.getWord(0x822), 0x83C);
X86Seg.loadDesc.call(this.segSS, this.getWord(0x820), 0x842);
X86Seg.loadDesc.call(this.segDS, this.getWord(0x81E), 0x848);
this.nCPL = this.segCS.level;
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.setPS(this.getWord(0x818));
this.setIP(this.getWord(0x81A));
/*
* TODO: The bytes at 0x851 and 0x85D "should be zeroes", but do we rely on that, or should we load zeroes ourselves?
* TODO: The bytes at 0x851 and 0x85D "should be zeroes", but do we rely on that, or do we load zeros ourselves?
*/
this.addrGDT = this.getWord(0x84E) | (this.getWord(0x850) << 16);
this.addrGDTLimit = this.addrGDT + this.getWord(0x852);
this.segLDT.loadDesc(this.getWord(0x81C), 0x854);
this.segLDT.loadDesc6(this.getWord(0x81C), 0x854);
this.addrIDT = this.getWord(0x85A) | (this.getWord(0x85C) << 16);
this.addrIDTLimit = this.addrIDT + this.getWord(0x85E);
this.segTSS.loadDesc(this.getWord(0x816), 0x860);
this.segTSS.loadDesc6(this.getWord(0x816), 0x860);
this.nStepCycles -= 195;
},
/**
@ -182,7 +181,7 @@ var X86Op0F = {
* @return {number}
*/
opLLDT: function(dst, src) {
if (FASTDISABLE) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
if (EAFUNCS) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
this.segLDT.load(dst);
this.nStepCycles -= (17 + (this.regEA < 0? 0 : 2));
return dst;
@ -194,7 +193,7 @@ var X86Op0F = {
* @return {number}
*/
opLTR: function(dst, src) {
if (FASTDISABLE) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
if (EAFUNCS) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
this.segTSS.load(dst);
this.nStepCycles -= (17 + (this.regEA < 0? 0 : 2));
return dst;
@ -206,7 +205,7 @@ var X86Op0F = {
* @return {number}
*/
opVERR: function(dst, src) {
if (FASTDISABLE) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
if (EAFUNCS) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
/*
* Currently, segVER.load() will return an error only if the selector is beyond the bounds of the
* descriptor table or the descriptor is not for a segment.
@ -224,12 +223,9 @@ var X86Op0F = {
*
* Otherwise, DPL must be greater than or equal to (have less or the same privilege as) both the
* current privilege level and the selector's RPL.
*
* TODO: Consider making a CPL (current privilege level) variable that tracks segCS.sel, so that we
* don't have to mask segCS.sel every time.
*/
if ((this.segVER.acc & X86.DESC.ACC.TYPE.CODE_CONFORMING) == X86.DESC.ACC.TYPE.CODE_CONFORMING ||
this.segVER.level >= (this.segCS.sel & X86.SEL.LEVEL) && this.segVER.level >= (dst & X86.SEL.LEVEL)) {
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.setZF();
return dst;
}
@ -245,7 +241,7 @@ var X86Op0F = {
* @return {number}
*/
opVERW: function(dst, src) {
if (FASTDISABLE) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
if (EAFUNCS) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
/*
* Currently, segVER.load() will return an error only if the selector is beyond the bounds of the
* descriptor table or the descriptor is not for a segment.
@ -259,11 +255,8 @@ var X86Op0F = {
/*
* DPL must be greater than or equal to (have less or the same privilege as) both the current
* privilege level and the selector's RPL.
*
* TODO: Consider making a CPL (current privilege level) variable that tracks segCS.sel, so that we
* don't have to mask segCS.sel every time.
*/
if (this.segVER.level >= (this.segCS.sel & X86.SEL.LEVEL) && this.segVER.level >= (dst & X86.SEL.LEVEL)) {
if (this.segVER.dpl >= this.segCS.cpl && this.segVER.dpl >= (dst & X86.SEL.RPL)) {
this.setZF();
return dst;
}
@ -371,7 +364,7 @@ var X86Op0F = {
} else {
this.addrGDT = this.getWord(this.regEA + 2) | (this.getByte(this.regEA + 4) << 16);
this.addrGDTLimit = this.addrGDT + dst;
if (FASTDISABLE) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
if (EAFUNCS) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
this.nStepCycles -= 11;
}
return dst;
@ -394,7 +387,7 @@ var X86Op0F = {
} else {
this.addrIDT = this.getWord(this.regEA + 2) | (this.getByte(this.regEA + 4) << 16);
this.addrIDTLimit = this.addrIDT + dst;
if (FASTDISABLE) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
if (EAFUNCS) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
this.nStepCycles -= 12;
}
return dst;
@ -418,7 +411,7 @@ var X86Op0F = {
opLMSW: function(dst, src) {
X86Help.opHelpLMSW.call(this, dst);
this.nStepCycles -= (this.regEA < 0? 3 : 6);
if (FASTDISABLE) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
if (EAFUNCS) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
}
};

View file

@ -651,7 +651,7 @@ var X86OpXX = {
*/
opCMPmb: function() {
X86Mods.aOpModsMemByte[this.getIPByte()].call(this, X86Grps.opGrpCMPb);
if (FASTDISABLE) this.setEAByte = this.setEAByteEnabled;
if (EAFUNCS) this.setEAByte = this.setEAByteEnabled;
},
/**
* @this {X86CPU}
@ -660,7 +660,7 @@ var X86OpXX = {
*/
opCMPmw: function() {
X86Mods.aOpModsMemWord[this.getIPByte()].call(this, X86Grps.opGrpCMPw);
if (FASTDISABLE) this.setEAWord = this.setEAWordEnabled;
if (EAFUNCS) this.setEAWord = this.setEAWordEnabled;
},
/**
* @this {X86CPU}
@ -669,7 +669,7 @@ var X86OpXX = {
*/
opCMPrb: function() {
X86Mods.aOpModsRegByte[this.getIPByte()].call(this, X86Grps.opGrpCMPb);
if (FASTDISABLE) this.setEAByte = this.setEAByteEnabled;
if (EAFUNCS) this.setEAByte = this.setEAByteEnabled;
},
/**
* @this {X86CPU}
@ -678,7 +678,7 @@ var X86OpXX = {
*/
opCMPrw: function() {
X86Mods.aOpModsRegWord[this.getIPByte()].call(this, X86Grps.opGrpCMPw);
if (FASTDISABLE) this.setEAWord = this.setEAWordEnabled;
if (EAFUNCS) this.setEAWord = this.setEAWordEnabled;
},
/**
* @this {X86CPU}
@ -687,7 +687,7 @@ var X86OpXX = {
*/
opCMPALb: function() {
this.regAX = (this.regAX & ~0xff) | X86Grps.opGrpCMPb.call(this, this.regAX & 0xff, this.getIPByte());
if (FASTDISABLE) this.setEAByte = this.setEAByteEnabled;
if (EAFUNCS) this.setEAByte = this.setEAByteEnabled;
/*
* In the absence of any EA calculations, opGrpCMPb() will deduct nOpCyclesArithRR, and for all CPUs through
* the 80286, we need deduct only one more cycle.
@ -701,7 +701,7 @@ var X86OpXX = {
*/
opCMPAXw: function() {
this.regAX = X86Grps.opGrpCMPw.call(this, this.regAX, this.getIPWord());
if (FASTDISABLE) this.setEAWord = this.setEAWordEnabled;
if (EAFUNCS) this.setEAWord = this.setEAWordEnabled;
/*
* In the absence of any EA calculations, opGrpCMPw() will deduct nOpCyclesArithRR, and for all CPUs through
* the 80286, we need deduct only one more cycle.
@ -1592,7 +1592,7 @@ var X86OpXX = {
*/
opGRP1b: function() {
X86Mods.aOpModsGrpByte[this.getIPByte()].call(this, X86Grps.aOpGRP1b, this.getIPByte);
if (FASTDISABLE) this.setEAByte = this.setEAByteEnabled;
if (EAFUNCS) this.setEAByte = this.setEAByteEnabled;
this.nStepCycles -= (this.regEAWrite < 0? 1 : this.CYCLES.nOpCyclesArithMID);
},
/**
@ -1602,7 +1602,7 @@ var X86OpXX = {
*/
opGRP1w: function() {
X86Mods.aOpModsGrpWord[this.getIPByte()].call(this, X86Grps.aOpGRP1w, this.getIPWord);
if (FASTDISABLE) this.setEAWord = this.setEAWordEnabled;
if (EAFUNCS) this.setEAWord = this.setEAWordEnabled;
this.nStepCycles -= (this.regEAWrite < 0? 1 : this.CYCLES.nOpCyclesArithMID);
},
/**
@ -1612,7 +1612,7 @@ var X86OpXX = {
*/
opGRP1sw: function() {
X86Mods.aOpModsGrpWord[this.getIPByte()].call(this, X86Grps.aOpGRP1w, this.getIPDisp);
if (FASTDISABLE) this.setEAWord = this.setEAWordEnabled;
if (EAFUNCS) this.setEAWord = this.setEAWordEnabled;
this.nStepCycles -= (this.regEAWrite < 0? 1 : this.CYCLES.nOpCyclesArithMID);
},
/**
@ -1622,7 +1622,7 @@ var X86OpXX = {
*/
opTESTrb: function() {
X86Mods.aOpModsMemByte[this.getIPByte()].call(this, X86Help.opHelpTESTb);
if (FASTDISABLE) this.setEAByte = this.setEAByteEnabled;
if (EAFUNCS) this.setEAByte = this.setEAByteEnabled;
},
/**
* @this {X86CPU}
@ -1631,7 +1631,7 @@ var X86OpXX = {
*/
opTESTrw: function() {
X86Mods.aOpModsMemWord[this.getIPByte()].call(this, X86Help.opHelpTESTw);
if (FASTDISABLE) this.setEAWord = this.setEAWordEnabled;
if (EAFUNCS) this.setEAWord = this.setEAWordEnabled;
},
/**
* @this {X86CPU}
@ -1682,9 +1682,9 @@ var X86OpXX = {
/*
* Like other MOV operations, the destination does not need to be read, just written.
*/
if (FASTDISABLE) this.modEAByte = this.modEAByteDisabled; else this.opFlags |= X86.OPFLAG.NOREAD;
if (EAFUNCS) this.modEAByte = this.modEAByteDisabled; else this.opFlags |= X86.OPFLAG.NOREAD;
X86Mods.aOpModsMemByte[this.getIPByte()].call(this, X86Help.opHelpMOV);
if (FASTDISABLE) this.modEAByte = this.modEAByteEnabled;
if (EAFUNCS) this.modEAByte = this.modEAByteEnabled;
},
/**
* @this {X86CPU}
@ -1695,9 +1695,9 @@ var X86OpXX = {
/*
* Like other MOV operations, the destination does not need to be read, just written.
*/
if (FASTDISABLE) this.modEAWord = this.modEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOREAD;
if (EAFUNCS) this.modEAWord = this.modEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOREAD;
X86Mods.aOpModsMemWord[this.getIPByte()].call(this, X86Help.opHelpMOV);
if (FASTDISABLE) this.modEAWord = this.modEAWordEnabled;
if (EAFUNCS) this.modEAWord = this.modEAWordEnabled;
},
/**
* @this {X86CPU}
@ -1747,9 +1747,9 @@ var X86OpXX = {
/*
* Like other MOV operations, the destination does not need to be read, just written.
*/
if (FASTDISABLE) this.modEAWord = this.modEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOREAD;
if (EAFUNCS) this.modEAWord = this.modEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOREAD;
X86Mods.aOpModsMemWord[bModRM].call(this, X86Help.opHelpMOVSegSrc);
if (FASTDISABLE) this.modEAWord = this.modEAWordEnabled;
if (EAFUNCS) this.modEAWord = this.modEAWordEnabled;
},
/**
* @this {X86CPU}
@ -1757,10 +1757,10 @@ var X86OpXX = {
* op=0x8D (lea reg,rm)
*/
opLEA: function() {
if (FASTDISABLE) this.getEAWord = this.getEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOREAD;
if (EAFUNCS) this.getEAWord = this.getEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOREAD;
this.segData = this.segStack = this.segZERO; // we can't have the EA calculation, if any, "polluted" by segment arithmetic
X86Mods.aOpModsRegWord[this.getIPByte()].call(this, X86Help.opHelpLEA);
if (FASTDISABLE) this.getEAWord = this.getEAWordEnabled;
if (EAFUNCS) this.getEAWord = this.getEAWordEnabled;
},
/**
* @this {X86CPU}
@ -1858,9 +1858,9 @@ var X86OpXX = {
/*
* Like other MOV operations, the destination does not need to be read, just written.
*/
if (FASTDISABLE) this.modEAWord = this.modEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOREAD;
if (EAFUNCS) this.modEAWord = this.modEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOREAD;
X86Mods.aOpModsGrpWord[this.getIPByte()].call(this, X86Grps.aOpGrpPOPw, this.popWord);
if (FASTDISABLE) this.modEAWord = this.modEAWordEnabled;
if (EAFUNCS) this.modEAWord = this.modEAWordEnabled;
},
/**
* @this {X86CPU}
@ -2198,7 +2198,7 @@ var X86OpXX = {
this.advanceIP(((this.opPrefixes & X86.OPFLAG.SEG)? -3 : -2));
this.opFlags |= X86.OPFLAG.REPEAT;
}
if (FASTDISABLE) this.setEAByte = this.setEAByteEnabled;
if (EAFUNCS) this.setEAByte = this.setEAByteEnabled;
}
},
/**
@ -2246,7 +2246,7 @@ var X86OpXX = {
this.advanceIP(((this.opPrefixes & X86.OPFLAG.SEG)? -3 : -2));
this.opFlags |= X86.OPFLAG.REPEAT;
}
if (FASTDISABLE) this.setEAWord = this.setEAWordEnabled;
if (EAFUNCS) this.setEAWord = this.setEAWordEnabled;
}
},
/**
@ -2453,7 +2453,7 @@ var X86OpXX = {
this.advanceIP(-2); // this instruction does not support segment overrides
this.opFlags |= X86.OPFLAG.REPEAT;
}
if (FASTDISABLE) this.setEAByte = this.setEAByteEnabled;
if (EAFUNCS) this.setEAByte = this.setEAByteEnabled;
}
},
/**
@ -2493,7 +2493,7 @@ var X86OpXX = {
this.advanceIP(-2); // this instruction does not support segment overrides
this.opFlags |= X86.OPFLAG.REPEAT;
}
if (FASTDISABLE) this.setEAWord = this.setEAWordEnabled;
if (EAFUNCS) this.setEAWord = this.setEAWordEnabled;
}
},
/**
@ -2707,9 +2707,9 @@ var X86OpXX = {
/*
* Like other MOV operations, the destination does not need to be read, just written.
*/
if (FASTDISABLE) this.modEAByte = this.modEAByteDisabled; else this.opFlags |= X86.OPFLAG.NOREAD;
if (EAFUNCS) this.modEAByte = this.modEAByteDisabled; else this.opFlags |= X86.OPFLAG.NOREAD;
X86Mods.aOpModsGrpByte[this.getIPByte()].call(this, X86Grps.aOpGrpMOVImm, this.getIPByte);
if (FASTDISABLE) this.modEAByte = this.modEAByteEnabled;
if (EAFUNCS) this.modEAByte = this.modEAByteEnabled;
},
/**
* @this {X86CPU}
@ -2720,9 +2720,9 @@ var X86OpXX = {
/*
* Like other MOV operations, the destination does not need to be read, just written.
*/
if (FASTDISABLE) this.modEAWord = this.modEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOREAD;
if (EAFUNCS) this.modEAWord = this.modEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOREAD;
X86Mods.aOpModsGrpWord[this.getIPByte()].call(this, X86Grps.aOpGrpMOVImm, this.getIPWord);
if (FASTDISABLE) this.modEAWord = this.modEAWordEnabled;
if (EAFUNCS) this.modEAWord = this.modEAWordEnabled;
},
/**
* @this {X86CPU}
@ -3253,7 +3253,7 @@ var X86OpXX = {
this.regMD16 = -1;
X86Mods.aOpModsGrpByte[this.getIPByte()].call(this, X86Grps.aOpGRP3b, X86Grps.opGrpNoSrc);
if (this.regMD16 >= 0) this.regAX = this.regMD16;
if (FASTDISABLE) this.setEAByte = this.setEAByteEnabled;
if (EAFUNCS) this.setEAByte = this.setEAByteEnabled;
},
/**
* @this {X86CPU}
@ -3280,7 +3280,7 @@ var X86OpXX = {
this.regAX = this.regMD16;
this.regDX = this.regMD32;
}
if (FASTDISABLE) this.setEAWord = this.setEAWordEnabled;
if (EAFUNCS) this.setEAWord = this.setEAWordEnabled;
},
/**
* @this {X86CPU}
@ -3352,7 +3352,7 @@ var X86OpXX = {
*/
opGRP4w: function() {
X86Mods.aOpModsGrpWord[this.getIPByte()].call(this, X86Grps.aOpGRP4w, X86Grps.opGrpNoSrc);
if (FASTDISABLE) this.setEAWord = this.setEAWordEnabled;
if (EAFUNCS) this.setEAWord = this.setEAWordEnabled;
}
};

View file

@ -33,6 +33,7 @@
"use strict";
if (typeof module !== 'undefined') {
var str = require("../../shared/lib/strlib");
var X86 = require("./x86");
var X86Help = require("./x86help");
}
@ -52,9 +53,11 @@ function X86Seg(cpu, sName, fProt)
this.base = 0;
this.limit = 0xffff;
this.acc = 0;
this.level = 0;
this.fCode = (sName == "CS");
this.sName = sName;
this.setProt(fProt);
this.cpl = 0;
this.dpl = 0;
this.updateAccess(fProt);
}
/*
@ -67,7 +70,7 @@ function X86Seg(cpu, sName, fProt)
* This is the default real-mode load() function.
*
* @this {X86Seg}
* @param {number} sel containing a selector
* @param {number} sel
* @param {boolean} [fSuppress] is true to suppress any errors
* @return {number} base address of selected segment, or -1 if error
*/
@ -75,7 +78,7 @@ X86Seg.loadReal = function loadReal(sel, fSuppress)
{
this.sel = sel;
this.limit = 0xffff; // TODO: Consider NOT setting the limit field in real-mode (unless it's required for, say, LOADALL support?)
this.level = 0;
this.cpl = this.dpl = 0;
return this.base = sel << 4;
};
@ -96,7 +99,7 @@ X86Seg.loadReal = function loadReal(sel, fSuppress)
* See X86.DESC for offset and bit definitions.
*
* @this {X86Seg}
* @param {number} sel containing a selector
* @param {number} sel
* @param {boolean} [fSuppress] is true to suppress any errors
* @return {number} base address of selected segment, or -1 if error
*/
@ -111,70 +114,21 @@ X86Seg.loadProt = function loadProt(sel, fSuppress)
addrDT = this.cpu.segLDT.base;
addrDTLimit = this.cpu.segLDT.limit;
}
var offDesc = addrDT + (sel & X86.SEL.MASK);
if (offDesc + 7 <= addrDTLimit) {
var addrDesc = addrDT + (sel & X86.SEL.MASK);
if (addrDesc + 7 <= addrDTLimit) {
/*
* TODO: This is only the first of many steps toward accurately counting cycles in protected mode;
* 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.
*/
this.cpu.nStepCycles -= 15;
return X86Seg.loadDesc.call(this, sel, offDesc, true);
return this.loadDesc8(sel, addrDesc);
}
return -1;
};
/**
* loadDesc(sel, offDesc, fProt)
*
* @this {X86Seg}
* @param {number} sel containing a selector
* @param {number} offDesc is the physical address of a descriptor
* @param {boolean} [fProt] is true if protected-mode, false if real-mode, undefined if TBD
* @return {number} base address of selected segment, or -1 if error
*/
X86Seg.loadDesc = function(sel, offDesc, fProt)
{
var limit = this.cpu.getWord(offDesc + X86.DESC.LIMIT.OFFSET);
var acc = this.cpu.getWord(offDesc + X86.DESC.ACC.OFFSET);
var base = this.cpu.getWord(offDesc + X86.DESC.BASE.OFFSET) | ((acc & X86.DESC.ACC.BASE1623) << 16);
Component.assert(this.cpu.getWord(offDesc + 0x06) == 0);
fProt = this.setProt(fProt);
/*
* For LSL (which uses fSuppress), we must support X86.DESC.ACC.TYPE.SEG as well as TSS and LDT.
*/
var accType = (acc & X86.DESC.ACC.TYPE.MASK);
if (accType & X86.DESC.ACC.TYPE.SEG) {
if (fProt) {
if ((accType & X86.DESC.ACC.TYPE.CODE_READABLE) == X86.DESC.ACC.TYPE.CODE) {
this.checkWrite = X86Seg.checkReadProtDisabled;
}
if ((accType & X86.DESC.ACC.TYPE.CODE) || !(accType & X86.DESC.ACC.TYPE.WRITEABLE)) {
this.checkWrite = X86Seg.checkWriteProtDisabled;
}
}
this.sel = sel;
this.limit = limit;
this.acc = acc;
this.level = (acc & X86.DESC.ACC.LEVEL.MASK) >> X86.DESC.ACC.LEVEL.SHIFT;
return this.base = base;
}
else if (accType && accType <= X86.DESC.ACC.TYPE.TSS_BUSY) {
this.sel = sel;
this.limit = limit;
this.acc = acc;
this.level = (acc & X86.DESC.ACC.LEVEL.MASK) >> X86.DESC.ACC.LEVEL.SHIFT;
return this.base = base;
}
return -1;
};
/**
* checkReadReal(off, cb)
* checkReadReal(off, cb, fSuppress)
*
* TODO: Invoke X86Help.opHelpFault.call(this.cpu, X86.EXCEPTION.GP_FAULT) if off is 0xffff and cb is 1;
* also, whether or not the opHelpFault() call should include an error code, since this is happening in real-mode.
@ -191,7 +145,7 @@ X86Seg.checkReadReal = function checkReadReal(off, cb, fSuppress)
};
/**
* checkWriteReal(off, cb)
* checkWriteReal(off, cb, fSuppress)
*
* TODO: Invoke X86Help.opHelpFault.call(this.cpu, X86.EXCEPTION.GP_FAULT) if off is 0xffff and cb is 1;
* also, whether or not the opHelpFault() call should include an error code, since this is happening in real-mode.
@ -208,7 +162,7 @@ X86Seg.checkWriteReal = function checkWriteReal(off, cb, fSuppress)
};
/**
* checkReadProtEnabled(off, cb)
* checkReadProtEnabled(off, cb, fSuppress)
*
* @this {X86Seg}
* @param {number} off is a segment-relative offset
@ -225,7 +179,7 @@ X86Seg.checkReadProtEnabled = function checkReadProtEnabled(off, cb, fSuppress)
};
/**
* checkReadProtDisabled(off, cb)
* checkReadProtDisabled(off, cb, fSuppress)
*
* @this {X86Seg}
* @param {number} off is a segment-relative offset
@ -242,7 +196,7 @@ X86Seg.checkReadProtDisabled = function checkReadProtDisabled(off, cb, fSuppress
};
/**
* checkWriteProtEnabled(off, cb)
* checkWriteProtEnabled(off, cb, fSuppress)
*
* @this {X86Seg}
* @param {number} off is a segment-relative offset
@ -259,7 +213,7 @@ X86Seg.checkWriteProtEnabled = function checkWriteProtEnabled(off, cb, fSuppress
};
/**
* checkWriteProtDisabled(off, cb)
* checkWriteProtDisabled(off, cb, fSuppress)
*
* @this {X86Seg}
* @param {number} off is a segment-relative offset
@ -280,40 +234,88 @@ X86Seg.checkWriteProtDisabled = function checkWriteProtDisabled(off, cb, fSuppre
*/
/**
* save()
* loadDesc6(sel, addrDesc)
*
* Early versions of PCjs saved only segment selectors, since that's all that mattered in real-mode;
* newer versions need to save/restore the entire segment object.
* Used to load a protected-mode selector that refers to a 6-byte descriptor "cache" (LOADALL) entry:
*
* word 0: base address low
* word 1: base address high (0-7), segment type (8-11), descriptor type (12), DPL (13-14), present bit (15)
* word 2: segment limit (0-15)
*
* @this {X86Seg}
* @return {Array}
* @param {number} sel is the selector
* @param {number} addrDesc is the offset
* @return {number} base address of selected segment, or -1 if error
*/
X86Seg.prototype.save = function()
X86Seg.prototype.loadDesc6 = function(sel, addrDesc)
{
return [this.sel, this.base, this.limit, this.acc, this.level, this.sName];
var acc = this.cpu.getWord(addrDesc + 2);
var base = this.cpu.getWord(addrDesc + 0) | ((acc & 0xff) << 16);
var limit = this.cpu.getWord(addrDesc + 4);
if (DEBUG) {
this.cpu.messageDebugger("loadDesc6(" + this.sName + "): base=" + str.toHex(base) + " limit=" + str.toHexWord(limit) + " acc=" + str.toHexWord(acc));
}
this.sel = sel;
this.base = base;
this.limit = limit;
this.acc = acc & X86.DESC.ACC.MASK;
this.updateAccess();
return base;
};
/**
* restore(a)
* loadDesc8(sel, addrDesc)
*
* Early versions of PCjs saved only segment selectors, since that's all that mattered in real-mode;
* newer versions need to save/restore the entire segment object.
* Used to load a protected-mode selector that refers to an 8-byte descriptor table (GDT, LDT, IDT) entry:
*
* word 0: segment limit (0-15)
* word 1: base address low
* word 2: base address high (0-7), segment type (8-11), descriptor type (12), DPL (13-14), present bit (15)
* word 3: used only on 80386 and up (should be set to zero for upward compatibility)
*
* See X86.DESC for offset and bit definitions.
*
* @this {X86Seg}
* @param {Array|number} a
* @param {number} sel is the selector
* @param {number} addrDesc is the offset
* @return {number} base address of selected segment, or -1 if error
*/
X86Seg.prototype.restore = function(a)
X86Seg.prototype.loadDesc8 = function(sel, addrDesc)
{
if (typeof a == "number") {
this.load(a);
} else {
this.sel = a[0];
this.base = a[1];
this.limit = a[2];
this.acc = a[3];
this.level = a[4];
this.sName = a[5];
var limit = this.cpu.getWord(addrDesc + X86.DESC.LIMIT.OFFSET);
var acc = this.cpu.getWord(addrDesc + X86.DESC.ACC.OFFSET);
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);
if (DEBUG) {
this.cpu.messageDebugger("loadDesc8(" + this.sName + "): base=" + str.toHex(base) + " limit=" + str.toHexWord(limit) + " acc=" + str.toHexWord(acc) + (ext? " ext=" + str.toHexWord(ext) : ""));
Component.assert(!ext);
}
/*
* For LSL (which uses fSuppress), we must support X86.DESC.ACC.TYPE.SEG as well as TSS and LDT.
*/
var accType;
if ((acc & X86.DESC.ACC.TYPE.SEG) || (accType = (acc & X86.DESC.ACC.TYPE.MASK)) && accType <= X86.DESC.ACC.TYPE.TSS_BUSY) {
this.sel = sel;
this.base = base;
this.limit = limit;
/*
* Note that bits 0-7 of acc will usually contain the BASE1623 bits from the descriptor entry,
* but it doesn't matter, because the only acc bits we pay attention to are bits 8-15; however,
* to keep things tidy, we zero bits 0-7. Perhaps we'll find other (internal) uses for those bits.
*/
this.acc = acc & X86.DESC.ACC.MASK;
this.type = acc & X86.DESC.ACC.TYPE.MASK;
this.updateAccess();
}
else {
base = -1;
}
return base;
};
/**
@ -333,16 +335,55 @@ X86Seg.prototype.setBase = function(addr)
};
/**
* setProt(fProt)
* save()
*
* This must be used to ensure that the segment register's state (ie, load and check methods) matches
* the current operating mode (real or protected).
* Early versions of PCjs saved only segment selectors, since that's all that mattered in real-mode;
* newer versions need to save/restore the entire segment object.
*
* @this {X86Seg}
* @param {boolean} [fProt]
* @return {Array}
*/
X86Seg.prototype.save = function()
{
return [this.sel, this.base, this.limit, this.acc, this.fCode, this.sName, this.cpl, this.dpl];
};
/**
* restore(a)
*
* Early versions of PCjs saved only segment selectors, since that's all that mattered in real-mode;
* newer versions need to save/restore the entire segment object.
*
* @this {X86Seg}
* @param {Array|number} a
*/
X86Seg.prototype.restore = function(a)
{
if (typeof a == "number") {
this.load(a);
} else {
this.sel = a[0];
this.base = a[1];
this.limit = a[2];
this.acc = a[3];
this.fCode = a[4];
this.sName = a[5];
this.cpl = a[6];
this.dpl = a[7];
}
};
/**
* updateAccess(fProt)
*
* Ensures that the segment register's access (ie, load and check methods) matches the specified (or current)
* operating mode (real or protected).
*
* @this {X86Seg}
* @param {boolean} [fProt] true for protected-mode access, false for real-mode access, undefined for current mode
* @return {boolean}
*/
X86Seg.prototype.setProt = function(fProt)
X86Seg.prototype.updateAccess = function(fProt)
{
if (fProt === undefined) {
fProt = !!(this.cpu.regMSW & X86.MSW.PE);
@ -351,10 +392,27 @@ X86Seg.prototype.setProt = function(fProt)
this.load = X86Seg.loadProt;
this.checkRead = X86Seg.checkReadProtEnabled;
this.checkWrite = X86Seg.checkWriteProtEnabled;
if (this.acc & X86.DESC.ACC.TYPE.SEG) {
/*
* If the READABLE bit of CODE_READABLE is not set, then disallow reads
*/
if ((this.acc & X86.DESC.ACC.TYPE.CODE_READABLE) == X86.DESC.ACC.TYPE.CODE_EXECONLY) {
this.checkWrite = X86Seg.checkReadProtDisabled;
}
/*
* If the CODE bit is set, or the the WRITEABLE bit is not set, then disallow writes
*/
if ((this.acc & X86.DESC.ACC.TYPE.CODE) || !(this.acc & X86.DESC.ACC.TYPE.WRITEABLE)) {
this.checkWrite = X86Seg.checkWriteProtDisabled;
}
}
this.cpl = this.sel & X86.SEL.RPL;
this.dpl = (this.acc & X86.DESC.ACC.DPL.MASK) >> X86.DESC.ACC.DPL.SHIFT;
} else {
this.load = X86Seg.loadReal;
this.checkRead = X86Seg.checkReadReal;
this.checkWrite = X86Seg.checkWriteReal;
this.cpl = this.dpl = 0;
}
return fProt;
};

View file

@ -9,7 +9,7 @@
<xsl:variable name="MACHINECLASS">pc</xsl:variable>
<xsl:variable name="APPCLASS">pcjs</xsl:variable>
<xsl:variable name="APPVERSION">1.0.0</xsl:variable>
<xsl:variable name="APPVERSION">1.x.x</xsl:variable>
<xsl:variable name="SITEHOST">www.pcjs.org</xsl:variable>
<xsl:template name="componentStyles">

View file

@ -46,7 +46,7 @@
* It's not that I'm trying to write "portable JavaScript", but some of this code was ported from C code
* I'd written about 14 years earlier, and portability is good, so I see no reason to rewrite code to make
* it less portable.
*
*
* UPDATE: I've since switched to JSHint, which seems to have more reasonable defaults.
*/
@ -62,7 +62,7 @@ if (typeof module !== 'undefined') {
/**
* Component(type, parms, constructor)
*
*
* @constructor
* @param {string} type
* @param {Object} [parms]
@ -83,7 +83,7 @@ if (typeof module !== 'undefined') {
function Component(type, parms, constructor)
{
this.type = type;
if (!parms) {
parms = {'id': "", 'name': ""};
}
@ -110,19 +110,23 @@ function Component(type, parms, constructor)
this[type] = constructor;
/*
* TODO: Decide how to reintegrate this code into the components that still want it....
* TODO: Decide how to reintegrate this code into the components that still want it....
*
if (this.initStep) this.initStep(parms);
*/
this.aFlags = {
fReady: false,
fBusy: false,
fBusyCancel: false,
fPowered: false,
fError: false
};
this.fnReady = null;
this.fReady = false;
this.fBusy = this.fBusyCancel = false;
this.fPowered = false;
this.clearError();
this.bindings = {};
this.dbg = null; // by default, no connection to a Debugger
this.getMachineNum(); // once again, make the function appear used
Component.add(this);
@ -139,10 +143,10 @@ Component.parmsURL = web.getURLParameters();
/**
* Component.inherit(p)
*
*
* Returns a newly created object that inherits properties from the prototype object p.
* It uses the ECMAScript 5 function Object.create() if it is defined, and otherwise falls back to an older technique.
*
*
* See: Flanagan, David (2011-04-18). JavaScript: The Definitive Guide: The Definitive Guide (Kindle Locations 9854-9903). OReilly Media - A. Kindle Edition (Example 6-1)
*
* @param {Object} p
@ -167,10 +171,10 @@ Component.inherit = function(p)
/**
* Component.extend(o, p)
*
*
* Copies the enumerable properties of p to o and returns o.
* If o and p have a property by the same name, o's property is overwritten.
*
*
* See: Flanagan, David (2011-04-18). JavaScript: The Definitive Guide: The Definitive Guide (Kindle Locations 9854-9903). OReilly Media - A. Kindle Edition (Example 6-2)
*
* @param {Object} o
@ -221,7 +225,7 @@ Component.all = [];
/**
* Component.add(component)
*
*
* @param {Component} component
*/
Component.add = function(component)
@ -236,7 +240,7 @@ Component.add = function(component)
/**
* Component.log(s, type)
*
*
* For diagnostic output only.
*
* @param {string} [s] is the message text
@ -258,7 +262,7 @@ Component.log = function(s, type)
/**
* Component.assert(f, s)
*
*
* Used to verify conditions that must be true (for DEBUG builds only; compiled builds should automatically have all
* references to Component.assert() removed).
*
@ -281,9 +285,9 @@ Component.assert = function(f, s)
/**
* Component.println(s, type, id)
*
*
* For non-diagnostic messages, which components may override to control the destination/appearance of their output.
*
*
* Components that inherit from this class should use the instance method, this.println(), rather than Component.println(),
* because if a Control Panel is loaded, it will override only the instance method, not the class method (overriding the class
* method would improperly affect any other machines loaded on the same page).
@ -301,7 +305,7 @@ Component.println = function(s, type, id)
/**
* Component.notice(s, fPrintOnly, id)
*
*
* notice() is like println() but implies a need for user notification, so we alert() as well.
*
* @param {string} s is the message text
@ -318,7 +322,7 @@ Component.notice = function(s, fPrintOnly, id)
/**
* Component.warning(s)
*
*
* @param {string} s describes the warning
*/
Component.warning = function(s)
@ -331,7 +335,7 @@ Component.warning = function(s)
/**
* Component.error(s)
*
*
* @param {string} s describes the error; an alert() is displayed as well
*/
Component.error = function(s)
@ -344,7 +348,7 @@ Component.error = function(s)
/**
* Component.getComponents(idRelated)
*
*
* We could store components as properties of an 'all' object, using the component's ID,
* and change this linear lookup into a property lookup, but some components may have no ID.
*
@ -357,7 +361,7 @@ Component.getComponents = function(idRelated)
var aComponents = [];
/*
* getComponentByID(id, idRelated)
*
*
* If idRelated is provided, we check it for a machine prefix, and use any
* existing prefix to constrain matches to IDs with the same prefix, in order to
* avoid matching components belonging to other machines.
@ -379,7 +383,7 @@ Component.getComponents = function(idRelated)
/**
* Component.getComponentByID(id, idRelated)
*
*
* We could store components as properties of an 'all' object, using the component's ID,
* and change this linear lookup into a property lookup, but some components may have no ID.
*
@ -411,7 +415,7 @@ Component.getComponentByID = function(id, idRelated)
/**
* Component.getComponentByType(sType, idRelated, componentPrev)
*
*
* @param {string} sType of the desired component
* @param {string} [idRelated] of related component
* @param {Component} [componentPrev] of previously returned component, if any
@ -449,7 +453,7 @@ Component.getComponentByType = function(sType, idRelated, componentPrev)
/**
* Component.getComponentParms(element)
*
*
* @param {Object} element from the DOM
*/
Component.getComponentParms = function(element)
@ -476,7 +480,7 @@ Component.getComponentParms = function(element)
/**
* Component.bindExternalControl(component, sControl, sBinding, sType)
*
*
* @param {Component} component
* @param {string} sControl
* @param {string} sBinding
@ -498,7 +502,7 @@ Component.bindExternalControl = function(component, sControl, sBinding, sType)
/**
* Component.bindComponentControls(component, element, sAppClass)
*
*
* @param {Component} component
* @param {Object} element from the DOM
* @param {string} sAppClass
@ -544,9 +548,9 @@ Component.bindComponentControls = function(component, element, sAppClass)
/**
* Component.getElementsByClass(element, sClass, sObjClass)
*
*
* This is a cross-browser helper function, since not all browser's support getElementsByClassName()
*
*
* TODO: This should probably be moved into weblib.js at some point, along with the control binding functions above,
* to keep all the browser-related code together.
*
@ -583,7 +587,7 @@ Component.prototype = {
constructor: Component,
/**
* toString()
*
*
* @this {Component}
* @return {string}
*/
@ -592,7 +596,7 @@ Component.prototype = {
},
/**
* getMachineNum()
*
*
* @this {Component}
* @return {number} unique machine number
*/
@ -607,7 +611,7 @@ Component.prototype = {
},
/**
* setBinding(sHTMLClass, sHTMLType, sBinding, control)
*
*
* Component's setBinding() method is intended to be overridden by subclasses.
*
* @this {Component}
@ -661,8 +665,8 @@ Component.prototype = {
};
}(control));
/**
* Override this.notice() with a replacement function that eliminates the web.alertUser() call
*
* Override this.notice() with a replacement function that eliminates the web.alertUser() call
*
* @this {Component}
* @param {string} s
* @param {boolean} [fPrintOnly]
@ -679,12 +683,12 @@ Component.prototype = {
},
/**
* log(s, type)
*
*
* For diagnostic output only.
*
*
* WARNING: Even though this function's body is completely wrapped in DEBUG, that won't prevent the Closure Compiler
* from including it, so all calls must still be prefixed with "if (DEBUG) ....". For this reason, the class method,
* Component.log(), is preferred, because the compiler IS smart enough to remove those calls.
* Component.log(), is preferred, because the compiler IS smart enough to remove those calls.
*
* @this {Component}
* @param {string} [s] is the message text
@ -702,7 +706,7 @@ Component.prototype = {
*
* Components using this.println() should wait until after their constructor has run to display any messages, because
* if a Control Panel has been loaded, its override will not take effect until its own constructor has run.
*
*
* @this {Component}
* @param {string} [s] is the message text
* @param {string} [type] is the message type
@ -713,7 +717,7 @@ Component.prototype = {
},
/**
* status(s)
*
*
* status() is like println() but it also includes information about the component (ie, the component ID),
* which is why there is no corresponding Component.status() function.
*
@ -724,7 +728,7 @@ Component.prototype = {
},
/**
* notice(s, fPrintOnly)
*
*
* notice() is like println() but implies a need for user notification, so we alert() as well; however, if this.println()
* is overridden, this.notice will be replaced with a similar override, on the assumption that the override is taking care
* of alerting the user.
@ -739,36 +743,36 @@ Component.prototype = {
},
/**
* setError(s)
*
*
* Set a fatal error condition
*
* @this {Component}
* @param {string} s describes a fatal error condition
*/
setError: function(s) {
this.fError = true;
this.aFlags.fError = true;
this.notice("Fatal error: " + s);
},
/**
* clearError()
*
*
* Clear any fatal error condition
*
* @this {Component}
*/
clearError: function() {
this.fError = false;
this.aFlags.fError = false;
},
/**
* isError()
*
*
* Report any fatal error condition
*
* @this {Component}
* @return {boolean} true if a fatal error condition exists, false if not
*/
isError: function() {
if (this.fError) {
if (this.aFlags.fError) {
this.println(this.toString() + " error");
return true;
}
@ -776,7 +780,7 @@ Component.prototype = {
},
/**
* isReady(fnReady)
*
*
* Return the "ready" state of the component; if the component is not ready, it will queue the optional
* notification function, otherwise it will immediately call the notification function, if any, without queuing it.
*
@ -789,27 +793,27 @@ Component.prototype = {
*/
isReady: function(fnReady) {
if (fnReady) {
if (this.fReady) {
if (this.aFlags.fReady) {
fnReady();
} else {
if (DEBUG) this.log("NOT ready");
this.fnReady = fnReady;
}
}
return this.fReady;
return this.aFlags.fReady;
},
/**
* setReady(fReady)
*
*
* Set the "ready" state of the component to true, and call any queued notification functions.
*
* @this {Component}
* @param {boolean} [fReady] is assumed to indicate "ready" unless EXPLICITLY set to false
*/
setReady: function(fReady) {
if (!this.fError) {
this.fReady = (fReady !== false);
if (this.fReady) {
if (!this.aFlags.fError) {
this.aFlags.fReady = (fReady !== false);
if (this.aFlags.fReady) {
if (DEBUG || this.name) this.log("ready");
var fnReady = this.fnReady;
this.fnReady = null;
@ -819,7 +823,7 @@ Component.prototype = {
},
/**
* isBusy(fCancel)
*
*
* Return the "busy" state of the component
*
* @this {Component}
@ -827,18 +831,18 @@ Component.prototype = {
* @return {boolean} true if "busy", false if not
*/
isBusy: function(fCancel) {
if (this.fBusy) {
if (this.aFlags.fBusy) {
if (fCancel) {
this.fBusyCancel = true;
this.aFlags.fBusyCancel = true;
} else if (fCancel === undefined) {
this.println(this.toString() + " busy");
}
}
return this.fBusy;
return this.aFlags.fBusy;
},
/**
* setBusy(fBusy)
*
*
* Update the current busy state; if an fCancel request is pending, it will be honored now.
*
* @this {Component}
@ -846,19 +850,19 @@ Component.prototype = {
* @return {boolean}
*/
setBusy: function(fBusy) {
if (this.fBusyCancel) {
if (this.fBusy) {
this.fBusy = false;
if (this.aFlags.fBusyCancel) {
if (this.aFlags.fBusy) {
this.aFlags.fBusy = false;
}
this.fBusyCancel = false;
this.aFlags.fBusyCancel = false;
return false;
}
if (this.fError) {
if (this.aFlags.fError) {
this.println(this.toString() + " error");
return false;
}
this.fBusy = fBusy;
return this.fBusy;
this.aFlags.fBusy = fBusy;
return this.aFlags.fBusy;
},
/**
* powerUp(fSave)
@ -869,7 +873,7 @@ Component.prototype = {
* @return {boolean} true if successful, false if failure
*/
powerUp: function(data, fRepower) {
this.fPowered = true;
this.aFlags.fPowered = true;
return true;
},
/**
@ -881,7 +885,7 @@ Component.prototype = {
* @return {Object|boolean} component state if fSave; otherwise, true if successful, false if failure
*/
powerDown: function(fSave, fShutdown) {
if (fShutdown) this.fPowered = false;
if (fShutdown) this.aFlags.fPowered = false;
return true;
}
};