Final preparations for open source roll-out

This commit is contained in:
Jeff Parsons 2014-10-12 00:08:15 -07:00 committed by jeffpar
commit 60669365f9
40 changed files with 2814 additions and 2639 deletions

View file

@ -270,6 +270,29 @@ C1PComputer.init = function()
var component;
var modules = {};
/*
* Let's see if the Control Panel is installed (NOTE: its ID must be "panel", and only one per machine is supported);
* the Panel needs our setPower() notifications, and this relieves us from having an explicit <module> entry for type="panel".
*/
var panel = Component.getComponentByID('panel', parmsComputer['id']);
if (panel) {
modules['panel'] = [panel];
/*
* Iterate through all the other components and update their print methods if the Control Panel has provided overrides.
*/
if (panel.controlPrint) {
var aComponents = Component.getComponents(parmsComputer['id']);
for (var iComponent = 0; iComponent < aComponents.length; iComponent++) {
component = aComponents[iComponent];
if (component == panel) continue;
component.notice = panel.notice;
component.println = panel.println;
component.controlPrint = panel.controlPrint;
}
}
}
var abMemory;
var addrStart = 0, addrEnd = 0;
@ -326,15 +349,6 @@ C1PComputer.init = function()
}
}
/*
* Let's see if the Control Panel is installed (NOTE: its ID must be "panel", and only one per machine is supported);
* the Panel needs our setPower() notifications, and this relieves us from having an explicit <module> entry for type="panel".
*/
component = Component.getComponentByID('panel', parmsComputer['id']);
if (component) {
modules['panel'] = [component];
}
var computer = new C1PComputer(parmsComputer, modules);
/*
* We may eventually add a "Power" button, but for now, all we have is a "Reset" button

View file

@ -809,7 +809,7 @@ C1PDiskController.prototype.loadDisk = function(sDiskName, sDiskData, nErrorCode
* to its trackNum index, but just in case that wasn't intended, we're going to mention it.
*/
if (iTrackNum != iTrack) {
this.warning("track " + iTrackNum + " out of order (expected " + iTrack + ")");
Component.warning("track " + iTrackNum + " out of order (expected " + iTrack + ")");
}
/*
* For each track, we start with an empty trackData array and "push" (ie, append) all the

View file

@ -56,19 +56,19 @@ Component.subclass(Component, C1PPanel);
* component that doesn't recognize the specified binding should simply ignore it.
*
* @this {C1PPanel}
* @param {string|null} c is the class of the HTML control (eg, "input", "output")
* @param {string|null} t is the type of the HTML control (eg, "button", "list", "text", "submit", "textarea")
* @param {string} s is the value of the 'binding' parameter stored in the HTML control's "data-value" attribute (eg, "reset")
* @param {Object} e is the HTML control DOM object (eg, HTMLButtonElement)
* @param {string|null} sHTMLClass is the class of the HTML control (eg, "input", "output")
* @param {string|null} sHTMLType is the type of the HTML control (eg, "button", "list", "text", "submit", "textarea", "canvas")
* @param {string} sBinding is the value of the 'binding' parameter stored in the HTML control's "data-value" attribute (eg, "reset")
* @param {Object} control is the HTML control DOM object (eg, HTMLButtonElement)
* @return {boolean} true if binding was successful, false if unrecognized binding request
*/
C1PPanel.prototype.setBinding = function(c, t, s, e)
C1PPanel.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, control)
{
if (this.cmp && this.cmp.setBinding(c, t, s, e)) return true;
if (this.cpu && this.cpu.setBinding(c, t, s, e)) return true;
if (this.kbd && this.kbd.setBinding(c, t, s, e)) return true;
if (DEBUGGER && this.dbg && this.dbg.setBinding(c, t, s, e)) return true;
return Component.prototype.setBinding.call(this, c, t, s, e);
if (this.cmp && this.cmp.setBinding(sHTMLClass, sHTMLType, sBinding, control)) return true;
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;
return Component.prototype.setBinding.call(this, sHTMLClass, sHTMLType, sBinding, control);
};
/**

View file

@ -731,7 +731,8 @@ DiskDump.readFile = function(sPath, sEncoding, done)
/**
* isExcluded(sName)
*
*
* @this {DiskDump}
* @param {string} sName is the basename of a file under consideration
* @return {boolean} is true if the file should be excluded, false if not
*/
@ -752,6 +753,7 @@ DiskDump.prototype.isExcluded = function(sName)
* object creation from any I/O that the object may perform, to ensure that a callback can never
* be called before the caller has actually received the newly created object.
*
* @this {DiskDump}
* @param {function(Error)} done
*/
DiskDump.prototype.loadFile = function(done)
@ -774,6 +776,7 @@ DiskDump.prototype.loadFile = function(done)
*
* Records the loaded disk data buffer
*
* @this {DiskDump}
* @param {Error} err
* @param {Buffer|string} buf
* @param {function(Error)} done
@ -818,6 +821,7 @@ DiskDump.prototype.setData = function(err, buf, done)
/**
* dumpLine(nIndent, sLine, sComment)
*
* @this {DiskDump}
* @param {number} [nIndent] is the relative number of characters to indent the given line (0 if none)
* @param {string} [sLine] is the given line
* @param {string} [sComment] is an optional comment to append to the line, if comment output is enabled
@ -840,6 +844,7 @@ DiskDump.prototype.dumpLine = function(nIndent, sLine, sComment)
/**
* dumpProp(sKey, value, fLast)
*
* @this {DiskDump}
* @param {string} sKey
* @param {number|string|null} value
* @param {boolean} [fLast]
@ -857,6 +862,7 @@ DiskDump.prototype.dumpProp = function(sKey, value, fLast)
/**
* dumpBuffer(sKey, buf, len, cbItem, offData)
*
* @this {DiskDump}
* @param {string|null} sKey is name of buffer data element
* @param {Buffer} buf is a Buffer containing the bytes to dump
* @param {number} len is the number of bytes to dump
@ -908,6 +914,7 @@ DiskDump.prototype.dumpBuffer = function(sKey, buf, len, cbItem, offData)
*
* Dumps track data for an OSI disk track
*
* @this {DiskDump}
* @param {string} sTrackSig
* @param {number} nTrackNum
* @param {number} nTrackType
@ -932,6 +939,7 @@ DiskDump.prototype.dumpTrackOSI = function(sTrackSig, nTrackNum, nTrackType, nTr
*
* Dumps sector data for an OSI disk sector
*
* @this {DiskDump}
* @param {number|null} nSectorSig
* @param {number} nSectorNum
* @param {number} nSectorPages
@ -968,6 +976,7 @@ DiskDump.prototype.dumpSectorOSI = function(nSectorSig, nSectorNum, nSectorPages
* NOTE: The C1Pjs Simulator doesn't support this feature (yet), which is why
* trimSector() isn't used when dumping OSI disk images.
*
* @this {DiskDump}
* @param {Buffer} buf
* @param {number} len
* @return {Array} containing [dwPattern, cbBuffer]
@ -1018,7 +1027,8 @@ DiskDump.ATTR_ARCHIVE = 0x20;
/**
* validateTime(dateTime)
*
*
* @this {DiskDump}
* @param {Date} dateTime
* @return {boolean} true if date/time modified, false if not
*/
@ -1062,6 +1072,7 @@ DiskDump.prototype.validateTime = function(dateTime)
/**
* buildData(cb)
*
* @this {DiskDump}
* @param {number} cb
* @param {Array.<number>} [abInit]
* @return {Array.<number>} of bytes zero-initialized
@ -1078,6 +1089,7 @@ DiskDump.prototype.buildData = function(cb, abInit)
/**
* copyData(ab)
*
* @this {DiskDump}
* @param {number} offDisk
* @param {Array.<number>} ab
* @return {number} number of bytes written
@ -1091,7 +1103,8 @@ DiskDump.prototype.copyData = function(offDisk, ab)
/**
* addManifestInfo(fileInfo)
*
*
* @this {DiskDump}
* @param {Object} fileInfo
*/
DiskDump.prototype.addManifestInfo = function(fileInfo)
@ -1105,6 +1118,7 @@ DiskDump.prototype.addManifestInfo = function(fileInfo)
* Returns an array (aFiles) via the done() callback, where each entry is a fileInfo object.
* If fileInfo refers to a subdirectory, then FILE_SIZE is -1 and FILE_DATA entry is another aFiles array.
*
* @this {DiskDump}
* @param {string} sDir is a fully-qualified directory name
* @param {boolean} [fRoot] should be true for the first directory read
* @param {function(Error,Array)} done
@ -1234,6 +1248,7 @@ DiskDump.prototype.readDir = function(sDir, fRoot, done)
* NOTE: sPath begins fully-qualified (see this.sDiskPath), but if any of the intermediate entries contains paths,
* it's our responsibility to join them with sServerRoot.
*
* @this {DiskDump}
* @param {string} sPath contains series of semi-colon-separated files (local or remote)
* @param {function(Error,Array)} done
*/
@ -1356,6 +1371,7 @@ DiskDump.prototype.readPath = function(sPath, done)
/**
* buildName(sFile)
*
* @this {DiskDump}
* @param {string} sFile is the basename of a file
* @return {string} containing a corresponding FAT-compatible filename
*/
@ -1391,6 +1407,7 @@ DiskDump.prototype.buildName = function(sFile)
* NOTE: When fileInfo is returned, there will be no FILE_PATH property, which means
* don't go looking for a corresponding entry in the host file system, because there isn't one.
*
* @this {DiskDump}
* @param {string} [sDir]
* @return {Object|null} fileInfo (or null if no suitable volume label)
*/
@ -1433,6 +1450,7 @@ DiskDump.prototype.buildVolLabel = function(sDir)
/**
* buildFAT(abFAT, aFiles, iCluster, cbCluster)
*
* @this {DiskDump}
* @param {Array.<number>} abFAT
* @param {Array} aFiles
* @param {number} iCluster
@ -1476,6 +1494,7 @@ DiskDump.prototype.buildFAT = function(abFAT, aFiles, iCluster, cbCluster)
/**
* buildFATEntry(abFat, iFat, v)
*
* @this {DiskDump}
* @param {Array.<number>} abFAT
* @param {number} iFAT
* @param {number} v
@ -1501,6 +1520,7 @@ DiskDump.prototype.buildFATEntry = function(abFAT, iFAT, v)
/**
* buildDir(abDir, aFiles, dateMod, iCluster, iParentCluster)
*
* @this {DiskDump}
* @param {Array.<number>} abDir
* @param {Array} aFiles
* @param {Date} [dateMod]
@ -1537,6 +1557,7 @@ DiskDump.prototype.buildDir = function(abDir, aFiles, dateMod, iCluster, iParent
*
* TODO: Create constants that define the various directory entry fields, including the overall size (32 bytes).
*
* @this {DiskDump}
* @param {Array.<number>} ab contains the bytes of a directory
* @param {number} off is the offset within ab to build the next directory entry
* @param {string} sFile is the file name
@ -1621,6 +1642,7 @@ DiskDump.prototype.buildDirEntry = function(ab, off, sFile, cbFile, bAttr, dateM
/**
* buildClusters(aFiles, offDisk, cbCluster, iParentCluster, done)
*
* @this {DiskDump}
* @param {Array} aFiles
* @param {number} offDisk
* @param {number} cbCluster
@ -1706,6 +1728,7 @@ DiskDump.prototype.buildClusters = function(aFiles, offDisk, cbCluster, iParentC
/**
* buildImage()
*
* @this {DiskDump}
* @param {boolean} fDir
* @param {function(Error)} done
*/
@ -1740,6 +1763,7 @@ DiskDump.prototype.buildImage = function(fDir, done)
* calculated total data and found a BPB we think will accommodate it. So, the code below
* will still have to be prepared for running out of disk space. This is just a good estimate.
*
* @this {DiskDump}
* @param {Array} aFiles
* @return {number} of bytes required for all files, including all subdirectories
*/
@ -1765,6 +1789,7 @@ DiskDump.prototype.calcFileSizes = function(aFiles)
/**
* buildMBR(cHeads, cSectorsPerTrack, cbSector, cTotalSectors)
*
* @this {DiskDump}
* @param {number} cHeads
* @param {number} cSectorsPerTrack
* @param {number} cbSector
@ -1835,6 +1860,7 @@ DiskDump.prototype.buildMBR = function(cHeads, cSectorsPerTrack, cbSector, cTota
* Note, however, that even if this function returns true, you won't receive the buffer until
* all the writes to have it have finished.
*
* @this {DiskDump}
* @param {Array} aFiles
* @param {function(Error)} done
* @return {boolean} true if disk allocation successful, false if not
@ -1996,6 +2022,7 @@ DiskDump.prototype.buildImageFromFiles = function(aFiles, done)
*
* Converts the disk image data to JSON.
*
* @this {DiskDump}
* @return {string|null} containing a JSON representation of the disk image, or null if unrecognized/malformed
*/
DiskDump.prototype.convertToJSON = function()
@ -2288,6 +2315,7 @@ DiskDump.prototype.convertToJSON = function()
* each containing an array of tracks. It's largely just a matter of reversing the meaning of the two outermost array
* elements, here and in the C1Pjs disk module.
*
* @this {DiskDump}
* @return {string|null} containing a JSON representation of the disk image, or null if unrecognized/malformed
*/
DiskDump.prototype.convertOSIDiskToJSON = function()
@ -2406,6 +2434,7 @@ DiskDump.prototype.convertOSIDiskToJSON = function()
* TODO: Consider creating a caching mechanism for these requests (ie, stash a limited number of these
* disk images under /tmp, using a name based on a hash of the source path).
*
* @this {DiskDump}
* @return {Buffer|null} containing the disk image's raw data, or null if no data available (or parse error)
*/
DiskDump.prototype.convertToIMG = function()

View file

@ -47,7 +47,7 @@ var DumpAPI = require("../../shared/lib/dumpapi");
* or a "--map" command-line option), which in turn triggers a call to loadMap(). Note that loadMap() will need
* to be a bit more general and use a worker function that calls either net.getFile() or fs.readFile(), similar
* to what our loadFile() function already does.
*
*
* @constructor
* @param {string|undefined} sFormat should be one of "json"|"data"|"hex"|"bytes"|"rom" (see the FORMAT constants)
* @param {boolean|string|undefined} fComments enables comments and other readability enhancements in the JSON output
@ -67,7 +67,7 @@ function FileDump(sFormat, fComments, fDecimal, sServerRoot)
this.buf = null;
/*
* TODO: Decide what to do with this usage info; we can't use it as a default, because setting this.json
* causes outputFile() to ignore this.buf indiscriminately (ie, it breaks non-JSON output modes).
* causes outputFile() to ignore this.buf indiscriminately (ie, it breaks non-JSON output modes).
*/
this.json = ""; // "[\n /**\n * " + FileDump.sAPIURL + " " + FileDump.sCopyright + "\n * " + FileDump.sUsage + "\n */\n]";
}
@ -101,24 +101,24 @@ FileDump.sUsage = "Usage: " + FileDump.sAPIURL + "?" + DumpAPI.QUERY.FILE + "=({
* text format that consists entirely of 2-character hex values (deprecated), and "bytes" is a JSON-like format
* that also uses hex values (but with "0x" prefixes) and is normally used only when comments are enabled (use
* --decimal to force decimal byte output).
*
*
* When a second file is "merged", the first file sets all even bytes and the second file sets all odd bytes.
* In fact, any number of files can be merged: if there are N files, file #1 sets bytes at "offset mod N == 0",
* file #2 sets all bytes at "offset mod N == 1", and file #N sets all bytes at "offset mod N == N - 1".
*
* Note that command-line arguments, if any, are not validated. For example, argv['comments'] may be any of
* boolean, string, or undefined, since the user may have typed "--comments" or "--comments=foo" or nothing at all.
*
*
* Examples
* ---
* filedump --file=devices/pc/video/ibm-ega.rom --format=bytes --decimal
*
*
* Notes
* ---
* Originally, we had to specify `--format=bytes` because the onLoadROM() code in rom.js assumed the data was
* always byte-sized, but it has since been updated to support dword arrays, so the default format ("json")
* works fine as well. Also, `--decimal` reduces the size of the output file significantly.
*
*
* If there's a ".map" file (eg, "ibm-ega.map"), it's automatically loaded and appended to the ROM data as a
* "symbols" property; we may want to consider an option to disable the processing of map files, but for now, the
* simple answer is: if you don't want one, don't create one.
@ -131,29 +131,29 @@ FileDump.CLI = function()
console.log("usage: filedump --file=({path}|{URL}) [--merge=({path}|{url})] [--format=(json|data|hex|bytes|rom)] [--comments] [--decimal] [--output={path}] [--overwrite]");
return;
}
var argv = args.argv;
var sFile = argv['file'];
if (!sFile) {
FileDump.logError(new Error("no filename specified"));
return;
}
var sOutputFile = argv['output'];
if (typeof sOutputFile != "string") {
FileDump.logError(new Error("bad or missing output filename"));
return;
}
if (sOutputFile && sOutputFile.charAt(0) != '/') sOutputFile = path.join(process.cwd(), sOutputFile);
var fOverwrite = argv['overwrite'];
var sFormat = FileDump.validateFormat(argv['format']);
if (sFormat === false) {
FileDump.logError(new Error("unrecognized format"));
return;
}
var sMergeFile, asMergeFiles = [];
var file = new FileDump(sFormat, argv['comments'], argv['decimal']);
if (argv['merge']) {
@ -227,6 +227,7 @@ FileDump.validateFormat = function(sFormat)
* object creation from any I/O that the object may perform, to ensure that a callback can never
* be called before the caller has actually received the newly created object.
*
* @this {FileDump}
* @param {string} sFile
* @param {number} iStart
* @param {number} nSkip
@ -241,10 +242,10 @@ FileDump.prototype.loadFile = function(sFile, iStart, nSkip, done)
*/
var obj = this;
var sFilePath = net.isRemote(sFile)? sFile : path.join(this.sServerRoot, sFile);
if (!this.sFilePath) this.sFilePath = sFilePath;
if (this.fDebug) console.log("loadFile(" + sFilePath + "," + iStart + "," + nSkip + ")");
if (net.isRemote(sFilePath)) {
net.getFile(sFilePath, null, function(err, status, buf) {
if (err) {
@ -273,6 +274,7 @@ FileDump.prototype.loadFile = function(sFile, iStart, nSkip, done)
*
* Records the given file data in the FileDump's buffer
*
* @this {FileDump}
* @param {Buffer} buf
* @param {number} iStart
* @param {number} nSkip
@ -299,6 +301,7 @@ FileDump.prototype.setData = function(buf, iStart, nSkip)
/**
* dumpLine(nIndent, sLine, sComment)
*
* @this {FileDump}
* @param {number} [nIndent] is the relative number of characters to indent the given line (0 if none)
* @param {string} [sLine] is the given line
* @param {string} [sComment] is an optional comment to append to the line, if comment output is enabled
@ -322,6 +325,7 @@ FileDump.prototype.dumpLine = function(nIndent, sLine, sComment)
/**
* dumpBuffer(sKey, buf, len, cbItem, offData)
*
* @this {FileDump}
* @param {string|null} sKey is name of buffer data element
* @param {Buffer} buf is a Buffer containing the bytes to dump
* @param {number} len is the number of bytes to dump
@ -334,7 +338,7 @@ FileDump.prototype.dumpBuffer = function(sKey, buf, len, cbItem, offData)
var chOpen = '', chClose = '', chSep = ' ', sHexPrefix = "";
this.sKey = sKey;
if (this.sFormat != DumpAPI.FORMAT.HEX) {
chOpen = '['; chClose = ']'; chSep = ','; sHexPrefix = "0x";
}
@ -385,6 +389,7 @@ FileDump.prototype.dumpBuffer = function(sKey, buf, len, cbItem, offData)
*
* NOTE: Since ".map" files are an internal construct, I support only local map files (for now)
*
* @this {FileDump}
* @param {string} sFilePath
* @param {function(Error,string)} done
*/
@ -413,13 +418,13 @@ FileDump.prototype.loadMap = function(sFilePath, done)
}
else {
// console.log("add this to obj.json:\n" + str);
/*
* Parse MAP data into a set of properties; for example, if the .map file contains:
*
* 0320 = HF_PORT
* 0320 = HF_PORT
* 0000:0034 4 HDISK_INT
* 0040:0042 1 CMD_BLOCK
* 0040:0042 1 CMD_BLOCK
* 0003 @ DISK_SETUP
* 0000:004C 4 ORG_VECTOR
* 0028 . MOV AX,WORD PTR ORG_VECTOR ;GET DISKETTE VECTOR
@ -436,26 +441,26 @@ FileDump.prototype.loadMap = function(sFilePath, done)
*
* then we should produce the following corresponding JSON:
*
* {
* "HF_PORT": {
* "v":800
* },
* "HDISK_INT": {
* "b":4, "s":0, "o":52
* },
* "ORG_VECTOR": {
* "b":4, "s":0, "o":76
* },
* "CMD_BLOCK": {
* "b":1, "s":64, "o":66
* },
* "DISK_SETUP": {
* "o":3
* },
* ".40": {
* "o":64, "a":"MOV AX,WORD PTR ORG_VECTOR ;GET DISKETTE VECTOR"
* }
* }
* {
* "HF_PORT": {
* "v":800
* },
* "HDISK_INT": {
* "b":4, "s":0, "o":52
* },
* "ORG_VECTOR": {
* "b":4, "s":0, "o":76
* },
* "CMD_BLOCK": {
* "b":1, "s":64, "o":66
* },
* "DISK_SETUP": {
* "o":3
* },
* ".40": {
* "o":64, "a":"MOV AX,WORD PTR ORG_VECTOR ;GET DISKETTE VECTOR"
* }
* }
*
* where "v" is the value of an absolute (unsized) value; "b" is either 1, 2, 4 or undefined; "s" is either a hard-coded
* segment or undefined; and "o" is the offset of an symbol. Also, if the symbol is not entirely upper-case, then we
@ -562,8 +567,10 @@ FileDump.prototype.loadMap = function(sFilePath, done)
/**
* buildJSON()
*
*
* Common code between the API helper (convertToJSON()) and the command-line helper (convertToFile()).
*
* @this {FileDump}
*/
FileDump.prototype.buildJSON = function()
{
@ -586,6 +593,7 @@ FileDump.prototype.buildJSON = function()
*
* Converts the data buffer to JSON.
*
* @this {FileDump}
* @param {function(Error,string)} done
*/
FileDump.prototype.convertToJSON = function(done)
@ -599,6 +607,7 @@ FileDump.prototype.convertToJSON = function(done)
*
* Converts the data buffer to JSON, as appropriate.
*
* @this {FileDump}
* @param {string} sOutputFile
* @param {boolean} fOverwrite
*/
@ -621,16 +630,17 @@ FileDump.prototype.convertToFile = function(sOutputFile, fOverwrite)
/**
* outputFile(sOutputFile, fOverwrite)
*
*
* @this {FileDump}
* @param {string} sOutputFile
* @param {boolean} fOverwrite
*/
FileDump.prototype.outputFile = function(sOutputFile, fOverwrite)
{
var data = this.json || this.buf;
var sFormat = this.sFormat.toUpperCase();
if (sOutputFile) {
try {
if (fs.existsSync(sOutputFile) && !fOverwrite) {

View file

@ -71,7 +71,10 @@ var fConsole = false;
/*
* fServerDebug controls server-related debug features; it is false by default and can be enabled using the
* setOptions() 'debug' property (or from the command-line interface using "--debug").
* setOptions() 'debug' property (or from the server's command-line interface using "--debug").
*
* This used to be named fDebug, which was fine, but it has been renamed to make the distinction between the
* server's debug state (fServerDebug) and the debug state of HTMLOut instances (this.fDebug) clearer.
*/
var fServerDebug = false;
@ -475,7 +478,7 @@ HTMLOut.filter = function(req, res, next)
* and adding an Etag, unless we ALSO change the req.method from "GET" to something else.
* Supposedly, we could also use app.disable('etag'), but I'm not sure that would prevent
* Express from changing the status code, and I'm tired of testing work-arounds for this
* irritating behavior in Safari.
* irritating behavior.
*/
req.method = "NONE";
res.set("Content-Type", "application/xml");
@ -486,6 +489,10 @@ HTMLOut.filter = function(req, res, next)
}
}
}
if (asNonDirectories.indexOf(sBaseName) >= 0) {
res.set("Content-Type", "text/plain");
}
/*
* Next, check for API requests (eg, "/api/v1/dump?disk=/disks/pc/dos/ibm/2.00/PCDOS200-DISK1.json&format=img")
@ -681,6 +688,7 @@ HTMLOut.setRoot = function(sRoot)
/**
* loadFile()
*
* @this {HTMLOut}
* @param {string} sFile
* @param {boolean} fTemplate
*/
@ -700,6 +708,7 @@ HTMLOut.prototype.loadFile = function(sFile, fTemplate)
*
* Records the given HTML template and immediately parses it.
*
* @this {HTMLOut}
* @param {Error} err
* @param {string} sData
* @param {string} sFile
@ -741,6 +750,7 @@ HTMLOut.prototype.setData = function(err, sData, sFile, fTemplate)
/**
* findTokens()
*
* @this {HTMLOut}
* @param {RegExp} reTokens
*/
HTMLOut.prototype.findTokens = function(reTokens)
@ -794,6 +804,8 @@ HTMLOut.prototype.findTokens = function(reTokens)
/**
* replaceTokens()
*
* @this {HTMLOut}
*/
HTMLOut.prototype.replaceTokens = function()
{
@ -866,6 +878,7 @@ HTMLOut.prototype.replaceTokens = function()
*
* aParms[0], if present, is used as the preferred title for the home page
*
* @this {HTMLOut}
* @param {string} sToken
* @param {string} [sIndent]
* @param {Array.<string>} [aParms]
@ -880,6 +893,7 @@ HTMLOut.prototype.getTitle = function(sToken, sIndent, aParms)
*
* Returns the current version in "package.json".
*
* @this {HTMLOut}
* @param {string} sToken
* @param {string} [sIndent]
* @param {Array.<string>} [aParms]
@ -902,6 +916,7 @@ HTMLOut.prototype.getVersion = function(sToken, sIndent, aParms)
/**
* getPath(sToken, sIndent, aParms)
*
* @this {HTMLOut}
* @param {string} sToken
* @param {string} [sIndent]
* @param {Array.<string>} [aParms]
@ -914,6 +929,7 @@ HTMLOut.prototype.getPath = function(sToken, sIndent, aParms)
/**
* getPCPath(sToken, sIndent, aParms)
*
* @this {HTMLOut}
* @param {string} sToken
* @param {string} [sIndent]
* @param {Array.<string>} [aParms]
@ -941,6 +957,7 @@ HTMLOut.prototype.getPCPath = function(sToken, sIndent, aParms)
* <a href="/apps/">[apps]</a>
* </li>
*
* @this {HTMLOut}
* @param {string} sToken
* @param {string} [sIndent]
* @param {Array.<string>} [aParms]
@ -962,8 +979,8 @@ HTMLOut.prototype.getDirList = function(sToken, sIndent, aParms)
asFiles.push("..");
/*
* For sorting purposes, I want all folders ending in "kb" and beginning with one or two
* digits to sort as if they all began with THREE digits (ie, with leading zeros as needed).
* For sorting purposes, I want all folders ending in "kb" and beginning with one to three
* digits to sort as if they all began with FOUR digits (ie, with leading zeros as needed).
* But I don't want to change the folder names that are ultimately displayed. So instead,
* I pad those names with slashes, since a leading slash will sort much like a leading zero
* without being a valid filename character, meaning we can trim away those leading slashes
@ -1002,7 +1019,7 @@ HTMLOut.prototype.getDirList = function(sToken, sIndent, aParms)
if (asFilesNonListed.indexOf(sBaseName) >= 0) continue;
} else {
/*
* Even when the server's in Debug mode, there are some files it makes no sense to list....
* Even when the server's in Debug mode, there are some files it makes no sense to list.
*/
if (sBaseName == "index.html") continue;
}
@ -1073,6 +1090,7 @@ HTMLOut.prototype.getDirList = function(sToken, sIndent, aParms)
*
* Return the current year.
*
* @this {HTMLOut}
* @param {string} sToken
* @param {string} [sIndent]
* @param {Array.<string>} [aParms]
@ -1087,6 +1105,7 @@ HTMLOut.prototype.getYear = function(sToken, sIndent, aParms)
*
* If we're in the "blog" folder, then enumerate all available blog entries and create a rendering of blog excerpts.
*
* @this {HTMLOut}
* @param {string} sToken
* @param {string} [sIndent]
* @param {Array.<string>} [aParms]
@ -1189,7 +1208,7 @@ HTMLOut.prototype.getBlog = function(sToken, sIndent, aParms)
for (var i = 0; i < aExcerpts.length; i++) {
sExcerpts += aExcerpts[i].excerpt + "\n\n";
}
var mExcerpts = new MarkOut(sExcerpts, sIndent, obj.req, aParms, obj.fDebug, fServerDebug);
var mExcerpts = new MarkOut(sExcerpts, sIndent, obj.req, aParms, obj.fDebug);
obj.aTokens[sToken] = mExcerpts.convertMD(" ").trim();
obj.replaceTokens();
}
@ -1222,7 +1241,8 @@ HTMLOut.prototype.getBlog = function(sToken, sIndent, aParms)
* Some wrinkles have been added to the above: getManifestXML() can alternatively call getMachineXML()
* with a specific machine XML file, which would have had the potential to bypass getReadMe() altogether, so
* getMachineXML() may now call getReadMe() -- which must NOT call getMachineXML() back whenever that happens.
*
*
* @this {HTMLOut}
* @param {string} sToken
* @param {string} [sIndent]
* @param {Array.<string>} [aParms]
@ -1240,6 +1260,7 @@ HTMLOut.prototype.getDefault = function(sToken, sIndent, aParms)
*
* If the HTML file specified by aParms[0] exists, insert its contents into the current HTML document.
*
* @this {HTMLOut}
* @param {string} sToken
* @param {string} [sIndent]
* @param {Array.<string>} [aParms]
@ -1280,6 +1301,7 @@ HTMLOut.prototype.getHTMLFile = function(sToken, sIndent, aParms)
*
* If "machine.xml" exists in the current directory, open it and determine if embedding it makes sense.
*
* @this {HTMLOut}
* @param {string} sToken
* @param {string} [sIndent]
* @param {Array.<string>|null} [aParms]
@ -1343,7 +1365,7 @@ HTMLOut.prototype.getMachineXML = function(sToken, sIndent, aParms, sXMLFile, sS
sMachineDef += (sStateFile? ":" + sStateFile : "");
s = '[Embedded ' + sMachineClass + '](' + sXMLFile + ' "' + sMachineDef + '")';
var m = new MarkOut(s, sIndent, obj.req, null, obj.fDebug, fServerDebug);
var m = new MarkOut(s, sIndent, obj.req, null, obj.fDebug);
s = m.convertMD(" ").trim();
obj.processMachines(m.getMachines(), function doneProcessXMLMachines() {
@ -1388,6 +1410,7 @@ HTMLOut.prototype.getMachineXML = function(sToken, sIndent, aParms, sXMLFile, sS
*
* If "manifest.xml" exists in the current directory, open it and embed it.
*
* @this {HTMLOut}
* @param {string} sToken
* @param {string} [sIndent]
* @param {Array.<string>} [aParms]
@ -1574,7 +1597,8 @@ HTMLOut.prototype.getManifestXML = function(sToken, sIndent, aParms)
* getReadMe(sToken, sIndent, aParms, sPrevious)
*
* If a "README.md" exists in the current directory, open it, convert it, and prepare for replacement.
*
*
* @this {HTMLOut}
* @param {string} sToken
* @param {string} [sIndent]
* @param {Array.<string>} [aParms]
@ -1607,7 +1631,7 @@ HTMLOut.prototype.getReadMe = function(sToken, sIndent, aParms, sPrevious)
obj.getMachineXML(sToken, sIndent); // we don't pass along aParms, because those are for Markdown files only
}
} else {
var m = new MarkOut(s, sIndent, obj.req, aParms, obj.fDebug, fServerDebug);
var m = new MarkOut(s, sIndent, obj.req, aParms, obj.fDebug);
s = m.convertMD(" ").trim();
/*
* If the Markdown document begins with a heading, stuff that into the <title> tag;
@ -1644,6 +1668,7 @@ HTMLOut.prototype.getReadMe = function(sToken, sIndent, aParms, sPrevious)
/**
* getSocketScripts(sToken, sIndent, aParms)
*
* @this {HTMLOut}
* @param {string} sToken
* @param {string} [sIndent]
* @param {Array.<string>} [aParms]
@ -1658,6 +1683,7 @@ HTMLOut.prototype.getSocketScripts = function(sToken, sIndent, aParms)
*
* Generate a random string of words, purely for entertainment purposes (eg, something in honor of "ADVENT").
*
* @this {HTMLOut}
* @param {string} [sIndent]
* @return {string}
*/
@ -1699,9 +1725,9 @@ HTMLOut.prototype.getRandomString = function(sIndent)
*
* Additional properties can include:
*
* 'compiled' (eg, true or false); if not defined, then we choose a value based on any Gort command,
* or failing that, the internal fServerDebug setting
* 'compiled' (eg, true or false); if not defined, we choose a value based on the module's fDebug setting
*
* @this {HTMLOut}
* @param {Array} aMachines is an array of objects containing information about each machine on the current page
* @param {function()} done
*/
@ -1785,6 +1811,7 @@ HTMLOut.prototype.processMachines = function(aMachines, done)
/**
* addFilesToHTML(asFiles)
*
* @this {HTMLOut}
* @param {Array.<string>} asFiles is a list of CSS and/or JS files to include in the HTML
* @param {string} [sScriptEmbed] is an optional script to embed in the <body> (after any JS files listed above)
*/
@ -1841,7 +1868,8 @@ HTMLOut.prototype.addFilesToHTML = function(asFiles, sScriptEmbed)
/**
* genOnClick(sURL)
*
*
* @this {HTMLOut}
* @param {string} sURL
* @param {string} [sFormat] (default is DumpAPI.FORMAT.IMG)
* @return {string}

View file

@ -93,10 +93,9 @@ var sDefaultFile = "./README.md";
* @param {string|null} [sIndent] sets the overall indentation of the document
* @param {Object} [req] is the web server's (ie, Express) request object, if any
* @param {Array.<string>|null} [aParms] is an array of overrides to use (see below)
* @param {boolean} [fDebug] turns on debugging features (eg, debug comments)
* @param {boolean} [fServerDebug] turns on server debug features (eg, special URL encoding rules)
* @param {boolean} [fDebug] turns on debugging features (eg, debug comments, special URL encodings, etc)
*/
function MarkOut(sMD, sIndent, req, aParms, fDebug, fServerDebug)
function MarkOut(sMD, sIndent, req, aParms, fDebug)
{
this.sMD = sMD;
this.sIndent = (sIndent || "");
@ -109,7 +108,6 @@ function MarkOut(sMD, sIndent, req, aParms, fDebug, fServerDebug)
this.sClassImageLabel = this.sClassImage + "-label";
}
this.fDebug = fDebug;
this.fServerDebug = fServerDebug;
this.sHTML = null;
this.aIDs = []; // this keeps tracks of auto-generated ID attributes for page elements, to insure uniqueness
this.aMachines = []; // this keeps tracks of embedded machines on the page
@ -242,6 +240,7 @@ MarkOut.setOptions = function(options)
* and make sure all the pre-requisites are in place (eg, CSS file and scripts in the HTML document's
* header).
*
* @this {MarkOut}
* @param {Object} infoMachine
*/
MarkOut.prototype.addMachine = function(infoMachine)
@ -252,6 +251,7 @@ MarkOut.prototype.addMachine = function(infoMachine)
/**
* getMachines()
*
* @this {MarkOut}
* @return {Array} of objects containing information about each machine defined by the document
*/
MarkOut.prototype.getMachines = function()
@ -266,7 +266,8 @@ MarkOut.prototype.getMachines = function()
* that's not a letter or a digit to a hyphen (-), and stripping all leading and trailing hyphens from
* the result. Furthermore, if the generated ID is not unique (among the set of ALL generated IDs),
* then no ID is produced.
*
*
* @this {MarkOut}
* @param {string} sText
* @returns {string|null} converts the given text to a unique ID (or null if resulting ID was not unique)
*/
@ -301,6 +302,7 @@ MarkOut.aHTMLEntities = {
/**
* convertMD()
*
* @this {MarkOut}
* @param {string} [sIndent] sets the indentation of HTML elements within the document
*/
MarkOut.prototype.convertMD = function(sIndent)
@ -414,6 +416,7 @@ MarkOut.prototype.convertMD = function(sIndent)
* If your text may contain some block markers (ie, double-linefeeds), or headers (either "Atx-style"
* or "Setext-style) that require the insertion of double-linefeed block markers, then call this function.
*
* @this {MarkOut}
* @param {string} sMD
* @param {string} [sIndent]
*/
@ -478,6 +481,7 @@ MarkOut.prototype.convertMDBlocks = function(sMD, sIndent)
/**
* convertMDBlock(sBlock, sIndent)
*
* @this {MarkOut}
* @param {string} sBlock
* @param {string} [sIndent]
*/
@ -623,6 +627,7 @@ MarkOut.prototype.convertMDBlock = function(sBlock, sIndent)
* Markdown apparently treats equivalently), I automatically use a list style that omits bullets.
* So, if you REALLY want bullets, use "-" or "+".
*
* @this {MarkOut}
* @param {string} sBlock
* @param {string} sIndent
* @return {string}
@ -688,6 +693,7 @@ MarkOut.prototype.convertMDList = function(sBlock, sIndent)
* galleries, which are nothing more than paragraphs containing a series of image links), so this
* code is disabled for now.
*
* @this {MarkOut}
* @param {string} s
* @return {string}
*/
@ -720,6 +726,7 @@ MarkOut.prototype.convertMDLines = function(s)
*
* TODO: Consider adding support for "reference"-style Markdown links.
*
* @this {MarkOut}
* @param {string} sBlock
* @return {string}
*/
@ -748,7 +755,7 @@ MarkOut.prototype.convertMDLinks = function(sBlock)
sType = "id"; // using the "name" attribute is deprecated as well
sURL = sURL.substr(1);
} else {
sURL = net.encodeURL(sURL, this.req, this.fServerDebug);
sURL = net.encodeURL(sURL, this.req, this.fDebug);
}
sBlock = str.replaceAll(aMatch[0], '<' + sTag + ' ' + sType + '="' + sURL + '"' + sTitle + '>' + sText + '</' + sTag + '>', sBlock);
}
@ -758,6 +765,7 @@ MarkOut.prototype.convertMDLinks = function(sBlock)
/**
* convertMDImageLinks(sBlock)
*
* @this {MarkOut}
* @param {string} sBlock
* @param {string} sIndent
* @return {string}
@ -778,7 +786,7 @@ MarkOut.prototype.convertMDImageLinks = function(sBlock, sIndent)
var sBlockOrig = sBlock;
var re = /!\[(.*?)\]\((.*?)(?:\s*"(.*?)"\)|\))/g;
while ((aMatch = re.exec(sBlockOrig))) {
var sImage = '<img src="' + net.encodeURL(aMatch[2], this.req, this.fServerDebug) + '" alt="' + aMatch[1] + '"';
var sImage = '<img src="' + net.encodeURL(aMatch[2], this.req, this.fDebug) + '" alt="' + aMatch[1] + '"';
if (aMatch[3]) {
/*
* The format of the special "link:" syntax is:
@ -814,10 +822,10 @@ MarkOut.prototype.convertMDImageLinks = function(sBlock, sIndent)
* The assumption here is that if we have "static" thumbs, then we should also have full "static"
* copies as well.
*/
if (aMatch[2].indexOf("static/") >= 0 && sURL.indexOf("://") > 0 && (this.fServerDebug || net.hasParm(net.REVEAL_COMMAND, net.REVEAL_PDFS, this.req))) {
if (aMatch[2].indexOf("static/") >= 0 && sURL.indexOf("://") > 0 && (this.fDebug || net.hasParm(net.REVEAL_COMMAND, net.REVEAL_PDFS, this.req))) {
sURL = aMatch[2].replace("/thumbs/", "/").replace(" 1.jpeg", ".pdf").replace(".jpg", ".pdf");
}
sURL = net.encodeURL(sURL, this.req, this.fServerDebug);
sURL = net.encodeURL(sURL, this.req, this.fDebug);
if (asParts[iPart] == "nogallery") {
fNoGallery = true;
iPart++;
@ -862,6 +870,7 @@ MarkOut.prototype.convertMDImageLinks = function(sBlock, sIndent)
/**
* convertMDMachineLinks(sBlock)
*
* @this {MarkOut}
* @param {string} sBlock
* @return {string}
*/
@ -992,6 +1001,7 @@ MarkOut.prototype.convertMDMachineLinks = function(sBlock)
* Also, for reasons noted in the code below, we don't support emphasis in the middle
* of words.
*
* @this {MarkOut}
* @param {string} sBlock
* @return {string}
*/
@ -1031,6 +1041,7 @@ MarkOut.prototype.convertMDEmphasis = function(sBlock)
/**
* addIndent(sIndent)
*
* @this {MarkOut}
* @param {string|undefined} sIndent
* @return {string} previous indent
*/
@ -1044,6 +1055,7 @@ MarkOut.prototype.addIndent = function(sIndent)
/**
* subIndent(sIndent)
*
* @this {MarkOut}
* @param {string|undefined} sIndent
*/
MarkOut.prototype.subIndent = function(sIndent)
@ -1064,6 +1076,7 @@ MarkOut.prototype.subIndent = function(sIndent)
* This is used purely (at the moment) for debugging purposes, so that we can clearly see
* what our simplistic Markdown parser is parsing at each stage.
*
* @this {MarkOut}
* @param {string} sLabel
* @param {string} sText
* @return {string}
@ -1080,6 +1093,7 @@ MarkOut.prototype.encodeComment = function(sLabel, sText)
* This is used purely (at the moment) for debugging purposes, so that we can clearly see
* what our simplistic Markdown parser is parsing at each stage.
*
* @this {MarkOut}
* @param {string} sText
* @return {string}
*

View file

@ -480,7 +480,7 @@ Bus.prototype.restoreMemory = function(a)
* configuration since it was last saved (the most likely explanation) or there's some internal
* inconsistency (eg, the block size is wrong).
*/
this.error("Unable to restore memory block " + iBlock);
Component.error("Unable to restore memory block " + iBlock);
return false;
}
}
@ -554,7 +554,7 @@ Bus.prototype.addPortInputNotify = function(start, end, component, fn)
if (fn !== undefined) {
for (var port = start; port <= end; port++) {
if (this.aPortInputNotify[port] !== undefined) {
this.warning("Input port " + str.toHexWord(port) + " registered by " + this.aPortInputNotify[port][0].id + ", ignoring " + component.id);
Component.warning("Input port " + str.toHexWord(port) + " registered by " + this.aPortInputNotify[port][0].id + ", ignoring " + component.id);
continue;
}
this.aPortInputNotify[port] = [component, fn, false, false];
@ -674,7 +674,7 @@ Bus.prototype.addPortOutputNotify = function(start, end, component, fn)
if (fn !== undefined) {
for (var port = start; port <= end; port++) {
if (this.aPortOutputNotify[port] !== undefined) {
this.warning("Output port " + str.toHexWord(port) + " registered by " + this.aPortOutputNotify[port][0].id + ", ignoring " + component.id);
Component.warning("Output port " + str.toHexWord(port) + " registered by " + this.aPortOutputNotify[port][0].id + ", ignoring " + component.id);
continue;
}
this.aPortOutputNotify[port] = [component, fn, false, false];
@ -764,7 +764,7 @@ Bus.prototype.removePortOutputNotify = function(start, end, component, fn)
*/
Bus.prototype.reportError = function(op, addr, size)
{
this.error("Memory block error (" + op + "," + str.toHex(addr) + "," + str.toHex(size) + ")");
Component.error("Memory block error (" + op + "," + str.toHex(addr) + "," + str.toHex(size) + ")");
return false;
};

View file

@ -157,12 +157,6 @@ function ChipSet(parmsChipSet)
* and (on the MODEL_5160) whether or not a coprocessor is installed. If no SW1 settings are provided,
* we look for individual 'fdrives' and 'monitor' settings and build a default SW1 value.
*
* TODO: Get rid of reliance on SW1 for MODEL_5170 and later; omitting it now results in a BIOS warning:
*
* ' 162-System Options Not Set-(Run SETUP)'
*
* ' (RESUME = "F1" KEY)'
*
* The defaults below select max memory, monochrome monitor (EGA monitor for MODEL_5170), and two floppies.
* Don't get too excited about "max memory" either: on a MODEL_5150, the max was 64Kb, and on a MODEL_5160,
* the max was 256Kb. However, the RAM component is free to install as much base memory as it likes,
@ -2566,14 +2560,14 @@ ChipSet.prototype.updateDMA = function(channel)
};
/**
* inPICL(iPIC, addrFrom)
* inPICLo(iPIC, addrFrom)
*
* @this {ChipSet}
* @param {number} iPIC
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
* @return {number} simulated port value
*/
ChipSet.prototype.inPICL = function(iPIC, addrFrom)
ChipSet.prototype.inPICLo = function(iPIC, addrFrom)
{
var b = 0;
var pic = this.aPICs[iPIC];
@ -2595,14 +2589,14 @@ ChipSet.prototype.inPICL = function(iPIC, addrFrom)
};
/**
* outPICL(iPIC, bOut, addrFrom)
* outPICLo(iPIC, bOut, addrFrom)
*
* @this {ChipSet}
* @param {number} iPIC
* @param {number} bOut
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
*/
ChipSet.prototype.outPICL = function(iPIC, bOut, addrFrom)
ChipSet.prototype.outPICLo = function(iPIC, bOut, addrFrom)
{
var pic = this.aPICs[iPIC];
this.messagePort(pic.port, bOut, addrFrom, "PIC" + iPIC, ChipSet.MESSAGE_PIC);
@ -2613,7 +2607,7 @@ ChipSet.prototype.outPICL = function(iPIC, bOut, addrFrom)
pic.nICW = 0;
pic.aICW[pic.nICW++] = bOut;
/*
* I used to do the rest of this initialization in outPICH(), once all the ICW commands had been received,
* I used to do the rest of this initialization in outPICHi(), once all the ICW commands had been received,
* but a closer reading of the 8259A spec indicates that that should happen now, on receipt on ICW1.
*
* Also, on p.10 of that spec, it says "The Interrupt Mask Register is cleared". I originally took that to
@ -2711,7 +2705,7 @@ ChipSet.prototype.outPICL = function(iPIC, bOut, addrFrom)
}
} else {
/*
* This must be an OCW3 request. If it's a "Read Register" command (PIC_LO.OCW3_READ_CMD), inPICL() will take care it.
* This must be an OCW3 request. If it's a "Read Register" command (PIC_LO.OCW3_READ_CMD), inPICLo() will take care it.
*
* TODO: If OCW3 specified a "Poll" command (PIC_LO.OCW3_POLL_CMD) or a "Special Mask Mode" command (PIC_LO.OCW3_SMM_CMD),
* that's unfortunate, because I don't support them yet.
@ -2724,14 +2718,14 @@ ChipSet.prototype.outPICL = function(iPIC, bOut, addrFrom)
};
/**
* inPICH(iPIC, addrFrom)
* inPICHi(iPIC, addrFrom)
*
* @this {ChipSet}
* @param {number} iPIC
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
* @return {number} simulated port value
*/
ChipSet.prototype.inPICH = function(iPIC, addrFrom)
ChipSet.prototype.inPICHi = function(iPIC, addrFrom)
{
var pic = this.aPICs[iPIC];
var b = pic.bIMR;
@ -2740,14 +2734,14 @@ ChipSet.prototype.inPICH = function(iPIC, addrFrom)
};
/**
* outPICH(iPIC, bOut, addrFrom)
* outPICHi(iPIC, bOut, addrFrom)
*
* @this {ChipSet}
* @param {number} iPIC
* @param {number} bOut
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
*/
ChipSet.prototype.outPICH = function(iPIC, bOut, addrFrom)
ChipSet.prototype.outPICHi = function(iPIC, bOut, addrFrom)
{
var pic = this.aPICs[iPIC];
this.messagePort(pic.port+1, bOut, addrFrom, "PIC" + iPIC, ChipSet.MESSAGE_PIC);
@ -4230,8 +4224,8 @@ ChipSet.aPortInput = {
0x06: /** @this {ChipSet} */ function(port, addrFrom) { return this.inDMAChannelAddr(ChipSet.DMA0.INDEX, 3, port, addrFrom); },
0x07: /** @this {ChipSet} */ function(port, addrFrom) { return this.inDMAChannelCount(ChipSet.DMA0.INDEX, 3, port, addrFrom); },
0x08: /** @this {ChipSet} */ function(port, addrFrom) { return this.inDMAStatus(ChipSet.DMA0.INDEX, port, addrFrom); },
0x20: /** @this {ChipSet} */ function(port, addrFrom) { return this.inPICL(ChipSet.PIC0.INDEX, addrFrom); },
0x21: /** @this {ChipSet} */ function(port, addrFrom) { return this.inPICH(ChipSet.PIC0.INDEX, addrFrom); },
0x20: /** @this {ChipSet} */ function(port, addrFrom) { return this.inPICLo(ChipSet.PIC0.INDEX, addrFrom); },
0x21: /** @this {ChipSet} */ function(port, addrFrom) { return this.inPICHi(ChipSet.PIC0.INDEX, addrFrom); },
0x40: /** @this {ChipSet} */ function(port, addrFrom) { return this.inTimer(ChipSet.TIMER0.INDEX, addrFrom); },
0x41: /** @this {ChipSet} */ function(port, addrFrom) { return this.inTimer(ChipSet.TIMER1.INDEX, addrFrom); },
0x42: /** @this {ChipSet} */ function(port, addrFrom) { return this.inTimer(ChipSet.TIMER2.INDEX, addrFrom); },
@ -4267,8 +4261,8 @@ ChipSet.aPortInput5170 = {
0x8D: /** @this {ChipSet} */ function(port, addrFrom) { return this.inDMAPageSpare(5, port, addrFrom); },
0x8E: /** @this {ChipSet} */ function(port, addrFrom) { return this.inDMAPageSpare(6, port, addrFrom); },
0x8F: /** @this {ChipSet} */ function(port, addrFrom) { return this.inDMAPageReg(ChipSet.DMA1.INDEX, 0, port, addrFrom); },
0xA0: /** @this {ChipSet} */ function(port, addrFrom) { return this.inPICL(ChipSet.PIC1.INDEX, addrFrom); },
0xA1: /** @this {ChipSet} */ function(port, addrFrom) { return this.inPICH(ChipSet.PIC1.INDEX, addrFrom); },
0xA0: /** @this {ChipSet} */ function(port, addrFrom) { return this.inPICLo(ChipSet.PIC1.INDEX, addrFrom); },
0xA1: /** @this {ChipSet} */ function(port, addrFrom) { return this.inPICHi(ChipSet.PIC1.INDEX, addrFrom); },
0xC0: /** @this {ChipSet} */ function(port, addrFrom) { return this.inDMAChannelAddr(ChipSet.DMA1.INDEX, 0, port, addrFrom); },
0xC2: /** @this {ChipSet} */ function(port, addrFrom) { return this.inDMAChannelCount(ChipSet.DMA1.INDEX, 0, port, addrFrom); },
0xC4: /** @this {ChipSet} */ function(port, addrFrom) { return this.inDMAChannelAddr(ChipSet.DMA1.INDEX, 1, port, addrFrom); },
@ -4298,8 +4292,8 @@ ChipSet.aPortOutput = {
0x0B: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAMode(ChipSet.DMA0.INDEX, port, bOut, addrFrom); },
0x0C: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAIndex(ChipSet.DMA0.INDEX, port, bOut, addrFrom); },
0x0D: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAClear(ChipSet.DMA0.INDEX, port, bOut, addrFrom); },
0x20: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outPICL(ChipSet.PIC0.INDEX, bOut, addrFrom); },
0x21: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outPICH(ChipSet.PIC0.INDEX, bOut, addrFrom); },
0x20: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outPICLo(ChipSet.PIC0.INDEX, bOut, addrFrom); },
0x21: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outPICHi(ChipSet.PIC0.INDEX, bOut, addrFrom); },
0x40: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outTimer(ChipSet.TIMER0.INDEX, bOut, addrFrom); },
0x41: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outTimer(ChipSet.TIMER1.INDEX, bOut, addrFrom); },
0x42: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outTimer(ChipSet.TIMER2.INDEX, bOut, addrFrom); },
@ -4336,8 +4330,8 @@ ChipSet.aPortOutput5170 = {
0x8D: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAPageSpare(5, port, bOut, addrFrom); },
0x8E: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAPageSpare(6, port, bOut, addrFrom); },
0x8F: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAPageReg(ChipSet.DMA1.INDEX, 0, port, bOut, addrFrom); },
0xA0: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outPICL(ChipSet.PIC1.INDEX, bOut, addrFrom); },
0xA1: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outPICH(ChipSet.PIC1.INDEX, bOut, addrFrom); },
0xA0: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outPICLo(ChipSet.PIC1.INDEX, bOut, addrFrom); },
0xA1: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outPICHi(ChipSet.PIC1.INDEX, bOut, addrFrom); },
0xC0: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAChannelAddr(ChipSet.DMA1.INDEX, 0, port, bOut, addrFrom); },
0xC2: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAChannelCount(ChipSet.DMA1.INDEX, 0, port, bOut, addrFrom); },
0xC4: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAChannelAddr(ChipSet.DMA1.INDEX, 1, port, bOut, addrFrom); },

View file

@ -139,15 +139,15 @@ function Computer(parmsComputer, parmsMachine, fSuspended) {
this.sUserID = this.queryUserID();
/*
* Find the appropriate CPU (and the Debugger, if any)
* Find the appropriate CPU (and Debugger and Control Panel, if any)
*/
this.cpu = Component.getComponentByType("CPU", this.id);
if (!this.cpu) {
Component.error("Unable to find CPU component");
return;
}
this.dbg = Component.getComponentByType("Debugger", this.id);
this.panel = Component.getComponentByType("Panel", this.id);
/*
* Initialize the Bus component
@ -160,6 +160,20 @@ function Computer(parmsComputer, parmsMachine, fSuspended) {
var aComponents = Component.getComponents(this.id);
for (var iComponent = 0; iComponent < aComponents.length; iComponent++) {
var component = aComponents[iComponent];
/*
* I can think of many "cleaner" ways for the Control Panel component to pass its
* notice(), println(), etc, overrides on to all the other components, but it's just
* too darn convenient to slam those overrides into the components directly.
*
* Adding more initBus() parameters was another option, but that function is already
* looking a bit unwieldy, and Control Panel functionality is a little far afield
* from Bus initialization.
*/
if (this.panel && this.panel.controlPrint) {
component.notice = this.panel.notice;
component.println = this.panel.println;
component.controlPrint = this.panel.controlPrint;
}
if (component.initBus) component.initBus(this, this.bus, this.cpu, this.dbg);
}
@ -557,7 +571,7 @@ Computer.prototype.powerRestore = function(component, stateComputer, fRepower, f
*/
if (!component.powerUp(data, fRepower)) {
if (data) {
this.error("Unable to restore state for " + component.type);
Component.error("Unable to restore state for " + component.type);
/*
* If this is a resume error for a machine that also has a predefined state
* AND we're not restoring from that state, then throw away the current state,
@ -1179,6 +1193,7 @@ Computer.init = function()
var eComputer = aeComputers[iComputer];
var parmsComputer = Component.getComponentParms(eComputer);
/*
* We set fSuspended in the Computer constructor because we want to "power up" the
* computer ourselves, after any/all bindings are in place.

View file

@ -254,11 +254,15 @@ CPU.prototype.powerUp = function(data, fRepower)
this.dbg.init();
} else {
/*
* TODO: Once we get rid of those nasty Component method overrides, this test will have to be revised as well
* The Computer (this.cmp) knows if there's a Control Panel (this.cmp.panel), and the Control Panel
* knows if there's a "print" control (this.cmp.panel.controlPrint), and if there IS a "print" control
* but no debugger, the machine is probably misconfigured (most likely, the page simply neglected to
* load the Debugger component).
*
* However, we don't actually need to check all that; it's always safe use println(), regardless whether
* a Control Panel with a "print" control is present or not.
*/
if (Component.controlPrint) {
this.warning("No debugger detected");
}
this.println("No debugger detected");
}
}
this.fPowered = true;

View file

@ -1,5 +1,5 @@
/**
* @fileoverview Implements the PCjs Debugger component.
* @fileoverview Implements the PCjs Debugger component.
* @author <a href="mailto:Jeff@pcjs.org">Jeff Parsons</a>
* @version 1.0
* @suppress {missingProperties}
@ -1562,7 +1562,7 @@ if (DEBUGGER) {
*/
if (fUpdateCPU !== false) this.cpu.updateCPU();
this.updateStatus(fRegs, false);
this.updateStatus(fRegs || false, false);
return (this.nCycles > 0);
};
@ -2846,8 +2846,8 @@ if (DEBUGGER) {
value = this.cpu.segSS.sel;
break;
/*
* I used to alias "PC" to "IP", until I discovered that early (perhaps even ALL?) versions of DEBUG
* treat "PC" as an alias for the 16-bit flags register. TODO: Add support for "PC" that matches DEBUG.
* I used to alias "PC" to "IP", until I discovered that early (perhaps even ALL?) versions of DEBUG.COM
* treat "PC" as an alias for the 16-bit flags register. TODO: Add support for "PC".
*/
case "IP":
value = this.cpu.regIP;
@ -3283,9 +3283,10 @@ if (DEBUGGER) {
*/
Debugger.prototype.doClear = function(sCmd)
{
if (Component.controlPrint) {
Component.controlPrint.value = "";
}
/*
* TODO: There should be a clear() component method that the Control Panel overrides to perform this function.
*/
if (this.controlPrint) this.controlPrint.value = "";
};
/**
@ -4275,7 +4276,7 @@ if (DEBUGGER) {
/*
* Limiting the amount of disassembled code to 256 bytes in non-DEBUG builds is partly to
* prevent the user from wedging the browser by dumping too many lines, but also a recognition
* that, in non-DEBUG builds, Component.println() keeps print output buffer truncated to 8Kb anyway.
* that, in non-DEBUG builds, this.println() keeps print output buffer truncated to 8Kb anyway.
*/
this.println("range too large");
return;

View file

@ -613,10 +613,10 @@ Disk.prototype.onLoadDisk = function(sDiskFile, sDiskData, nErrorCode, sDiskPath
}
if (!aDiskData.length) {
this.error("Empty disk image: " + this.sDiskName);
Component.error("Empty disk image: " + this.sDiskName);
}
else if (aDiskData.length == 1) {
this.error(aDiskData[0]);
Component.error(aDiskData[0]);
}
/*
* aDiskData is an array of cylinders, each of which is an array of heads, each of which
@ -731,7 +731,7 @@ Disk.prototype.onLoadDisk = function(sDiskFile, sDiskData, nErrorCode, sDiskPath
disk = this;
}
} catch (e) {
this.error("Disk image error: " + e.message);
Component.error("Disk image error: " + e.message);
}
}
if (this.fnNotify) {

View file

@ -153,7 +153,7 @@ function FDC(parmsFDC) {
*/
this.pAutoMount = eval("(" + parmsFDC['autoMount'] + ")");
} catch (e) {
this.error("FDC auto-mount error: " + e.message + " (" + parmsFDC['autoMount'] + ")");
Component.error("FDC auto-mount error: " + e.message + " (" + parmsFDC['autoMount'] + ")");
this.pAutoMount = null;
}
}
@ -395,7 +395,7 @@ FDC.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, control)
try {
dataValue = eval("({" + sValue + "})");
} catch (e) {
fdc.error("FDC option error: " + (e.message || e));
Component.error("FDC option error: " + (e.message || e));
}
}
var sDesc = dataValue['desc'];
@ -744,6 +744,10 @@ FDC.prototype.saveController = function()
/**
* initDrive(drive, iDrive, data)
*
* TODO: Consider a separate Drive class that both FDC and HDC can use, since there's a lot of commonality
* between the drive objects created by both controllers. This will clean up overall drive management and allow
* us to factor out some common Drive methods (eg, advanceSector()).
*
* @this {FDC}
* @param {Object} drive
@ -1933,8 +1937,7 @@ FDC.prototype.doFormat = function(drive)
* NOTE: Since the FDC isn't aware of the extent of the transfer, all readByte() can do is return bytes
* until the current track (or, in the case of a multi-track request, the current cylinder) has been exhausted.
*
* TODO: Research the requirements, if any, for multi-track I/O and determine what if anything needs to be
* done. At the very least, if it must be supported, there would need to be some head-incrementing somewhere.
* TODO: Research the requirements, if any, for multi-track I/O and determine what else needs to be done.
*
* @this {FDC}
* @param {Object} drive
@ -1958,7 +1961,11 @@ FDC.prototype.readByte = function(drive, done)
break;
}
drive.ibSector = 0;
drive.bSector++;
/*
* 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.
*/
this.advanceSector(drive);
} while (true);
}
done(b, false);
@ -1981,8 +1988,7 @@ FDC.prototype.readByte = function(drive, done)
* NOTE: Since the FDC isn't aware of the extent of the transfer, all writeByte() can do is accept bytes
* until the current track (or, in the case of a multi-track request, the current cylinder) has been exhausted.
*
* TODO: Research the requirements, if any, for multi-track I/O and determine what if anything needs to be
* done. At the very least, if it must be supported, there would need to be some head-incrementing somewhere.
* TODO: Research the requirements, if any, for multi-track I/O and determine what else needs to be done.
*
* @this {FDC}
* @param {Object} drive
@ -2010,11 +2016,40 @@ FDC.prototype.writeByte = function(drive, b)
break;
}
drive.ibSector = 0;
drive.bSector++;
/*
* We "pre-advance" bSector et al now, instead of waiting to advance it right before the seek().
* This allows the initial call to writeByte() to perform a seek without triggering an unwanted advance.
*/
this.advanceSector(drive);
} while (true);
return b;
};
/**
* advanceSector(drive)
*
* This increments the sector number; when the sector number reaches drive.nSectors on the current track, we
* increment drive.bHead and reset drive.bSector, and when drive.bHead reaches drive.nHeads, we reset drive.bHead
* and increment drive.bCylinder.
*
* @this {FDC}
* @param {Object} drive
*/
FDC.prototype.advanceSector = function(drive)
{
Component.assert(drive.bCylinder < drive.nCylinders);
drive.bSector++;
var bSectorStart = 1;
if (drive.bSector >= drive.nSectors + bSectorStart) {
drive.bSector = bSectorStart;
drive.bHead++;
if (drive.bHead >= drive.nHeads) {
drive.bHead = 0;
drive.bCylinder++;
}
}
};
/**
* writeFormat(drive, b)
*
@ -2085,9 +2120,9 @@ FDC.prototype.intBIOSDiskette = function(addr)
var DL = this.cpu.regDX & 0xff;
var DH = this.cpu.regDX >> 8;
if (this.dbg && this.dbg.messageEnabled(this.dbg.MESSAGE_FDC) && DL < 0x80) {
this.dbg.message("FDC.intBIOS(AH=" + str.toHexByte(AH) + ",D=" + str.toHexByte(DL) + ",C=" + str.toHexByte(CH) + ",H=" + str.toHexByte(DH) + ",S=" + str.toHexByte(CL) + ",N=" + str.toHexByte(AL) + ") at " + str.toHexAddr(addr - this.cpu.segCS.base, this.cpu.segCS.sel));
this.dbg.message("\nFDC.intBIOS(AH=" + str.toHexByte(AH) + ",D=" + str.toHexByte(DL) + ",C=" + str.toHexByte(CH) + ",H=" + str.toHexByte(DH) + ",S=" + str.toHexByte(CL) + ",N=" + str.toHexByte(AL) + ") at " + str.toHexAddr(addr - this.cpu.segCS.base, this.cpu.segCS.sel));
// this.cpu.haltCPU();
this.cpu.addInterruptReturn(addr, function (fdc, nCycles) {
this.cpu.addInterruptReturn(addr, function(fdc, nCycles) {
return function onBIOSDisketteReturn(nLevel) {
nCycles = fdc.cpu.getCycles() - nCycles;
fdc.messageDebugger("FDC.intBIOS(" + nLevel + "): C=" + (fdc.cpu.getCF()? 1 : 0) + " (cycles=" + nCycles + ")");

File diff suppressed because it is too large Load diff

View file

@ -74,8 +74,8 @@ if (typeof module !== 'undefined') {
* supported in theory, but in practice, they're not.
*
* NOTE: Since Memory blocks are low-level objects that have no UI requirements, they do not
* inherit from the Component class; so, if you want to use print(), for example, you must
* rely on class methods like Component.println() rather than object methods like this.println().
* inherit from the Component class; so, if you want to use println(), for example, you must
* use the methods in the Debugger class.
*
* Because Memory blocks now allow us to have a "sparse" address space, we could choose to
* take the memory hit of allocating 4K arrays per block, where each element stores only one byte,
@ -160,10 +160,6 @@ Memory.prototype = {
* @return {number}
*/
readNone: function(off) {
/*
* This can happen so frequently that the browser can't come up for air, so it's best to do this only under special circumstances...
*/
// if (DEBUG) Component.println("readNone(" + str.toHexWord(this.addr + off) + ")");
return 0;
},
/**
@ -174,10 +170,6 @@ Memory.prototype = {
* @param {number} v (could be either a byte or word value, since we use the same handler for both kinds of accesses)
*/
writeNone: function(off, v) {
/*
* This can happen so frequently that the browser can't come up for air, so it's best to do this only under special circumstances...
*/
// if (DEBUG) Component.println("writeNone(" + str.toHexWord(this.addr + off) + "): " + str.toHexWord(v));
},
/**
* readByteTArray(off)
@ -537,13 +529,13 @@ Memory.prototype = {
if (this.cReadBreakpoints++ === 0) {
this.setReadAccess(Memory.afnVerify);
}
if (DEBUG) Component.println("read breakpoint added to memory block " + str.toHex(this.addr));
if (DEBUG) this.dbg.println("read breakpoint added to memory block " + str.toHex(this.addr));
}
else {
if (this.cWriteBreakpoints++ === 0) {
this.setWriteAccess(Memory.afnVerify);
}
if (DEBUG) Component.println("write breakpoint added to memory block " + str.toHex(this.addr));
if (DEBUG) this.dbg.println("write breakpoint added to memory block " + str.toHex(this.addr));
}
}
},
@ -559,14 +551,14 @@ Memory.prototype = {
if (!fWrite) {
if (--this.cReadBreakpoints === 0) {
this.resetReadAccess();
if (DEBUG) Component.println("all read breakpoints removed from memory block " + str.toHex(this.addr));
if (DEBUG) this.dbg.println("all read breakpoints removed from memory block " + str.toHex(this.addr));
}
Component.assert(this.cReadBreakpoints >= 0);
}
else {
if (--this.cWriteBreakpoints === 0) {
this.resetWriteAccess();
if (DEBUG) Component.println("all write breakpoints removed from memory block " + str.toHex(this.addr));
if (DEBUG) this.dbg.println("all write breakpoints removed from memory block " + str.toHex(this.addr));
}
Component.assert(this.cWriteBreakpoints >= 0);
}

View file

@ -228,7 +228,7 @@ Mouse.prototype.powerUp = function(data, fRepower) {
var componentScreen = this.cmp.getComponentByType("Video");
if (componentScreen) this.canvasScreen = componentScreen.getCanvas();
} else {
this.warning(this.id + ": " + this.sAdapterType + " " + this.idAdapter + " unavailable");
Component.warning(this.id + ": " + this.sAdapterType + " " + this.idAdapter + " unavailable");
}
}
if (this.fActive) {

View file

@ -67,7 +67,8 @@ Component.subclass(Component, Panel);
* @param {Object} control is the HTML control DOM object (eg, HTMLButtonElement)
* @return {boolean} true if binding was successful, false if unrecognized binding request
*/
Panel.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, control) {
Panel.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, control)
{
if (this.cmp && this.cmp.setBinding(sHTMLClass, sHTMLType, sBinding, control)) return true;
if (this.cpu && this.cpu.setBinding(sHTMLClass, sHTMLType, sBinding, control)) return true;
if (this.kbd && this.kbd.setBinding(sHTMLClass, sHTMLType, sBinding, control)) return true;
@ -84,7 +85,8 @@ Panel.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, control)
* @param {X86CPU} cpu
* @param {Debugger} dbg
*/
Panel.prototype.initBus = function(cmp, bus, cpu, dbg) {
Panel.prototype.initBus = function(cmp, bus, cpu, dbg)
{
this.cmp = cmp;
this.cpu = cpu;
this.dbg = dbg;
@ -99,7 +101,8 @@ Panel.prototype.initBus = function(cmp, bus, cpu, dbg) {
* @param {boolean} [fRepower]
* @return {boolean} true if successful, false if failure
*/
Panel.prototype.powerUp = function(data, fRepower) {
Panel.prototype.powerUp = function(data, fRepower)
{
if (!fRepower) {
Panel.init();
}
@ -113,7 +116,8 @@ Panel.prototype.powerUp = function(data, fRepower) {
* @param {boolean} fSave
* @return {Object|boolean}
*/
Panel.prototype.powerDown = function(fSave) {
Panel.prototype.powerDown = function(fSave)
{
return true;
};

View file

@ -182,7 +182,7 @@ RAM.prototype.reset = function() {
}
if (this.chipset) this.chipset.addCMOSMemory(this.addrRAM, this.sizeRAM);
} else {
this.error("No RAM allocated");
Component.error("No RAM allocated");
}
};

View file

@ -221,11 +221,11 @@ ROM.prototype.onLoadROM = function(sROMFile, sROMData, nErrorCode)
this.aSymbols = rom['symbols'];
if (!this.abROM.length) {
this.error("Empty ROM: " + sROMFile);
Component.error("Empty ROM: " + sROMFile);
return;
}
else if (this.abROM.length == 1) {
this.error(this.abROM[0]);
Component.error(this.abROM[0]);
return;
}
} catch (e) {

View file

@ -2478,11 +2478,11 @@ Video.prototype.onLoadSetFonts = function(sFontFile, sFontData, nErrorCode)
var abFontData = eval("(" + sFontData + ")");
if (!abFontData.length) {
this.error("Empty font ROM image: " + sFontFile);
Component.error("Empty font ROM image: " + sFontFile);
return;
}
else if (abFontData.length == 1) {
this.error(abFontData[0]);
Component.error(abFontData[0]);
return;
}
/*

View file

@ -37,15 +37,15 @@ var X86 = {
/*
* CPU model numbers
*/
MODEL_8086: 8086,
MODEL_8088: 8088,
MODEL_80186: 80186,
MODEL_80188: 80188,
MODEL_80286: 80286,
MODEL_8086: 8086,
MODEL_8088: 8088,
MODEL_80186: 80186,
MODEL_80188: 80188,
MODEL_80286: 80286,
/*
* Processor Status flag definitions (stored in regPS)
*/
PS: {
PS: {
CF: 0x0001, // bit 0: Carry flag
BIT1: 0x0002, // bit 1: reserved, always set
PF: 0x0004, // bit 2: Parity flag
@ -124,23 +124,23 @@ var X86 = {
},
/*
* Processor Exception Interrupts
*
*
* Of the following exceptions, all are designed to be restartable, except for 0x08 and 0x09 (and 0x0D
* after an attempt to write to a read-only segment).
*
*
* Error codes are pushed onto the stack for 0x08 (always 0) and 0x0A through 0x0D.
*
*
* Priority: Instruction exception, TRAP, NMI, Processor Extension Segment Overrun, and finally INTR.
*
*
* All exceptions can also occur in real-mode, except where noted. A GP_FAULT in real-mode can be triggered
* by "any memory reference instruction that attempts to reference [a] 16-bit word at offset 0FFFFH".
*
* Interrupts beyond 0x10 (up through 0x1F) are reserved for future exceptions.
*
*
* Implementation Detail: For any opcode we know must generate a UD_FAULT interrupt, we invoke opInvalid().
* We reserve the term "undefined" for opcodes that require further investigation, and we invoke opUndefined()
* in those cases until an opcode's behavior has been defined; at that point, it's either valid or invalid.
*
*
* As for "illegal", that's a silly (and redundant) term in this context, so we don't use it. Similarly,
* the term "undocumented" should be limited to operations that are valid but that Intel did not document.
*/
@ -195,7 +195,7 @@ var X86 = {
/*
* Bit values for opFlags, which are all reset to zero prior to each instruction
*/
OPFLAG: {
OPFLAG: {
NOREAD: 0x0001,
NOWRITE: 0x0002,
NOINTR: 0x0004, // indicates a segreg has been set, or a prefix, or an STI (delay INTR acknowledgement)
@ -221,9 +221,9 @@ var X86 = {
*/
OPCODE: {
ES: 0x26, // opES()
CS: 0x2E, // opCS()
SS: 0x36, // opSS()
DS: 0x3E, // opDS()
CS: 0x2E, // opCS()
SS: 0x36, // opSS()
DS: 0x3E, // opDS()
PUSHSP: 0x54,
PUSHA: 0x60,
POPA: 0x61,
@ -239,31 +239,31 @@ var X86 = {
OUTSW: 0x6F,
ENTER: 0xC8,
LEAVE: 0xC9,
CALLF: 0x9A, // opCALLf()
MOVSB: 0xA4, // opMOVSb()
MOVSW: 0xA5, // opMOVSw()
CMPSB: 0xA6,
CMPSW: 0xA7,
STOSB: 0xAA,
STOSW: 0xAB,
LODSB: 0xAC,
LODSW: 0xAD,
SCASB: 0xAE,
SCASW: 0xAF,
INT3: 0xCC,
INTn: 0xCD,
INTO: 0xCE,
CALLF: 0x9A, // opCALLf()
MOVSB: 0xA4, // opMOVSb()
MOVSW: 0xA5, // opMOVSw()
CMPSB: 0xA6,
CMPSW: 0xA7,
STOSB: 0xAA,
STOSW: 0xAB,
LODSB: 0xAC,
LODSW: 0xAD,
SCASB: 0xAE,
SCASW: 0xAF,
INT3: 0xCC,
INTn: 0xCD,
INTO: 0xCE,
LOOPNZ: 0xE0,
LOOPZ: 0xE1,
LOOP: 0xE2,
CALL: 0xE8,
CALL: 0xE8,
JMP: 0xE9, // JMP opcode (2-byte displacement)
JMPS: 0xEB, // JMP opcode (1-byte displacement)
LOCK: 0xF0,
REPNZ: 0xF2,
REPZ: 0xF3,
CALLW: 0x10FF,
CALLDW: 0x18FF,
LOCK: 0xF0,
REPNZ: 0xF2,
REPZ: 0xF3,
CALLW: 0x10FF,
CALLDW: 0x18FF,
UD2: 0x0B0F // UD2 (invalid opcode guaranteed to generate UD_FAULT on all post-8086 processors)
}
};
@ -288,9 +288,9 @@ X86.PS.SET = (X86.PS.BIT1 | X86.PS.IOPL | X86.PS.NT | X86.PS.BIT15);
/*
* getPS() brings all the direct and indirect flags together, and setPS() performs the
* reverse, setting all the corresponding "result registers" to match the indirect flags.
*
*
* These "result registers" are created/reset by an initial call to setPS(0); they include:
*
*
* this.resultSize (must be set to one of: SIZE_BYTE or SIZE_WORD)
* this.resultValue
* this.resultParitySign

View file

@ -122,21 +122,20 @@ function X86CPU(parmsCPU) {
* "INT 0x00" generated by a divide-by-zero or any other kind of interrupt (nor any interrupt simulated
* with "PUSHF/CALLF").
*
* aInterruptReturn is a stack of return address notifications set up by software interrupt notification
* aInterruptReturn is a hash of return address notifications set up by software interrupt notification
* functions that want to receive return notifications. A software interrupt function must call
* cpu.addInterruptReturn(fn).
*
* WARNING: There's no specific mechanism in place to insure that software interrupt return notifications
* don't get "orphaned" and stack up if an interrupt handler bypasses the normal return path (INT 0x24 is
* one example of an "evil" software interrupt). So use this feature sparingly, avoid "evil" software
* interrupts, and/or add a mechanism to detect and clean up orphans.
* WARNING: There's no mechanism in place to insure that software interrupt return notifications don't
* get "orphaned" if an interrupt handler bypasses the normal return path (INT 0x24 is one example of an
* "evil" software interrupt).
*/
this.aInterruptNotify = [];
this.aInterruptReturn = [];
/*
* Since aReturnNotify is a "sparse array", this global count gives the CPU a quick way of knowing whether
* or not RETF or IRET instructions need to bother checking the array.
* or not RETF or IRET instructions need to bother calling checkInterruptReturn().
*/
this.cInterruptReturn = 0;
@ -931,27 +930,27 @@ X86CPU.prototype.checkInterruptNotify = function(nInt)
X86CPU.prototype.addInterruptReturn = function(addr, fn)
{
if (fn !== undefined) {
if (this.aInterruptReturn[addr] === undefined)
this.aInterruptReturn[addr] = [];
this.aInterruptReturn[addr].push(fn);
this.cInterruptReturn++;
if (this.aInterruptReturn[addr] == null) {
this.cInterruptReturn++;
}
this.aInterruptReturn[addr] = fn;
}
};
/**
* checkInterruptReturn(addr)
*
* It is expected (though not required) that callers will check cInterruptReturn and avoid calling
* this function if the count is zero.
*
* @this {X86CPU}
* @param {number} addr is a physical (non-segmented) address
*/
X86CPU.prototype.checkInterruptReturn = function(addr)
{
var aNotify = this.aInterruptReturn[addr];
if (aNotify !== undefined) {
while (aNotify.length > 0) {
var fn = aNotify.pop();
fn(--this.cInterruptReturn);
}
var fn = this.aInterruptReturn[addr];
if (fn != null) {
fn(--this.cInterruptReturn);
delete this.aInterruptReturn[addr];
}
};

View file

@ -2329,8 +2329,8 @@ var X86OpXX = {
}
if (nReps--) {
/*
* NOTE: Storing a word imposes another 4-cycle penalty on the 8088, so consider that if you think the
* cycle times here are too high.
* NOTE: Storing a word imposes another 4-cycle penalty on the 8088, so consider that
* if you think the cycle times here are too high.
*/
this.setSOWord(this.segES, this.regDI, this.regAX);
this.regDI = (this.regDI + ((this.regPS & X86.PS.DF)? -2 : 2)) & 0xffff;

View file

@ -118,8 +118,8 @@ X86Seg.loadProt = function loadProt(sel, fSuppress)
/*
* TODO: This is only the first of many steps toward accurately counting cycles in protected mode;
* I simply noticed that "POP segreg" takes 5 cycles in real mode and 20 in protected mode, so I'm
* starting with a 15-cycle penalty. Obviously the penalty will be much greater when the load fails.
* 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;

View file

@ -14,7 +14,7 @@ global *Buffer* object, as indicated by:
/* global Buffer: false */
And [weblib.js](weblib.js) is appropriate only for client modules, because it contains code that relies on the
brower's global *window* object, as indicated by:
browser's global *window* object, as indicated by:
/* global window: true */
@ -25,4 +25,4 @@ when running within Node, allowing any other code to test the existence of *wind
instead of:
if (typeof window !== 'undefined') {...}
if (typeof window !== "undefined") {...}

View file

@ -114,6 +114,7 @@ function Component(type, parms, constructor)
*
if (this.initStep) this.initStep(parms);
*/
this.fnReady = null;
this.fReady = false;
this.fBusy = this.fBusyCancel = false;
@ -244,12 +245,14 @@ Component.add = function(component)
Component.log = function(s, type)
{
if (DEBUG) {
var msElapsed, sMsg = (type? (type + ": ") : "") + (s || "");
if (Component.msStart === undefined) {
Component.msStart = usr.getTime();
if (s) {
var msElapsed, sMsg = (type? (type + ": ") : "") + s;
if (Component.msStart === undefined) {
Component.msStart = usr.getTime();
}
msElapsed = usr.getTime() - Component.msStart;
console.log(msElapsed + "ms: " + sMsg.replace(/\n/g, " "));
}
msElapsed = usr.getTime() - Component.msStart;
console.log(sMsg? (msElapsed + "ms: " + sMsg.replace(/\n/g, " ")) : "");
}
};
@ -266,13 +269,10 @@ Component.assert = function(f, s)
{
if (DEBUG) {
if (!f) {
if (!s) {
/*
* TODO: An accompanying source file/line number/function call would be nice, if there was a browser-independent way....
*/
s = "assertion failure";
}
Component.log(s);
/*
* TODO: An accompanying source file/line number/function call would be nice, if there was a browser-independent way....
*/
Component.log(s || "assertion failure");
throw new Error(s);
}
}
@ -363,7 +363,7 @@ Component.getComponents = function(idRelated)
if ((i = idRelated.indexOf('.')) > 0)
idRelated = idRelated.substr(0, i + 1);
else
idRelated = undefined;
idRelated = "";
}
for (i = 0; i < Component.all.length; i++) {
var component = Component.all[i];
@ -427,7 +427,7 @@ Component.getComponentByType = function(sType, idRelated, componentPrev)
if ((i = idRelated.indexOf('.')) > 0) {
idRelated = idRelated.substr(0, i + 1);
} else {
idRelated = undefined;
idRelated = "";
}
}
for (i = 0; i < Component.all.length; i++) {
@ -605,10 +605,7 @@ Component.prototype = {
/**
* setBinding(sHTMLClass, sHTMLType, sBinding, control)
*
* Component's setBinding() method is intended to be overridden by subclasses. The only
* exception is the Panel component, which passes two special bindings ("clear" and "print")
* back to us if no one else accepted them, so that we can redirect all println() requests
* to those controls.
* Component's setBinding() method is intended to be overridden by subclasses.
*
* @this {Component}
* @param {string|null} sHTMLClass is the class of the HTML control (eg, "input", "output")
@ -619,67 +616,63 @@ Component.prototype = {
*/
setBinding: function(sHTMLClass, sHTMLType, sBinding, control) {
switch (sBinding) {
case "clear":
if (!this.bindings[sBinding]) {
this.bindings[sBinding] = control;
control.onclick = (function(component) {
return function() {
if (component.bindings['print']) {
component.bindings['print'].value = "";
}
};
}(this));
}
return true;
case "print":
if (!this.bindings[sBinding]) {
this.bindings[sBinding] = control;
control.value = ""; // this was added for Firefox (Safari automatically clears the <textarea> on a page reload, but Firefox does not)
/*
* TODO: Get rid of these Component method overrides, because they're going to cause issues
* if the day ever comes (and it WILL) that we want multiple machines on a single page with their
* own Control Panels.
*/
Component.println = (function(control) {
return function printControl(s, type) {
s = (type !== undefined? (type + ": ") : "") + (s || "");
if (!DEBUG) { // in non-DEBUG builds, prevent the <textarea> from getting too large, otherwise printing becomes slower and slower
if (control.value.length > 8192) {
control.value = control.value.substr(control.value.length - 4096);
}
}
control.value += s + "\n";
control.scrollTop = control.scrollHeight;
if (DEBUG) console.log(s);
};
}(control));
/*
* Override Component.notice() with a replacement function that eliminates the web.alertUser() call
*/
Component.notice = function(s, fPrintOnly, id) {
Component.println(s, "notice", id);
case "clear":
if (!this.bindings[sBinding]) {
this.bindings[sBinding] = control;
control.onclick = (function(component) {
return function clearPanel() {
if (component.bindings['print']) {
component.bindings['print'].value = "";
}
};
/*
* HACK: Save this particular HTML element so that the Debugger can access it, too
*/
Component.controlPrint = control;
}
return true;
default:
}(this));
}
return true;
case "print":
if (!this.bindings[sBinding]) {
this.bindings[sBinding] = control;
/*
* Now that we're giving the Panel component multiple shots at binding its controls,
* to relax initialization dependencies, we need to chill when unrecognized requests come in.
*
if (sHTMLClass == "input") {
control.onclick = function() {
Component.println("unsupported " + sHTMLType + ": " + sBinding);
};
}
this.log("setBinding(\"" + sHTMLClass + "\",\"" + sHTMLType + "\",\"" + sBinding + "\"): unrecognized binding");
* HACK: Save this particular HTML element so that the Debugger can access it, too
*/
break;
this.controlPrint = control;
/*
* This was added for Firefox (Safari automatically clears the <textarea> on a page reload,
* but Firefox does not).
*/
control.value = "";
this.println = (function(control) {
return function printPanel(s, type) {
s = (type !== undefined? (type + ": ") : "") + (s || "");
/*
* In non-DEBUG builds, prevent the <textarea> from getting too large;
* otherwise, printing becomes slower and slower.
*/
if (!DEBUG) {
if (control.value.length > 8192) {
control.value = control.value.substr(control.value.length - 4096);
}
}
control.value += s + "\n";
control.scrollTop = control.scrollHeight;
if (DEBUG) console.log(s);
};
}(control));
/**
* Override this.notice() with a replacement function that eliminates the web.alertUser() call
*
* @this {Component}
* @param {string} s
* @param {boolean} [fPrintOnly]
* @param {string} [id]
*/
this.notice = function noticePanel(s, fPrintOnly, id) {
this.println(s, "notice", id);
};
}
return true;
default:
return false;
}
return false;
},
/**
* log(s, type)
@ -695,7 +688,9 @@ Component.prototype = {
* @param {string} [type] is the message type
*/
log: function(s, type) {
if (DEBUG) Component.log(s, type || this.id || this.type);
if (DEBUG) {
Component.log(s, type || this.id || this.type);
}
},
/**
* println(s, type)
@ -724,9 +719,9 @@ Component.prototype = {
/**
* notice(s, fPrintOnly)
*
* notice() is like println() but implies a need for user notification, which means calling log() isn't good enough, so we alert() as well;
* however, if Component.println() is overridden, Component.notice will be replaced with the same override, on the assumption that the override
* is taking care of user notification.
* notice() is like println() but implies a need for user notification, which means calling log() isn't good enough,
* so we alert() as well; however, if Component.println() is overridden, Component.notice will be replaced with the
* same override, on the assumption that the override is taking care of alerting the user.
*
* @this {Component}
* @param {string} s is the message text
@ -736,24 +731,6 @@ Component.prototype = {
notice: function(s, fPrintOnly, id) {
Component.notice(s, fPrintOnly, id || this.id);
},
/**
* warning(s)
*
* @this {Component}
* @param {string} s describes the warning
*/
warning: function(s) {
Component.warning(s);
},
/**
* error(s)
*
* @this {Component}
* @param {string} s describes the error; an alert() is displayed as well
*/
error: function(s) {
Component.error(s);
},
/**
* setError(s)
*

View file

@ -67,7 +67,7 @@ usr.binarySearch = function(a, v, fnCompare) {
/**
* binaryInsert(a, v, fnCompare)
*
*
* If element v already exists in array a, the array is unchanged (we don't allow duplicates); otherwise, the
* element is inserted into the array at the appropriate index.
*
@ -151,7 +151,7 @@ usr.aMonthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
* i: minutes, with leading zeros (00,...,59)
* j: day of the month, without leading zeros (1,...,31)
* l: day of the week ("Sunday",...,"Saturday")
* m: month, with leading zeros (01,...,12)
* m: month, with leading zeros (01,...,12)
* s: seconds, with leading zeros (00,...,59)
* F: month ("January",...,"December")
* H: hour in 24-hour format, with leading zeros (00,...,23)

View file

@ -45,7 +45,7 @@
* decodeURI() Decodes a URI
* decodeURIComponent() Decodes a URI component
* encodeURI() Encodes a URI
* encodeURIComponent() Encodes a URI component
* encodeURIComponent() Encodes a URI component
* escape() Deprecated in version 1.5. Use encodeURI() or encodeURIComponent() instead
* eval() Evaluates a string and executes it as if it was script code
* isFinite() Determines whether a value is a finite, legal number
@ -55,7 +55,7 @@
* parseInt() Parses a string and returns an integer
* String() Converts an object's value to a string
* unescape() Deprecated in version 1.5. Use decodeURI() or decodeURIComponent() instead
*
*
* And according to http://www.w3schools.com/jsref/obj_window.asp, these are the properties and functions
* of the *window* object.
*
@ -86,7 +86,7 @@
* self Returns the current window
* status Sets or returns the text in the statusbar of a window
* top Returns the topmost browser window
*
*
* Method Description
* ---
* alert() Displays an alert box with a message and an OK button
@ -122,7 +122,7 @@
* 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.
*/
@ -155,16 +155,16 @@ var web = {};
*/
web.loadResource = function(sURL, fAsync, data, componentNotify, fnNotify, pNotify)
{
fAsync = !!fAsync; // ensure that fAsync is a valid boolean (Internet Explorer xmlHTTP functions insist on it)
fAsync = !!fAsync; // ensure that fAsync is a valid boolean (Internet Explorer xmlHTTP functions insist on it)
if (typeof module !== 'undefined') {
/*
* We don't even need to load Component, because we can't use any of the code below
* within Node anyway. Instead, we must hand this request off to our network library.
*
*
* if (!Component) Component = require("./component");
*/
var net = require("./netlib");
return net.loadResource(sURL, fAsync, data, componentNotify, fnNotify, pNotify);
return net.loadResource(sURL, fAsync, data, componentNotify, fnNotify, pNotify);
}
var nErrorCode = 0;
var sURLData = null;
@ -312,7 +312,7 @@ web.confirmUser = function(sPrompt)
/**
* promptUser()
*
*
* @param {string} sPrompt
* @param {string} [sDefault]
* @returns {string|null}
@ -330,7 +330,7 @@ web.promptUser = function(sPrompt, sDefault)
* getLocalStorageItem(sKey)
*
* Returns the requested key value, or null if the key does not exist, or undefined if localStorage is not available
*
*
* @param {string} sKey
* @return {string|null|undefined} sValue
*/
@ -345,7 +345,7 @@ web.getLocalStorageItem = function(sKey)
/**
* setLocalStorageItem(sKey, sValue)
*
*
* @param {string} sKey
* @param {string} sValue
* return {boolean} true if localStorage is available, false if not
@ -427,13 +427,13 @@ web.getURLParameters = function(sParms)
* Note that window.location.href returns the entire URL, whereas window.location.search
* returns only the parameters, if any (starting with the '?', which we skip over with a substr() call).
*/
sParms = window.location.search.substr(1);
sParms = window.location.search.substr(1);
}
var match;
var pl = /\+/g; // RegExp for replacing addition symbol with a space
var search = /([^&=]+)=?([^&]*)/g;
var decode = function(s) { return decodeURIComponent(s.replace(pl, " ")); };
while ((match = search.exec(sParms))) {
aParms[decode(match[1])] = decode(match[2]);
}
@ -482,7 +482,7 @@ web.onCountRepeat = function(n, fn, fnComplete, msDelay)
web.onClickRepeat = function(e, msDelay, msRepeat, fn)
{
var ms = 0, timer = null, fIgnoreMouseEvents = false;
var fnRepeat = function doClickRepeat() {
if (fn(ms === msRepeat)) {
timer = setTimeout(fnRepeat, ms);
@ -628,7 +628,7 @@ web.enablePageEvents = function(fEnable)
/**
* sendPageEvent(sEvent)
*
*
* This allows us to manually trigger page events.
*
* @param {string} sEvent (one of 'init', 'show' or 'exit')