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

@ -242,25 +242,25 @@ if (DEBUGGER) {
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,
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
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
};
/*
@ -274,23 +274,23 @@ if (DEBUGGER) {
"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",
"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"
"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
@ -843,7 +843,8 @@ if (DEBUGGER) {
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]
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

@ -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).
* 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).
*
* 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.
*
* 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.
*/
@ -101,15 +95,13 @@ 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

@ -44,3 +44,8 @@
* 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
},
@ -93,20 +93,19 @@ var X86 = {
TYPE: {
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
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
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
/*
* 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,
@ -115,13 +114,25 @@ var X86 = {
GATE_CALL: 0x0400,
GATE_TASK: 0x0500,
GATE_INT: 0x0600,
GATE_TRAP: 0x0700
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
@ -279,6 +233,107 @@ X86Seg.checkWriteProtDisabled = function checkWriteProtDisabled(off, cb, fSuppre
* Object methods
*/
/**
* loadDesc6(sel, addrDesc)
*
* 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}
* @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.loadDesc6 = function(sel, addrDesc)
{
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;
};
/**
* loadDesc8(sel, addrDesc)
*
* 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 {number} sel is the selector
* @param {number} addrDesc is the offset
* @return {number} base address of selected segment, or -1 if error
*/
X86Seg.prototype.loadDesc8 = function(sel, addrDesc)
{
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;
};
/**
* setBase(addr)
*
* This is used in unusual situations where the base must be set independently; normally, the base
* is set according to the selector provided to load(), but there are a few cases where setBase() is
* required (eg, in resetRegs() where the 80286 wants the real-mode CS selector to be 0xF000 but the
* CS base must be 0xFF0000, and LOADALL).
*
* @this {X86Seg}
* @param {number} addr
*/
X86Seg.prototype.setBase = function(addr)
{
this.base = addr;
};
/**
* save()
*
@ -290,7 +345,7 @@ X86Seg.checkWriteProtDisabled = function checkWriteProtDisabled(off, cb, fSuppre
*/
X86Seg.prototype.save = function()
{
return [this.sel, this.base, this.limit, this.acc, this.level, this.sName];
return [this.sel, this.base, this.limit, this.acc, this.fCode, this.sName, this.cpl, this.dpl];
};
/**
@ -311,38 +366,24 @@ X86Seg.prototype.restore = function(a)
this.base = a[1];
this.limit = a[2];
this.acc = a[3];
this.level = a[4];
this.fCode = a[4];
this.sName = a[5];
this.cpl = a[6];
this.dpl = a[7];
}
};
/**
* setBase(addr)
* updateAccess(fProt)
*
* This is used in unusual situations where the base must be set independently; normally, the base
* is set according to the selector provided to load(), but there are a few cases where setBase() is
* required (eg, in resetRegs() where the 80286 wants the real-mode CS selector to be 0xF000 but the
* CS base must be 0xFF0000, and LOADALL).
* 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 {number} addr
*/
X86Seg.prototype.setBase = function(addr)
{
this.base = addr;
};
/**
* setProt(fProt)
*
* 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).
*
* @this {X86Seg}
* @param {boolean} [fProt]
* @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

@ -114,11 +114,15 @@ function Component(type, parms, constructor)
*
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
@ -746,7 +750,7 @@ Component.prototype = {
* @param {string} s describes a fatal error condition
*/
setError: function(s) {
this.fError = true;
this.aFlags.fError = true;
this.notice("Fatal error: " + s);
},
/**
@ -757,7 +761,7 @@ Component.prototype = {
* @this {Component}
*/
clearError: function() {
this.fError = false;
this.aFlags.fError = false;
},
/**
* isError()
@ -768,7 +772,7 @@ Component.prototype = {
* @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;
}
@ -789,14 +793,14 @@ 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)
@ -807,9 +811,9 @@ Component.prototype = {
* @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;
@ -827,14 +831,14 @@ 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)
@ -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;
}
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long