Merge branch 'master' of https://github.com/jeffpar/pcjs into c1pserialupload
This commit is contained in:
commit
e9e7633fa7
294 changed files with 10332 additions and 3960 deletions
|
|
@ -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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@
|
|||
<cpu id="cpu6502"/>
|
||||
<ram id="ram8K" size="0x2000"/>
|
||||
<rom id="romNull" size="0x8000"/>
|
||||
<rom id="romBasic" size="0x2000" image="/devices/c1p/roms/basic-gcpatch.hex"/>
|
||||
<rom id="romSystem" size="0x0800" image="/devices/c1p/roms/system.hex"/>
|
||||
<rom id="romBasic" size="0x2000" image="/devices/c1p/rom/basic-gcpatch.hex"/>
|
||||
<rom id="romSystem" size="0x0800" image="/devices/c1p/rom/system.hex"/>
|
||||
<video id="video" screenwidth="256" screenheight="192" cols="32" rows="32" charset="/devices/c1p/video/chargen1x.png" padding="8px"/>
|
||||
<keyboard id="keyboard">
|
||||
<control type="button" class="input" binding="ctrl-c">CTRL-C</control>
|
||||
|
|
@ -53,8 +53,8 @@
|
|||
the "bindings" that connect the components to the visual elements.</p>
|
||||
<p>Here are some working examples:
|
||||
<ul>
|
||||
<li><a href="/configs/c1p/machines/8kb/large/debugger/">Challenger 1P w/Debugger</a></li>
|
||||
<li><a href="/configs/c1p/machines/8kb/array/">Challenger 1P "Server Array" Demo</a></li>
|
||||
<li><a href="/devices/c1p/machine/8kb/large/debugger/">Challenger 1P w/Debugger</a></li>
|
||||
<li><a href="/devices/c1p/machine/8kb/array/">Challenger 1P "Server Array" Demo</a></li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>Here's what a machine definition XML file typically looks like:
|
||||
|
|
@ -75,8 +75,8 @@
|
|||
<lt/>cpu id="cpu6502"/<gt/>
|
||||
<lt/>ram id="ram8K" size="0x2000"/<gt/>
|
||||
<lt/>rom id="romNull" size="0x8000"/<gt/>
|
||||
<lt/>rom id="romBasic" size="0x2000" image="/devices/c1p/roms/basic-gcpatch.hex"/<gt/>
|
||||
<lt/>rom id="romSystem" size="0x0800" image="/devices/c1p/roms/system.hex"/<gt/>
|
||||
<lt/>rom id="romBasic" size="0x2000" image="/devices/c1p/rom/basic-gcpatch.hex"/<gt/>
|
||||
<lt/>rom id="romSystem" size="0x0800" image="/devices/c1p/rom/system.hex"/<gt/>
|
||||
<lt/>video id="video" screenwidth="256" screenheight="192" cols="32" rows="32"
|
||||
charset="/devices/c1p/video/chargen1x.png" width="256px" padding="8px"/<gt/>
|
||||
<lt/>keyboard id="keyboard"<gt/>
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -194,8 +194,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");
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -1,19 +1,31 @@
|
|||
DiskDump
|
||||
===
|
||||
Module (and command-line utility) for converting disk images to/from various formats (eg, JSON,
|
||||
commented JSON, and IMG files).
|
||||
|
||||
Building images from folders/files
|
||||
**DiskDump** is a Node module with both a command-line interface and a web server API for converting disk images
|
||||
to/from various formats (eg, JSON files, JSON files with comments, IMG disk images, etc).
|
||||
|
||||
Building Disk Images from Folders/Files
|
||||
---
|
||||
I finally ported the code in [convdisk.php](/bin/convdisk.php) that creates disk images
|
||||
from the contents of local files/folders, which you can now access via the *DiskDump* API.
|
||||
In addition to converting disk images to/from JSON, DiskDump can also create disk images from the contents of local
|
||||
files/folders.
|
||||
|
||||
For example:
|
||||
For example, from the root directory of the project, you could run:
|
||||
|
||||
http://www.pcjs.org/api/v1/dump?path=/apps/pc/1981/visicalc/bin/vc.com;../README.md&format=json
|
||||
node my_modules/diskdump/bin/diskdump --path="apps/pc/1981/visicalc/README.md" --format=img --output=disk.img
|
||||
|
||||
to produce a `disk.img` containing one file, "README.md", which you could then mount on your local operating
|
||||
system *or* inside a PCjs machine.
|
||||
|
||||
To make the disk image more useful, you might want to download a copy of [VisiCalc](http://www.bricklin.com/history/vcexecutable.htm)
|
||||
into that folder as well, so that you could then run:
|
||||
|
||||
node my_modules/diskdump/bin/diskdump --path="apps/pc/1981/visicalc/vc.com;README.md" --format=img --output=disk.img
|
||||
|
||||
to produce a `disk.img` containing both "VC.COM" and "README.md". In fact, this is exactly how the
|
||||
[disk.json](/apps/pc/1981/visicalc/disk.json) stored in the [VisiCalc](/apps/pc/1981/visicalc/) folder was generated.
|
||||
|
||||
The equivalent web server API request would look like:
|
||||
|
||||
http://localhost:8088/api/v1/dump?path=/apps/pc/1981/visicalc/vc.com;README.md&format=img
|
||||
|
||||
would be equivalent to the older PHP script operation:
|
||||
|
||||
http://jsmachines.net/bin/convdisk.php?file=/apps/pc/1981/visicalc/bin/vc.com&format=json&download=true
|
||||
|
||||
These commands produce a "disk.json", a copy of which is stored at [/apps/pc/1981/visicalc](/apps/pc/1981/visicalc/).
|
||||
DiskDump is a port of the original [JavaScript Machines](http://jsmachines.net/) **convdisk.php** utility.
|
||||
|
|
|
|||
|
|
@ -2718,7 +2718,12 @@ DiskDump.prototype.convertToIMG = function()
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!fDebug && buf.length < 3000000) { // arbitrary size threshold between diskette images and hard disk images
|
||||
/*
|
||||
* Since there's no way (and rightly so) of setting fDebug via the API, I've added the check for
|
||||
* fJSONComments as another way of disabling "branding" via the API; requesting an IMG file with comments
|
||||
* is otherwise a nonsensical request.
|
||||
*/
|
||||
if (!fDebug && !this.fJSONComments && buf.length < 3000000) { // arbitrary size threshold between diskette images and hard disk images
|
||||
/*
|
||||
* Mimic the BPB test in convertToJSON(), because we don't want to blast an OEM string into non-DOS diskette images
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -520,7 +520,7 @@ HTMLOut.filter = function(req, res, next)
|
|||
* crack at the URL and redirect with a trailing slash as appropriate.
|
||||
*
|
||||
* This isn't just a cosmetic issue, because without "strict routing" and the "express-slash" module,
|
||||
* URLs like "http://localhost:9126/configs/pc/machines/5150/mda/64kb/debugger" will cause problems for
|
||||
* URLs like "http://localhost:8088/devices/pc/machine/5150/mda/64kb/debugger" will cause problems for
|
||||
* client-side JavaScript when it tries to do an XMLHttpRequest with a relative filename (eg, "machine.xml");
|
||||
* that request will fetch the "machine.xml" in the parent directory instead of the "debugger" directory.
|
||||
*
|
||||
|
|
@ -1392,7 +1392,7 @@ HTMLOut.prototype.getMachineXML = function(sToken, sIndent, aParms, sXMLFile, sS
|
|||
*
|
||||
* But, instead of displaying a cryptic error message inside our beautiful HTML template, eg:
|
||||
*
|
||||
* htmlout error: ENOENT, open '/Users/Jeff/Sites/pcjs/configs/pc/machines/5160/cga/256kb/win101/debugger/machine.xml'
|
||||
* htmlout error: ENOENT, open '/Users/Jeff/Sites/pcjs/devices/pc/machine/5160/cga/256kb/win101/debugger/machine.xml'
|
||||
*
|
||||
* we have one more fallback: a random string! Less useful, but more entertaining. Well, maybe not even that.
|
||||
*
|
||||
|
|
@ -1623,7 +1623,7 @@ HTMLOut.prototype.getReadMe = function(sToken, sIndent, aParms, sPrevious)
|
|||
/*
|
||||
* Instead of displaying a cryptic error message inside our beautiful HTML template, eg:
|
||||
*
|
||||
* htmlout error: ENOENT, open '/Users/Jeff/Sites/pcjs/configs/pc/machines/5160/cga/256kb/win101/debugger/README.md'
|
||||
* htmlout error: ENOENT, open '/Users/Jeff/Sites/pcjs/devices/pc/machine/5160/cga/256kb/win101/debugger/README.md'
|
||||
*
|
||||
* which is all this will give us:
|
||||
*
|
||||
|
|
|
|||
|
|
@ -90,32 +90,38 @@ var logFile = null;
|
|||
* Redirect permanent /videos/pcjs/ /disks/pc/dos/microsoft/4.0M/
|
||||
* RedirectMatch permanent /demos/pc/.* /configs/pc/machines/
|
||||
*/
|
||||
var externalRedirects = {
|
||||
var aExternalRedirects = {
|
||||
"/c1p": "/docs/c1pjs/",
|
||||
"/c1pjs": "/docs/c1pjs/",
|
||||
"/pc": "/docs/about/pcjs/",
|
||||
"/pcjs": "/docs/about/pcjs/",
|
||||
"/configs/c1p/embed": "/docs/c1pjs/embed/",
|
||||
"/configs/c1p/machines/array": "/configs/c1p/machines/8kb/array/",
|
||||
"/configs/c1p/machines/array.xml": "/configs/c1p/machines/8kb/array/",
|
||||
"/configs/c1p/machines/machine.xml": "/configs/c1p/machines/8kb/large/",
|
||||
"/configs/pc/machines/5150/mda/demo/pc-mda-64k.xml": "/configs/pc/machines/5150/mda/64kb/",
|
||||
"/configs/pc/machines/5150/cga/donkey/pc-cga-64k.xml": "/configs/pc/machines/5150/cga/64kb/donkey/",
|
||||
"/configs/pc/machines/5150/cga/donkey/pc-dbg-64k.xml": "/configs/pc/machines/5150/cga/64kb/donkey/debugger/",
|
||||
"/configs/pc/machines/5160/cga/demo": "/configs/pc/machines/5160/cga/256kb/demo/",
|
||||
"/configs/pc/machines/5160/cga/demo/xt-cga-256k.xml": "/configs/pc/machines/5160/cga/256kb/demo/",
|
||||
"/configs/pc/machines/5160/cga/demo/xt-dbg-256k.xml": "/configs/pc/machines/5160/cga/256kb/demo/debugger/",
|
||||
"/configs/pc/machines/5160/cga/win101/xt-cga-win101.xml": "/configs/pc/machines/5160/cga/256kb/win101/",
|
||||
"/configs/pc/machines/5160/cga/machine-512k-win101.xml": "/configs/pc/machines/5160/cga/512kb/win101/softkbd/",
|
||||
"/configs/c1p/machines/array": "/devices/c1p/machine/8kb/array/",
|
||||
"/configs/c1p/machines/array.xml": "/devices/c1p/machine/8kb/array/",
|
||||
"/configs/c1p/machines/machine.xml": "/devices/c1p/machine/8kb/large/",
|
||||
"/configs/pc/disks": "/disks/pc/",
|
||||
"/configs/pc/machines/5150/mda/demo/pc-mda-64k.xml": "/devices/pc/machine/5150/mda/64kb/",
|
||||
"/configs/pc/machines/5150/cga/donkey/pc-cga-64k.xml": "/devices/pc/machine/5150/cga/64kb/donkey/",
|
||||
"/configs/pc/machines/5150/cga/donkey/pc-dbg-64k.xml": "/devices/pc/machine/5150/cga/64kb/donkey/debugger/",
|
||||
"/configs/pc/machines/5160/cga/demo": "/devices/pc/machine/5160/cga/256kb/demo/",
|
||||
"/configs/pc/machines/5160/cga/demo/xt-cga-256k.xml": "/devices/pc/machine/5160/cga/256kb/demo/",
|
||||
"/configs/pc/machines/5160/cga/demo/xt-dbg-256k.xml": "/devices/pc/machine/5160/cga/256kb/demo/debugger/",
|
||||
"/configs/pc/machines/5160/cga/win101/xt-cga-win101.xml": "/devices/pc/machine/5160/cga/256kb/win101/",
|
||||
"/configs/pc/machines/5160/cga/machine-512k-win101.xml": "/devices/pc/machine/5160/cga/512kb/win101/softkbd/",
|
||||
"/demos/c1p/embed.html": "/docs/c1pjs/embed/",
|
||||
"/demos/c1p/embed.xml": "/configs/c1p/machines/8kb/embed/machine.xml",
|
||||
"/demos/pc/cga": "/configs/pc/machines/5150/cga/",
|
||||
"/demos/pc/donkey/pc-cga-64k.xml": "/configs/pc/machines/5150/cga/64kb/donkey/",
|
||||
"/demos/pc/cga-win101": "/configs/pc/machines/5160/cga/256kb/win101/",
|
||||
"/demos/pc/cga-win101/xt-cga-win101.xml": "/configs/pc/machines/5160/cga/256kb/win101/",
|
||||
"/devices/c1p/array.xml": "/configs/c1p/machines/8kb/array/",
|
||||
"/devices/pc/5160/cga/machine-dos400m.xml": "/configs/pc/machines/5160/cga/640kb/dos400m/",
|
||||
"/videos/pcjs": "/configs/pc/machines/5160/cga/640kb/dos400m/"
|
||||
"/demos/c1p/embed.xml": "/devices/c1p/machine/8kb/embed/machine.xml",
|
||||
"/demos/pc/cga": "/devices/pc/machine/5150/cga/",
|
||||
"/demos/pc/donkey/pc-cga-64k.xml": "/devices/pc/machine/5150/cga/64kb/donkey/",
|
||||
"/demos/pc/cga-win101": "/devices/pc/machine/5160/cga/256kb/win101/",
|
||||
"/demos/pc/cga-win101/xt-cga-win101.xml": "/devices/pc/machine/5160/cga/256kb/win101/",
|
||||
"/devices/c1p/array.xml": "/devices/c1p/machine/8kb/array/",
|
||||
"/devices/pc/5160/cga/machine-dos400m.xml": "/devices/pc/machine/5160/cga/640kb/dos400m/",
|
||||
"/videos/pcjs": "/devices/pc/machine/5160/cga/640kb/dos400m/"
|
||||
};
|
||||
|
||||
var aExternalRedirectPatterns = {
|
||||
"^/configs/c1p/machines/(.*)": "/devices/c1p/machine/$1",
|
||||
"^/configs/pc/machines/(.*)": "/devices/pc/machine/$1"
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -124,14 +130,11 @@ var externalRedirects = {
|
|||
* we could make the replacement process "additive", by continuing comparisons/replacements until the
|
||||
* end is reached, but let's not, unless there's an actual need.
|
||||
*
|
||||
* In fact, until I find a compelling need for any of these redirects, I'm going to disable them, so that we
|
||||
* don't waste time running RegExp tests on every server request.
|
||||
*
|
||||
* Feel free to use subgroups on the left-hand side, and references to them (eg, $1, $2, etc) on the right.
|
||||
*/
|
||||
var internalRedirects = {
|
||||
// "^/apps/pc/visicalc/": "/apps/pc/1981/visicalc/",
|
||||
// "^/demos/pc/.*": "/configs/pc/machines/"
|
||||
var aInternalRedirectPatterns = {
|
||||
// "^/apps/pc/visicalc/": "/apps/pc/1981/visicalc/",
|
||||
// "^/demos/pc/.*": "/devices/pc/machine/"
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -181,6 +184,7 @@ var userVolumes = {};
|
|||
*/
|
||||
HTTPAPI.redirect = function(req, res, next)
|
||||
{
|
||||
var re;
|
||||
var sPath = req.path;
|
||||
if (sPath.slice(-1) == '/') sPath = sPath.slice(0, -1);
|
||||
|
||||
|
|
@ -190,15 +194,23 @@ HTTPAPI.redirect = function(req, res, next)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (externalRedirects[sPath] !== undefined) {
|
||||
res.redirect(301, externalRedirects[sPath]);
|
||||
if (aExternalRedirects[sPath] !== undefined) {
|
||||
res.redirect(301, aExternalRedirects[sPath]);
|
||||
return true;
|
||||
}
|
||||
|
||||
for (sPath in internalRedirects) {
|
||||
for (sPath in aExternalRedirectPatterns) {
|
||||
re = new RegExp(sPath);
|
||||
if (re.exec(req.url)) {
|
||||
res.redirect(301, req.url.replace(re, aExternalRedirectPatterns[sPath]));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (sPath in aInternalRedirectPatterns) {
|
||||
var re = new RegExp(sPath);
|
||||
if (re.exec(req.url)) {
|
||||
req.url = req.url.replace(re, internalRedirects[sPath]);
|
||||
req.url = req.url.replace(re, aInternalRedirectPatterns[sPath]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -880,7 +880,7 @@ MarkOut.prototype.convertMDMachineLinks = function(sBlock)
|
|||
* Before we call convertMDLinks() to process any normal Markdown-style links, we first
|
||||
* look for our own special flavor of "machine" Markdown links; ie:
|
||||
*
|
||||
* [IBM PC](/configs/pc/foo/ "PCjs:demoPC:stylesheet:version:options:state")
|
||||
* [IBM PC](/devices/pc/machine/5150/mda/64kb/ "PCjs:demoPC:stylesheet:version:options:state")
|
||||
*
|
||||
* where a special title attribute triggers generation of an embedded machine rather than
|
||||
* a link. Use "PCjs" or "C1Pjs" to automatically include the latest version of either
|
||||
|
|
@ -888,7 +888,7 @@ MarkOut.prototype.convertMDMachineLinks = function(sBlock)
|
|||
* If you need to use the script with the built-in Debugger (ie, either "pc-dbg.js" or
|
||||
* "c1p-dbg.js"), then include "debugger" in the list of comma-delimited options, as in:
|
||||
*
|
||||
* [IBM PC](/configs/pc/foo/ "PCjs:demoPC:::debugger")
|
||||
* [IBM PC](/devices/pc/machine/5150/mda/64kb/ "PCjs:demoPC:::debugger")
|
||||
*
|
||||
* If the link ends with a slash, then it's an implied reference to a "machine.xml".
|
||||
*
|
||||
|
|
|
|||
|
|
@ -87,5 +87,5 @@
|
|||
"name": "",
|
||||
"messages": ""
|
||||
},
|
||||
"xml": "/configs/pc/machines/5150/mda/64kb/machine.xml"
|
||||
"xml": "/devices/pc/machine/5150/mda/64kb/machine.xml"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -245,12 +245,6 @@ function loadMachine(sFile)
|
|||
}
|
||||
|
||||
console.log(obj['id'] + " object created");
|
||||
if (fDebug) {
|
||||
/*
|
||||
* TODO: Determine why a simple "console.log(obj)" call fails on the Video object
|
||||
*/
|
||||
console.log(JSON.stringify(obj));
|
||||
}
|
||||
aComponents[i].objects.push(obj);
|
||||
|
||||
if (obj.type == "Debugger") {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
"PCJSCLASS": true,
|
||||
"DEBUGGER": true,
|
||||
"PREFETCH": true,
|
||||
"FASTDISABLE": true,
|
||||
"EAFUNCS": true,
|
||||
"FATARRAYS": true,
|
||||
"TYPEDARRAYS": true,
|
||||
"Component": true,
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ if (typeof module !== 'undefined') {
|
|||
var web = require("../../shared/lib/weblib");
|
||||
var Component = require("../../shared/lib/component");
|
||||
var State = require("./state");
|
||||
var Debugger = require("./debugger");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -3959,23 +3960,23 @@ ChipSet.prototype.out8042InBuffCmd = function(port, bOut, addrFrom)
|
|||
|
||||
case ChipSet.KBC.CMD.DISABLE_KBD: // 0xAD
|
||||
this.set8042CmdData(this.b8042CmdData | ChipSet.KBC.DATA.CMD.NO_CLOCK);
|
||||
if (DEBUG) this.messageDebugger("keyboard disabled", Debugger.MESSAGE_KBD);
|
||||
if (DEBUG) this.messageDebugger("keyboard disabled", Debugger.MESSAGE_KBD | Debugger.MESSAGE_PORT);
|
||||
/*
|
||||
* NOTE: The MODEL_5170 BIOS calls "KBD_RESET" (F000:17D2) while the keyboard interface is disabled,
|
||||
* yet we must still deliver the Keyboard's CMDRES.BATSUCCESS response code? Seems like an odd thing for
|
||||
* yet we must still deliver the Keyboard's CMDRES.BAT_SUCC response code? Seems like an odd thing for
|
||||
* a "disabled interface" to do.
|
||||
*/
|
||||
break;
|
||||
|
||||
case ChipSet.KBC.CMD.ENABLE_KBD: // 0xAE
|
||||
this.set8042CmdData(this.b8042CmdData & ~ChipSet.KBC.DATA.CMD.NO_CLOCK);
|
||||
if (DEBUG) this.messageDebugger("keyboard re-enabled", Debugger.MESSAGE_KBD);
|
||||
if (DEBUG) this.messageDebugger("keyboard re-enabled", Debugger.MESSAGE_KBD | Debugger.MESSAGE_PORT);
|
||||
break;
|
||||
|
||||
case ChipSet.KBC.CMD.SELF_TEST: // 0xAA
|
||||
if (this.kbd) this.kbd.shiftScanCode(true);
|
||||
this.set8042CmdData(this.b8042CmdData | ChipSet.KBC.DATA.CMD.NO_CLOCK);
|
||||
if (DEBUG) this.messageDebugger("keyboard disabled on reset", Debugger.MESSAGE_KBD);
|
||||
if (DEBUG) this.messageDebugger("keyboard disabled on reset", Debugger.MESSAGE_KBD | Debugger.MESSAGE_PORT);
|
||||
this.set8042OutBuff(ChipSet.KBC.DATA.SELF_TEST.OK);
|
||||
this.set8042OutPort(ChipSet.KBC.OUTPORT.NO_RESET | ChipSet.KBC.OUTPORT.A20_ON);
|
||||
break;
|
||||
|
|
@ -4024,7 +4025,7 @@ ChipSet.prototype.set8042CmdData = function(b)
|
|||
*
|
||||
* And indeed, if we call the original MODEL_5150/MODEL_5160 setEnable() Keyboard interface here,
|
||||
* and both the data and clock lines have transitioned high (ie, both parameters are true), then it
|
||||
* will call resetDevice(), generating a Keyboard.CMDRES.BATSUCCESS response.
|
||||
* will call resetDevice(), generating a Keyboard.CMDRES.BAT_SUCC response.
|
||||
*
|
||||
* This agrees with my understanding of what happens when the 8042 toggles the clock line high
|
||||
* (ie, clears NO_CLOCK): the TechRef's "Basic Assurance Test" section says that when the Keyboard is
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ if (typeof module !== 'undefined') {
|
|||
var Component = require("../../shared/lib/component");
|
||||
var Bus = require("./bus");
|
||||
var State = require("./state");
|
||||
var Debugger = require("./debugger");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -123,11 +124,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 +545,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 +650,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 +755,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 +763,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 +821,7 @@ Computer.prototype.powerOff = function(fSave, fShutdown)
|
|||
}
|
||||
}
|
||||
|
||||
if (fShutdown) this.fPowered = false;
|
||||
if (fShutdown) this.aFlags.fPowered = false;
|
||||
|
||||
return sState;
|
||||
};
|
||||
|
|
@ -963,7 +964,7 @@ Computer.prototype.queryUserID = function(fPrompt)
|
|||
sUserID = web.getLocalStorageItem(Computer.STATE_USERID);
|
||||
if (sUserID !== undefined) {
|
||||
if (!sUserID && fPrompt) {
|
||||
sUserID = web.promptUser("To save machine states on the pcjs.org server, you need a user ID (email Jeff@pcjs.org).\n\nOnce you have an ID, enter it below.");
|
||||
sUserID = web.promptUser("To save machine states on the pcjs.org server, you need a user ID (email support@pcjs.org).\n\nOnce you have an ID, enter it below.");
|
||||
if (sUserID) {
|
||||
sUserID = this.verifyUserID(sUserID);
|
||||
if (!sUserID) this.notice("Your user ID has not been approved.");
|
||||
|
|
@ -1176,7 +1177,7 @@ Computer.prototype.getComponentByType = function(sType, componentPrev)
|
|||
/**
|
||||
* messageDebugger(sMessage, fForce)
|
||||
*
|
||||
* This is a combination of the Debugger's messageEnabled(MESSAGE_CMP) and message() functions, for convenience.
|
||||
* This is a combination of the Debugger's messageEnabled(MESSAGE_COMPUTER) and message() functions, for convenience.
|
||||
*
|
||||
* @this {Computer}
|
||||
* @param {string} sMessage is any caller-defined message string
|
||||
|
|
@ -1185,7 +1186,7 @@ Computer.prototype.getComponentByType = function(sType, componentPrev)
|
|||
Computer.prototype.messageDebugger = function(sMessage, fForce)
|
||||
{
|
||||
if (DEBUGGER && this.dbg) {
|
||||
if (fForce || this.dbg.messageEnabled(Debugger.MESSAGE_CMP)) this.dbg.message(sMessage);
|
||||
if (fForce || this.dbg.messageEnabled(Debugger.MESSAGE_COMPUTER)) this.dbg.message(sMessage);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1221,7 +1222,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 +1252,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 +1299,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
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ if (typeof module !== 'undefined') {
|
|||
var str = require("../../shared/lib/strlib");
|
||||
var usr = require("../../shared/lib/usrlib");
|
||||
var Component = require("../../shared/lib/component");
|
||||
var Debugger = require("./debugger");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -80,23 +81,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 +107,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 +119,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 +140,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 +266,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 +281,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 +293,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 +320,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 +335,7 @@ CPU.prototype.isPowered = function()
|
|||
*/
|
||||
CPU.prototype.isRunning = function()
|
||||
{
|
||||
return this.fRunning;
|
||||
return this.aFlags.fRunning;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -361,14 +363,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 +389,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 +423,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 +494,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 +523,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 +607,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 +649,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 +668,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 +683,7 @@ CPU.prototype.getCycles = function(fScaled)
|
|||
*/
|
||||
CPU.prototype.getCyclesPerSecond = function()
|
||||
{
|
||||
return this.nCyclesPerSecond;
|
||||
return this.aCounts.nCyclesPerSecond;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -695,7 +697,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 +711,7 @@ CPU.prototype.resetCycles = function()
|
|||
* @return {number} the current speed multiplier
|
||||
*/
|
||||
CPU.prototype.getSpeed = function() {
|
||||
return this.nCyclesMultiplier;
|
||||
return this.aCounts.nCyclesMultiplier;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -722,7 +724,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 +737,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 +758,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 +771,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 +787,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 +803,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 +820,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 +834,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 +860,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 +910,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 +936,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 +984,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 +1031,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 +1062,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 +1110,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()
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -169,30 +169,31 @@ function Debugger(parmsDbg)
|
|||
} // endif DEBUGGER
|
||||
}
|
||||
|
||||
Debugger.MESSAGE_MEM = 0x00000001;
|
||||
Debugger.MESSAGE_PORT = 0x00000002;
|
||||
Debugger.MESSAGE_DMA = 0x00000004;
|
||||
Debugger.MESSAGE_PIC = 0x00000008;
|
||||
Debugger.MESSAGE_TIMER = 0x00000010;
|
||||
Debugger.MESSAGE_CMOS = 0x00000020;
|
||||
Debugger.MESSAGE_RTC = 0x00000040;
|
||||
Debugger.MESSAGE_8042 = 0x00000080;
|
||||
Debugger.MESSAGE_CHIPSET = 0x00000100;
|
||||
Debugger.MESSAGE_KBD = 0x00000200;
|
||||
Debugger.MESSAGE_VIDEO = 0x00000400;
|
||||
Debugger.MESSAGE_FDC = 0x00000800;
|
||||
Debugger.MESSAGE_HDC = 0x00001000;
|
||||
Debugger.MESSAGE_DISK = 0x00002000;
|
||||
Debugger.MESSAGE_SERIAL = 0x00004000;
|
||||
Debugger.MESSAGE_SPEAKER = 0x00008000;
|
||||
Debugger.MESSAGE_STATE = 0x00010000;
|
||||
Debugger.MESSAGE_MOUSE = 0x00020000;
|
||||
Debugger.MESSAGE_CMP = 0x00040000;
|
||||
Debugger.MESSAGE_CPU = 0x00080000;
|
||||
Debugger.MESSAGE_DOS = 0x00100000;
|
||||
Debugger.MESSAGE_INT = 0x00200000;
|
||||
Debugger.MESSAGE_LOG = 0x01000000;
|
||||
Debugger.MESSAGE_HALT = 0x10000000;
|
||||
Debugger.MESSAGE_MEM = 0x00000001;
|
||||
Debugger.MESSAGE_PORT = 0x00000002;
|
||||
Debugger.MESSAGE_DMA = 0x00000004;
|
||||
Debugger.MESSAGE_PIC = 0x00000008;
|
||||
Debugger.MESSAGE_TIMER = 0x00000010;
|
||||
Debugger.MESSAGE_CMOS = 0x00000020;
|
||||
Debugger.MESSAGE_RTC = 0x00000040;
|
||||
Debugger.MESSAGE_8042 = 0x00000080;
|
||||
Debugger.MESSAGE_CHIPSET = 0x00000100;
|
||||
Debugger.MESSAGE_KBD = 0x00000200;
|
||||
Debugger.MESSAGE_KEYS = 0x00000400;
|
||||
Debugger.MESSAGE_VIDEO = 0x00000800;
|
||||
Debugger.MESSAGE_FDC = 0x00001000;
|
||||
Debugger.MESSAGE_HDC = 0x00002000;
|
||||
Debugger.MESSAGE_DISK = 0x00004000;
|
||||
Debugger.MESSAGE_SERIAL = 0x00008000;
|
||||
Debugger.MESSAGE_SPEAKER = 0x00010000;
|
||||
Debugger.MESSAGE_STATE = 0x00020000;
|
||||
Debugger.MESSAGE_MOUSE = 0x00040000;
|
||||
Debugger.MESSAGE_COMPUTER = 0x00080000;
|
||||
Debugger.MESSAGE_CPU = 0x00100000;
|
||||
Debugger.MESSAGE_DOS = 0x00200000;
|
||||
Debugger.MESSAGE_INT = 0x00400000;
|
||||
Debugger.MESSAGE_LOG = 0x01000000;
|
||||
Debugger.MESSAGE_HALT = 0x10000000;
|
||||
|
||||
if (DEBUGGER) {
|
||||
|
||||
|
|
@ -235,62 +236,62 @@ if (DEBUGGER) {
|
|||
* 286 or 386, then I might as well leave some of that support in place, since the impact is minimal).
|
||||
*/
|
||||
Debugger.INS = {
|
||||
NONE: 0, AAA: 1, AAD: 2, AAM: 3, AAS: 4, ADC: 5, ADD: 6, AND: 7,
|
||||
ARPL: 8, ASIZE: 9, BOUND: 10, BSF: 11, BSR: 12, BT: 13, BTC: 14, BTR: 15,
|
||||
BTS: 16, CALL: 17, CBW: 18, CLC: 19, CLD: 20, CLI: 21, CLTS: 22, CMC: 23,
|
||||
CMP: 24, CMPSB: 25, CMPSW: 26, CS: 27, CWD: 28, DAA: 29, DAS: 30, DEC: 31,
|
||||
DIV: 32, DS: 33, ENTER: 34, ES: 35, ESC: 36, FADD: 37, FBLD: 38, FBSTP: 39,
|
||||
FCOM: 40, FCOMP: 41, FDIV: 42, FDIVR: 43, FIADD: 44, FICOM: 45, FICOMP: 46, FIDIV: 47,
|
||||
FIDIVR: 48, FILD: 49, FIMUL: 50, FIST: 51, FISTP: 52, FISUB: 53, FISUBR: 54, FLD: 55,
|
||||
FLDCW: 56, FLDENV: 57, FMUL: 58, FNSAVE: 59, FNSTCW: 60, FNSTENV: 61, FNSTSW: 62, FRSTOR: 63,
|
||||
FS: 64, FST: 65, FSTP: 66, FSUB: 67, FSUBR: 68, GBP: 69, GS: 70, HLT: 71,
|
||||
IDIV: 72, IMUL: 73, IN: 74, INC: 75, INS: 76, INT: 77, INT3: 78, INTO: 79,
|
||||
IRET: 80, JBE: 81, JC: 82, JCXZ: 83, JG: 84, JGE: 85, JL: 86, JLE: 87,
|
||||
JMP: 88, JNBE: 89, JNC: 90, JNO: 91, JNP: 92, JNS: 93, JNZ: 94, JO: 95,
|
||||
JP: 96, JS: 97, JZ: 98, LAHF: 99, LAR: 100, LDS: 101, LEA: 102, LEAVE: 103,
|
||||
LES: 104, LFS: 105, LGDT: 106, LGS: 107, LIDT: 108, LLDT: 109, LMSW: 110, LOCK: 111,
|
||||
LODSB: 112, LODSW: 113, LOOP: 114, LOOPNZ: 115, LOOPZ: 116, LSL: 117, LSS: 118, LTR: 119,
|
||||
MOV: 120, MOVSB: 121, MOVSW: 122, MOVSX: 123, MOVZX: 124, MUL: 125, NEG: 126, NOP: 127,
|
||||
NOT: 128, OR: 129, OSIZE: 130, OUT: 131, OUTS: 132, POP: 133, POPA: 134, POPF: 135,
|
||||
PUSH: 136, PUSHA: 137, PUSHF: 138, RCL: 139, RCR: 140, REPNZ: 141, REPZ: 142, RET: 143,
|
||||
RETF: 144, ROL: 145, ROR: 146, SAHF: 147, SAR: 148, SBB: 149, SCASB: 150, SCASW: 151,
|
||||
SETBE: 152, SETC: 153, SETG: 154, SETGE: 155, SETL: 156, SETLE: 157, SETNBE: 158, SETNC: 159,
|
||||
SETNO: 160, SETNP: 161, SETNS: 162, SETNZ: 163, SETO: 164, SETP: 165, SETS: 166, SETZ: 167,
|
||||
SGDT: 168, SHL: 169, SHLD: 170, SHR: 171, SHRD: 172, SIDT: 173, SLDT: 174, SMSW: 175,
|
||||
SS: 176, STC: 177, STD: 178, STI: 179, STOSB: 180, STOSW: 181, STR: 182, SUB: 183,
|
||||
TEST: 184, VERR: 185, VERW: 186, WAIT: 187, XCHG: 188, XLAT: 189, XOR: 190, GRP1B: 191,
|
||||
GRP1W: 192, GRP1SW: 193, GRP2B: 194, GRP2W: 195, GRP2B1: 196, GRP2W1: 197, GRP2BC: 198, GRP2WC: 199,
|
||||
GRP3B: 200, GRP3W: 201, GRP4B: 202, GRP4W: 203, OP0F: 204, GRP6: 205, GRP7: 206
|
||||
NONE: 0, AAA: 1, AAD: 2, AAM: 3, AAS: 4, ADC: 5, ADD: 6, AND: 7,
|
||||
ARPL: 8, ASIZE: 9, BOUND: 10, BSF: 11, BSR: 12, BT: 13, BTC: 14, BTR: 15,
|
||||
BTS: 16, CALL: 17, CBW: 18, CLC: 19, CLD: 20, CLI: 21, CLTS: 22, CMC: 23,
|
||||
CMP: 24, CMPSB: 25, CMPSW: 26, CS: 27, CWD: 28, DAA: 29, DAS: 30, DEC: 31,
|
||||
DIV: 32, DS: 33, ENTER: 34, ES: 35, ESC: 36, FADD: 37, FBLD: 38, FBSTP: 39,
|
||||
FCOM: 40, FCOMP: 41, FDIV: 42, FDIVR: 43, FIADD: 44, FICOM: 45, FICOMP: 46, FIDIV: 47,
|
||||
FIDIVR: 48, FILD: 49, FIMUL: 50, FIST: 51, FISTP: 52, FISUB: 53, FISUBR: 54, FLD: 55,
|
||||
FLDCW: 56, FLDENV: 57, FMUL: 58, FNSAVE: 59, FNSTCW: 60, FNSTENV:61, FNSTSW: 62, FRSTOR: 63,
|
||||
FS: 64, FST: 65, FSTP: 66, FSUB: 67, FSUBR: 68, GBP: 69, GS: 70, HLT: 71,
|
||||
IDIV: 72, IMUL: 73, IN: 74, INC: 75, INS: 76, INT: 77, INT3: 78, INTO: 79,
|
||||
IRET: 80, JBE: 81, JC: 82, JCXZ: 83, JG: 84, JGE: 85, JL: 86, JLE: 87,
|
||||
JMP: 88, JNBE: 89, JNC: 90, JNO: 91, JNP: 92, JNS: 93, JNZ: 94, JO: 95,
|
||||
JP: 96, JS: 97, JZ: 98, LAHF: 99, LAR: 100, LDS: 101, LEA: 102, LEAVE: 103,
|
||||
LES: 104, LFS: 105, LGDT: 106, LGS: 107, LIDT: 108, LLDT: 109, LMSW: 110, LOADALL:111,
|
||||
LOCK: 112, LODSB: 113, LODSW: 114, LOOP: 115, LOOPNZ: 116, LOOPZ: 117, LSL: 118, LSS: 119,
|
||||
LTR: 120, MOV: 121, MOVSB: 122, MOVSW: 123, MOVSX: 124, MOVZX: 125, MUL: 126, NEG: 127,
|
||||
NOP: 128, NOT: 129, OR: 130, OSIZE: 131, OUT: 132, OUTS: 133, POP: 134, POPA: 135,
|
||||
POPF: 136, PUSH: 137, PUSHA: 138, PUSHF: 139, RCL: 140, RCR: 141, REPNZ: 142, REPZ: 143,
|
||||
RET: 144, RETF: 145, ROL: 146, ROR: 147, SAHF: 148, SAR: 149, SBB: 150, SCASB: 151,
|
||||
SCASW: 152, SETBE: 153, SETC: 154, SETG: 155, SETGE: 156, SETL: 157, SETLE: 158, SETNBE: 159,
|
||||
SETNC: 160, SETNO: 161, SETNP: 162, SETNS: 163, SETNZ: 164, SETO: 165, SETP: 166, SETS: 167,
|
||||
SETZ: 168, SGDT: 169, SHL: 170, SHLD: 171, SHR: 172, SHRD: 173, SIDT: 174, SLDT: 175,
|
||||
SMSW: 176, SS: 177, STC: 178, STD: 179, STI: 180, STOSB: 181, STOSW: 182, STR: 183,
|
||||
SUB: 184, TEST: 185, VERR: 186, VERW: 187, WAIT: 188, XCHG: 189, XLAT: 190, XOR: 191,
|
||||
GRP1B: 192, GRP1W: 193, GRP1SW: 194, GRP2B: 195, GRP2W: 196, GRP2B1: 197, GRP2W1: 198, GRP2BC: 199,
|
||||
GRP2WC: 200, GRP3B: 201, GRP3W: 202, GRP4B: 203, GRP4W: 204, OP0F: 205, GRP6: 206, GRP7: 207
|
||||
};
|
||||
|
||||
/*
|
||||
* Instruction names, indexed by instruction ordinal (above)
|
||||
*/
|
||||
Debugger.asIns = [
|
||||
"DB", "AAA", "AAD", "AAM", "AAS", "ADC", "ADD", "AND",
|
||||
"ARPL", "AS:", "BOUND", "BSF", "BSR", "BT", "BTC", "BTR",
|
||||
"BTS", "CALL", "CBW", "CLC", "CLD", "CLI", "CLTS", "CMC",
|
||||
"CMP", "CMPSB", "CMPSW", "CS:", "CWD", "DAA", "DAS", "DEC",
|
||||
"DIV", "DS:", "ENTER", "ES:", "ESC", "FADD", "FBLD", "FBSTP",
|
||||
"FCOM", "FCOMP", "FDIV", "FDIVR", "FIADD", "FICOM", "FICOMP", "FIDIV",
|
||||
"FIDIVR", "FILD", "FIMUL", "FIST", "FISTP", "FISUB", "FISUBR", "FLD",
|
||||
"FLDCW", "FLDENV", "FMUL", "FNSAVE", "FNSTCW", "FNSTENV", "FNSTSW", "FRSTOR",
|
||||
"FS:", "FST", "FSTP", "FSUB", "FSUBR", "GBP", "GS:", "HLT",
|
||||
"IDIV", "IMUL", "IN", "INC", "INS", "INT", "INT3", "INTO",
|
||||
"IRET", "JBE", "JC", "JCXZ", "JG", "JGE", "JL", "JLE",
|
||||
"JMP", "JNBE", "JNC", "JNO", "JNP", "JNS", "JNZ", "JO",
|
||||
"JP", "JS", "JZ", "LAHF", "LAR", "LDS", "LEA", "LEAVE",
|
||||
"LES", "LFS", "LGDT", "LGS", "LIDT", "LLDT", "LMSW", "LOCK",
|
||||
"LODSB", "LODSW", "LOOP", "LOOPNZ", "LOOPZ", "LSL", "LSS", "LTR",
|
||||
"MOV", "MOVSB", "MOVSW", "MOVSX", "MOVZX", "MUL", "NEG", "NOP",
|
||||
"NOT", "OR", "OS:", "OUT", "OUTS", "POP", "POPA", "POPF",
|
||||
"PUSH", "PUSHA", "PUSHF", "RCL", "RCR", "REPNZ", "REPZ", "RET",
|
||||
"RETF", "ROL", "ROR", "SAHF", "SAR", "SBB", "SCASB", "SCASW",
|
||||
"SETBE", "SETC", "SETG", "SETGE", "SETL", "SETLE", "SETNBE", "SETNC",
|
||||
"SETNO", "SETNP", "SETNS", "SETNZ", "SETO", "SETP", "SETS", "SETZ",
|
||||
"SGDT", "SHL", "SHLD", "SHR", "SHRD", "SIDT", "SLDT", "SMSW",
|
||||
"SS:", "STC", "STD", "STI", "STOSB", "STOSW", "STR", "SUB",
|
||||
"TEST", "VERR", "VERW", "WAIT", "XCHG", "XLAT", "XOR"
|
||||
"DB", "AAA", "AAD", "AAM", "AAS", "ADC", "ADD", "AND",
|
||||
"ARPL", "AS:", "BOUND", "BSF", "BSR", "BT", "BTC", "BTR",
|
||||
"BTS", "CALL", "CBW", "CLC", "CLD", "CLI", "CLTS", "CMC",
|
||||
"CMP", "CMPSB", "CMPSW", "CS:", "CWD", "DAA", "DAS", "DEC",
|
||||
"DIV", "DS:", "ENTER", "ES:", "ESC", "FADD", "FBLD", "FBSTP",
|
||||
"FCOM", "FCOMP", "FDIV", "FDIVR", "FIADD", "FICOM", "FICOMP", "FIDIV",
|
||||
"FIDIVR", "FILD", "FIMUL", "FIST", "FISTP", "FISUB", "FISUBR", "FLD",
|
||||
"FLDCW", "FLDENV", "FMUL", "FNSAVE", "FNSTCW", "FNSTENV","FNSTSW", "FRSTOR",
|
||||
"FS:", "FST", "FSTP", "FSUB", "FSUBR", "GBP", "GS:", "HLT",
|
||||
"IDIV", "IMUL", "IN", "INC", "INS", "INT", "INT3", "INTO",
|
||||
"IRET", "JBE", "JC", "JCXZ", "JG", "JGE", "JL", "JLE",
|
||||
"JMP", "JNBE", "JNC", "JNO", "JNP", "JNS", "JNZ", "JO",
|
||||
"JP", "JS", "JZ", "LAHF", "LAR", "LDS", "LEA", "LEAVE",
|
||||
"LES", "LFS", "LGDT", "LGS", "LIDT", "LLDT", "LMSW", "LOADALL",
|
||||
"LOCK", "LODSB", "LODSW", "LOOP", "LOOPNZ", "LOOPZ", "LSL", "LSS",
|
||||
"LTR", "MOV", "MOVSB", "MOVSW", "MOVSX", "MOVZX", "MUL", "NEG",
|
||||
"NOP", "NOT", "OR", "OS:", "OUT", "OUTS", "POP", "POPA",
|
||||
"POPF", "PUSH", "PUSHA", "PUSHF", "RCL", "RCR", "REPNZ", "REPZ",
|
||||
"RET", "RETF", "ROL", "ROR", "SAHF", "SAR", "SBB", "SCASB",
|
||||
"SCASW", "SETBE", "SETC", "SETG", "SETGE", "SETL", "SETLE", "SETNBE",
|
||||
"SETNC", "SETNO", "SETNP", "SETNS", "SETNZ", "SETO", "SETP", "SETS",
|
||||
"SETZ", "SGDT", "SHL", "SHLD", "SHR", "SHRD", "SIDT", "SLDT",
|
||||
"SMSW", "SS:", "STC", "STD", "STI", "STOSB", "STOSW", "STR",
|
||||
"SUB", "TEST", "VERR", "VERW", "WAIT", "XCHG", "XLAT", "XOR"
|
||||
];
|
||||
|
||||
Debugger.CPU_86 = 0;
|
||||
|
|
@ -464,7 +465,8 @@ if (DEBUGGER) {
|
|||
"rtc": Debugger.MESSAGE_RTC,
|
||||
"8042": Debugger.MESSAGE_8042,
|
||||
"chipset": Debugger.MESSAGE_CHIPSET, // ie, anything else in ChipSet besides DMA, PIC, TIMER, CMOS, RTC and 8042
|
||||
"keyboard": Debugger.MESSAGE_KBD,
|
||||
"kbd": Debugger.MESSAGE_KBD,
|
||||
"keys": Debugger.MESSAGE_KEYS,
|
||||
"video": Debugger.MESSAGE_VIDEO,
|
||||
"fdc": Debugger.MESSAGE_FDC,
|
||||
"hdc": Debugger.MESSAGE_HDC,
|
||||
|
|
@ -473,14 +475,14 @@ if (DEBUGGER) {
|
|||
"speaker": Debugger.MESSAGE_SPEAKER,
|
||||
"state": Debugger.MESSAGE_STATE,
|
||||
"mouse": Debugger.MESSAGE_MOUSE,
|
||||
"computer": Debugger.MESSAGE_CMP,
|
||||
"computer": Debugger.MESSAGE_COMPUTER,
|
||||
"cpu": Debugger.MESSAGE_CPU,
|
||||
"dos": Debugger.MESSAGE_DOS,
|
||||
"int": Debugger.MESSAGE_INT,
|
||||
"log": Debugger.MESSAGE_LOG,
|
||||
/*
|
||||
* Now we turn to message actions rather than message types; for example, setting "halt"
|
||||
* on or off doesn't enable "halt" messages, but rather halts the CPU on any above message.
|
||||
* on or off doesn't enable "halt" messages, but rather halts the CPU on any message above.
|
||||
*/
|
||||
"halt": Debugger.MESSAGE_HALT
|
||||
};
|
||||
|
|
@ -524,7 +526,7 @@ if (DEBUGGER) {
|
|||
*
|
||||
* On the 8086, it functioned as POP CS
|
||||
* On the 80186, it generated an illegal opcode (UD_FAULT) exception
|
||||
* On the 80286, it introduced a series of new (and growing) two-byte opcodes
|
||||
* On the 80286, it introduced a new (and growing) series of two-byte opcodes
|
||||
*
|
||||
* Based on the active CPU model, we make every effort to execute and disassemble this (and every other)
|
||||
* opcode appropriately, by setting the opcode's entry in aaOpDescs accordingly. 0x0F defaults to the 8086
|
||||
|
|
@ -840,10 +842,11 @@ if (DEBUGGER) {
|
|||
];
|
||||
|
||||
Debugger.aaOp0FDescs = {
|
||||
0x00: [Debugger.INS.GRP6, Debugger.TYPE_MODRM | Debugger.TYPE_WORD | Debugger.TYPE_BOTH],
|
||||
0x01: [Debugger.INS.GRP7, Debugger.TYPE_MODRM | Debugger.TYPE_WORD | Debugger.TYPE_BOTH],
|
||||
0x02: [Debugger.INS.LAR, Debugger.TYPE_REG | Debugger.TYPE_WORD | Debugger.TYPE_IN | Debugger.TYPE_286, Debugger.TYPE_MEM | Debugger.TYPE_WORD | Debugger.TYPE_IN],
|
||||
0x03: [Debugger.INS.LSL, Debugger.TYPE_REG | Debugger.TYPE_WORD | Debugger.TYPE_IN | Debugger.TYPE_286, Debugger.TYPE_MEM | Debugger.TYPE_WORD | Debugger.TYPE_IN]
|
||||
0x00: [Debugger.INS.GRP6, Debugger.TYPE_MODRM | Debugger.TYPE_WORD | Debugger.TYPE_BOTH],
|
||||
0x01: [Debugger.INS.GRP7, Debugger.TYPE_MODRM | Debugger.TYPE_WORD | Debugger.TYPE_BOTH],
|
||||
0x02: [Debugger.INS.LAR, Debugger.TYPE_REG | Debugger.TYPE_WORD | Debugger.TYPE_IN | Debugger.TYPE_286, Debugger.TYPE_MEM | Debugger.TYPE_WORD | Debugger.TYPE_IN],
|
||||
0x03: [Debugger.INS.LSL, Debugger.TYPE_REG | Debugger.TYPE_WORD | Debugger.TYPE_IN | Debugger.TYPE_286, Debugger.TYPE_MEM | Debugger.TYPE_WORD | Debugger.TYPE_IN],
|
||||
0x05: [Debugger.INS.LOADALL, Debugger.TYPE_286]
|
||||
};
|
||||
|
||||
Debugger.aaGrpDescs = [
|
||||
|
|
@ -1778,8 +1781,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 +1848,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 +1864,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 +2568,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 +3498,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 +3621,7 @@ if (DEBUGGER) {
|
|||
*/
|
||||
Debugger.prototype.doHalt = function(sCount)
|
||||
{
|
||||
if (this.fRunning && sCount === undefined) {
|
||||
if (this.aFlags.fRunning && sCount === undefined) {
|
||||
this.haltCPU();
|
||||
return;
|
||||
}
|
||||
|
|
@ -3713,11 +3716,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 +3983,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 +3998,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 +4536,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);
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ var DEBUGGER = true; // this @define is overridden by the Closure Com
|
|||
* @define {boolean}
|
||||
*
|
||||
* PREFETCH enables the use of a prefetch queue.
|
||||
*
|
||||
*
|
||||
* See the Bus component for details.
|
||||
*/
|
||||
var PREFETCH = false;
|
||||
|
|
@ -72,27 +72,21 @@ var PREFETCH = false;
|
|||
/**
|
||||
* @define {boolean}
|
||||
*
|
||||
* FASTDISABLE turns on memory-function switching to dynamically disable memory accesses whenever the CPU wants
|
||||
* to disable spurious memory reads (which are mostly harmless) or stale memory writes (which tend to be destructive
|
||||
* and are NOT mostly harmless).
|
||||
*
|
||||
* If FASTDISABLE is false, then the code falls back to setting/testing internal OP_NOREAD and OP_NOWRITE opFlags
|
||||
* as needed.
|
||||
*
|
||||
* At the moment, it seems that FASTDISABLE is a bit slower than relying on the OP_NOREAD/OP_NOWRITE flags, so it's
|
||||
* turned off; apparently, I was a bit too optimistic calling it "FAST". But your mileage may vary, depending on the
|
||||
* browser and its version.
|
||||
* EAFUNCS enables dynamic function switching whenever the CPU needs to disable one or both EA (Effective Address)
|
||||
* memory functions for a ModRM instruction that doesn't observe the normal "read/modify/write" behavior. The goal
|
||||
* is to avoid useless memory reads (which are mostly harmless) and stale memory writes (which are mostly destructive).
|
||||
*
|
||||
* See the X86CPU component for details, since it is the CPU, not the underlying Bus or Memory components, that needs
|
||||
* to be able to do this.
|
||||
* If EAFUNCS is false, then the CPU falls back to setting/testing internal OP_NOREAD and OP_NOWRITE opFlags as
|
||||
* needed. At the moment, it seems that "EAFUNCS mode" is a bit slower than "EATESTS mode", 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 an Array of numbers for every Memory block,
|
||||
* where each a number represents ONE byte; very wasteful, but potentially slightly faster.
|
||||
*
|
||||
* See the Memory component for details.
|
||||
*/
|
||||
|
|
@ -100,16 +94,14 @@ var FATARRAYS = false;
|
|||
|
||||
/**
|
||||
* @define {boolean}
|
||||
*
|
||||
* TYPEDARRAYS enables use of typed arrays for Memory blocks. This used to be a compile-time-only option, but since I've
|
||||
* added memory access functions for typed arrays (see Memory.afnTypedArray), I can turn the support on dynamically now.
|
||||
* Originally, I didn't see much of a speed increase over the original (non-typed) implementation, but that will probably
|
||||
* change over time.
|
||||
*
|
||||
* TYPEDARRAYS enables use of typed arrays for Memory blocks. This used to be a compile-time-only option, but I've
|
||||
* added Memory access functions for typed arrays (see Memory.afnTypedArray), so support can be enabled dynamically.
|
||||
*
|
||||
* However, TYPEDARRAYS has always been slightly slower than the original DWORDS implementation (which uses an Array
|
||||
* of numbers that stores 32 bits -- 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;
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -91,11 +91,11 @@
|
|||
* 1) Creating new (empty) disk images
|
||||
* 2) Pre-loading pre-built JSON-encoded disk images (converting them to JSON on the fly as needed)
|
||||
*
|
||||
* An example of #1 is in /configs/pc/machines/5160/cga/256kb/demo/machine.xml:
|
||||
* An example of #1 is in /devices/pc/machine/5160/cga/256kb/demo/machine.xml:
|
||||
*
|
||||
* <hdc id="hdcXT" drives='[{name:"10Mb Hard Disk",type:3}]'/>
|
||||
*
|
||||
* and an example of #2 is in /configs/pc/disks/fixed/win101.xml:
|
||||
* and an example of #2 is in /disks/pc/fixed/win101.xml:
|
||||
*
|
||||
* <hdc id="hdcXT" drives='[{name:"10Mb Hard Disk",path:"/disks/pc/fixed/win101/10mb.json",type:3}]'/>
|
||||
*
|
||||
|
|
@ -164,6 +164,7 @@ if (typeof module !== 'undefined') {
|
|||
var DiskAPI = require("../../shared/lib/diskapi");
|
||||
var DumpAPI = require("../../shared/lib/dumpapi");
|
||||
var Component = require("../../shared/lib/component");
|
||||
var Debugger = require("./debugger");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -578,7 +579,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) {
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ if (typeof module !== 'undefined') {
|
|||
var Disk = require("./disk");
|
||||
var Computer = require("./computer");
|
||||
var State = require("./state");
|
||||
var Debugger = require("./debugger");
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -102,7 +103,8 @@ if (typeof module !== 'undefined') {
|
|||
/**
|
||||
* FDC(parmsFDC)
|
||||
*
|
||||
* The FDC component simulates an NEC PD765A, and has one component-specific property:
|
||||
* The FDC component simulates a NEC µPD765A or Intel 8272A compatible floppy disk controller, and has one
|
||||
* component-specific property:
|
||||
*
|
||||
* autoMount: one or more JSON-encoded objects, each containing 'name' and 'path' properties
|
||||
*
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ if (typeof module !== 'undefined') {
|
|||
var ChipSet = require("./chipset");
|
||||
var Disk = require("./disk");
|
||||
var State = require("./state");
|
||||
var Debugger = require("./debugger");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2430,22 +2431,26 @@ HDC.prototype.readByte = function(drive, done, fAutoInc)
|
|||
*/
|
||||
if (done) {
|
||||
var hdc = this;
|
||||
drive.disk.seek(drive.wCylinder, drive.bHead, drive.bSector + drive.bSectorBias, false, function(sector, fAsync) {
|
||||
var b = -1;
|
||||
if ((drive.sector = sector)) {
|
||||
drive.ibSector = 0;
|
||||
/*
|
||||
* We "pre-advance" bSector et al now, instead of waiting to advance it right before the seek().
|
||||
* This allows the initial call to readByte() to perform a seek without triggering an unwanted advance.
|
||||
*/
|
||||
hdc.advanceSector(drive);
|
||||
b = drive.disk.read(drive.sector, drive.ibSector);
|
||||
drive.ibSector += inc;
|
||||
} else {
|
||||
drive.errorCode = HDC.XTC.DATA.ERR.NO_SECTOR;
|
||||
}
|
||||
done(b, fAsync);
|
||||
});
|
||||
if (drive.disk) {
|
||||
drive.disk.seek(drive.wCylinder, drive.bHead, drive.bSector + drive.bSectorBias, false, function(sector, fAsync) {
|
||||
if ((drive.sector = sector)) {
|
||||
drive.ibSector = 0;
|
||||
/*
|
||||
* We "pre-advance" bSector et al now, instead of waiting to advance it right before the seek().
|
||||
* This allows the initial call to readByte() to perform a seek without triggering an unwanted advance.
|
||||
*/
|
||||
hdc.advanceSector(drive);
|
||||
b = drive.disk.read(drive.sector, drive.ibSector);
|
||||
drive.ibSector += inc;
|
||||
} else {
|
||||
drive.errorCode = HDC.XTC.DATA.ERR.NO_SECTOR;
|
||||
}
|
||||
done(b, fAsync);
|
||||
});
|
||||
return b;
|
||||
}
|
||||
drive.errorCode = HDC.XTC.DATA.ERR.NO_SECTOR;
|
||||
done(b, false);
|
||||
}
|
||||
return b;
|
||||
};
|
||||
|
|
@ -2487,9 +2492,11 @@ HDC.prototype.writeByte = function(drive, b)
|
|||
* hence the bSectorBias below. I could change how sector numbers are stored in the image,
|
||||
* but it seems preferable to keep the image format consistent and controller-independent.
|
||||
*/
|
||||
drive.disk.seek(drive.wCylinder, drive.bHead, drive.bSector + drive.bSectorBias, true, function(sector, fAsync) {
|
||||
drive.sector = sector;
|
||||
});
|
||||
if (drive.disk) {
|
||||
drive.disk.seek(drive.wCylinder, drive.bHead, drive.bSector + drive.bSectorBias, true, function(sector, fAsync) {
|
||||
drive.sector = sector;
|
||||
});
|
||||
}
|
||||
if (!drive.sector) {
|
||||
drive.errorCode = HDC.XTC.DATA.ERR.NO_SECTOR;
|
||||
b = -1;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -51,6 +51,7 @@
|
|||
if (typeof module !== 'undefined') {
|
||||
var str = require("../../shared/lib/strlib");
|
||||
var Component = require("../../shared/lib/component");
|
||||
var Debugger = require("./debugger");
|
||||
}
|
||||
/**
|
||||
* @class DataView
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ if (typeof module !== 'undefined') {
|
|||
var Component = require("../../shared/lib/component");
|
||||
var SerialPort = require("./serial");
|
||||
var State = require("./state");
|
||||
var Debugger = require("./debugger");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -38,9 +38,14 @@
|
|||
* nearly all of debugger.js will be conditionally removed by the compiler, reducing it to little more than a
|
||||
* "type skeleton", which also solves some type-related warnings we would otherwise have if we tried to remove
|
||||
* debugger.js from the compilation process altogether.
|
||||
*
|
||||
*
|
||||
* However, when we're in "development mode" and running uncompiled code in debugger-less configurations,
|
||||
* I would still like to skip loading debugger.js altogether. To do that, we must arrange for an additional file,
|
||||
* nodebugger.js, to be loaded as early as possible, which must explicitly UPDATE the value of DEBUGGER to *false*.
|
||||
*/
|
||||
DEBUGGER = false;
|
||||
|
||||
/*
|
||||
* We still need a Debugger "stub" object, so that attempts to reference Debugger constants won't trigger exceptions.
|
||||
*/
|
||||
var Debugger = {};
|
||||
|
|
|
|||
|
|
@ -72,6 +72,9 @@ Panel.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, control)
|
|||
if (this.cpu && this.cpu.setBinding(sHTMLClass, sHTMLType, sBinding, control)) return true;
|
||||
if (this.kbd && this.kbd.setBinding(sHTMLClass, sHTMLType, sBinding, control)) return true;
|
||||
if (DEBUGGER && this.dbg && this.dbg.setBinding(sHTMLClass, sHTMLType, sBinding, control)) return true;
|
||||
/*
|
||||
* TODO: Determine how to declare this superclass method in order to avoid a type warning
|
||||
*/
|
||||
return Component.prototype.setBinding.call(this, sHTMLClass, sHTMLType, sBinding, control);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -78,7 +78,6 @@ Component.subclass(Component, RAM);
|
|||
RAM.prototype.initBus = function(cmp, bus, cpu, dbg) {
|
||||
this.bus = bus;
|
||||
this.cpu = cpu;
|
||||
this.cmp = cmp;
|
||||
this.chipset = cmp.getComponentByType("ChipSet");
|
||||
this.setReady();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ if (typeof module !== 'undefined') {
|
|||
var web = require("../../shared/lib/weblib");
|
||||
var Component = require("../../shared/lib/component");
|
||||
var ChipSet = require("./chipset");
|
||||
var Debugger = require("./debugger");
|
||||
var State = require("./state");
|
||||
}
|
||||
|
||||
|
|
@ -299,7 +300,7 @@ SerialPort.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, cont
|
|||
* BACKSPACE from being interpreted by the browser as a "Back" operation.
|
||||
*/
|
||||
event = event || window.event;
|
||||
var keyCode = event.charCode || event.keyCode;
|
||||
var keyCode = event.keyCode;
|
||||
if (keyCode === 8) {
|
||||
if (event.preventDefault) event.preventDefault();
|
||||
serial.sendRBR([keyCode]);
|
||||
|
|
@ -307,12 +308,12 @@ SerialPort.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, cont
|
|||
};
|
||||
control.onkeypress = function onKeyPressSerial(event) {
|
||||
/*
|
||||
* Browser-independent charCode extraction (refer to keyPress() and the other key
|
||||
* Browser-independent keyCode extraction (refer to keyPress() and the other key
|
||||
* event handlers in keyboard.js).
|
||||
*/
|
||||
event = event || window.event;
|
||||
var charCode = event.which || event.keyCode;
|
||||
serial.sendRBR([charCode]);
|
||||
var keyCode = event.which || event.keyCode;
|
||||
serial.sendRBR([keyCode]);
|
||||
};
|
||||
return true;
|
||||
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ if (typeof module !== 'undefined') {
|
|||
var ChipSet = require("./chipset");
|
||||
var Keyboard = require("./keyboard");
|
||||
var State = require("./state");
|
||||
var Debugger = require("./debugger");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2209,15 +2210,15 @@ Video.prototype.processTouchEvent = function(event, fStart)
|
|||
*/
|
||||
if (/* xThird == 1 && */ yThird != 1) {
|
||||
if (!yThird) {
|
||||
this.kbd.keyPressSimulate(Keyboard.CHARCODE.U_ARROW, true);
|
||||
this.kbd.keyPressSimulate(Keyboard.KEYCODE.UP, true);
|
||||
} else {
|
||||
this.kbd.keyPressSimulate(Keyboard.CHARCODE.D_ARROW, true);
|
||||
this.kbd.keyPressSimulate(Keyboard.KEYCODE.DOWN, true);
|
||||
}
|
||||
} else if (/* yThird == 1 && */ xThird != 1) {
|
||||
if (!xThird) {
|
||||
this.kbd.keyPressSimulate(Keyboard.CHARCODE.L_ARROW, true);
|
||||
this.kbd.keyPressSimulate(Keyboard.KEYCODE.LEFT, true);
|
||||
} else {
|
||||
this.kbd.keyPressSimulate(Keyboard.CHARCODE.R_ARROW, true);
|
||||
this.kbd.keyPressSimulate(Keyboard.KEYCODE.RIGHT, true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -3820,9 +3821,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,
|
||||
|
|
@ -5085,9 +5086,9 @@ Video.init = function()
|
|||
*
|
||||
* UPDATE: Unfortunately, Android keyboards like to compose whole words before transmitting any of the
|
||||
* intervening characters; our textarea's keyDown/keyUp event handlers DO receive intervening key events,
|
||||
* but their keyCode and charCode properties are ZERO. Virtually the only usable key event we receive is
|
||||
* the Enter key, which makes this hack useless. Android users will have to use machines that display
|
||||
* their own on-screen keyboard, or use an external keyboard.
|
||||
* but their keyCode property is ZERO. Virtually the only usable key event we receive is the Enter key,
|
||||
* which makes this hack useless. Android users will have to use machines that display their own on-screen
|
||||
* keyboard, or use an external keyboard.
|
||||
*
|
||||
* See this Chromium issue for more information: https://code.google.com/p/chromium/issues/detail?id=118639
|
||||
*
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ var X86 = {
|
|||
SET: 0xfff0 // on the 80286, these are always set (TODO: Verify)
|
||||
},
|
||||
SEL: {
|
||||
LEVEL: 0x0003, // selector privilege level (0-3)
|
||||
RPL: 0x0003, // requested privilege level (0-3)
|
||||
LDT: 0x0004, // table indicator (0: GDT, 1: LDT)
|
||||
MASK: 0xfff8 // table index
|
||||
},
|
||||
|
|
@ -91,37 +91,48 @@ var X86 = {
|
|||
BASE1623: 0x00ff,
|
||||
MASK: 0xff00,
|
||||
TYPE: {
|
||||
MASK: 0x1f00,
|
||||
SEG: 0x1000,
|
||||
MASK: 0x1f00,
|
||||
SEG: 0x1000,
|
||||
NONSEG: 0x0f00,
|
||||
/*
|
||||
* The rest of these apply only when SEG is set
|
||||
* The following bits apply only when SEG is set
|
||||
*/
|
||||
ACCESSED: 0x0100,
|
||||
READABLE: 0x0200, // CODE: set if readable, clear if execute-only
|
||||
WRITEABLE: 0x0200, // DATA: set if writable, clear if read-only
|
||||
CONFORMING: 0x0400, // CODE: set if conforming, clear if not
|
||||
EXPDOWN: 0x0400, // DATA: set if expand-down, clear if not
|
||||
CODE: 0x0800, // set for CODE, clear for DATA
|
||||
CODE_READABLE: 0x0A00, // both CODE and READABLE
|
||||
CODE_CONFORMING: 0x0C00, // both CODE and CONFORMING
|
||||
CODE_CONFORMING_READABLE: 0x0E00, // all of CODE and CONFORMING and READABLE
|
||||
CODE: 0x0800, // set for CODE, clear for DATA
|
||||
ACCESSED: 0x0100, // set if accessed, clear if not accessed
|
||||
READABLE: 0x0200, // CODE: set if readable, clear if exec-only
|
||||
WRITEABLE: 0x0200, // DATA: set if writable, clear if read-only
|
||||
CONFORMING: 0x0400, // CODE: set if conforming, clear if not
|
||||
EXPDOWN: 0x0400, // DATA: set if expand-down, clear if not
|
||||
/*
|
||||
* The rest of these apply only when SEG is clear
|
||||
* The following are all the possible (valid) types (well, except for the variations
|
||||
* of DATA and CODE where the ACCESSED bit (0x0100) may also be set)
|
||||
*/
|
||||
TSS: 0x0100,
|
||||
LDT: 0x0200,
|
||||
TSS_LDT: 0x0300,
|
||||
TSS_BUSY: 0x0300,
|
||||
GATE_CALL: 0x0400,
|
||||
GATE_TASK: 0x0500,
|
||||
GATE_INT: 0x0600,
|
||||
GATE_TRAP: 0x0700
|
||||
TSS: 0x0100,
|
||||
LDT: 0x0200,
|
||||
TSS_LDT: 0x0300,
|
||||
TSS_BUSY: 0x0300,
|
||||
GATE_CALL: 0x0400,
|
||||
GATE_TASK: 0x0500,
|
||||
GATE_INT: 0x0600,
|
||||
GATE_TRAP: 0x0700,
|
||||
DATA_READONLY: 0x1000,
|
||||
DATA_WRITEABLE: 0x1200,
|
||||
DATA_EXPDOWN_READONLY: 0x1400,
|
||||
DATA_EXPDOWN_WRITEABLE: 0x1600,
|
||||
CODE_EXECONLY: 0x1800,
|
||||
CODE_READABLE: 0x1a00,
|
||||
CODE_CONFORMING_EXECONLY: 0x1c00,
|
||||
CODE_CONFORMING_READABLE: 0x1e00
|
||||
},
|
||||
LEVEL: {
|
||||
DPL: {
|
||||
MASK: 0x6000,
|
||||
SHIFT: 13
|
||||
},
|
||||
PRESENT: 0x8000
|
||||
},
|
||||
EXT: { // descriptor extension word (reserved on the 80286; "must be zero")
|
||||
OFFSET: 0x6,
|
||||
MASK: 0xffff
|
||||
}
|
||||
},
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ if (typeof module !== 'undefined') {
|
|||
var X86Mods = require("./x86mods");
|
||||
var X86OpXX = require("./x86opxx");
|
||||
var X86Op0F = require("./x86op0f");
|
||||
var Debugger = require("./debugger");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -143,14 +144,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 +468,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 +492,7 @@ X86CPU.prototype.initMemory = function(aMemBlocks, addrLimit, blockShift, blockL
|
|||
*/
|
||||
X86CPU.prototype.setAddressMask = function(addrMask)
|
||||
{
|
||||
this.addrMask = addrMask;
|
||||
this.addrMemMask = addrMask;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -727,7 +728,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 +761,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 +825,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 +922,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 +1005,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 +1046,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 +1119,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 +1245,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 +1326,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 +1641,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 +1739,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 +1752,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 +1774,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 +1787,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 +1810,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 +1831,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 +1850,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 +1869,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 +1879,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 +1891,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 +1907,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 +1923,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 +1939,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 +1953,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 +1965,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 +2042,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 +2054,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 +2102,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 +2438,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 +2455,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 +2537,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 +2584,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 +2598,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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
},
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -64,26 +67,26 @@ function X86Seg(cpu, sName, fProt)
|
|||
/**
|
||||
* loadReal(sel, fSuppress)
|
||||
*
|
||||
* This is the default real-mode load() function.
|
||||
* The default segment load() function for real-mode.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
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.limit = 0xffff;
|
||||
this.cpl = this.dpl = 0;
|
||||
return this.base = sel << 4;
|
||||
};
|
||||
|
||||
/**
|
||||
* loadProt(sel, fSuppress)
|
||||
*
|
||||
* This replaces the segment's default load() function whenever the segment is notified (eg, by the CPU's setProtMode()
|
||||
* function) the processor is now in protected-mode.
|
||||
* This replaces the segment's default load() function whenever the segment is notified via updateAccess() by the
|
||||
* CPU's setProtMode() that the processor is now in protected-mode.
|
||||
*
|
||||
* Segments in protected-mode are referenced by selectors, which are indexes into descriptor tables (GDT, LDT, IDT) whose
|
||||
* descriptors are 4-word (8-byte) entries:
|
||||
|
|
@ -96,7 +99,7 @@ X86Seg.loadReal = function loadReal(sel, fSuppress)
|
|||
* See X86.DESC for offset and bit definitions.
|
||||
*
|
||||
* @this {X86Seg}
|
||||
* @param {number} sel containing a selector
|
||||
* @param {number} sel
|
||||
* @param {boolean} [fSuppress] is true to suppress any errors
|
||||
* @return {number} base address of selected segment, or -1 if error
|
||||
*/
|
||||
|
|
@ -111,70 +114,21 @@ X86Seg.loadProt = function loadProt(sel, fSuppress)
|
|||
addrDT = this.cpu.segLDT.base;
|
||||
addrDTLimit = this.cpu.segLDT.limit;
|
||||
}
|
||||
var offDesc = addrDT + (sel & X86.SEL.MASK);
|
||||
if (offDesc + 7 <= addrDTLimit) {
|
||||
var addrDesc = addrDT + (sel & X86.SEL.MASK);
|
||||
if (addrDesc + 7 <= addrDTLimit) {
|
||||
/*
|
||||
* TODO: This is only the first of many steps toward accurately counting cycles in protected mode;
|
||||
* I simply noted that "POP segreg" takes 5 cycles in real mode and 20 in protected mode, so I'm
|
||||
* starting with a 15-cycle difference. Obviously the difference will be much greater when the load fails.
|
||||
*/
|
||||
this.cpu.nStepCycles -= 15;
|
||||
return X86Seg.loadDesc.call(this, sel, offDesc, true);
|
||||
return this.loadDesc8(sel, addrDesc);
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* loadDesc(sel, offDesc, fProt)
|
||||
*
|
||||
* @this {X86Seg}
|
||||
* @param {number} sel containing a selector
|
||||
* @param {number} offDesc is the physical address of a descriptor
|
||||
* @param {boolean} [fProt] is true if protected-mode, false if real-mode, undefined if TBD
|
||||
* @return {number} base address of selected segment, or -1 if error
|
||||
*/
|
||||
X86Seg.loadDesc = function(sel, offDesc, fProt)
|
||||
{
|
||||
var limit = this.cpu.getWord(offDesc + X86.DESC.LIMIT.OFFSET);
|
||||
var acc = this.cpu.getWord(offDesc + X86.DESC.ACC.OFFSET);
|
||||
var base = this.cpu.getWord(offDesc + X86.DESC.BASE.OFFSET) | ((acc & X86.DESC.ACC.BASE1623) << 16);
|
||||
|
||||
Component.assert(this.cpu.getWord(offDesc + 0x06) == 0);
|
||||
|
||||
fProt = this.setProt(fProt);
|
||||
|
||||
/*
|
||||
* For LSL (which uses fSuppress), we must support X86.DESC.ACC.TYPE.SEG as well as TSS and LDT.
|
||||
*/
|
||||
var accType = (acc & X86.DESC.ACC.TYPE.MASK);
|
||||
|
||||
if (accType & X86.DESC.ACC.TYPE.SEG) {
|
||||
if (fProt) {
|
||||
if ((accType & X86.DESC.ACC.TYPE.CODE_READABLE) == X86.DESC.ACC.TYPE.CODE) {
|
||||
this.checkWrite = X86Seg.checkReadProtDisabled;
|
||||
}
|
||||
if ((accType & X86.DESC.ACC.TYPE.CODE) || !(accType & X86.DESC.ACC.TYPE.WRITEABLE)) {
|
||||
this.checkWrite = X86Seg.checkWriteProtDisabled;
|
||||
}
|
||||
}
|
||||
this.sel = sel;
|
||||
this.limit = limit;
|
||||
this.acc = acc;
|
||||
this.level = (acc & X86.DESC.ACC.LEVEL.MASK) >> X86.DESC.ACC.LEVEL.SHIFT;
|
||||
return this.base = base;
|
||||
}
|
||||
else if (accType && accType <= X86.DESC.ACC.TYPE.TSS_BUSY) {
|
||||
this.sel = sel;
|
||||
this.limit = limit;
|
||||
this.acc = acc;
|
||||
this.level = (acc & X86.DESC.ACC.LEVEL.MASK) >> X86.DESC.ACC.LEVEL.SHIFT;
|
||||
return this.base = base;
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* checkReadReal(off, cb)
|
||||
* checkReadReal(off, cb, fSuppress)
|
||||
*
|
||||
* TODO: Invoke X86Help.opHelpFault.call(this.cpu, X86.EXCEPTION.GP_FAULT) if off is 0xffff and cb is 1;
|
||||
* also, whether or not the opHelpFault() call should include an error code, since this is happening in real-mode.
|
||||
|
|
@ -191,7 +145,7 @@ X86Seg.checkReadReal = function checkReadReal(off, cb, fSuppress)
|
|||
};
|
||||
|
||||
/**
|
||||
* checkWriteReal(off, cb)
|
||||
* checkWriteReal(off, cb, fSuppress)
|
||||
*
|
||||
* TODO: Invoke X86Help.opHelpFault.call(this.cpu, X86.EXCEPTION.GP_FAULT) if off is 0xffff and cb is 1;
|
||||
* also, whether or not the opHelpFault() call should include an error code, since this is happening in real-mode.
|
||||
|
|
@ -208,7 +162,7 @@ X86Seg.checkWriteReal = function checkWriteReal(off, cb, fSuppress)
|
|||
};
|
||||
|
||||
/**
|
||||
* checkReadProtEnabled(off, cb)
|
||||
* checkReadProtEnabled(off, cb, fSuppress)
|
||||
*
|
||||
* @this {X86Seg}
|
||||
* @param {number} off is a segment-relative offset
|
||||
|
|
@ -225,7 +179,7 @@ X86Seg.checkReadProtEnabled = function checkReadProtEnabled(off, cb, fSuppress)
|
|||
};
|
||||
|
||||
/**
|
||||
* checkReadProtDisabled(off, cb)
|
||||
* checkReadProtDisabled(off, cb, fSuppress)
|
||||
*
|
||||
* @this {X86Seg}
|
||||
* @param {number} off is a segment-relative offset
|
||||
|
|
@ -242,7 +196,7 @@ X86Seg.checkReadProtDisabled = function checkReadProtDisabled(off, cb, fSuppress
|
|||
};
|
||||
|
||||
/**
|
||||
* checkWriteProtEnabled(off, cb)
|
||||
* checkWriteProtEnabled(off, cb, fSuppress)
|
||||
*
|
||||
* @this {X86Seg}
|
||||
* @param {number} off is a segment-relative offset
|
||||
|
|
@ -259,7 +213,7 @@ X86Seg.checkWriteProtEnabled = function checkWriteProtEnabled(off, cb, fSuppress
|
|||
};
|
||||
|
||||
/**
|
||||
* checkWriteProtDisabled(off, cb)
|
||||
* checkWriteProtDisabled(off, cb, fSuppress)
|
||||
*
|
||||
* @this {X86Seg}
|
||||
* @param {number} off is a segment-relative offset
|
||||
|
|
@ -280,40 +234,88 @@ X86Seg.checkWriteProtDisabled = function checkWriteProtDisabled(off, cb, fSuppre
|
|||
*/
|
||||
|
||||
/**
|
||||
* save()
|
||||
* loadDesc6(sel, addrDesc)
|
||||
*
|
||||
* Early versions of PCjs saved only segment selectors, since that's all that mattered in real-mode;
|
||||
* newer versions need to save/restore the entire segment object.
|
||||
* Used to load a protected-mode selector that refers to a 6-byte descriptor "cache" (LOADALL) entry:
|
||||
*
|
||||
* word 0: base address low
|
||||
* word 1: base address high (0-7), segment type (8-11), descriptor type (12), DPL (13-14), present bit (15)
|
||||
* word 2: segment limit (0-15)
|
||||
*
|
||||
* @this {X86Seg}
|
||||
* @return {Array}
|
||||
* @param {number} sel is the selector
|
||||
* @param {number} addrDesc is the offset
|
||||
* @return {number} base address of selected segment, or -1 if error
|
||||
*/
|
||||
X86Seg.prototype.save = function()
|
||||
X86Seg.prototype.loadDesc6 = function(sel, addrDesc)
|
||||
{
|
||||
return [this.sel, this.base, this.limit, this.acc, this.level, this.sName];
|
||||
var acc = this.cpu.getWord(addrDesc + 2);
|
||||
var base = this.cpu.getWord(addrDesc + 0) | ((acc & 0xff) << 16);
|
||||
var limit = this.cpu.getWord(addrDesc + 4);
|
||||
|
||||
if (DEBUG) {
|
||||
this.cpu.messageDebugger("loadDesc6(" + this.sName + "): base=" + str.toHex(base) + " limit=" + str.toHexWord(limit) + " acc=" + str.toHexWord(acc));
|
||||
}
|
||||
|
||||
this.sel = sel;
|
||||
this.base = base;
|
||||
this.limit = limit;
|
||||
this.acc = acc & X86.DESC.ACC.MASK;
|
||||
this.updateAccess();
|
||||
|
||||
return base;
|
||||
};
|
||||
|
||||
/**
|
||||
* restore(a)
|
||||
* loadDesc8(sel, addrDesc)
|
||||
*
|
||||
* Early versions of PCjs saved only segment selectors, since that's all that mattered in real-mode;
|
||||
* newer versions need to save/restore the entire segment object.
|
||||
* Used to load a protected-mode selector that refers to an 8-byte descriptor table (GDT, LDT, IDT) entry:
|
||||
*
|
||||
* word 0: segment limit (0-15)
|
||||
* word 1: base address low
|
||||
* word 2: base address high (0-7), segment type (8-11), descriptor type (12), DPL (13-14), present bit (15)
|
||||
* word 3: used only on 80386 and up (should be set to zero for upward compatibility)
|
||||
*
|
||||
* See X86.DESC for offset and bit definitions.
|
||||
*
|
||||
* @this {X86Seg}
|
||||
* @param {Array|number} a
|
||||
* @param {number} sel is the selector
|
||||
* @param {number} addrDesc is the offset
|
||||
* @return {number} base address of selected segment, or -1 if error
|
||||
*/
|
||||
X86Seg.prototype.restore = function(a)
|
||||
X86Seg.prototype.loadDesc8 = function(sel, addrDesc)
|
||||
{
|
||||
if (typeof a == "number") {
|
||||
this.load(a);
|
||||
} else {
|
||||
this.sel = a[0];
|
||||
this.base = a[1];
|
||||
this.limit = a[2];
|
||||
this.acc = a[3];
|
||||
this.level = a[4];
|
||||
this.sName = a[5];
|
||||
var limit = this.cpu.getWord(addrDesc + X86.DESC.LIMIT.OFFSET);
|
||||
var acc = this.cpu.getWord(addrDesc + X86.DESC.ACC.OFFSET);
|
||||
var base = this.cpu.getWord(addrDesc + X86.DESC.BASE.OFFSET) | ((acc & X86.DESC.ACC.BASE1623) << 16);
|
||||
var ext = (DEBUG? this.cpu.getWord(addrDesc + X86.DESC.EXT.OFFSET) : 0);
|
||||
|
||||
if (DEBUG) {
|
||||
this.cpu.messageDebugger("loadDesc8(" + this.sName + "): base=" + str.toHex(base) + " limit=" + str.toHexWord(limit) + " acc=" + str.toHexWord(acc) + (ext? " ext=" + str.toHexWord(ext) : ""));
|
||||
Component.assert(!ext);
|
||||
}
|
||||
|
||||
/*
|
||||
* For LSL (which uses fSuppress), we must support X86.DESC.ACC.TYPE.SEG as well as TSS and LDT.
|
||||
*/
|
||||
var accType;
|
||||
if ((acc & X86.DESC.ACC.TYPE.SEG) || (accType = (acc & X86.DESC.ACC.TYPE.MASK)) && accType <= X86.DESC.ACC.TYPE.TSS_BUSY) {
|
||||
this.sel = sel;
|
||||
this.base = base;
|
||||
this.limit = limit;
|
||||
/*
|
||||
* Note that bits 0-7 of acc will usually contain the BASE1623 bits from the descriptor entry,
|
||||
* but it doesn't matter, because the only acc bits we pay attention to are bits 8-15; however,
|
||||
* to keep things tidy, we zero bits 0-7. Perhaps we'll find other (internal) uses for those bits.
|
||||
*/
|
||||
this.acc = acc & X86.DESC.ACC.MASK;
|
||||
this.type = acc & X86.DESC.ACC.TYPE.MASK;
|
||||
this.updateAccess();
|
||||
}
|
||||
else {
|
||||
base = -1;
|
||||
}
|
||||
return base;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -333,16 +335,55 @@ X86Seg.prototype.setBase = function(addr)
|
|||
};
|
||||
|
||||
/**
|
||||
* setProt(fProt)
|
||||
* save()
|
||||
*
|
||||
* This must be used to ensure that the segment register's state (ie, load and check methods) matches
|
||||
* the current operating mode (real or protected).
|
||||
* Early versions of PCjs saved only segment selectors, since that's all that mattered in real-mode;
|
||||
* newer versions need to save/restore the entire segment object.
|
||||
*
|
||||
* @this {X86Seg}
|
||||
* @param {boolean} [fProt]
|
||||
* @return {Array}
|
||||
*/
|
||||
X86Seg.prototype.save = function()
|
||||
{
|
||||
return [this.sel, this.base, this.limit, this.acc, this.fCode, this.sName, this.cpl, this.dpl];
|
||||
};
|
||||
|
||||
/**
|
||||
* restore(a)
|
||||
*
|
||||
* Early versions of PCjs saved only segment selectors, since that's all that mattered in real-mode;
|
||||
* newer versions need to save/restore the entire segment object.
|
||||
*
|
||||
* @this {X86Seg}
|
||||
* @param {Array|number} a
|
||||
*/
|
||||
X86Seg.prototype.restore = function(a)
|
||||
{
|
||||
if (typeof a == "number") {
|
||||
this.load(a);
|
||||
} else {
|
||||
this.sel = a[0];
|
||||
this.base = a[1];
|
||||
this.limit = a[2];
|
||||
this.acc = a[3];
|
||||
this.fCode = a[4];
|
||||
this.sName = a[5];
|
||||
this.cpl = a[6];
|
||||
this.dpl = a[7];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* updateAccess(fProt)
|
||||
*
|
||||
* Ensures that the segment register's access (ie, load and check methods) matches the specified (or current)
|
||||
* operating mode (real or protected).
|
||||
*
|
||||
* @this {X86Seg}
|
||||
* @param {boolean} [fProt] true for protected-mode access, false for real-mode access, undefined for current mode
|
||||
* @return {boolean}
|
||||
*/
|
||||
X86Seg.prototype.setProt = function(fProt)
|
||||
X86Seg.prototype.updateAccess = function(fProt)
|
||||
{
|
||||
if (fProt === undefined) {
|
||||
fProt = !!(this.cpu.regMSW & X86.MSW.PE);
|
||||
|
|
@ -351,10 +392,27 @@ X86Seg.prototype.setProt = function(fProt)
|
|||
this.load = X86Seg.loadProt;
|
||||
this.checkRead = X86Seg.checkReadProtEnabled;
|
||||
this.checkWrite = X86Seg.checkWriteProtEnabled;
|
||||
if (this.acc & X86.DESC.ACC.TYPE.SEG) {
|
||||
/*
|
||||
* If the READABLE bit of CODE_READABLE is not set, then disallow reads
|
||||
*/
|
||||
if ((this.acc & X86.DESC.ACC.TYPE.CODE_READABLE) == X86.DESC.ACC.TYPE.CODE_EXECONLY) {
|
||||
this.checkWrite = X86Seg.checkReadProtDisabled;
|
||||
}
|
||||
/*
|
||||
* If the CODE bit is set, or the the WRITEABLE bit is not set, then disallow writes
|
||||
*/
|
||||
if ((this.acc & X86.DESC.ACC.TYPE.CODE) || !(this.acc & X86.DESC.ACC.TYPE.WRITEABLE)) {
|
||||
this.checkWrite = X86Seg.checkWriteProtDisabled;
|
||||
}
|
||||
}
|
||||
this.cpl = this.sel & X86.SEL.RPL;
|
||||
this.dpl = (this.acc & X86.DESC.ACC.DPL.MASK) >> X86.DESC.ACC.DPL.SHIFT;
|
||||
} else {
|
||||
this.load = X86Seg.loadReal;
|
||||
this.checkRead = X86Seg.checkReadReal;
|
||||
this.checkWrite = X86Seg.checkWriteReal;
|
||||
this.cpl = this.dpl = 0;
|
||||
}
|
||||
return fProt;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@
|
|||
position: absolute;
|
||||
height: 34px;
|
||||
line-height: 34px; /* the equivalent of "vertical-align: middle" for single-line elements */
|
||||
background-color: #ffffff;
|
||||
}
|
||||
.pcjs-reference {
|
||||
float: left;
|
||||
|
|
@ -112,4 +113,4 @@
|
|||
.pcjs-registers {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
@ -27,7 +27,7 @@
|
|||
</xsl:template>
|
||||
|
||||
<xsl:template name="machine">
|
||||
<xsl:param name="href">/configs/pc/machines/5150/mda/64kb/index.xml</xsl:param>
|
||||
<xsl:param name="href">/devices/pc/machine/5150/mda/64kb/machine.xml</xsl:param>
|
||||
<xsl:param name="state" select="''"/>
|
||||
<xsl:variable name="componentFile"><xsl:value-of select="$rootDir"/><xsl:value-of select="$href"/></xsl:variable>
|
||||
<xsl:apply-templates select="document($componentFile)/machine">
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@
|
|||
* It's not that I'm trying to write "portable JavaScript", but some of this code was ported from C code
|
||||
* I'd written about 14 years earlier, and portability is good, so I see no reason to rewrite code to make
|
||||
* it less portable.
|
||||
*
|
||||
*
|
||||
* UPDATE: I've since switched to JSHint, which seems to have more reasonable defaults.
|
||||
*/
|
||||
|
||||
|
|
@ -62,7 +62,7 @@ if (typeof module !== 'undefined') {
|
|||
|
||||
/**
|
||||
* Component(type, parms, constructor)
|
||||
*
|
||||
*
|
||||
* @constructor
|
||||
* @param {string} type
|
||||
* @param {Object} [parms]
|
||||
|
|
@ -83,7 +83,7 @@ if (typeof module !== 'undefined') {
|
|||
function Component(type, parms, constructor)
|
||||
{
|
||||
this.type = type;
|
||||
|
||||
|
||||
if (!parms) {
|
||||
parms = {'id': "", 'name': ""};
|
||||
}
|
||||
|
|
@ -110,20 +110,22 @@ function Component(type, parms, constructor)
|
|||
this[type] = constructor;
|
||||
|
||||
/*
|
||||
* TODO: Decide how to reintegrate this code into the components that still want it....
|
||||
* TODO: Decide how to reintegrate this code into the components that still want it....
|
||||
*
|
||||
if (this.initStep) this.initStep(parms);
|
||||
*/
|
||||
|
||||
this.aFlags = {
|
||||
fReady: false,
|
||||
fBusy: false,
|
||||
fBusyCancel: false,
|
||||
fPowered: false,
|
||||
fError: false
|
||||
};
|
||||
|
||||
this.fnReady = null;
|
||||
this.fReady = false;
|
||||
this.fBusy = this.fBusyCancel = false;
|
||||
this.fPowered = false;
|
||||
this.clearError();
|
||||
this.bindings = {};
|
||||
this.dbg = null; // by default, no connection to a Debugger
|
||||
|
||||
this.getMachineNum(); // once again, make the function appear used
|
||||
|
||||
Component.add(this);
|
||||
}
|
||||
|
|
@ -139,10 +141,10 @@ Component.parmsURL = web.getURLParameters();
|
|||
|
||||
/**
|
||||
* Component.inherit(p)
|
||||
*
|
||||
*
|
||||
* Returns a newly created object that inherits properties from the prototype object p.
|
||||
* It uses the ECMAScript 5 function Object.create() if it is defined, and otherwise falls back to an older technique.
|
||||
*
|
||||
*
|
||||
* See: Flanagan, David (2011-04-18). JavaScript: The Definitive Guide: The Definitive Guide (Kindle Locations 9854-9903). OReilly Media - A. Kindle Edition (Example 6-1)
|
||||
*
|
||||
* @param {Object} p
|
||||
|
|
@ -167,10 +169,10 @@ Component.inherit = function(p)
|
|||
|
||||
/**
|
||||
* Component.extend(o, p)
|
||||
*
|
||||
*
|
||||
* Copies the enumerable properties of p to o and returns o.
|
||||
* If o and p have a property by the same name, o's property is overwritten.
|
||||
*
|
||||
*
|
||||
* See: Flanagan, David (2011-04-18). JavaScript: The Definitive Guide: The Definitive Guide (Kindle Locations 9854-9903). OReilly Media - A. Kindle Edition (Example 6-2)
|
||||
*
|
||||
* @param {Object} o
|
||||
|
|
@ -221,7 +223,7 @@ Component.all = [];
|
|||
|
||||
/**
|
||||
* Component.add(component)
|
||||
*
|
||||
*
|
||||
* @param {Component} component
|
||||
*/
|
||||
Component.add = function(component)
|
||||
|
|
@ -236,7 +238,7 @@ Component.add = function(component)
|
|||
|
||||
/**
|
||||
* Component.log(s, type)
|
||||
*
|
||||
*
|
||||
* For diagnostic output only.
|
||||
*
|
||||
* @param {string} [s] is the message text
|
||||
|
|
@ -258,7 +260,7 @@ Component.log = function(s, type)
|
|||
|
||||
/**
|
||||
* Component.assert(f, s)
|
||||
*
|
||||
*
|
||||
* Used to verify conditions that must be true (for DEBUG builds only; compiled builds should automatically have all
|
||||
* references to Component.assert() removed).
|
||||
*
|
||||
|
|
@ -281,9 +283,9 @@ Component.assert = function(f, s)
|
|||
|
||||
/**
|
||||
* Component.println(s, type, id)
|
||||
*
|
||||
*
|
||||
* For non-diagnostic messages, which components may override to control the destination/appearance of their output.
|
||||
*
|
||||
*
|
||||
* Components that inherit from this class should use the instance method, this.println(), rather than Component.println(),
|
||||
* because if a Control Panel is loaded, it will override only the instance method, not the class method (overriding the class
|
||||
* method would improperly affect any other machines loaded on the same page).
|
||||
|
|
@ -301,7 +303,7 @@ Component.println = function(s, type, id)
|
|||
|
||||
/**
|
||||
* Component.notice(s, fPrintOnly, id)
|
||||
*
|
||||
*
|
||||
* notice() is like println() but implies a need for user notification, so we alert() as well.
|
||||
*
|
||||
* @param {string} s is the message text
|
||||
|
|
@ -318,7 +320,7 @@ Component.notice = function(s, fPrintOnly, id)
|
|||
|
||||
/**
|
||||
* Component.warning(s)
|
||||
*
|
||||
*
|
||||
* @param {string} s describes the warning
|
||||
*/
|
||||
Component.warning = function(s)
|
||||
|
|
@ -331,7 +333,7 @@ Component.warning = function(s)
|
|||
|
||||
/**
|
||||
* Component.error(s)
|
||||
*
|
||||
*
|
||||
* @param {string} s describes the error; an alert() is displayed as well
|
||||
*/
|
||||
Component.error = function(s)
|
||||
|
|
@ -344,7 +346,7 @@ Component.error = function(s)
|
|||
|
||||
/**
|
||||
* Component.getComponents(idRelated)
|
||||
*
|
||||
*
|
||||
* We could store components as properties of an 'all' object, using the component's ID,
|
||||
* and change this linear lookup into a property lookup, but some components may have no ID.
|
||||
*
|
||||
|
|
@ -357,7 +359,7 @@ Component.getComponents = function(idRelated)
|
|||
var aComponents = [];
|
||||
/*
|
||||
* getComponentByID(id, idRelated)
|
||||
*
|
||||
*
|
||||
* If idRelated is provided, we check it for a machine prefix, and use any
|
||||
* existing prefix to constrain matches to IDs with the same prefix, in order to
|
||||
* avoid matching components belonging to other machines.
|
||||
|
|
@ -379,7 +381,7 @@ Component.getComponents = function(idRelated)
|
|||
|
||||
/**
|
||||
* Component.getComponentByID(id, idRelated)
|
||||
*
|
||||
*
|
||||
* We could store components as properties of an 'all' object, using the component's ID,
|
||||
* and change this linear lookup into a property lookup, but some components may have no ID.
|
||||
*
|
||||
|
|
@ -411,7 +413,7 @@ Component.getComponentByID = function(id, idRelated)
|
|||
|
||||
/**
|
||||
* Component.getComponentByType(sType, idRelated, componentPrev)
|
||||
*
|
||||
*
|
||||
* @param {string} sType of the desired component
|
||||
* @param {string} [idRelated] of related component
|
||||
* @param {Component} [componentPrev] of previously returned component, if any
|
||||
|
|
@ -449,7 +451,7 @@ Component.getComponentByType = function(sType, idRelated, componentPrev)
|
|||
|
||||
/**
|
||||
* Component.getComponentParms(element)
|
||||
*
|
||||
*
|
||||
* @param {Object} element from the DOM
|
||||
*/
|
||||
Component.getComponentParms = function(element)
|
||||
|
|
@ -476,7 +478,7 @@ Component.getComponentParms = function(element)
|
|||
|
||||
/**
|
||||
* Component.bindExternalControl(component, sControl, sBinding, sType)
|
||||
*
|
||||
*
|
||||
* @param {Component} component
|
||||
* @param {string} sControl
|
||||
* @param {string} sBinding
|
||||
|
|
@ -498,7 +500,7 @@ Component.bindExternalControl = function(component, sControl, sBinding, sType)
|
|||
|
||||
/**
|
||||
* Component.bindComponentControls(component, element, sAppClass)
|
||||
*
|
||||
*
|
||||
* @param {Component} component
|
||||
* @param {Object} element from the DOM
|
||||
* @param {string} sAppClass
|
||||
|
|
@ -529,7 +531,7 @@ Component.bindComponentControls = function(component, element, sAppClass)
|
|||
if (parms && parms['binding']) {
|
||||
component.setBinding(sClass, parms['type'], parms['binding'], control);
|
||||
} else {
|
||||
Component.log('Component.bindComponentControls("' + component.toString() + '"): no binding info for ' + parms['type'], "warning");
|
||||
Component.log('Component.bindComponentControls("' + component.toString() + '"): missing binding' + (parms? ' for ' + parms['type'] : ''), "warning");
|
||||
}
|
||||
aClasses = [];
|
||||
break;
|
||||
|
|
@ -544,9 +546,9 @@ Component.bindComponentControls = function(component, element, sAppClass)
|
|||
|
||||
/**
|
||||
* Component.getElementsByClass(element, sClass, sObjClass)
|
||||
*
|
||||
*
|
||||
* This is a cross-browser helper function, since not all browser's support getElementsByClassName()
|
||||
*
|
||||
*
|
||||
* TODO: This should probably be moved into weblib.js at some point, along with the control binding functions above,
|
||||
* to keep all the browser-related code together.
|
||||
*
|
||||
|
|
@ -583,7 +585,7 @@ Component.prototype = {
|
|||
constructor: Component,
|
||||
/**
|
||||
* toString()
|
||||
*
|
||||
*
|
||||
* @this {Component}
|
||||
* @return {string}
|
||||
*/
|
||||
|
|
@ -592,7 +594,7 @@ Component.prototype = {
|
|||
},
|
||||
/**
|
||||
* getMachineNum()
|
||||
*
|
||||
*
|
||||
* @this {Component}
|
||||
* @return {number} unique machine number
|
||||
*/
|
||||
|
|
@ -607,7 +609,7 @@ Component.prototype = {
|
|||
},
|
||||
/**
|
||||
* setBinding(sHTMLClass, sHTMLType, sBinding, control)
|
||||
*
|
||||
*
|
||||
* Component's setBinding() method is intended to be overridden by subclasses.
|
||||
*
|
||||
* @this {Component}
|
||||
|
|
@ -661,8 +663,8 @@ Component.prototype = {
|
|||
};
|
||||
}(control));
|
||||
/**
|
||||
* Override this.notice() with a replacement function that eliminates the web.alertUser() call
|
||||
*
|
||||
* Override this.notice() with a replacement function that eliminates the web.alertUser() call
|
||||
*
|
||||
* @this {Component}
|
||||
* @param {string} s
|
||||
* @param {boolean} [fPrintOnly]
|
||||
|
|
@ -679,12 +681,12 @@ Component.prototype = {
|
|||
},
|
||||
/**
|
||||
* log(s, type)
|
||||
*
|
||||
*
|
||||
* For diagnostic output only.
|
||||
*
|
||||
*
|
||||
* WARNING: Even though this function's body is completely wrapped in DEBUG, that won't prevent the Closure Compiler
|
||||
* from including it, so all calls must still be prefixed with "if (DEBUG) ....". For this reason, the class method,
|
||||
* Component.log(), is preferred, because the compiler IS smart enough to remove those calls.
|
||||
* Component.log(), is preferred, because the compiler IS smart enough to remove those calls.
|
||||
*
|
||||
* @this {Component}
|
||||
* @param {string} [s] is the message text
|
||||
|
|
@ -702,7 +704,7 @@ Component.prototype = {
|
|||
*
|
||||
* Components using this.println() should wait until after their constructor has run to display any messages, because
|
||||
* if a Control Panel has been loaded, its override will not take effect until its own constructor has run.
|
||||
*
|
||||
*
|
||||
* @this {Component}
|
||||
* @param {string} [s] is the message text
|
||||
* @param {string} [type] is the message type
|
||||
|
|
@ -713,7 +715,7 @@ Component.prototype = {
|
|||
},
|
||||
/**
|
||||
* status(s)
|
||||
*
|
||||
*
|
||||
* status() is like println() but it also includes information about the component (ie, the component ID),
|
||||
* which is why there is no corresponding Component.status() function.
|
||||
*
|
||||
|
|
@ -724,7 +726,7 @@ Component.prototype = {
|
|||
},
|
||||
/**
|
||||
* notice(s, fPrintOnly)
|
||||
*
|
||||
*
|
||||
* notice() is like println() but implies a need for user notification, so we alert() as well; however, if this.println()
|
||||
* is overridden, this.notice will be replaced with a similar override, on the assumption that the override is taking care
|
||||
* of alerting the user.
|
||||
|
|
@ -739,36 +741,36 @@ Component.prototype = {
|
|||
},
|
||||
/**
|
||||
* setError(s)
|
||||
*
|
||||
*
|
||||
* Set a fatal error condition
|
||||
*
|
||||
* @this {Component}
|
||||
* @param {string} s describes a fatal error condition
|
||||
*/
|
||||
setError: function(s) {
|
||||
this.fError = true;
|
||||
this.aFlags.fError = true;
|
||||
this.notice("Fatal error: " + s);
|
||||
},
|
||||
/**
|
||||
* clearError()
|
||||
*
|
||||
*
|
||||
* Clear any fatal error condition
|
||||
*
|
||||
* @this {Component}
|
||||
*/
|
||||
clearError: function() {
|
||||
this.fError = false;
|
||||
this.aFlags.fError = false;
|
||||
},
|
||||
/**
|
||||
* isError()
|
||||
*
|
||||
*
|
||||
* Report any fatal error condition
|
||||
*
|
||||
* @this {Component}
|
||||
* @return {boolean} true if a fatal error condition exists, false if not
|
||||
*/
|
||||
isError: function() {
|
||||
if (this.fError) {
|
||||
if (this.aFlags.fError) {
|
||||
this.println(this.toString() + " error");
|
||||
return true;
|
||||
}
|
||||
|
|
@ -776,7 +778,7 @@ Component.prototype = {
|
|||
},
|
||||
/**
|
||||
* isReady(fnReady)
|
||||
*
|
||||
*
|
||||
* Return the "ready" state of the component; if the component is not ready, it will queue the optional
|
||||
* notification function, otherwise it will immediately call the notification function, if any, without queuing it.
|
||||
*
|
||||
|
|
@ -789,27 +791,27 @@ Component.prototype = {
|
|||
*/
|
||||
isReady: function(fnReady) {
|
||||
if (fnReady) {
|
||||
if (this.fReady) {
|
||||
if (this.aFlags.fReady) {
|
||||
fnReady();
|
||||
} else {
|
||||
if (DEBUG) this.log("NOT ready");
|
||||
this.fnReady = fnReady;
|
||||
}
|
||||
}
|
||||
return this.fReady;
|
||||
return this.aFlags.fReady;
|
||||
},
|
||||
/**
|
||||
* setReady(fReady)
|
||||
*
|
||||
*
|
||||
* Set the "ready" state of the component to true, and call any queued notification functions.
|
||||
*
|
||||
* @this {Component}
|
||||
* @param {boolean} [fReady] is assumed to indicate "ready" unless EXPLICITLY set to false
|
||||
*/
|
||||
setReady: function(fReady) {
|
||||
if (!this.fError) {
|
||||
this.fReady = (fReady !== false);
|
||||
if (this.fReady) {
|
||||
if (!this.aFlags.fError) {
|
||||
this.aFlags.fReady = (fReady !== false);
|
||||
if (this.aFlags.fReady) {
|
||||
if (DEBUG || this.name) this.log("ready");
|
||||
var fnReady = this.fnReady;
|
||||
this.fnReady = null;
|
||||
|
|
@ -819,7 +821,7 @@ Component.prototype = {
|
|||
},
|
||||
/**
|
||||
* isBusy(fCancel)
|
||||
*
|
||||
*
|
||||
* Return the "busy" state of the component
|
||||
*
|
||||
* @this {Component}
|
||||
|
|
@ -827,18 +829,18 @@ Component.prototype = {
|
|||
* @return {boolean} true if "busy", false if not
|
||||
*/
|
||||
isBusy: function(fCancel) {
|
||||
if (this.fBusy) {
|
||||
if (this.aFlags.fBusy) {
|
||||
if (fCancel) {
|
||||
this.fBusyCancel = true;
|
||||
this.aFlags.fBusyCancel = true;
|
||||
} else if (fCancel === undefined) {
|
||||
this.println(this.toString() + " busy");
|
||||
}
|
||||
}
|
||||
return this.fBusy;
|
||||
return this.aFlags.fBusy;
|
||||
},
|
||||
/**
|
||||
* setBusy(fBusy)
|
||||
*
|
||||
*
|
||||
* Update the current busy state; if an fCancel request is pending, it will be honored now.
|
||||
*
|
||||
* @this {Component}
|
||||
|
|
@ -846,19 +848,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 +871,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 +883,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;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ function parseXML(sXML, sXMLFile, idMachine, sStateFile, fResolve, display, done
|
|||
}
|
||||
/*
|
||||
* If the resource we requested is not really an XML file (or the file didn't exist and the server simply returned
|
||||
* a message like "Cannot GET /configs/pc/machines/5150/cga/64kb/donkey/index.xml"), we'd like to display a more
|
||||
* a message like "Cannot GET /devices/pc/machine/5150/cga/64kb/donkey/machine.xml"), we'd like to display a more
|
||||
* meaningful message, because the XML DOM parsers will blithely return a document that contains nothing useful; eg:
|
||||
*
|
||||
* This page contains the following errors:error on line 1 at column 1:
|
||||
|
|
|
|||
|
|
@ -118,14 +118,6 @@
|
|||
|
||||
/* global window: true, setTimeout: false, clearTimeout: false, SITEHOST: false */
|
||||
|
||||
/*
|
||||
* We must defer loading the Component module until the function(s) requiring it are
|
||||
* called; otherwise, we create an initialization cycle in which Component requires weblib
|
||||
* and weblib requires Component.
|
||||
*
|
||||
* In an ideal world, weblib would not be dependent on Component, but we really want to use
|
||||
* its logging functions.
|
||||
*/
|
||||
if (typeof module !== 'undefined') {
|
||||
var Component;
|
||||
require("./defines");
|
||||
|
|
@ -135,6 +127,49 @@ if (typeof module !== 'undefined') {
|
|||
|
||||
var web = {};
|
||||
|
||||
/*
|
||||
* We must defer loading the Component module until the function(s) requiring it are
|
||||
* called; otherwise, we create an initialization cycle in which Component requires weblib
|
||||
* and weblib requires Component.
|
||||
*
|
||||
* In an ideal world, weblib would not be dependent on Component, but we really want to use
|
||||
* its I/O functions. The simplest solution is to create wrapper functions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* log(s, type)
|
||||
*
|
||||
* For diagnostic output only. DEBUG must be true (or "--debug" specified via the command-line)
|
||||
* for Component.log() to display anything.
|
||||
*
|
||||
* @param {string} [s] is the message text
|
||||
* @param {string} [type] is the message type
|
||||
*/
|
||||
web.log = function(s, type)
|
||||
{
|
||||
if (typeof module !== 'undefined') {
|
||||
if (!Component) Component = require("./component");
|
||||
}
|
||||
Component.log(s, type);
|
||||
};
|
||||
|
||||
/**
|
||||
* notice(s, fPrintOnly, id)
|
||||
*
|
||||
* If Component.notice() calls web.alertUser(), it will fall back to web.log() if all else fails.
|
||||
*
|
||||
* @param {string} s is the message text
|
||||
* @param {boolean} [fPrintOnly]
|
||||
* @param {string} [id] is the caller's ID, if any
|
||||
*/
|
||||
web.notice = function(s, fPrintOnly, id)
|
||||
{
|
||||
if (typeof module !== 'undefined') {
|
||||
if (!Component) Component = require("./component");
|
||||
}
|
||||
Component.notice(s, fPrintOnly, id);
|
||||
};
|
||||
|
||||
/**
|
||||
* loadResource(sURL, fAsync, data, componentNotify, fnNotify, pNotify)
|
||||
*
|
||||
|
|
@ -188,11 +223,11 @@ web.loadResource = function(sURL, fAsync, data, componentNotify, fnNotify, pNoti
|
|||
* from the local file system (ie, when using the "file:" protocol), we have to be a bit more "flexible".
|
||||
*/
|
||||
if (xmlHTTP.status == 200 || !xmlHTTP.status && sURLData.length && web.getHostProtocol() == "file:") {
|
||||
Component.log("xmlHTTP.onreadystatechange(" + sURL + "): returned " + sURLData.length + " bytes");
|
||||
web.log("xmlHTTP.onreadystatechange(" + sURL + "): returned " + sURLData.length + " bytes");
|
||||
}
|
||||
else {
|
||||
nErrorCode = xmlHTTP.status || -1;
|
||||
Component.log("xmlHTTP.onreadystatechange(" + sURL + "): error code " + nErrorCode);
|
||||
web.log("xmlHTTP.onreadystatechange(" + sURL + "): error code " + nErrorCode);
|
||||
}
|
||||
if (fnNotify) {
|
||||
if (!componentNotify) {
|
||||
|
|
@ -212,12 +247,12 @@ web.loadResource = function(sURL, fAsync, data, componentNotify, fnNotify, pNoti
|
|||
sData += p + '=' + encodeURIComponent(data[p]);
|
||||
}
|
||||
sData = sData.replace(/%20/g, '+');
|
||||
Component.log("web.loadResource(POST " + sURL + "): " + sData.length + " bytes");
|
||||
web.log("web.loadResource(POST " + sURL + "): " + sData.length + " bytes");
|
||||
xmlHTTP.open("POST", sURL, fAsync);
|
||||
xmlHTTP.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
xmlHTTP.send(sData);
|
||||
} else {
|
||||
Component.log("web.loadResource(GET " + sURL + ")");
|
||||
web.log("web.loadResource(GET " + sURL + ")");
|
||||
xmlHTTP.open("GET", sURL, fAsync);
|
||||
xmlHTTP.send();
|
||||
}
|
||||
|
|
@ -225,10 +260,10 @@ web.loadResource = function(sURL, fAsync, data, componentNotify, fnNotify, pNoti
|
|||
if (!fAsync) {
|
||||
sURLData = xmlHTTP.responseText;
|
||||
if (xmlHTTP.status == 200) {
|
||||
Component.log("web.loadResource(" + sURL + "): returned " + sURLData.length + " bytes");
|
||||
web.log("web.loadResource(" + sURL + "): returned " + sURLData.length + " bytes");
|
||||
} else {
|
||||
nErrorCode = xmlHTTP.status || -1;
|
||||
Component.log("web.loadResource(" + sURL + "): error code " + nErrorCode);
|
||||
web.log("web.loadResource(" + sURL + "): error code " + nErrorCode);
|
||||
}
|
||||
if (fnNotify) {
|
||||
if (!componentNotify) {
|
||||
|
|
@ -249,7 +284,7 @@ web.loadResource = function(sURL, fAsync, data, componentNotify, fnNotify, pNoti
|
|||
*
|
||||
* @param {string} sApp (eg, "PCjs")
|
||||
* @param {string} sVer (eg, "1.02")
|
||||
* @param {string} sURL (eg, "/configs/pc/machines/5150/mda/64kb/index.xml")
|
||||
* @param {string} sURL (eg, "/devices/pc/machine/5150/mda/64kb/machine.xml")
|
||||
* @param {string} sUser (ie, the user key, if any)
|
||||
* @param {string} sType (eg, "bug"); one of ReportAPI.TYPE.*
|
||||
* @param {string} sReport (eg, unparsed state data)
|
||||
|
|
@ -315,11 +350,7 @@ web.getUserAgent = function()
|
|||
*/
|
||||
web.alertUser = function(sMessage)
|
||||
{
|
||||
if (window) {
|
||||
window.alert(sMessage);
|
||||
} else {
|
||||
console.log(sMessage);
|
||||
}
|
||||
if (window) window.alert(sMessage); else web.log(sMessage);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -393,7 +424,7 @@ web.hasLocalStorage = function() {
|
|||
*/
|
||||
web.logLocalStorageError = function(e)
|
||||
{
|
||||
Component.log(e.message, "localStorage error");
|
||||
web.log(e.message, "localStorage error");
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -506,9 +537,9 @@ web.isUserAgent = function(s)
|
|||
var userAgent = web.getUserAgent();
|
||||
/*
|
||||
* Here's one case where we have to be careful with Component, because when isUserAgent() is called by
|
||||
* the init code below, component.js hasn't been loaded yet. The simplest solution is to remove the call.
|
||||
* the init code below, component.js hasn't been loaded yet. The simple solution for now is to remove the call.
|
||||
*
|
||||
* if (Component) Component.log("agent: " + userAgent);
|
||||
* web.log("agent: " + userAgent);
|
||||
*
|
||||
* And yes, it would be pointless to use the conditional (?) operator below, if not for the Google Closure
|
||||
* Compiler (v20130823) failing to detect the entire expression as a boolean.
|
||||
|
|
@ -596,7 +627,7 @@ web.onClickRepeat = function(e, msDelay, msRepeat, fn)
|
|||
}
|
||||
};
|
||||
e.onmousedown = function() {
|
||||
// Component.println("onMouseDown()");
|
||||
// web.log("onMouseDown()");
|
||||
if (!fIgnoreMouseEvents) {
|
||||
if (!timer) {
|
||||
ms = msDelay;
|
||||
|
|
@ -605,21 +636,21 @@ web.onClickRepeat = function(e, msDelay, msRepeat, fn)
|
|||
}
|
||||
};
|
||||
e.ontouchstart = function() {
|
||||
// Component.println("onTouchStart()");
|
||||
// web.log("onTouchStart()");
|
||||
if (!timer) {
|
||||
ms = msDelay;
|
||||
fnRepeat();
|
||||
}
|
||||
};
|
||||
e.onmouseup = e.onmouseout = function() {
|
||||
// Component.println("onMouseUp()/onMouseOut()");
|
||||
// web.log("onMouseUp()/onMouseOut()");
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
timer = null;
|
||||
}
|
||||
};
|
||||
e.ontouchend = e.ontouchcancel = function() {
|
||||
// Component.println("onTouchEnd()/onTouchCancel()");
|
||||
// web.log("onTouchEnd()/onTouchCancel()");
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
timer = null;
|
||||
|
|
@ -722,7 +753,7 @@ web.doPageEvent = function(afn)
|
|||
afn[i]();
|
||||
}
|
||||
} catch(e) {
|
||||
Component.notice("An unexpected exception occurred:\n\n" + e.message + "\n\nPlease send this information to Jeff@pcjs.org. Thanks.");
|
||||
web.notice("An unexpected exception occurred:\n\n" + e.message + "\n\nPlease send this information to support@pcjs.org. Thanks.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,11 +17,11 @@ files.
|
|||
|
||||
[*machine.xsl*](machine.xsl) is an XML stylesheet that takes things a step further and transforms a machine XML
|
||||
into a stand-alone HTML document, which also includes all necessary compiled scripts (eg, c1p.js, c1p-dbg.js,
|
||||
pc.js or pc-dbg.js). Most machine XML files explcitly link to this stylesheet, so that simply loading the XML
|
||||
pc.js or pc-dbg.js). Most machine XML files explicitly link to this stylesheet, so that simply loading the XML
|
||||
file in your web browser creates a working virtual machine.
|
||||
|
||||
[*manifest.xsl*](manifest.xsl) is an XML stylesheet that renders a software manifest XML file into a standalone
|
||||
document; it may even contain a referene to a machine XML file.
|
||||
document; it may even contain a reference to a machine XML file.
|
||||
|
||||
[*document.xsl*](document.xsl) is a collection of XSL templates used exclusively by [*outline.xsl*](outline.xsl),
|
||||
which is a more grandiose version of [*machine.xsl*](machine.xsl), designed to support XML-based documentation
|
||||
|
|
@ -32,4 +32,4 @@ in a README.md document.
|
|||
|
||||
Since the XML document syntax that [*outline.xsl*](outline.xsl) supports was never very well documented, I'm tempted
|
||||
to deprecate it and port any XML documents that still rely on it (mostly the older IAS Electronic Computer Project
|
||||
documents) to Markdown files.
|
||||
documents) to Markdown files.
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
<li><a href="/">Home</a></li>
|
||||
<li><a href="/apps/pc/">Apps</a></li>
|
||||
<li><a href="/disks/pc/">Disks</a></li>
|
||||
<li><a href="/configs/">Machines</a></li>
|
||||
<li><a href="/devices/">Machines</a></li>
|
||||
<li><a href="/docs/">Docs</a></li>
|
||||
<li><a href="/pubs/">Pubs</a></li>
|
||||
<li><a href="/blog/">Blog</a></li>
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
<li><a href="/">Home</a></li>
|
||||
<li><a href="/apps/pc/">Apps</a></li>
|
||||
<li><a href="/disks/pc/">Disks</a></li>
|
||||
<li><a href="/configs/">Machines</a></li>
|
||||
<li><a href="/devices/">Machines</a></li>
|
||||
<li><a href="/docs/">Docs</a></li>
|
||||
<li><a href="/pubs/">Pubs</a></li>
|
||||
<li><a href="/blog/">Blog</a></li>
|
||||
|
|
|
|||
Loading…
Reference in a new issue