Merge branch 'master' of https://github.com/jeffpar/pcjs into c1pserialupload

This commit is contained in:
Stephan Mühlstrasser 2014-11-06 18:47:02 +01:00
commit e9e7633fa7
294 changed files with 10332 additions and 3960 deletions

View file

@ -57,8 +57,8 @@ function C1PCPU(parmsCPU)
Component.call(this, "C1PCPU", parmsCPU);
this.clearRegs();
this.fPower = false;
this.fRunning = false;
this.aFlags.fPowered = false;
this.aFlags.fRunning = false;
this.fAutoStart = parmsCPU["autoStart"];
/*
@ -482,7 +482,7 @@ Component.subclass(Component, C1PCPU);
*/
C1PCPU.prototype.reset = function(fPowerOn)
{
if (this.fRunning)
if (this.aFlags.fRunning)
this.halt();
this.clearRegs();
this.regPC = this.getWord(this.VECTOR_RESET);
@ -516,7 +516,7 @@ C1PCPU.prototype.setBinding = function(c, t, s, e)
this.bindings[s] = e;
e.onclick = function(cpu) {
return function() {
if (!cpu.fRunning)
if (!cpu.aFlags.fRunning)
cpu.run();
else
cpu.halt();
@ -579,7 +579,7 @@ C1PCPU.prototype.setBuffer = function(abMemory, start, end)
*/
C1PCPU.prototype.setPower = function(fOn, cmp)
{
if (fOn && !this.fPower) {
if (fOn && !this.aFlags.fPowered) {
this.cmp = cmp;
/*
* Attach the Debugger, if any, to the CPU, so that the CPU can periodically
@ -607,7 +607,7 @@ C1PCPU.prototype.setPower = function(fOn, cmp)
};
}(video);
}
this.fPower = true;
this.aFlags.fPowered = true;
this.reset(true);
this.update();
}
@ -880,7 +880,7 @@ C1PCPU.prototype.displayStatus = function()
*/
C1PCPU.prototype.isRunning = function()
{
return this.fRunning;
return this.aFlags.fRunning;
};
/**
@ -1051,7 +1051,7 @@ C1PCPU.prototype.run = function()
if (this.cmp) this.cmp.stop(this.msRunStart, this.nRunCycles);
return;
}
if (!this.fRunning) {
if (!this.aFlags.fRunning) {
/*
* setSpeed() without a speed parameter leaves the selected speed in place, but also resets the
* cycle counter and timestamp for the current series of run() calls, calculates the maximum number
@ -1060,7 +1060,7 @@ C1PCPU.prototype.run = function()
*/
this.setSpeed();
if (this.cmp) this.cmp.start();
this.fRunning = true;
this.aFlags.fRunning = true;
if (this.bindings["run"]) this.bindings["run"].innerHTML = "Halt";
this.setFocus();
}
@ -1107,7 +1107,7 @@ C1PCPU.prototype.run = function()
this.nCyclesNextYield += this.nCyclesPerYield;
break;
}
} while (this.fRunning);
} while (this.aFlags.fRunning);
}
catch (e) {
this.halt();
@ -1268,8 +1268,8 @@ C1PCPU.prototype.halt = function()
this.isBusy(true);
this.nBurstCycles -= this.nStepCycles;
this.nStepCycles = 0;
if (this.fRunning) {
this.fRunning = false;
if (this.aFlags.fRunning) {
this.aFlags.fRunning = false;
if (this.bindings["run"]) this.bindings["run"].innerHTML = "Run";
}
};
@ -1303,7 +1303,7 @@ C1PCPU.prototype.update = function()
*/
C1PCPU.prototype.getCycles = function()
{
return (this.fRunning? this.nRunCycles + this.nBurstCycles - this.nStepCycles : 0);
return (this.aFlags.fRunning? this.nRunCycles + this.nBurstCycles - this.nStepCycles : 0);
};
/**

View file

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

View file

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

View file

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

View file

@ -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/>

View file

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

View file

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

View file

@ -44,7 +44,7 @@ function C1PSerialPort(parmsSerial)
{
Component.call(this, "C1PSerialPort", parmsSerial);
this.fPower = false;
this.aFlags.fPowered = false;
this.fDemo = parmsSerial['demo'];
this.STATUS_NONE = 0x00;
@ -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");

View file

@ -308,8 +308,8 @@ C1PVideo.prototype.setPower = function(fOn, cmp)
* it ourselves, too. This also means that updateScreen() need check only fPower and not isReady(),
* since we guarantee that the former implies the latter.
*/
if (fOn && !this.fPower && this.isReady()) {
this.fPower = true;
if (fOn && !this.aFlags.fPowered && this.isReady()) {
this.aFlags.fPowered = true;
if (DEBUGGER) this.dbg = cmp.getComponentByType("debugger");
/*
* If we have an associated keyboard, then ensure that the keyboard will be notified whenever
@ -328,8 +328,8 @@ C1PVideo.prototype.setPower = function(fOn, cmp)
}
}
else
if (!fOn && this.fPower) {
this.fPower = false;
if (!fOn && this.aFlags.fPowered) {
this.aFlags.fPowered = false;
/*
* This is where we would add some method of blanking the display, without the disturbing the video
* buffer contents, and blocking all further updates to the display.
@ -442,7 +442,7 @@ C1PVideo.prototype.initScreen = function()
C1PVideo.prototype.updateScreen = function()
{
var offset = 0;
if (this.fPower) {
if (this.aFlags.fPowered) {
while (offset < this.cbScreen) {
var b = this.abMem[this.offVideo + offset];
if (this.abScreen[offset] != b) {

View file

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

View file

@ -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.

View file

@ -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
*/

View file

@ -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:
*

View file

@ -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;
}
}

View file

@ -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".
*

View file

@ -87,5 +87,5 @@
"name": "",
"messages": ""
},
"xml": "/configs/pc/machines/5150/mda/64kb/machine.xml"
"xml": "/devices/pc/machine/5150/mda/64kb/machine.xml"
}

View file

@ -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") {

View file

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

View file

@ -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

View file

@ -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

View file

@ -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()
/*

View file

@ -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);

View file

@ -64,7 +64,7 @@ var DEBUGGER = true; // this @define is overridden by the Closure Com
* @define {boolean}
*
* PREFETCH enables the use of a prefetch queue.
*
*
* See the Bus component for details.
*/
var PREFETCH = false;
@ -72,27 +72,21 @@ var PREFETCH = false;
/**
* @define {boolean}
*
* FASTDISABLE turns on memory-function switching to dynamically disable memory accesses whenever the CPU wants
* to disable spurious memory reads (which are mostly harmless) or stale memory writes (which tend to be destructive
* and are NOT mostly harmless).
*
* If FASTDISABLE is false, then the code falls back to setting/testing internal OP_NOREAD and OP_NOWRITE opFlags
* as needed.
*
* At the moment, it seems that FASTDISABLE is a bit slower than relying on the OP_NOREAD/OP_NOWRITE flags, so it's
* turned off; apparently, I was a bit too optimistic calling it "FAST". But your mileage may vary, depending on the
* browser and its version.
* EAFUNCS enables dynamic function switching whenever the CPU needs to disable one or both EA (Effective Address)
* memory functions for 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;
/*

View file

@ -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) {

View file

@ -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
*

View file

@ -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

View file

@ -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

View file

@ -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");
}
/**

View file

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

View file

@ -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);
};

View file

@ -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();
};

View file

@ -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;

View file

@ -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
*

View file

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

View file

@ -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);
}
}

View file

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

View file

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

View file

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

View file

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

View file

@ -33,6 +33,7 @@
"use strict";
if (typeof module !== 'undefined') {
var str = require("../../shared/lib/strlib");
var X86 = require("./x86");
var X86Help = require("./x86help");
}
@ -52,9 +53,11 @@ function X86Seg(cpu, sName, fProt)
this.base = 0;
this.limit = 0xffff;
this.acc = 0;
this.level = 0;
this.fCode = (sName == "CS");
this.sName = sName;
this.setProt(fProt);
this.cpl = 0;
this.dpl = 0;
this.updateAccess(fProt);
}
/*
@ -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;
};

View file

@ -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;
}
}
}

View file

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

View file

@ -46,7 +46,7 @@
* It's not that I'm trying to write "portable JavaScript", but some of this code was ported from C code
* I'd written about 14 years earlier, and portability is good, so I see no reason to rewrite code to make
* it less portable.
*
*
* UPDATE: I've since switched to JSHint, which seems to have more reasonable defaults.
*/
@ -62,7 +62,7 @@ if (typeof module !== 'undefined') {
/**
* Component(type, parms, constructor)
*
*
* @constructor
* @param {string} type
* @param {Object} [parms]
@ -83,7 +83,7 @@ if (typeof module !== 'undefined') {
function Component(type, parms, constructor)
{
this.type = type;
if (!parms) {
parms = {'id': "", 'name': ""};
}
@ -110,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;
}
};

View file

@ -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:

View file

@ -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.");
}
}
};

View file

@ -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.

View file

@ -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>

View file

@ -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>