diff --git a/blog/2014/10/17/README.md b/blog/2014/10/17/README.md index bed33aef5..3d46e0e8e 100644 --- a/blog/2014/10/17/README.md +++ b/blog/2014/10/17/README.md @@ -16,7 +16,7 @@ when the keyboard's "clock" line is toggled (see *set8042CmdData()* in [chipset. a 40-track diskette). + The BIOS Diskette Reset function does something odd after resetting the Floppy Disk Controller: it issues not one but *four* "SENSE INTERRUPT STATUS" commands to the FDC, and expects each response to -return an incrementally larger drive number. I found this a bit mystifying, considering that the IBM's +return an incrementally larger drive number. I found this a bit mystifying, considering that IBM's own FDC/HDC "combo card" supports a maximum of *two* diskette drives. But, there's no point in arguing with a BIOS that's almost 30 years old. + The BIOS attempts to detect what its authors must have considered a common problem: failure to run SETUP @@ -28,22 +28,22 @@ to discover that the ATC had this behavior, and now I'm wondering how many other immediate "STATUS" register updates. This PCjs release also fixes a problem reported by a user: if you disable **localStorage** support in your -browser, previous versions would fault. I knew that every browser that supports PCjs also supports -**localStorage**, but I didn't consider what might happen if a user had decided to turn it off. +browser, previous versions of PCjs would fault. While every browser that supports PCjs also supports +**localStorage**, I didn't consider what might happen if a user decided to turn it off. The only downside to turning off **localStorage** is that none of your PCjs machines will be able save/restore -their state when you leave/return to the page, so they will always reboot. +their state when you leave/return to the page; they will always reboot. Browser's don't always refer to the **localStorage** feature by its actual name, either. For example, in Chrome, the setting that enables/disables **localStorage** is hidden under "Advanced Settings" => "Privacy" => -"Content Settings" => "Cookies" => "Allow local data to be set (recommended)". Which is a little misleading -and annoying, because **localStorage** != **cookie**. +"Content Settings" => "Cookies" => "Allow local data to be set (recommended)". Which is somewhat misleading +and a little annoying, because **localStorage** is *not* a **cookie**. PCjs *never* sets any cookies. Cookies are bits of data that your browser saves and then automatically sends -off to the server every time you make a request. **localStorage** is nothing more than local storage. Granted, -a JavaScript application could certainly abuse it and send it around like a cookie, but PCjs doesn't do that. -The only exception is when PCjs detects a problem, and even then, you must first agree to submit your machine's -state as part of the bug report. +off to the server every time you make a request. **localStorage** is nothing more than local storage; it is +*not* automatically sent anywhere. Granted, a JavaScript application could abuse it and send it around like a +cookie, but PCjs does *not* do that; the only exception is when PCjs detects a problem, and even then, you must +first agree to submit your machine's state as part of the bug report. *[@jeffpar](http://twitter.com/jeffpar)* *October 17, 2014* diff --git a/docs/about/pcjs/README.md b/docs/about/pcjs/README.md index 2111f0a2a..a7033b2b1 100644 --- a/docs/about/pcjs/README.md +++ b/docs/about/pcjs/README.md @@ -45,8 +45,8 @@ The following features are targeted for version 1.16: ### History -+ v1.15 introduced PC AT (Model 5170) emulation, as discussed on our [Blog](/blog/2014/09/13/). -+ v1.14 introduced limited EGA emulation, as discussed on our [Blog](/blog/2014/07/30/). ++ v1.15 introduced PC AT (Model 5170) emulation, as discussed in the [blog](/blog/2014/09/13/). ++ v1.14 introduced limited EGA emulation, as discussed in the [blog](/blog/2014/07/30/). + v1.13 introduced manifest files that describe software packages that can be used with PCjs. More information on software manifests is available [here](/apps/). + v1.12.1 coincided with the first release of the new PCjs web server running on [Node.js](http://nodejs.org). diff --git a/my_modules/diskdump/lib/diskdump.js b/my_modules/diskdump/lib/diskdump.js index 4d9850771..f094e014a 100644 --- a/my_modules/diskdump/lib/diskdump.js +++ b/my_modules/diskdump/lib/diskdump.js @@ -36,17 +36,17 @@ "use strict"; -var fs = require("fs"); -var path = require("path"); -var http = require("http"); -var mkdirp = require("mkdirp"); -var crypto = require("crypto"); -var net = require("../../shared/lib/netlib"); -var proc = require("../../shared/lib/proclib"); -var str = require("../../shared/lib/strlib"); -var usr = require("../../shared/lib/usrlib"); +var fs = require("fs"); +var path = require("path"); +var http = require("http"); +var mkdirp = require("mkdirp"); +var crypto = require("crypto"); +var net = require("../../shared/lib/netlib"); +var proc = require("../../shared/lib/proclib"); +var str = require("../../shared/lib/strlib"); +var usr = require("../../shared/lib/usrlib"); var DumpAPI = require("../../shared/lib/dumpapi"); -var X86 = require("../../pcjs-client/lib/x86"); +var X86 = require("../../pcjs-client/lib/x86"); /** * @class exports @@ -73,7 +73,7 @@ var fNormalize = true; * * TODO: Honor the caller's mbHD size. At the moment, any hard disk build request translates to 10Mb, * since we rely on a "canned" BPB in aDefaultBPBs. - * + * * TODO: If sServerRoot is set, make sure the final sDiskPath refers to something in either /apps/ or /disks/, * to prevent random enumeration of other server resources. * @@ -114,7 +114,7 @@ function DiskDump(sDiskPath, asExclude, sFormat, fComments, mbHD, sServerRoot, s /* * If we have to enumerate one or more files during the buildImage() process, this array * will save them, in case the caller wants to query that information later, in updateManifest(). - * + * * Originally, I thought each saved entry would be a subset of what the fileInfo objects contain, * but it turns out I pretty much need everything. This, in turn, means that some of the original * buildImage() functions could simply use this.aManifestInfo, instead of their own aFiles array, @@ -196,7 +196,7 @@ DiskDump.MY_OEM_STRING = "PCJS.ORG"; /** * The BPBs that buildImage() currently supports; these BPBs should be in order of smallest to largest capacity, - * to help insure we don't select a disk format larger than necessary. + * to help insure we don't select a disk format larger than necessary. */ DiskDump.aDefaultBPBs = [ [ // define BPB for 160Kb diskette @@ -279,7 +279,7 @@ DiskDump.aDefaultBPBs = [ * diskdump --dir={directory} [--format=json|data|hex|bytes|img] [--comments] [--output={file}] * diskdump --disk={disk image} [--format=json|data|hex|bytes|img] [--comments] [--output={file}] * diskdump --path={file[;file]...} [--format=json|data|hex|bytes|img] [--comments] [--output={file}] - * + * * NOTE: --img is permitted as an alias for --disk * * Arguments @@ -290,9 +290,9 @@ DiskDump.aDefaultBPBs = [ * * 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. - * + * * Additional command-line arguments include: - * + * * --mbhd={number}: requests a hard disk image with the given number of megabytes (eg, 10 for a 10mb image) * --exclude={filename}: specifies a filename that should be excluded from the image; repeat as often as needed * --overwrite: allows the --output option to overwrite an existing file; default is to NOT overwrite @@ -320,7 +320,7 @@ DiskDump.CLI = function() var sDiskPath = null, sServerRoot = ""; var sDir = argv['dir'], sDisk = (argv['disk'] || argv['img']), sPath = argv['path']; - + if (typeof sDir == "string") { sDiskPath = sDir; } @@ -345,7 +345,7 @@ DiskDump.CLI = function() if (sManifestFile && sManifestFile.charAt(0) != '/') { sManifestFile = path.join(process.cwd(), sManifestFile); } - + var sOutput = ""; var sOutputFile = argv['output']; if (typeof sOutputFile == "string" && !str.endsWith(sOutputFile, ".img") && !str.endsWith(sOutputFile, ".json")) { @@ -362,14 +362,14 @@ DiskDump.CLI = function() } } else { sOutput = "disk"; - } + } sOutputFile = sOutput + '.' + argv['format']; } if (sOutputFile && sOutputFile.charAt(0) != '/') sOutputFile = path.join(process.cwd(), sOutputFile); var fOverwrite = argv['overwrite']; var sManifestTitle = argv['title']; - + if (sDiskPath) { var disk = new DiskDump(sDiskPath, asExclude, argv['format'], argv['comments'], argv['mbhd'], sServerRoot, sManifestFile); if (sDir) { @@ -394,7 +394,7 @@ DiskDump.CLI = function() else { console.log("usage: diskdump --dir={dir}|--disk={disk}|--path={file}[;{file}...] [--format=json|data|hex|bytes|img] [--comments] [--output={file}] [--manifest={file}]"); } - + if (err) { DiskDump.logError(err); process.exit(1); @@ -432,9 +432,9 @@ DiskDump.outputDisk = function(err, disk, sDiskPath, sOutputFile, fOverwrite, sM } } if (data) { - + var cbDisk = (disk.bufDisk? disk.bufDisk.length : data.length); - + if (sOutputFile) { var fUnchanged; @@ -448,7 +448,7 @@ DiskDump.outputDisk = function(err, disk, sDiskPath, sOutputFile, fOverwrite, sM } fUnchanged = DiskDump.updateManifest(disk, disk.sManifestFile, sDiskPath, sOutputFile, true, sManifestTitle, md5Disk, md5JSON); } - + try { if (fUnchanged) { console.log(sOutputFile + " unchanged"); @@ -468,7 +468,7 @@ DiskDump.outputDisk = function(err, disk, sDiskPath, sOutputFile, fOverwrite, sM } else { /* * We'll dump JSON to the console, but not a raw disk buffer; we could add an option to - * "stringify" buffers, but if that's what the caller wants, they should use "--format=json". + * "stringify" buffers, but if that's what the caller wants, they should use "--format=json". */ if (typeof data == "string") { console.log(data); @@ -480,7 +480,7 @@ DiskDump.outputDisk = function(err, disk, sDiskPath, sOutputFile, fOverwrite, sM err = new Error("unable to convert " + disk.sDiskPath); } } - + if (err) { DiskDump.logError(err); process.exit(1); @@ -489,7 +489,7 @@ DiskDump.outputDisk = function(err, disk, sDiskPath, sOutputFile, fOverwrite, sM /** * getManifestAttr(sID, sTag) - * + * * @param sID * @param sTag * @return {string|null} @@ -503,14 +503,14 @@ DiskDump.getManifestAttr = function(sID, sTag) /** * updateManifest(disk, sManifestFile, sDiskPath, sOutputFile, fOverwrite, sTitle, md5Disk, md5JSON) - * + * * This function reports a change if EITHER the md5Disk value does not match the original * "md5" value recorded in the manifest OR the manifest itself has changed. If md5JSON is * also provided, we require that to match as well. - * + * * Since this function is for command-line use only, we use *Sync functions, so that we can * return the results immediately. - * + * * @param {DiskDump} disk * @param {string} sManifestFile * @param {string} sDiskPath @@ -523,9 +523,9 @@ DiskDump.getManifestAttr = function(sID, sTag) */ DiskDump.updateManifest = function(disk, sManifestFile, sDiskPath, sOutputFile, fOverwrite, sTitle, md5Disk, md5JSON) { - var fUnchanged, fExists = false, sXML, err = null; + var fUnchanged, fExists = false, sXML, err = null; var sMatchDisk = null, sIDDisk = null, sMD5Disk = null, sMD5JSON = null; - + try { sXML = fs.readFileSync(sManifestFile, {encoding: "utf8"}); fExists = true; @@ -544,7 +544,7 @@ DiskDump.updateManifest = function(disk, sManifestFile, sDiskPath, sOutputFile, sXML += '\t
...
...sequences * to become one single (unified)
sequence.
@@ -435,13 +435,13 @@ MarkOut.prototype.convertMDBlocks = function(sMD, sIndent)
sMD = str.replaceArray({"":"h6>", "h#####>":"h5>", "h####>":"h4>", "h###>":"h3>", "h##>":"h2>", "h#>":"h1>"}, sMD);
-
+
/*
* Convert all "Setext-style headers" (ie, series of equal-signs or dashes) to their equivalents.
*/
sMD = sMD.replace(/([^\n]+)\n([=-])[=-]*(\n|$)/g, "$1 \n\n");
sMD = str.replaceArray({"h=>":"h1>", "h->":"h2>"}, sMD);
-
+
/*
* Auto-generate IDs for headings
*/
@@ -710,20 +710,20 @@ MarkOut.prototype.convertMDLines = function(s)
* we strip the '#' and use the remainder of the link as the name of the anchor. To reference a named
* anchor from another link, you have to specify a path with '#' and the anchor name appended, in order
* to distinguish an anchor name from an anchor reference.
- *
+ *
* Note that the need for named anchors is somewhat diminished now that I automatically generate IDs for
* all heading tags (eg, ); refer to the generateID() function that's used in convertMDBlocks().
- *
+ *
* Another extension to Markdown that I've added is detecting empty parentheses alongside a likely URL,
* and automatically converting it to a link; eg:
- *
+ *
* [http://www.ascii-code.com/]()
- *
+ *
* Also, if a URL contains any asterisks, we replace them with the current version number from "package.json".
*
* I prefer this solution over GFM's "autolinking" solution, which is too "loosey-goosey" for my taste
* (see https://help.github.com/articles/github-flavored-markdown#url-autolinking).
- *
+ *
* TODO: Consider adding support for "reference"-style Markdown links.
*
* @this {MarkOut}
@@ -794,11 +794,11 @@ MarkOut.prototype.convertMDImageLinks = function(sBlock, sIndent)
* link:url[:width[:height]]
*
* If "link:" is specified, a URL is required, but image width and height are optional.
- *
+ *
* Alternatively:
- *
+ *
* link:url:nogallery[:width[:height]]
- *
+ *
* to disable the automatic "gallery-ification" of image links (an optional width and height
* can still follow).
*/
@@ -814,11 +814,11 @@ MarkOut.prototype.convertMDImageLinks = function(sBlock, sIndent)
* If the image link (aMatch[2]) contains "static/" but the sURL is external, AND we're in
* "reveal mode", then transform sURL into a "static/" URL as well; encodeURL() will take care
* of the rest of the transformation.
- *
+ *
* This feature is used with READMEs like /pubs/pc/programming/README.md, where normally we
* want to link to documents stored on sites like archive.org, minuszerodegrees.net or bitsavers,
* unless you're in "reveal mode", in which case we'll serve up our own "backup copies".
- *
+ *
* The assumption here is that if we have "static" thumbs, then we should also have full "static"
* copies as well.
*/
@@ -908,7 +908,7 @@ MarkOut.prototype.convertMDMachineLinks = function(sBlock)
* We don't have the XML file open here, and I don't think it's worth the hit to open it.
* Besides, the XML config file isn't necessarily on the same server (although whenever this
* script is being used, it very likely is).
- *
+ *
* TODO: Consider cracking open the XML file anyway, even though the Markdown module is supposed
* to be non-blocking; I'd like to be smarter about defaults (eg, specifying "debugger" when the
* XML file clearly needs it).
@@ -926,7 +926,7 @@ MarkOut.prototype.convertMDMachineLinks = function(sBlock)
var sMachineFunc = "embed" + sMachine;
var sMachineClass = sMachine.toLowerCase();
var aMachineParms = aMatch[4].split(':');
- var sMachineMessage = "(If you see this message, " + sMachine + "js may still be loading)";
+ var sMachineMessage = "(If you see this message, " + sMachine + "js is still loading, or JavaScript has been disabled)";
var sMachineID = aMachineParms[0];
var sMachineXSLFile = aMachineParms[1] || "";
@@ -957,11 +957,11 @@ MarkOut.prototype.convertMDMachineLinks = function(sBlock)
/*
* Now that we're providing all of the following machine information to addMachine(), we don't
- * need to install the machine embed code here; processMachines() in HTMLOut will take care of that now.
+ * need to install the machine embed code here; processMachines() in HTMLOut will take care of that now.
*
sReplacement += this.sIndent + '';
*/
-
+
sBlock = sBlock.replace(aMatch[0], sReplacement);
reMachines.lastIndex = 0; // reset lastIndex, since we just modified the string that reMachines is iterating over
cMatches++;
@@ -987,17 +987,17 @@ MarkOut.prototype.convertMDMachineLinks = function(sBlock)
/**
* convertMDEmphasis(sBlock)
- *
+ *
* We look for sequences like **strength**, __strength__, *emphasis* and _emphasis_;
* we convert the stronger (double-character) forms first, followed by the weaker
* (single-character) forms, since we don't want to misconstrue the former as containing
* the latter.
- *
+ *
* Also, standard Markdown says that "if you surround an * or _ with spaces, it’ll be
* treated as a literal asterisk or underscore." Well, we don't. You can already escape
* special characters with a backslash to make them literal, so I don't feel like
* complicating the RegExps below to accommodate a syntax I don't use or want to support.
- *
+ *
* Also, for reasons noted in the code below, we don't support emphasis in the middle
* of words.
*
@@ -1009,17 +1009,17 @@ MarkOut.prototype.convertMDEmphasis = function(sBlock)
{
/*
* Standard Markdown allows * or _ in the middle of a word, as in:
- *
+ *
* un*frigging*believable
- *
+ *
* but we do not. That's because a Markdown link like:
- *
+ *
* [my_modules](/my_modules/)
- *
+ *
* would otherwise be misconstrued as containing emphasis (and it doesn't
* matter whether we process emphasis BEFORE or AFTER links -- an HTML link
* poses the same problem as a Markdown link).
- *
+ *
* To resolve this, I require something non-alphanumeric to both precede AND
* follow the emphasis characters. I would expect that "something" to normally
* be whitespace, but we make it a bit more flexible, so that you can do things
@@ -1103,4 +1103,4 @@ MarkOut.prototype.encodeWhitespace = function(sText)
};
*/
-module.exports = MarkOut;
\ No newline at end of file
+module.exports = MarkOut;
diff --git a/my_modules/pcjs-client/lib/bus.js b/my_modules/pcjs-client/lib/bus.js
index a76fde17e..7f698ea92 100644
--- a/my_modules/pcjs-client/lib/bus.js
+++ b/my_modules/pcjs-client/lib/bus.js
@@ -34,15 +34,15 @@
"use strict";
if (typeof module !== 'undefined') {
- var str = require("../../shared/lib/strlib");
- var Component = require("../../shared/lib/component");
- var Memory = require("./mem");
- var State = require("./state");
+ var str = require("../../shared/lib/strlib");
+ var Component = require("../../shared/lib/component");
+ var Memory = require("./mem");
+ var State = require("./state");
}
/**
* Bus(cpu, dbg)
- *
+ *
* The Bus component manages "physical" memory and I/O address spaces.
*
* The Bus component has no UI elements, so it does not require an init() handler,
@@ -81,7 +81,7 @@ function Bus(parmsBus, cpu, dbg)
/*
* Compute all the Bus memory block addressing values that we rely on, based on the width of the bus.
- *
+ *
* Regarding this.blockTotal, we want to avoid address-overflow-detection expressions like:
*
* iBlock < this.blockTotal? iBlock : 0
@@ -106,12 +106,12 @@ function Bus(parmsBus, cpu, dbg)
* this.blockLimit Bus.BLOCK.LIMIT 0xfff
* this.blockTotal Bus.BLOCK.TOTAL ((this.addrLimit + this.blockSize) / this.blockSize) | 0
* this.blockMask Bus.BLOCK.MASK (this.blockTotal - 1) (ie, 0xff)
- *
+ *
* Note that the blockShift calculation below chooses a 4Kb physical memory block size for a 20-bit bus
* (1Mb address space) and a 16Kb physical memory block for a 24-bit bus (16Mb address space). This yields
* a 256-block array for the smaller bus and a 1024-block array for the larger bus. If we left the block
* size at 4Kb in all cases, we'd end up with a 4096-block array for an 80286, which seems a bit excessive.
- *
+ *
* I can't think of any reason why a coarser block granularity (of 16Kb) should hurt anything, other than
* wasting a little memory for ROMs smaller than the block size. Realize that this is strictly a physical
* memory implementation detail, which should have no bearing on segment or page granularity of any future
@@ -138,11 +138,11 @@ function Bus(parmsBus, cpu, dbg)
* WARNING: Unlike the (old) read and write memory notification functions, these support only one
* pair of input/output functions per port. A more sophisticated architecture could support a list
* of chained functions across multiple components, but I doubt that will be necessary here.
- *
+ *
* UPDATE: The Debugger now piggy-backs on these arrays to indicate ports for which it wants notification
* of I/O. In those cases, the registered component/function elements may or may not be set, but the following
* additional element will be set:
- *
+ *
* [2]: true to break on I/O, false to ignore I/O
*
* The false case is important if fPortInputBreakAll and/or fPortOutputBreakAll is set, because it allows the
@@ -163,7 +163,7 @@ Component.subclass(Component, Bus);
/**
* initMemory()
- *
+ *
* Allocate enough (empty) Memory blocks to span the entire physical address space.
*
* @this {Bus}
@@ -192,7 +192,7 @@ Bus.prototype.reset = function()
/**
* addMemory(addr, size, fReadOnly, controller)
- *
+ *
* Adds new Memory blocks to the specified address range. Any Memory blocks previously
* added to that range must first be removed via removeMemory(); otherwise, you'll get
* an allocation conflict error. Moreover, the address range must start at a block-granular
@@ -228,7 +228,7 @@ Bus.prototype.addMemory = function(addr, size, fReadOnly, controller)
/**
* cleanMemory(addr, size)
- *
+ *
* @this {Bus}
* @param {number} addr
* @param {number} size
@@ -318,7 +318,7 @@ Bus.prototype.setMemoryAccess = function(addr, size, afn)
* removeMemory(addr, size)
*
* Replaces every block in the specified address range with empty Memory blocks that will ignore all reads/writes.
- *
+ *
* @this {Bus}
* @param {number} addr
* @param {number} size
@@ -410,7 +410,7 @@ Bus.prototype.setWordDirect = function(addr, w)
* All dirty blocks will be stored in a single array, as pairs of block numbers and data arrays, like so:
*
* [iBlock0, [dw0, dw1, ...], iBlock1, [dw0, dw1, ...], ...]
- *
+ *
* In a normal 4Kb block, there will be 1K DWORD values in the data array. Remember that each DWORD is a signed 32-bit
* integer (because they are formed using bit-wise operator rather than floating-point math operators), so don't be
* surprised to see negative numbers in the data.
@@ -459,7 +459,7 @@ Bus.prototype.saveMemory = function()
* component to be restored, all those blocks (and their attributes) should be in place now.
*
* See saveMemory() for a description of how the memory block contents are saved.
- *
+ *
* @this {Bus}
* @param {Array} a
* @return {boolean} true if successful, false if not
@@ -490,7 +490,7 @@ Bus.prototype.restoreMemory = function(a)
/**
* addMemoryBreakpoint(addr, fWrite)
- *
+ *
* @this {Bus}
* @param {number} addr
* @param {boolean} fWrite is true for a memory write breakpoint, false for a memory read breakpoint
@@ -505,7 +505,7 @@ Bus.prototype.addMemoryBreakpoint = function(addr, fWrite)
/**
* removeMemoryBreakpoint(addr, fWrite)
- *
+ *
* @this {Bus}
* @param {number} addr
* @param {boolean} fWrite is true for a memory write breakpoint, false for a memory read breakpoint
@@ -540,7 +540,7 @@ Bus.prototype.addPortInputBreak = function(port)
/**
* addPortInputNotify(start, end, component, fn)
- *
+ *
* Add a port input-notification handler to the list of such handlers.
*
* @this {Bus}
@@ -565,7 +565,7 @@ Bus.prototype.addPortInputNotify = function(start, end, component, fn)
/**
* addPortInputTable(component, table, offset)
- *
+ *
* Add port input-notification handlers from the specified table (a batch version of addPortInputNotify)
*
* @this {Bus}
@@ -578,7 +578,7 @@ Bus.prototype.addPortInputTable = function(component, table, offset)
if (offset === undefined) offset = 0;
for (var port in table) {
/*
- * JavaScript coerces property keys to strings, so we use parseInt() to coerce them back to numbers.
+ * JavaScript coerces property keys to strings, so we use parseInt() to coerce them back to numbers.
*/
port = parseInt(port, 10);
this.addPortInputNotify(port + offset, port + offset, component, table[port]);
@@ -587,7 +587,7 @@ Bus.prototype.addPortInputTable = function(component, table, offset)
/**
* checkPortInputNotify(port, addrFrom)
- *
+ *
* @this {Bus}
* @param {number} port
* @param {number} [addrFrom] is the EIP value at the time of the input
@@ -619,7 +619,7 @@ Bus.prototype.checkPortInputNotify = function(port, addrFrom)
/**
* removePortInputNotify(start, end, component, fn)
- *
+ *
* Remove a port input-notification handler from the list of such handlers (to be ENABLED later if needed)
*
* @this {Bus}
@@ -660,7 +660,7 @@ Bus.prototype.addPortOutputBreak = function(port)
/**
* addPortOutputNotify(start, end, component, fn)
- *
+ *
* Add a port output-notification handler to the list of such handlers.
*
* @this {Bus}
@@ -685,7 +685,7 @@ Bus.prototype.addPortOutputNotify = function(start, end, component, fn)
/**
* addPortOutputTable(component, table, offset)
- *
+ *
* Add port output-notification handlers from the specified table (a batch version of addPortOutputNotify)
*
* @this {Bus}
@@ -698,7 +698,7 @@ Bus.prototype.addPortOutputTable = function(component, table, offset)
if (offset === undefined) offset = 0;
for (var port in table) {
/*
- * JavaScript converts property keys to strings (brilliant), so we use parseInt() to convert them back to numbers.
+ * JavaScript converts property keys to strings (brilliant), so we use parseInt() to convert them back to numbers.
*/
port = parseInt(port, 10);
this.addPortOutputNotify(port + offset, port + offset, component, table[port]);
@@ -707,7 +707,7 @@ Bus.prototype.addPortOutputTable = function(component, table, offset)
/**
* checkPortOutputNotify(port, bOut, addrFrom)
- *
+ *
* @this {Bus}
* @param {number} port
* @param {number} bOut
@@ -734,7 +734,7 @@ Bus.prototype.checkPortOutputNotify = function(port, bOut, addrFrom)
/**
* removePortOutputNotify(start, end, component, fn)
- *
+ *
* Remove a port output-notification handler from the list of such handlers (to be ENABLED later if needed)
*
* @this {Bus}
diff --git a/my_modules/pcjs-client/lib/chipset.js b/my_modules/pcjs-client/lib/chipset.js
index dc596aa84..dbaa8fe36 100644
--- a/my_modules/pcjs-client/lib/chipset.js
+++ b/my_modules/pcjs-client/lib/chipset.js
@@ -34,11 +34,11 @@
"use strict";
if (typeof module !== 'undefined') {
- var str = require("../../shared/lib/strlib");
- var usr = require("../../shared/lib/usrlib");
- var web = require("../../shared/lib/weblib");
- var Component = require("../../shared/lib/component");
- var State = require("./state");
+ var str = require("../../shared/lib/strlib");
+ var usr = require("../../shared/lib/usrlib");
+ var web = require("../../shared/lib/weblib");
+ var Component = require("../../shared/lib/component");
+ var State = require("./state");
}
/**
@@ -52,12 +52,12 @@ if (typeof module !== 'undefined') {
* sound: true to enable (experimental) sound support (default); false to disable
* scaleTimers: true to divide timer cycle counts by the CPU's cycle multiplier (default is false)
* fdrives: 0-4 floppy drives (default is 2 if no sw1 value provided)
- * monitor: none|tv|color|mono (default is mono if no sw1 value provided)
+ * monitor: none|tv|color|mono (default is mono if no sw1 value provided)
* rtcDate: optional RTC date to be used on resets; use the ISO 8601 format; eg: "2014-10-01T08:00:00-0700"
*
* The conventions used for the sw1 and sw2 strings are that the left-most character represents DIP switch [1],
* the right-most character represents DIP switch [8], and "1" means the DIP switch is ON and "0" means it is OFF.
- *
+ *
* Internally, we convert the above strings into binary values that the 8255A PPI returns, where DIP switch [1]
* is bit 0 and DIP switch [8] is bit 7, and 0 indicates the switch is ON and 1 indicates it is OFF.
*
@@ -68,7 +68,7 @@ if (typeof module !== 'undefined') {
* SW1[3,4] (bits 3-2) "xx11xxxx" (00): 16Kb, "xx01xxxx" (01): 32Kb, "xx10xxxx" (10): 48Kb, "xx00xxxx" (11): 64Kb
* SW1[5,6] (bits 5-4) "xxxx11xx" (00): none, "xxxx01xx" (01): tv, "xxxx10xx" (10): color, "xxxx00xx" (11): mono
* SW1[7,8] (bits 7-6) "xxxxxx11" (00): 1 FD, "xxxxxx01" (01): 2 FD, "xxxxxx10" (10): 3 FD, "xxxxxx00" (11): 4 FD
- *
+ *
* Note: FD refers to floppy drive, and IPL refers to an "Initial Program Load" floppy drive.
*
* SW2[1-4] (bits 3-0) "NNNNxxxx": number of 32Kb blocks of I/O expansion RAM present
@@ -127,7 +127,7 @@ if (typeof module !== 'undefined') {
* NMI Mask Register or the state that the BIOS "POST" (Power-On Self-Test) sets.
*
* [2] These devices cannot be used together since their port addresses overlap.
- *
+ *
* MODEL_5170 Description
* ---------- -----------
* 070 [3] CMOS Address ChipSet.CMOS.ADDR.PORT
@@ -135,7 +135,7 @@ if (typeof module !== 'undefined') {
* 0F0 Coprocessor Clear Busy (output 0x00)
* 0F1 Coprocessor Reset (output 0x00)
* 1F0-1F7 Hard Drive Controller (ATC) [see the HDC component]
- *
+ *
* [3] Port 0x70 doubles as the NMI Mask Register: output a CMOS address with bit 7 clear to enable NMI
* or with bit 7 set to disable NMI (apparently the inverse of the older NMI Mask Register at port 0xA0).
* Also, apparently unlike previous models, the MODEL_5170 POST leaves NMI enabled. And fortunately, the
@@ -151,12 +151,12 @@ function ChipSet(parmsChipSet)
this.model = parmsChipSet['model'];
this.model = (this.model !== undefined? parseInt(this.model, 10) : ChipSet.MODEL_5150);
-
+
/*
* SW1 describes the number of floppy drives, the amount of base memory, the primary monitor type,
* 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.
- *
+ *
* 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,
@@ -166,7 +166,7 @@ function ChipSet(parmsChipSet)
* required to boot is therefore 32Kb. Whether that's actually enough to run any or all versions of PC-DOS is
* a separate question. FYI, with only 16Kb, the ROM BIOS will still try to boot, and fail miserably.
*/
- this.sw1Init = 0;
+ this.sw1Init = 0;
var sw1 = parmsChipSet['sw1'];
if (sw1) {
this.sw1Init = this.parseSwitches(sw1, ChipSet.PPI_SW.MEMORY.X4 | ChipSet.PPI_SW.MONITOR.MONO);
@@ -182,12 +182,12 @@ function ChipSet(parmsChipSet)
this.sw1Init |= (ChipSet.aMonitorSwitches[sMonitor] << ChipSet.PPI_SW.MONITOR.SHIFT);
}
}
-
+
/*
* SW2 describes the number of 32Kb blocks of I/O expansion RAM that's present in the system. The MODEL_5150 ROM BIOS
* only checked/supported the first four switches, so the maximum amount of additional RAM specifiable was 15 * 32Kb,
* or 480Kb. With a maximum of 64Kb on the motherboard, the MODEL_5150 ROM BIOS could support a grand total of 544Kb.
- *
+ *
* For MODEL_5160 (PC XT) and up, memory expansion cards had their own configuration switches, and the motherboard SW2
* switches for I/O expansion RAM were eliminated. Instead, the ROM BIOS scans the entire address space (up to 0xA0000)
* looking for additional memory. As a result, the only mechanism we provide for adding RAM (above the maximum of 256Kb
@@ -205,20 +205,20 @@ function ChipSet(parmsChipSet)
if (this.model >= ChipSet.MODEL_5170) {
this.cDMACs = this.cPICs = 2;
}
-
+
this.fScaleTimers = parmsChipSet['scaleTimers'] || false;
this.sRTCDate = parmsChipSet['rtcDate'];
/*
* Here, I'm finally getting around to trying the Web Audio API. Fortunately, based on what little I know about
* sound generation, using the API to make the same noises as the IBM PC speaker should be straightforward.
- *
+ *
* To start, we create an audio context, unless the 'sound' parameter has been explicitly set to false.
- *
+ *
* From:
- *
+ *
* http://developer.apple.com/library/safari/#documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/PlayingandSynthesizingSounds/PlayingandSynthesizingSounds.html
- *
+ *
* "Similar to how HTML5 canvas requires a context on which lines and curves are drawn, Web Audio requires an audio context
* on which sounds are played and manipulated. This context will be the parent object of further audio objects to come....
* Your audio context is typically created when your page initializes and should be long-lived. You can play multiple sounds
@@ -233,7 +233,7 @@ function ChipSet(parmsChipSet)
if (DEBUG) this.log("webkitAudioContext not available");
}
}
-
+
/*
* I used to defer ChipSet's reset() to powerUp(), which then gave us the option of doing either
* reset() OR restore(), instead of both. However, on MODEL_5170 machines, the initial CMOS data
@@ -241,7 +241,7 @@ function ChipSet(parmsChipSet)
* HDC calls setCMOSDriveType() or RAM calls addCMOSMemory()), the CMOS will be ready to take their calls.
*/
this.reset();
-
+
this.setReady();
}
@@ -249,7 +249,7 @@ Component.subclass(Component, ChipSet);
/*
* Supported Models
- *
+ *
* Unless otherwise noted, all BIOS references refer to the *original* BIOS released with each model
*/
ChipSet.MODEL_5150 = 5150; // used in reference to the 1st 5150 BIOS, dated Apr 24, 1981
@@ -287,14 +287,14 @@ ChipSet.aMonitorSwitches = {
/*
* 8237A DMA Controller (DMAC) I/O ports
- *
+ *
* MODEL_5150 and up uses DMA channel 0 for memory refresh cycles and channel 2 for the FDC
* MODEL_5160 and up uses DMA channel 3 for HDC transfers (XTC only)
* MODEL_5170 and up contain *two* DMA Controllers, which we refer to as DMA0 and DMA1; channel 4
- * on DMA1 is used to "cascade" channels 0-3 from DMA0, so only channels 5-7 are available on DMA1
- *
+ * on DMA1 is used to "cascade" channels 0-3 from DMA0, so only channels 5-7 are available on DMA1
+ *
* QUESTION: Why does the MODEL_5150 ROM BIOS set the page register for channel 1 (port 0x83) to zero?
- *
+ *
* For FDC DMA notes, refer to: http://wiki.osdev.org/ISA_DMA
* For general DMA notes, refer to: http://www.freebsd.org/doc/en/books/developers-handbook/dma.html
*/
@@ -322,7 +322,7 @@ ChipSet.DMA0 = {
CH1_PAGE: 0x83, // OUT: DMA channel 1 page register
CH0_PAGE: 0x87 // OUT: DMA channel 0 page register (unusable; See "The Inside Out" book, p.246)
}
-};
+};
ChipSet.DMA1 = {
INDEX: 1,
PORT: {
@@ -385,9 +385,9 @@ ChipSet.DMA_HDC = 0x03; // DMA channel assigned to the Hard Drive Contro
/*
* 8259A Programmable Interrupt Controller (PIC) I/O ports
- *
+ *
* Internal registers:
- *
+ *
* ICW1 Initialization Command Word 1 (sent to port ChipSet.PIC_LO)
* ICW2 Initialization Command Word 2 (sent to port ChipSet.PIC_HI)
* ICW3 Initialization Command Word 3 (sent to port ChipSet.PIC_HI)
@@ -396,18 +396,18 @@ ChipSet.DMA_HDC = 0x03; // DMA channel assigned to the Hard Drive Contro
* IRR Interrupt Request Register
* ISR Interrupt Service Register
* IRLow (IR having lowest priority; IR+1 will have highest priority; default is 7)
- *
+ *
* Note that ICW2 effectively contains the starting IDT vector number (ie, for IRQ 0),
* which must be multiplied by 4 to calculate the vector offset, since every vector is 4 bytes long.
- *
+ *
* Also, since the low 3 bits of ICW2 are ignored in 8086/8088 mode (ie, they are effectively
* treated as zeros), this means that the starting IDT vector can only be a multiple of 8.
*
* So, if ICW2 is set to 0x08, the starting vector number (ie, for IRQ 0) will be 0x08, and the
* 4-byte address for the corresponding ISR will be located at offset 0x20 in the real-mode IDT.
- *
+ *
* ICW4 is typically set to 0x09, indicating 8086 mode, non-automatic EOI, buffered/slave mode.
- *
+ *
* QUESTION: Why did the original ROM BIOS choose buffered/slave over buffered/master? Did it simply
* not matter in pre-AT systems with only one PIC, or am I misreading something?
*
@@ -465,16 +465,16 @@ ChipSet.PIC_HI = { // ChipSet.PIC1.PORT_HI or ChipSet.PIC2.PORT_HI
/*
* The priorities of IRQs 0-7 are normally high to low, unless the master PIC has been reprogrammed.
* Also, if a slave PIC is present, the priorities of IRQs 8-15 fall between the priorities of IRQs 1 and 3.
- *
+ *
* As the MODEL_5170 TechRef states:
- *
+ *
* "Interrupt requests are prioritized, with IRQ9 through IRQ12 and IRQ14 through IRQ15 having the
* highest priority (IRQ9 is the highest) and IRQ3 through IRQ7 having the lowest priority (IRQ7 is
* the lowest).
- *
+ *
* Interrupt 13 (IRQ.COPROC) is used on the system board and is not available on the I/O channel.
* Interrupt 8 (IRQ.RTC) is used for the real-time clock."
- *
+ *
* This priority scheme is a byproduct of IRQ8 through IRQ15 (slave PIC interrupts) being tied to IRQ2 of
* the master PIC. As a result, the two other system board interrupts, IRQ0 and IRQ1, continue to have the
* highest priority, by default.
@@ -495,7 +495,7 @@ ChipSet.IRQ = {
};
/*
- * 8253 Programmable Interval Timer (PIT) I/O ports
+ * 8253 Programmable Interval Timer (PIT) I/O ports
*/
ChipSet.TIMER0 = {
INDEX: 0,
@@ -538,10 +538,10 @@ ChipSet.TIMER_TICKS_PER_SEC = 1193181;
/*
* 8255A Programmable Peripheral Interface (PPI) I/O ports, for Cassette/Speaker/Keyboard/SW1/etc
- *
+ *
* Normally, 0x99 is written to PPI_CTRL.PORT, indicating that PPI_A.PORT and PPI_C.PORT are INPUT ports
* and PPI_B.PORT is an OUTPUT port.
- *
+ *
* However, the MODEL_5160 ROM BIOS initially writes 0x89 instead, making PPI_A.PORT an OUTPUT port.
* I'm guessing that's just part of some "diagnostic mode", because all it writes to PPI_A.PORT are a series
* of "checkpoint" values (ie, 0x01, 0x02, and 0x03) before updating PPI_CTRL.PORT with the usual 0x99.
@@ -584,7 +584,7 @@ ChipSet.PPI_CTRL = { // this.bPPICtrl
/*
* On the MODEL_5150, the following PPI_SW bits are exposed through PPI_A.
- *
+ *
* On the MODEL_5160, either the low or high 4 bits are exposed through PPI_C.SW, if PPI_B.ENABLE_SW_HI is clear or set.
*/
ChipSet.PPI_SW = {
@@ -617,27 +617,27 @@ ChipSet.PPI_SW = {
/*
* 8042 Keyboard Controller I/O ports (MODEL_5170)
- *
+ *
* On the MODEL_5170, port 0x60 is designated KBC.DATA rather than PPI_A, although the BIOS also refers to it
* as "PORT_A: 8042 KEYBOARD SCAN/DIAG OUTPUTS"). This is the 8042's output buffer and should be read only when
* KBC.STATUS.OUTBUFF_FULL is set.
- *
+ *
* Similarly, port 0x61 is designated KBC.RWREG rather than PPI_B; the BIOS also refers to it as "PORT_B: 8042
* READ WRITE REGISTER", but it is not otherwise discussed in the MODEL_5170 TechRef's 8042 documentation.
* There are brief references to bits 0 and 1 (KBC.RWREG.CLK_TIMER2 and KBC.RWREG.SPK_TIMER2), and the BIOS sets
* bits 2-7 to "DISABLE PARITY CHECKERS" (principally KBC.RWREG.DISABLE_CHK, which are bits 2 and 3); why the BIOS
* also sets bits 4-7 (or if those bits are even settable) is unclear, since it uses 11111100B rather than defined
* constants.
- *
+ *
* The bottom line: on a MODEL_5170, port 0x61 is still used for speaker control and parity checking, so we use
* the same register (bPPIB) but install different I/O handlers. It's also bi-directional: at one point, the BIOS
* reads KBC.RWREG.REFRESH_BIT (bit 4) to verify that it's alternating.
- *
+ *
* PPI_C and PPI_CTRL don't seem to be documented or used by the MODEL_5170 BIOS, so I'm assuming they're obsolete.
- *
+ *
* NOTE: For more information on the 8042 Controller, including information on undocumented commands, refer to the
* documents in /devices/pc/keyboard/, as well as the following websites:
- *
+ *
* http://halicery.com/8042/8042_INTERN_TXT.htm
* http://www.os2museum.com/wp/?p=589 ("IBM PC/AT 8042 Keyboard Controller Commands")
*/
@@ -649,7 +649,7 @@ ChipSet.KBC = {
PC_MODE: 0x20,
NO_CLOCK: 0x10, // disable keyboard by driving "clock" line low
NO_INHIBIT: 0x08, // disable inhibit function
- SYS_FLAG: 0x04, // this value is propagated to ChipSet.KBC.STATUS.SYS_FLAG
+ SYS_FLAG: 0x04, // this value is propagated to ChipSet.KBC.STATUS.SYS_FLAG
INT_ENABLE: 0x01 // generate an interrupt when the controller places data in the output buffer
},
SELF_TEST: { // result of ChipSet.KBC.CMD.SELF_TEST command (0xAA)
@@ -695,7 +695,7 @@ ChipSet.KBC = {
CMD: { // this.b8042InBuff (on write to port 0x64, interpret this as a CMD)
PORT: 0x64,
READ_CMD: 0x20,
- WRITE_CMD: 0x60, // followed by a command byte written to KBC.DATA.PORT (see KBC.DATA.CMD)
+ WRITE_CMD: 0x60, // followed by a command byte written to KBC.DATA.PORT (see KBC.DATA.CMD)
SELF_TEST: 0xAA, // self-test (KBC.DATA.SELF_TEST.OK is placed in the output buffer if no errors)
INTF_TEST: 0xAB, // interface test
DIAG_DUMP: 0xAC, // diagnostic dump
@@ -723,9 +723,9 @@ ChipSet.KBC = {
/*
* MC146818A RTC/CMOS Ports (MODEL_5170)
- *
+ *
* Write a CMOS address to ChipSet.CMOS.ADDR.PORT, then read/write data from/to ChipSet.CMOS.DATA.PORT.
- *
+ *
* The ADDR port also controls NMI: write an address with bit 7 clear to enable NMI or set to disable NMI.
*/
ChipSet.CMOS = {
@@ -759,7 +759,7 @@ ChipSet.CMOS = {
EXTMEM2_LO: 0x30,
EXTMEM2_HI: 0x31,
CENTURY_DATE: 0x32, // BCD value for the current century (eg, 0x19 for 20th century, 0x20 for 21st century)
- BOOT_INFO: 0x33, // 0x80 if 128Kb expansion memory installed, 0x40 if Setup Utility wants an initial setup message
+ BOOT_INFO: 0x33, // 0x80 if 128Kb expansion memory installed, 0x40 if Setup Utility wants an initial setup message
MASK: 0x3F,
TOTAL: 0x40,
NMI_DISABLE: 0x80
@@ -810,7 +810,7 @@ ChipSet.CMOS = {
DSHD: 2 // double-sided high-density drive (96 TPI, 80 tracks, 1.2Mb max)
},
/*
- * HDRIVE types are defined by table in the HDC component, which uses setCMOSDriveType() to update the CMOS
+ * HDRIVE types are defined by table in the HDC component, which uses setCMOSDriveType() to update the CMOS
*/
HDRIVE: { // abCMOSData[ChipSet.CMOS.ADDR.HDRIVE]
D0_MASK: 0xF0, // Drive 0 type in high nibble
@@ -831,10 +831,10 @@ ChipSet.CMOS = {
*
* The MODEL_5170 TechRef lists 0x80-0x9F as the range for DMA page registers, but that seems a bit
* overbroad; at one point, it says:
- *
+ *
* "I/O address hex 080 is used as a diagnostic-checkpoint port or register.
* This port corresponds to a read/write register in the DMA page register (74LS6I2)."
- *
+ *
* 0x80 is the neighborhood, but that particular port is not documented as a DMA page register.
* We'll refer to it as manufacturing port (see bMFGData). Be aware that the MODEL_5170 BIOS is littered
* with manufacturing test ("MFG_TST") code which, if enabled, writes to other DMA page registers,
@@ -910,7 +910,7 @@ ChipSet.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, control
/**
* initBus(cmp, bus, cpu, dbg)
- *
+ *
* @this {ChipSet}
* @param {Computer} cmp
* @param {Bus} bus
@@ -928,7 +928,7 @@ ChipSet.prototype.initBus = function(cmp, bus, cpu, dbg)
* This divisor is invariant, so we calculate it as soon as we're able to query the CPU's base speed.
*/
this.nTicksDivisor = Math.round(cpu.getCyclesPerSecond() / ChipSet.TIMER_TICKS_PER_SEC);
-
+
bus.addPortInputTable(this, ChipSet.aPortInput);
bus.addPortOutputTable(this, ChipSet.aPortOutput);
if (this.model < ChipSet.MODEL_5170) {
@@ -961,7 +961,7 @@ ChipSet.prototype.initBus = function(cmp, bus, cpu, dbg)
/**
* powerUp(data, fRepower)
- *
+ *
* @this {ChipSet}
* @param {Object|null} data
* @param {boolean} [fRepower]
@@ -981,7 +981,7 @@ ChipSet.prototype.powerUp = function(data, fRepower)
/**
* powerDown(fSave)
- *
+ *
* @this {ChipSet}
* @param {boolean} fSave
* @return {Object|boolean}
@@ -993,7 +993,7 @@ ChipSet.prototype.powerDown = function(fSave)
/**
* reset(fSoft)
- *
+ *
* @this {ChipSet}
* @param {boolean} [fSoft] is true if "soft" reset, otherwise "hard" reset (see below for details)
*/
@@ -1038,7 +1038,7 @@ ChipSet.prototype.reset = function(fSoft)
this.bPPIC = undefined; // tracks writes to port 0x62, in case PPI_CTRL.C_IN_LO or PPI_CTRL.C_IN_HI is not set
this.bPPICtrl = undefined; // tracks writes to port 0x63 (eg, 0x99); read-only
this.bNMI = ChipSet.NMI.DISABLE;// tracks writes to the NMI Mask Register
-
+
/*
* ChipSet state introduced by the MODEL_5170
*/
@@ -1050,13 +1050,13 @@ ChipSet.prototype.reset = function(fSoft)
* the subsequent data byte is saved in b8042OutPort.
*
* TODO: Consider a UI for the Keyboard INHIBIT switch. By default, our keyboard is never inhibited
- * (ie, locked). Also, note that the hardware changes this bit only when new data is sent to b8042OutBuff.
+ * (ie, locked). Also, note that the hardware changes this bit only when new data is sent to b8042OutBuff.
*/
this.b8042Status = ChipSet.KBC.STATUS.NO_INHIBIT;
this.b8042InBuff = 0;
this.b8042CmdData = ChipSet.KBC.DATA.CMD.NO_CLOCK;
this.b8042OutBuff = 0;
-
+
/*
* TODO: Provide more control over these 8042 "Input Port" bits (eg, the keyboard lock)
*/
@@ -1068,7 +1068,7 @@ ChipSet.prototype.reset = function(fSoft)
this.bMFGData = 0;
this.abDMAPageSpare = new Array(7);
-
+
this.bCMOSAddr = 0; // NMI is enabled, since the ChipSet.CMOS.ADDR.NMI_DISABLE bit is not set in bCMOSAddr
/*
@@ -1080,10 +1080,10 @@ ChipSet.prototype.reset = function(fSoft)
if (!fSoft) this.abCMOSData = new Array(ChipSet.CMOS.ADDR.TOTAL);
this.initRTCDate(this.sRTCDate);
-
+
/*
* initCMOSData() will initialize a variety of "legacy" CMOS bytes, but it will NOT overwrite any memory
- * size or hard drive type information that might have been set, via addCMOSMemory() or setCMOSDriveType().
+ * size or hard drive type information that might have been set, via addCMOSMemory() or setCMOSDriveType().
*/
this.initCMOSData();
}
@@ -1100,22 +1100,22 @@ ChipSet.prototype.reset = function(fSoft)
/**
* initRTCDate(sDate)
- *
+ *
* Initialize the RTC portion of the CMOS registers to match the specified date/time (or if none is specified,
* the current date/time). The date/time should be expressed in the ISO 8601 format; eg: "2011-10-10T14:48:00".
- *
+ *
* NOTE: There are two approaches we could take here: always store the RTC bytes in binary, and convert them
* to/from BCD on-demand (ie, as the simulation reads/writes the CMOS RTC registers); or init/update them in the
* format specified by CMOS_STATUSB.BINARY (1 for binary, 0 for BCD). Both approaches require BCD conversion
* functions, but the former seems more efficient, in part because the periodic calls to updateRTCDate() won't
* require any conversions.
- *
+ *
* We take the same approach with the CMOS_STATUSB.HOUR24 setting: internally, we always operate in 24-hour mode,
* but externally, we convert the RTC hour values to the 12-hour format as needed.
- *
+ *
* Thus, all I/O to the RTC bytes must be routed through the getRTCByte() and setRTCByte() functions, to ensure
* that all the necessary on-demand conversions occur.
- *
+ *
* @this {ChipSet}
* @param {string} [sDate]
*/
@@ -1125,10 +1125,10 @@ ChipSet.prototype.initRTCDate = function(sDate)
* NOTE: I've already been burned once by a JavaScript library function that did NOT treat an undefined
* parameter (ie, a parameter === undefined) the same as an omitted parameter (eg, the async parameter in
* xmlHTTP.open() in IE), so I'm taking no chances here: if sDate is undefined, then explicitly call Date()
- * with no parameters.
+ * with no parameters.
*/
var date = sDate? new Date(sDate) : new Date();
-
+
/*
* Example of a valid Date string:
*
@@ -1147,7 +1147,7 @@ ChipSet.prototype.initRTCDate = function(sDate)
} else if (sDate) {
this.println("CMOS date: " + date);
}
-
+
this.abCMOSData[ChipSet.CMOS.ADDR.RTC_SEC] = date.getSeconds();
this.abCMOSData[ChipSet.CMOS.ADDR.RTC_SEC_ALRM] = 0;
this.abCMOSData[ChipSet.CMOS.ADDR.RTC_MIN] = date.getMinutes();
@@ -1160,9 +1160,9 @@ ChipSet.prototype.initRTCDate = function(sDate)
var nYear = date.getFullYear();
this.abCMOSData[ChipSet.CMOS.ADDR.RTC_YEAR] = nYear % 100;
var nCentury = (nYear / 100);
- this.abCMOSData[ChipSet.CMOS.ADDR.CENTURY_DATE] = (nCentury % 10) | ((nCentury / 10) << 4);
+ this.abCMOSData[ChipSet.CMOS.ADDR.CENTURY_DATE] = (nCentury % 10) | ((nCentury / 10) << 4);
this.nCyclesCMOSLastUpdate = -1;
-
+
this.abCMOSData[ChipSet.CMOS.ADDR.RTC_STATUSA] = 0x26; // hard-coded default; refer to ChipSet.CMOS.STATUSA.DV and ChipSet.CMOS.STATUSA.RS
this.abCMOSData[ChipSet.CMOS.ADDR.RTC_STATUSB] = ChipSet.CMOS.STATUSB.HOUR24; // default to BCD mode (ChipSet.CMOS.STATUSB.BINARY not set)
this.abCMOSData[ChipSet.CMOS.ADDR.RTC_STATUSC] = 0x00;
@@ -1171,16 +1171,16 @@ ChipSet.prototype.initRTCDate = function(sDate)
/**
* getRTCByte(iRTC)
- *
+ *
* @param {number} iRTC
* @return {number} b
*/
ChipSet.prototype.getRTCByte = function(iRTC)
{
Component.assert(iRTC >= 0 && iRTC <= ChipSet.CMOS.ADDR.RTC_STATUSD);
-
+
var b = this.abCMOSData[iRTC];
-
+
if (iRTC < ChipSet.CMOS.ADDR.RTC_STATUSA) {
var f12HourValue = false;
if (iRTC == ChipSet.CMOS.ADDR.RTC_HOUR || iRTC == ChipSet.CMOS.ADDR.RTC_HOUR_ALRM) {
@@ -1197,10 +1197,10 @@ ChipSet.prototype.getRTCByte = function(iRTC)
if (!(this.abCMOSData[ChipSet.CMOS.ADDR.RTC_STATUSB] & ChipSet.CMOS.STATUSB.BINARY)) {
/*
* We're in BCD mode, so we must convert b from BINARY to BCD. But first:
- *
+ *
* If b is a 12-hour value (ie, we're in 12-hour mode) AND the hour is a PM value
* (ie, in the range 0x81-0x8C), then it must be adjusted to yield 81-92 in BCD.
- *
+ *
* AM hour values (0x01-0x0C) need no adjustment; they naturally convert to 01-12 in BCD.
*/
if (f12HourValue && b > 0x80) {
@@ -1216,7 +1216,7 @@ ChipSet.prototype.getRTCByte = function(iRTC)
*/
this.abCMOSData[iRTC] ^= ChipSet.CMOS.STATUSA.UIP;
}
- }
+ }
return b;
};
@@ -1237,7 +1237,7 @@ ChipSet.prototype.setRTCByte = function(iRTC, b)
/*
* We're in BCD mode, so we must convert b from BCD to BINARY (we assume it's valid
* BCD; ie, that both nibbles contain only 0-9, not A-F).
- */
+ */
b = (b >> 4) * 10 + (b & 0xf);
fBCD = true;
}
@@ -1245,7 +1245,7 @@ ChipSet.prototype.setRTCByte = function(iRTC, b)
if (fBCD) {
/*
* If the original BCD hour was 0x81-0x92, then the previous BINARY-to-BCD conversion
- * transformed it to 0x51-0x5C, so we must add 0x30.
+ * transformed it to 0x51-0x5C, so we must add 0x30.
*/
if (b > 12) {
Component.assert(b >= 0x51 && b <= 0x5c);
@@ -1275,10 +1275,10 @@ ChipSet.prototype.updateRTCDate = function()
var nCyclesDelta = 0;
var nCyclesPerSecond = this.cpu.getCyclesPerSecond();
var nCyclesUpdate = this.cpu.getCycles(this.fScaleTimers);
-
+
/*
* If nCyclesCMOSLastUpdate hasn't been set yet (ie, if this is our first updateRTCDate() call),
- * then do nothing except initialize nCyclesCMOSLastUpdate.
+ * then do nothing except initialize nCyclesCMOSLastUpdate.
*/
if (this.nCyclesCMOSLastUpdate >= 0) {
nCyclesDelta = nCyclesUpdate - this.nCyclesCMOSLastUpdate;
@@ -1400,7 +1400,7 @@ ChipSet.prototype.addCMOSMemory = function(addr, size)
* setCMOSDriveType(iDrive, bType)
*
* For use by the HDC component, to update the CMOS drive configuration to match HDC's internal configuration.
- *
+ *
* TODO: Extend this to support FDC drive updates, so that FDC can eventually specify diskette drive types
* (ie, DSDD or DSHD) in the same way that HDC does; currently, MODEL_5170 diskette drives always default to DSHD
* (see getSWFloppyDriveType()).
@@ -1428,13 +1428,13 @@ ChipSet.prototype.setCMOSDriveType = function(iDrive, bType)
/**
* updateCMOSChecksum()
- *
+ *
* This sums all the CMOS bytes from 0x10-0x2D, creating a 16-bit checksum. That's a total of 30 (unsigned) 8-bit
* values which could sum to at most 30*255 or 7650 (0x1DE2). Since there's no way that can overflow 16 bits, we don't
* worry about masking it with 0xffff.
- *
+ *
* WARNING: The IBM PC AT TechRef, p.1-53 (p.75) claims that the checksum is on bytes 0x10-0x20, but that's simply wrong.
- *
+ *
* @this {ChipSet}
*/
ChipSet.prototype.updateCMOSChecksum = function()
@@ -1449,7 +1449,7 @@ ChipSet.prototype.updateCMOSChecksum = function()
/**
* save()
- *
+ *
* @this {ChipSet}
* @return {Object}
*
@@ -1473,7 +1473,7 @@ ChipSet.prototype.save = function()
/**
* restore(data)
- *
+ *
* @this {ChipSet}
* @param {Object} data
* @return {boolean} true if successful, false if failure
@@ -1494,27 +1494,27 @@ ChipSet.prototype.restore = function(data)
for (i = 0; i < this.cDMACs; i++) {
this.initDMAController(i, a.length == 1? a[0][i] : a);
}
-
+
a = data[2];
this.aPICs = new Array(this.cPICs);
for (i = 0; i < this.cPICs; i++) {
this.initPIC(i, i === 0? ChipSet.PIC0.PORT_LO : ChipSet.PIC1.PORT_LO, a[0][i]);
}
-
+
a = data[3];
this.bTimerCtrl = a[0];
this.aTimers = new Array(3);
for (i = 0; i < this.aTimers.length; i++) {
this.initTimer(i, a[1][i]);
}
-
+
a = data[4];
this.bPPIA = a[0];
this.bPPIB = a[1];
this.bPPIC = a[2];
this.bPPICtrl = a[3];
this.bNMI = a[4];
-
+
a = data[5];
if (a) {
Component.assert(this.model >= ChipSet.MODEL_5170);
@@ -1537,7 +1537,7 @@ ChipSet.prototype.restore = function(data)
/*
* TODO: Decide whether restore() should faithfully preserve the RTC date/time that save() saved,
* or always reinitialize the date/time, or give the user (or the machine configuration) the option.
- *
+ *
* For now, we're always reinitializing the RTC date. Alternatively, we could selectively update
* the CMOS bytes above, instead of overwriting them all, in which case this extra call to initRTCDate()
* could be avoided.
@@ -1571,7 +1571,7 @@ ChipSet.prototype.initDMAController = function(iDMAC, aState)
/**
* initDMAChannel(controller, iChannel, aState)
- *
+ *
* @this {ChipSet}
* @param {Object} controller
* @param {number} iChannel
@@ -1598,7 +1598,7 @@ ChipSet.prototype.initDMAChannel = function(controller, iChannel, aState)
/**
* initDMAFunction(channel)
- *
+ *
* @param {Object} channel
* @param {Component|string} component
* @param {string} sFunction
@@ -1623,7 +1623,7 @@ ChipSet.prototype.initDMAFunction = function(channel, component, sFunction, obj)
/**
* saveDMAControllers()
- *
+ *
* @this {ChipSet}
* @return {Array}
*/
@@ -1645,7 +1645,7 @@ ChipSet.prototype.saveDMAControllers = function()
/**
* saveDMAChannels(controller)
- *
+ *
* @this {ChipSet}
* @param {Object} controller
* @return {Array}
@@ -1672,7 +1672,7 @@ ChipSet.prototype.saveDMAChannels = function(controller)
/**
* initPIC(iPIC, aState)
- *
+ *
* @this {ChipSet}
* @param {number} iPIC
* @param {number} port
@@ -1696,7 +1696,7 @@ ChipSet.prototype.initPIC = function(iPIC, port, aState)
/**
* savePICs()
- *
+ *
* @this {ChipSet}
* @return {Array}
*/
@@ -1721,7 +1721,7 @@ ChipSet.prototype.savePICs = function()
/**
* initTimer(iTimer, aState)
- *
+ *
* @this {ChipSet}
* @param {number} iTimer
* @param {Array} [aState]
@@ -1749,7 +1749,7 @@ ChipSet.prototype.initTimer = function(iTimer, aState)
/**
* saveTimers()
- *
+ *
* @this {ChipSet}
* @return {Array}
*/
@@ -1779,7 +1779,7 @@ ChipSet.prototype.saveTimers = function()
/**
* getSWMemorySize(fInit)
- *
+ *
* @this {ChipSet}
* @param {boolean|undefined} [fInit] is true for init switch value(s) only, current value(s) otherwise
* @return {number} number of Kb of specified memory (NOT necessarily the same as installed memory; see RAM component)
@@ -1793,7 +1793,7 @@ ChipSet.prototype.getSWMemorySize = function(fInit)
/**
* getSWFloppyDrives(fInit)
- *
+ *
* @this {ChipSet}
* @param {boolean|undefined} [fInit] is true for init switch value(s) only, current value(s) otherwise
* @return {number} number of floppy drives specified by SW1 (range is 0 to 4)
@@ -1809,7 +1809,7 @@ ChipSet.prototype.getSWFloppyDrives = function(fInit)
*
* @this {ChipSet}
* @param {number} iDrive (0-based)
- * @return {number} one of the ChipSet.CMOS.FDRIVE values (ie, NONE: 0, DSDD: 1, DSHD: 2)
+ * @return {number} one of the ChipSet.CMOS.FDRIVE values (ie, NONE: 0, DSDD: 1, DSHD: 2)
*/
ChipSet.prototype.getSWFloppyDriveType = function(iDrive)
{
@@ -1824,7 +1824,7 @@ ChipSet.prototype.getSWFloppyDriveType = function(iDrive)
/**
* getSWVideoMonitor(fInit)
- *
+ *
* @this {ChipSet}
* @param {boolean|undefined} [fInit] is true for init switch value(s) only, current value(s) otherwise
* @return {number} one of ChipSet.MONITOR.*
@@ -1837,7 +1837,7 @@ ChipSet.prototype.getSWVideoMonitor = function(fInit)
/**
* addSwitches(s, control, n, v, oTips)
- *
+ *
* @this {ChipSet}
* @param {string} s is the name of the control
* @param {Object} control is the HTML control DOM object
@@ -1880,7 +1880,7 @@ ChipSet.prototype.addSwitches = function(s, control, n, v, oTips)
/**
* getSwitch(control)
- *
+ *
* @this {ChipSet}
* @param {Object} control is an HTML control DOM object
* @return {boolean} true if the switch represented by e is "on", false if "off"
@@ -1892,7 +1892,7 @@ ChipSet.prototype.getSwitch = function(control)
/**
* setSwitch(control, f)
- *
+ *
* @this {ChipSet}
* @param {Object} control is an HTML control DOM object
* @param {boolean} f is true if the switch represented by e should be "on", false if "off"
@@ -1906,7 +1906,7 @@ ChipSet.prototype.setSwitch = function(control, f)
/**
* toggleSwitch(control)
- *
+ *
* @this {ChipSet}
* @param {Object} control is an HTML control DOM object
*/
@@ -1932,7 +1932,7 @@ ChipSet.prototype.toggleSwitch = function(control)
/**
* updateSwitchDesc()
- *
+ *
* @this {ChipSet}
*/
ChipSet.prototype.updateSwitchDesc = function()
@@ -1963,7 +1963,7 @@ ChipSet.prototype.updateSwitchDesc = function()
/**
* dumpPIC()
- *
+ *
* @this {ChipSet}
*/
ChipSet.prototype.dumpPIC = function()
@@ -1984,7 +1984,7 @@ ChipSet.prototype.dumpPIC = function()
/**
* dumpTimer()
- *
+ *
* @this {ChipSet}
*/
ChipSet.prototype.dumpTimer = function()
@@ -2026,7 +2026,7 @@ ChipSet.prototype.dumpCMOS = function()
/**
* inDMAChannelAddr(iDMAC, iChannel, port, addrFrom)
- *
+ *
* @this {ChipSet}
* @param {number} iDMAC
* @param {number} iChannel
@@ -2046,7 +2046,7 @@ ChipSet.prototype.inDMAChannelAddr = function(iDMAC, iChannel, port, addrFrom)
/**
* outDMAChannelAddr(iDMAC, iChannel, port, bOut, addrFrom)
- *
+ *
* @this {ChipSet}
* @param {number} iDMAC
* @param {number} iChannel
@@ -2065,7 +2065,7 @@ ChipSet.prototype.outDMAChannelAddr = function outDMAChannelAddr(iDMAC, iChannel
/**
* inDMAChannelCount(iDMAC, iChannel, port, addrFrom)
- *
+ *
* @this {ChipSet}
* @param {number} iDMAC
* @param {number} iChannel
@@ -2085,7 +2085,7 @@ ChipSet.prototype.inDMAChannelCount = function(iDMAC, iChannel, port, addrFrom)
/**
* outDMAChannelCount(iDMAC, iChannel, port, bOut, addrFrom)
- *
+ *
* @this {ChipSet}
* @param {number} iDMAC
* @param {number} iChannel (ports 0x01, 0x03, 0x05, 0x07)
@@ -2104,7 +2104,7 @@ ChipSet.prototype.outDMAChannelCount = function(iDMAC, iChannel, port, bOut, add
/**
* inDMAStatus(iDMAC, port, addrFrom)
- *
+ *
* @this {ChipSet}
* @param {number} iDMAC
* @param {number} port
@@ -2132,7 +2132,7 @@ ChipSet.prototype.inDMAStatus = function(iDMAC, port, addrFrom)
* HACK: Unlike the MODEL_5150, the MODEL_5160 ROM BIOS checks DMA channel 0 for TC (@F000:E4DF)
* after running a number of unrelated tests, since enough time would have passed for channel 0 to
* have reached TC at least once. So I simply OR in a hard-coded TC bit for channel 0 every time
- * status is read.
+ * status is read.
*/
var controller = this.aDMACs[iDMAC];
var b = controller.bStatus | 0x1;
@@ -2143,7 +2143,7 @@ ChipSet.prototype.inDMAStatus = function(iDMAC, port, addrFrom)
/**
* outDMACmd(iDMAC, port, bOut, addrFrom)
- *
+ *
* @this {ChipSet}
* @param {number} iDMAC
* @param {number} port
@@ -2158,7 +2158,7 @@ ChipSet.prototype.outDMACmd = function(iDMAC, port, bOut, addrFrom)
/**
* outDMAReq(iDMAC, port, bOut, addrFrom)
- *
+ *
* @this {ChipSet}
* @param {number} iDMAC
* @param {number} port
@@ -2184,7 +2184,7 @@ ChipSet.prototype.outDMAReq = function(iDMAC, port, bOut, addrFrom)
*/
var iChannel = (bOut & 0x3);
/*
- * Bit 2 is the request bit (0 to reset, 1 to set), which must be propagated to the corresponding bit (4-7) in the status register
+ * Bit 2 is the request bit (0 to reset, 1 to set), which must be propagated to the corresponding bit (4-7) in the status register
*/
var iChannelBit = ((bOut & 0x4) << (iChannel + 2));
controller.bStatus = (controller.bStatus & ~(0x10 << iChannel)) | iChannelBit;
@@ -2193,7 +2193,7 @@ ChipSet.prototype.outDMAReq = function(iDMAC, port, bOut, addrFrom)
/**
* outDMAMask(iDMAC, port, bOut, addrFrom)
- *
+ *
* @this {ChipSet}
* @param {number} iDMAC
* @param {number} port
@@ -2212,7 +2212,7 @@ ChipSet.prototype.outDMAMask = function(iDMAC, port, bOut, addrFrom)
/**
* outDMAMode(iDMAC, port, bOut, addrFrom)
- *
+ *
* @this {ChipSet}
* @param {number} iDMAC
* @param {number} port
@@ -2228,7 +2228,7 @@ ChipSet.prototype.outDMAMode = function(iDMAC, port, bOut, addrFrom)
/**
* outDMAIndex(iDMAC, port, bOut, addrFrom)
- *
+ *
* @this {ChipSet}
* @param {number} iDMAC
* @param {number} port
@@ -2246,7 +2246,7 @@ ChipSet.prototype.outDMAIndex = function(iDMAC, port, bOut, addrFrom)
/**
* outDMAClear(iDMAC, port, bOut, addrFrom)
- *
+ *
* @this {ChipSet}
* @param {number} iDMAC
* @param {number} port
@@ -2284,7 +2284,7 @@ ChipSet.prototype.inDMAPageReg = function(iDMAC, iChannel, port, addrFrom)
/**
* outDMAPageReg(iDMAC, iChannel, port, bOut, addrFrom)
- *
+ *
* @this {ChipSet}
* @param {number} iDMAC
* @param {number} iChannel
@@ -2333,8 +2333,8 @@ ChipSet.prototype.outDMAPageSpare = function(iSpare, port, bOut, addrFrom)
* checkDMA()
*
* Called by the CPU whenever INTR.DMA is set.
- *
- * @return {boolean} true if one or more async DMA channels are still active (unmasked), false to reset INTR.DMA
+ *
+ * @return {boolean} true if one or more async DMA channels are still active (unmasked), false to reset INTR.DMA
*/
ChipSet.prototype.checkDMA = function()
{
@@ -2388,7 +2388,7 @@ ChipSet.prototype.requestDMA = function(iDMAChannel, done)
{
var iDMAC = iDMAChannel >> 2;
var controller = this.aDMACs[iDMAC];
-
+
var iChannel = iDMAChannel & 0x3;
var channel = controller.aChannels[iChannel];
@@ -2402,7 +2402,7 @@ ChipSet.prototype.requestDMA = function(iDMAChannel, done)
* We can't simply slam done into channel.done; that would be fine if requestDMA() was called only by functions
* like HDC.doRead() and HDC.doWrite(), but we're also called whenever a DMA channel is unmasked, and in those cases,
* we need to preserve whatever handler may have been previously set.
- *
+ *
* However, in an effort to ensure we don't end up with stale done handlers, connectDMA() will reset channel.done.
*/
if (done) channel.done = done;
@@ -2422,7 +2422,7 @@ ChipSet.prototype.requestDMA = function(iDMAChannel, done)
/**
* advanceDMA(channel, fInit)
- *
+ *
* @param {Object} channel
* @param {boolean} [fInit]
*/
@@ -2442,7 +2442,7 @@ ChipSet.prototype.advanceDMA = function(channel, fInit)
* the data transfer functions provide an fAsync parameter to their callbacks; fAsync must be true if the callback was
* truly asynchronous (ie, it had to wait for a remote I/O request to finish), or false if the data was already available
* and the callback was performed synchronously.
- *
+ *
* Whenever a callback is issued asynchronously, we will immediately daisy-chain another pair of updateDMA()/advanceDMA()
* calls, which will either finish the DMA operation if no more remote I/O requests are required, or will queue up another
* I/O request, which will in turn trigger another async callback. Thus, the DMA request keeps itself going without
@@ -2482,7 +2482,7 @@ ChipSet.prototype.advanceDMA = function(channel, fInit)
/*
* While it makes sense to call bus.setByteDirect(), since DMA deals with physical memory,
* we lose the ability to trap accesses with write breakpoints by not using obj.cpu.setByte().
- *
+ *
* TODO: Consider providing a Bus memory interface that honors write breakpoints.
*/
obj.bus.setByteDirect(addrCur, b);
@@ -2502,7 +2502,7 @@ ChipSet.prototype.advanceDMA = function(channel, fInit)
/*
* While it makes sense to call bus.getByteDirect(), since DMA deals with physical memory,
* we lose the ability to trap accesses with read breakpoints by not using obj.cpu.getByte().
- *
+ *
* TODO: Determine whether we should support async dmaWrite() functions (currently not required),
* and consider providing a Bus memory interface that honors read breakpoints.
*/
@@ -2511,7 +2511,7 @@ ChipSet.prototype.advanceDMA = function(channel, fInit)
/*
* In this case, I think I have no choice but to terminate the DMA operation in response to a failure,
* because the ROM BIOS FDC.REG_DATA.CMD.FORMAT_TRACK command specifies a count that is MUCH too large (a side-effect
- * of the ROM BIOS using the same "DMA_SETUP" code for reads, writes AND formats).
+ * of the ROM BIOS using the same "DMA_SETUP" code for reads, writes AND formats).
*/
channel.fError = true;
}
@@ -2551,7 +2551,7 @@ ChipSet.prototype.updateDMA = function(channel)
}
/*
* In situations where an HDC DMA operation took too long, the Fixed Disk BIOS would give up, but the DMA operation would continue.
- *
+ *
* TODO: Verify that the Fixed Disk BIOS shuts down (ie, re-masks) a DMA channel for failed requests, and that this handles those failures.
*/
if (!channel.masked) return false;
@@ -2562,7 +2562,7 @@ ChipSet.prototype.updateDMA = function(channel)
controller.bStatus = (controller.bStatus & ~(0x10 << channel.iChannel)) | (0x1 << channel.iChannel);
/*
- * EOP is supposed to automatically (re)mask the channel, unless it's set for auto-initialize.
+ * EOP is supposed to automatically (re)mask the channel, unless it's set for auto-initialize.
*/
if (!(channel.mode & ChipSet.DMA_MODE.AUTOINIT)) {
channel.masked = true;
@@ -2578,7 +2578,7 @@ ChipSet.prototype.updateDMA = function(channel)
channel.done(!channel.fError);
channel.done = null;
}
-
+
/*
* While it might make sense to call cpu.setDMA() here, it's simpler to let the CPU issue one more call
* to chipset.checkDMA() and let the CPU update INTR.DMA on its own, based on the return value from checkDMA().
@@ -2588,7 +2588,7 @@ ChipSet.prototype.updateDMA = function(channel)
/**
* inPICLo(iPIC, addrFrom)
- *
+ *
* @this {ChipSet}
* @param {number} iPIC
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
@@ -2617,7 +2617,7 @@ ChipSet.prototype.inPICLo = function(iPIC, addrFrom)
/**
* outPICLo(iPIC, bOut, addrFrom)
- *
+ *
* @this {ChipSet}
* @param {number} iPIC
* @param {number} bOut
@@ -2636,10 +2636,10 @@ ChipSet.prototype.outPICLo = function(iPIC, bOut, addrFrom)
/*
* 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
* mean that all interrupts were masked, but based on what MS-DOS 4.0M expects to happen after this code runs:
- *
+ *
* 0070:44C6 B013 MOV AL,13
* 0070:44C8 E620 OUT 20,AL
* 0070:44CA B050 MOV AL,50
@@ -2658,12 +2658,12 @@ ChipSet.prototype.outPICLo = function(iPIC, bOut, addrFrom)
* sequence, because they need to be (re)initialized at some point. However, if some component is currently
* requesting an interrupt, what should I do about that? Originally, I had decided to clear them ONLY if they
* were still undefined, but that change appeared to break the ROM BIOS handling of CTRL-ALT-DEL, so I'm back
- * to unconditionally zeroing them.
+ * to unconditionally zeroing them.
*/
pic.bIRR = pic.bISR = 0;
/*
* The spec also says that "Special Mask Mode is cleared and Status Read is set to IRR". I attempt to insure
- * the latter, but as for special mask mode... well, that mode isn't supported yet.
+ * the latter, but as for special mask mode... well, that mode isn't supported yet.
*/
pic.bOCW3 = ChipSet.PIC_LO.OCW3 | ChipSet.PIC_LO.OCW3_READ_IRR;
}
@@ -2688,7 +2688,7 @@ ChipSet.prototype.outPICLo = function(iPIC, bOut, addrFrom)
* Less "specifically", a non-specific EOI command. The search for the highest priority in-service
* interrupt must start with whichever interrupt is opposite the lowest priority interrupt (normally 7,
* but technically whatever bIRLow is currently set to). For example:
- *
+ *
* If bIRLow is 7, then the priority order is: 0, 1, 2, 3, 4, 5, 6, 7.
* If bIRLow is 6, then the priority order is: 7, 0, 1, 2, 3, 4, 5, 6.
* If bIRLow is 5, then the priority order is: 6, 7, 0, 1, 2, 3, 4, 5.
@@ -2732,7 +2732,7 @@ ChipSet.prototype.outPICLo = function(iPIC, bOut, addrFrom)
}
} else {
/*
- * This must be an OCW3 request. If it's a "Read Register" command (PIC_LO.OCW3_READ_CMD), inPICLo() 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.
@@ -2746,7 +2746,7 @@ ChipSet.prototype.outPICLo = function(iPIC, bOut, addrFrom)
/**
* inPICHi(iPIC, addrFrom)
- *
+ *
* @this {ChipSet}
* @param {number} iPIC
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
@@ -2762,7 +2762,7 @@ ChipSet.prototype.inPICHi = function(iPIC, addrFrom)
/**
* outPICHi(iPIC, bOut, addrFrom)
- *
+ *
* @this {ChipSet}
* @param {number} iPIC
* @param {number} bOut
@@ -2800,7 +2800,7 @@ ChipSet.prototype.outPICHi = function(iPIC, bOut, addrFrom)
/**
* checkIRR(iPIC, nDelay)
- *
+ *
* @this {ChipSet}
* @param {number} iPIC
* @param {number} [nDelay] is an optional number of instructions to delay acknowledgment of the IRQ (see getIRRVector)
@@ -2818,7 +2818,7 @@ ChipSet.prototype.checkIRR = function(iPIC, nDelay)
/**
* setIRR(nIRQ, nDelay)
- *
+ *
* @this {ChipSet}
* @param {number} nIRQ (IRQ 0-7 implies iPIC 0, and IRQ 8-15 implies iPIC 1)
* @param {number} [nDelay] is an optional number of instructions to delay acknowledgment of the IRQ (see getIRRVector)
@@ -2832,7 +2832,7 @@ ChipSet.prototype.setIRR = function(nIRQ, nDelay)
if (DEBUG) this.messageDebugger("setIRR(" + nIRQ + ")", ChipSet.MESSAGE_PIC, nIRQ);
pic.nDelay = nDelay || 0;
/*
- * When any slave IRR goes high, I'm assuming that the master's slave IRR line should go high as well
+ * When any slave IRR goes high, I'm assuming that the master's slave IRR line should go high as well
*/
if (iPIC == 1) this.aPICs[0].bIRR |= 0x4;
this.checkIRR(iPIC);
@@ -2840,7 +2840,7 @@ ChipSet.prototype.setIRR = function(nIRQ, nDelay)
/**
* clearIRR(nIRQ)
- *
+ *
* @this {ChipSet}
* @param {number} nIRQ (IRQ 0-7 implies iPIC 0, which is all we currently support anyway)
*/
@@ -2854,7 +2854,7 @@ ChipSet.prototype.clearIRR = function(nIRQ)
pic.bIRR &= ~bIRR;
if (DEBUG) this.messageDebugger("clearIRR(" + nIRQ + ")", ChipSet.MESSAGE_PIC, nIRQ);
/*
- * When all slave IRRs go low, I'm assuming that the master's slave IRR line should go low as well
+ * When all slave IRRs go low, I'm assuming that the master's slave IRR line should go low as well
*/
if (iPIC == 1 && !pic.bIRR) this.aPICs[0].bIRR &= ~0x4;
/*
@@ -2869,7 +2869,7 @@ ChipSet.prototype.clearIRR = function(nIRQ)
/**
* checkIMR(nIRQ)
- *
+ *
* @this {ChipSet}
* @param {number} nIRQ
* @return {boolean} true if the specified IRQ is masked, false if not
@@ -2884,7 +2884,7 @@ ChipSet.prototype.checkIMR = function(nIRQ)
/**
* getIRRVector()
- *
+ *
* getIRRVector() is called by the CPU whenever PS_IF is set and OP_NOINTR is clear. Ordinarily, an immediate
* response would seem perfectly reasonable, but unfortunately, there are places in the original ROM BIOS like
* "KBD_RESET" (F000:E688) that enable interrupts but still expect nothing to happen for several more instructions.
@@ -2893,7 +2893,7 @@ ChipSet.prototype.checkIMR = function(nIRQ)
* support a third response (-2) that basically means: don't change the CPU interrupt state, just keep calling until
* we return one of the first two responses. The number of times we delay our normal response is determined by the
* component that originally called setIRR with an optional delay parameter.
- *
+ *
* @this {ChipSet}
* @param {number} [iPIC]
* @return {number} IDT vector # of the next highest-priority interrupt, -1 if none, or -2 for "please try your call again later"
@@ -2910,7 +2910,7 @@ ChipSet.prototype.getIRRVector = function(iPIC)
if (!pic.nDelay) {
var bIR = pic.bIRR & ((pic.bISR | pic.bIMR) ^ 0xff);
/*
- * The search for the next highest priority requested interrupt (that's also not in-service and not masked)
+ * The search for the next highest priority requested interrupt (that's also not in-service and not masked)
* must start with whichever interrupt is opposite the lowest priority interrupt (normally 7, but technically
* whatever bIRLow is currently set to). For example:
*
@@ -2929,7 +2929,7 @@ ChipSet.prototype.getIRRVector = function(iPIC)
var bIRNext = 1 << nIRL;
if (bIR & bIRNext) {
-
+
if (!iPIC && nIRL == 2) {
/*
* Slave interrupts are tied to the master PIC on IRQ2; query the slave PIC for the vector #
@@ -2941,12 +2941,12 @@ ChipSet.prototype.getIRRVector = function(iPIC)
*/
nIDT = pic.aICW[1] + nIRL;
}
-
+
if (nIDT >= 0) {
pic.bISR |= bIRNext;
pic.bIRR &= ~bIRNext;
}
-
+
var nIRQ = pic.nIRQBase + nIRL;
if (DEBUG) this.messageDebugger("getIRRVector(): IRQ " + nIRQ + " going into service", ChipSet.MESSAGE_PIC, nIRQ);
if (MAXDEBUG && DEBUGGER) {
@@ -2954,7 +2954,7 @@ ChipSet.prototype.getIRRVector = function(iPIC)
}
break;
}
-
+
if (nIRL++ == pic.bIRLow) break;
}
} else {
@@ -2966,7 +2966,7 @@ ChipSet.prototype.getIRRVector = function(iPIC)
/**
* inTimer(iTimer, addrFrom)
- *
+ *
* @this {ChipSet}
* @param {number} iTimer (ports 0x40, 0x41, 0x42)
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
@@ -2988,7 +2988,7 @@ ChipSet.prototype.inTimer = function(iTimer, addrFrom)
/**
* outTimer(iTimer, bOut, addrFrom)
- *
+ *
* @this {ChipSet}
* @param {number} iTimer (ports 0x40, 0x41, 0x42)
* @param {number} bOut
@@ -2997,7 +2997,7 @@ ChipSet.prototype.inTimer = function(iTimer, addrFrom)
ChipSet.prototype.outTimer = function(iTimer, bOut, addrFrom)
{
this.messagePort(ChipSet.TIMER0.PORT + iTimer, bOut, addrFrom, "TIMER" + iTimer, ChipSet.MESSAGE_TIMER);
-
+
var timer = this.aTimers[iTimer];
if (timer.countIndex == timer.countBytes) this.resetTimerIndex(iTimer);
timer.countInit[timer.countIndex++] = bOut;
@@ -3024,11 +3024,11 @@ ChipSet.prototype.outTimer = function(iTimer, bOut, addrFrom)
*/
if (iTimer == ChipSet.TIMER0.INDEX) this.clearIRR(ChipSet.IRQ.TIMER0);
}
-
+
if (iTimer == ChipSet.TIMER2.INDEX) {
this.setSpeaker();
}
-
+
/*
* HACK to detect lower-than-normal initial timer counts and reduce the length of CPU bursts, using
* cpu.setBurstDivisor(). Alternatively, the CPU could ask us for a cycle limit, via getTimerCycleLimit(),
@@ -3044,7 +3044,7 @@ ChipSet.prototype.outTimer = function(iTimer, bOut, addrFrom)
this.cpu.setBurstDivisor(Math.round(0x10000 / countInit));
}
}
-
+
if (iTimer == ChipSet.TIMER0.INDEX && timer.mode == ChipSet.TIMER_CTRL.MODE0 && timer.rw == ChipSet.TIMER_CTRL.RW_LSB) {
/*
* HACK to satisfy the quick h/w interrupt turn-around expected by the ROM BIOS when it sets TIMER0 to a
@@ -3053,11 +3053,11 @@ ChipSet.prototype.outTimer = function(iTimer, bOut, addrFrom)
* same time a timer interrupt is expected. Note that in some cases, if the number of cycles remaining
* in the current burst is less than the target, this will have the effect of *lengthening* the current
* burst instead of shortening it, but stepCPU() should be OK with that.
- *
+ *
* Notice how this complements the setBurstDivisor() HACK above: while that code is concerned with how
* to deal with low timer counts prior to starting new bursts, here we're concerned with low timer counts
* (in particular, single-byte LSB counts) programmed in the middle of a burst.
- *
+ *
* The MODEL_5170 BIOS performs a virtually identical test ("TEST.18"), although unsurprisingly, it uses an
* initial timer count that is explicitly twice that other of earlier models (0x16 * 2 = 0x2C). Fortunately,
* it still uses an LSB-only count; however, the original hack calculated the burst-cycle threshold using a
@@ -3071,7 +3071,7 @@ ChipSet.prototype.outTimer = function(iTimer, bOut, addrFrom)
/**
* inTimerCtrl(port, addrFrom)
- *
+ *
* @this {ChipSet}
* @param {number} port (0x43)
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
@@ -3086,7 +3086,7 @@ ChipSet.prototype.inTimerCtrl = function(port, addrFrom)
/**
* outTimerCtrl(port, bOut, addrFrom)
- *
+ *
* @this {ChipSet}
* @param {number} port (0x43)
* @param {number} bOut
@@ -3114,26 +3114,26 @@ ChipSet.prototype.outTimerCtrl = function(port, bOut, addrFrom)
this.latchTimer(iTimer);
} else {
this.setTimerMode(iTimer, bcd, mode, rw);
-
+
/*
* The 5150 ROM BIOS code @F000:E285 ("TEST.7") would fail after a warm boot (eg, after a CTRL-ALT-DEL) because
* it assumed that no TIMER0 interrupt would occur between the point it unmasked the TIMER0 interrupt and the
* point it started reprogramming TIMER0.
- *
+ *
* Similarly, the 5160 ROM BIOS @F000:E35D ("8253 TIMER CHECKOUT") would fail after initializing the EGA BIOS,
* because the EGA BIOS uses TIMER0 during its diagnostics; as in the previous example, by the time the 8253
* test code runs later, there's now a pending TIMER0 interrupt, which triggers an interrupt as soon as IRQ0 is
* unmasked @F000:E364.
- *
+ *
* After looking at this problem at bit more closely the second time around (while debugging the EGA BIOS),
* it turns out I missed an important 8253 feature: whenever a new MODE0 control word OR a new MODE0 count
* is written, fOUT (which is what drives IRQ0) goes low. So, by simply adding an appropriate clearIRR() call
* both here and in outTimer(), this annoying problem seems to be gone.
- *
+ *
* TODO: Determine if there are situations/modes where I should NOT automatically clear IRQ0 on behalf of TIMER0.
*/
if (iTimer == ChipSet.TIMER0.INDEX) this.clearIRR(ChipSet.IRQ.TIMER0);
-
+
/*
* Another TIMER0 HACK: The "CASSETTE DATA WRAP TEST" @F000:E51E occasionally reports an error when the second of
* two TIMER0 counts it latches is greater than the first. You would think the ROM BIOS would expect this, since
@@ -3141,7 +3141,7 @@ ChipSet.prototype.outTimerCtrl = function(port, bOut, addrFrom)
* recently that this should never happen? I'm not sure, but for now, let's try resetting TIMER0's count immediately
* after TIMER2 has been reprogrammed for the test in question (ie, when interrupts are masked and PPIB is set as
* shown below).
- *
+ *
* FWIW, I believe the cassette hardware was discontinued after MODEL_5150, and even if the test fails, it's non-fatal;
* the ROM BIOS displays an error (131) and moves on.
*/
@@ -3160,7 +3160,7 @@ ChipSet.prototype.outTimerCtrl = function(port, bOut, addrFrom)
/**
* getTimerInit(iTimer)
- *
+ *
* @this {ChipSet}
* @param {number} iTimer
* @return {number} initial timer count
@@ -3175,7 +3175,7 @@ ChipSet.prototype.getTimerInit = function(iTimer)
/**
* getTimerStart(iTimer)
- *
+ *
* @this {ChipSet}
* @param {number} iTimer
* @return {number} starting timer count (from the initial timer count for the current countdown)
@@ -3204,7 +3204,7 @@ ChipSet.prototype.getTimerCycleLimit = function(iTimer)
/**
* latchTimer(iTimer)
- *
+ *
* @this {ChipSet}
* @param {number} iTimer
*/
@@ -3214,7 +3214,7 @@ ChipSet.prototype.latchTimer = function(iTimer)
* Update the timer's current count
*/
this.updateTimer(iTimer);
-
+
/*
* Now we can latch it
*/
@@ -3222,7 +3222,7 @@ ChipSet.prototype.latchTimer = function(iTimer)
timer.countLatched[0] = timer.countCurrent[0];
timer.countLatched[1] = timer.countCurrent[1];
timer.fLatched = true;
-
+
/*
* VERIFY: That a latch request resets the timer index
*/
@@ -3234,7 +3234,7 @@ ChipSet.prototype.latchTimer = function(iTimer)
*
* FYI: After setting a timer's mode, the CPU must set the timer's count before it becomes operational;
* ie, before fCounting becomes true.
- *
+ *
* @this {ChipSet}
* @param {number} iTimer
* @param {number} bcd
@@ -3258,7 +3258,7 @@ ChipSet.prototype.setTimerMode = function(iTimer, bcd, mode, rw)
/**
* resetTimerIndex(iTimer)
- *
+ *
* @this {ChipSet}
* @param {number} iTimer
*/
@@ -3271,7 +3271,7 @@ ChipSet.prototype.resetTimerIndex = function(iTimer)
/**
* updateTimer(iTimer, fCycleReset)
- *
+ *
* updateTimer() calculates and updates a timer's current count purely on an "on-demand" basis; we don't actually
* adjust timer counters every 4 CPU cycles, since updating timers that frequently would be prohibitively slow. If
* you're single-stepping the CPU, then yes, updateTimer() will be called after every stepCPU(), via updateAllTimers(),
@@ -3302,10 +3302,10 @@ ChipSet.prototype.updateTimer = function(iTimer, fCycleReset)
* We determine the current timer count based on how many instruction cycles have elapsed since we started
* the timer. Timers are supposed to be "ticking" at a rate of 1193181.8181 times per second, which is
* the system clock of 14.31818Mhz, divided by 12.
- *
+ *
* Similarly, for an 8088, there are supposed to be 4.77Mhz instruction cycles per second, which comes from
* the system clock of 14.31818Mhz, divided by 3.
- *
+ *
* If we divide 4,772,727 CPU cycles per second by 1,193,181 ticks per second, we get 4 cycles per tick,
* which agrees with the ratio of the clock divisors: 12 / 3 == 4.
*
@@ -3314,11 +3314,11 @@ ChipSet.prototype.updateTimer = function(iTimer, fCycleReset)
* so that the timers fire with the same real-world frequency that the user expects. However, that will
* break any code (eg, the ROM BIOS diagnostics) that assumes that the timers are ticking once every 4 cycles
* (or more like every 5 cycles on a 6Mhz 80286).
- *
+ *
* So, when using a machine with the ChipSet "scaletimers" property set, make sure you reset the machine's
* speed prior to rebooting, otherwise you're likely to see ROM BIOS errors. Ditto for any application code
* that makes similar assumptions about the relationship between CPU and timer speeds.
- *
+ *
* In general, you're probably better off NOT using the "scaletimers" property, and simply allowing the timers
* to tick faster as you increase CPU speed (which is why fScaleTimers defaults to false).
*/
@@ -3329,7 +3329,7 @@ ChipSet.prototype.updateTimer = function(iTimer, fCycleReset)
* time we're called, using the cycle count recorded when the timer was initialized. countStart is set
* to countInit when fCounting is first set, and then it is refreshed from countInit at the expiration of
* every count, so that if someone loaded a new countInit in the meantime (eg, BASICA), we'll pick it up.
- *
+ *
* For the original MODEL_5170, the number of cycles per tick is approximately 6,000,000 / 1,193,181,
* or 5.028575, so we can no longer always divide cycles by 4 with a simple right-shift by 2. The proper
* divisor (eg, 4 for MODEL_5150 and MODEL_5160, 5 for MODEL_5170, etc) is nTicksDivisor, which initBus()
@@ -3345,10 +3345,10 @@ ChipSet.prototype.updateTimer = function(iTimer, fCycleReset)
var countInit = this.getTimerInit(iTimer);
var countStart = this.getTimerStart(iTimer);
-
+
var fFired = false;
var count = countStart - ticks;
-
+
/*
* NOTE: This mode is used by ROM BIOS test code that wants to verify timer interrupts are arriving
* neither too slowly nor too quickly. As a result, I've had to add some corresponding trickery
@@ -3372,20 +3372,20 @@ ChipSet.prototype.updateTimer = function(iTimer, fCycleReset)
* to see the count changing; it wasn't looking for interrupts. See ROM BIOS "TEST.03" code @F000:E0DE,
* where TIMER1 is programmed for MODE2, LSB (the same settings, incidentally, used immediately afterward
* for TIMER1 in conjunction with DMA channel 0 memory refreshes).
- *
+ *
* Now this mode generates interrupts. Note that "OUT" goes "low" when the count reaches 1, then "high"
* one tick later, at which point the count is reloaded and counting continues.
- *
+ *
* Chances are, we will often miss the exact point at which the count becomes 1 (or more importantly, one
* tick later, when the count *would* become 0, since that's when "OUT" transitions from "low" to "high"),
* but as with MODE3, hopefully no one will mind.
- *
+ *
* FYI, technically, it appears that the count is never supposed to reach 0, and that an initial count of 1
* is "illegal", whatever that means.
*/
else
if (timer.mode == ChipSet.TIMER_CTRL.MODE2) {
- timer.fOUT = (count != 1); // yes, this line does seem rather pointless....
+ timer.fOUT = (count != 1); // yes, this line does seem rather pointless....
if (count <= 0) {
count = countInit + count;
if (count <= 0) {
@@ -3452,7 +3452,7 @@ ChipSet.prototype.updateTimer = function(iTimer, fCycleReset)
/**
* updateAllTimers(fCycleReset)
- *
+ *
* @this {ChipSet}
* @param {boolean|undefined} [fCycleReset] is true if a cycle-count reset is about to occur
*/
@@ -3466,7 +3466,7 @@ ChipSet.prototype.updateAllTimers = function(fCycleReset)
/**
* inPPIA(port, addrFrom)
- *
+ *
* @this {ChipSet}
* @param {number} port (0x60)
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
@@ -3489,7 +3489,7 @@ ChipSet.prototype.inPPIA = function(port, addrFrom)
/**
* outPPIA(port, bOut, addrFrom)
- *
+ *
* @this {ChipSet}
* @param {number} port (0x60)
* @param {number} bOut
@@ -3533,7 +3533,7 @@ ChipSet.prototype.outPPIB = function(port, bOut, addrFrom)
/**
* updatePPIB(bOut)
- *
+ *
* On MODEL_5170 and up, this updates the "simulated" PPI_B. The only common (and well-documented) PPI_B bits
* across all models are PPI_B.CLK_TIMER2 and PPI_B.SPK_TIMER2, so its possible that this function may need to
* limit its updates to just those bits, and move any model-specific requirements back into the appropriate I/O
@@ -3551,7 +3551,7 @@ ChipSet.prototype.updatePPIB = function(bOut)
/*
* Originally, this code didn't catch the "ERROR_BEEP" case @F000:EC34, which first turns both PPI_B.CLK_TIMER2 (0x01)
* and PPI_B.SPK_TIMER2 (0x02) off, then turns on only PPI_B.SPK_TIMER2 (0x02), then restores the original port value.
- *
+ *
* So, when the ROM BIOS keyboard buffer got full, we didn't issue a BEEP alert. I've fixed that by limiting the test
* to PPI_B.SPK_TIMER2 and ignoring PPI_B.CLK_TIMER2.
*/
@@ -3561,7 +3561,7 @@ ChipSet.prototype.updatePPIB = function(bOut)
/**
* inPPIC(port, addrFrom)
- *
+ *
* @this {ChipSet}
* @param {number} port (0x62)
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
@@ -3609,7 +3609,7 @@ ChipSet.prototype.inPPIC = function(port, addrFrom)
/**
* outPPIC(port, bOut, addrFrom)
- *
+ *
* @this {ChipSet}
* @param {number} port (0x62)
* @param {number} bOut
@@ -3623,7 +3623,7 @@ ChipSet.prototype.outPPIC = function(port, bOut, addrFrom)
/**
* inPPICtrl(port, addrFrom)
- *
+ *
* @this {ChipSet}
* @param {number} port (0x63)
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
@@ -3638,7 +3638,7 @@ ChipSet.prototype.inPPICtrl = function(port, addrFrom)
/**
* outPPICtrl(port, bOut, addrFrom)
- *
+ *
* @this {ChipSet}
* @param {number} port (0x63)
* @param {number} bOut
@@ -3670,7 +3670,7 @@ ChipSet.prototype.in8042OutBuff = function(port, addrFrom)
/**
* out8042InBuffData(port, bOut, addrFrom)
- *
+ *
* This writes to the 8042's input buffer; using this port (ie, 0x60 instead of 0x64) designates the
* the byte as a KBC.DATA.CMD "data byte". Before clearing KBC.STATUS.CMD_FLAG, however, we see if it's set,
* and then based on the previous KBC.CMD "command byte", we do whatever needs to be done with this "data byte".
@@ -3683,10 +3683,10 @@ ChipSet.prototype.in8042OutBuff = function(port, addrFrom)
ChipSet.prototype.out8042InBuffData = function(port, bOut, addrFrom)
{
this.messagePort(port, bOut, addrFrom, "8042_INBUF.DATA", ChipSet.MESSAGE_8042);
-
+
if (this.b8042Status & ChipSet.KBC.STATUS.CMD_FLAG) {
switch (this.b8042InBuff) {
-
+
case ChipSet.KBC.CMD.WRITE_CMD:
this.set8042CmdData(bOut);
break;
@@ -3694,17 +3694,17 @@ ChipSet.prototype.out8042InBuffData = function(port, bOut, addrFrom)
case ChipSet.KBC.CMD.WRITE_OUTPORT:
this.set8042OutPort(bOut);
break;
-
+
/*
* This case is reserved for command bytes that the 8042 is not expecting, which should therefore be passed on
* to the Keyboard itself.
- *
+ *
* Here's some relevant MODEL_5170 ROM BIOS code, "XMIT_8042" (missing from the original MODEL_5170 ROM BIOS listing),
* which sends a command code in AL to the Keyboard and waits for a response, returning it in AL. Note that
* the only "success" exit path from this function involves LOOPing 64K times before finally reading the Keyboard's
* response; either the hardware and/or this code seems a bit brain-damaged if that's REALLY what you had to do to ensure
* a valid response....
- *
+ *
* F000:1B25 86E0 XCHG AH,AL
* F000:1B27 2BC9 SUB CX,CX
* F000:1B29 E464 IN AL,64
@@ -3737,11 +3737,11 @@ ChipSet.prototype.out8042InBuffData = function(port, bOut, addrFrom)
* F000:1B60 E460 IN AL,60
* F000:1B62 83E901 SUB CX,0001 ; EXIT WITH SUCCESS (CX != 0)
* F000:1B65 C3 RET
- *
+ *
* But WAIT, the FUN doesn't end there. After this function returns, "KBD_RESET" waits for a Keyboard interrupt
* to occur, hoping for scan code 0xAA as the Keyboard's final response. "KBD_RESET" also returns CX to the caller,
* and the caller ("TEST.21") assumes there was no interrupt if CX is zero.
- *
+ *
* MOV AL,0FDH
* OUT INTA01,AL
* MOV INTR_FLAG,0
@@ -3754,7 +3754,7 @@ ChipSet.prototype.out8042InBuffData = function(port, bOut, addrFrom)
* DEC BL
* JNZ G11
* ...
- *
+ *
* However, if [INTR_FLAG] is set immediately, the above code will exit immediately, without ever decrementing CX.
* CX can be zero not only if the loop exhausted it, but also if no looping was required; the latter is not an
* error, but "TEST.21" assumes that it is.
@@ -3786,21 +3786,21 @@ ChipSet.prototype.in8042RWReg = function(port, addrFrom)
*
* Also, "TEST.09" of the MODEL_5170 BIOS expects the REFRESH_BIT to alternate, so we used to
* do this:
- *
+ *
* this.bPPIB ^= ChipSet.KBC.RWREG.REFRESH_BIT;
*
* However, the MODEL_5170_REV3 BIOS not only checks REFRESH_BIT in "TEST.09", but includes
* an additional test right before "TEST.11A", which requires the bit change "a bit less"
* frequently. This new test sets CX to zero, and at the end of the test (@F000:05B8), CX
* must be in the narrow range of 0xF600 through 0xF9FD.
- *
+ *
* In fact, the new "WAITF" function @F000:1A3A tells us exactly how frequently REFRESH_BIT
* is expected to change now. That function performs a "FIXED TIME WAIT", where CX is a
* "COUNT OF 15.085737us INTERVALS TO WAIT".
- *
+ *
* So we now tie the state of the REFRESH_BIT to bit 6 of the current CPU cycle count,
* effectively toggling the bit after every 64 cycles. On an 8Mhz CPU that can do 8 cycles
- * in 1us, 64 cycles represents 8us, so that might be a bit fast for "WAITF", but bit 6
+ * in 1us, 64 cycles represents 8us, so that might be a bit fast for "WAITF", but bit 6
* is the only choice that also satisfies the pre-"TEST.11A" test as well.
*/
var b = this.bPPIB & ~(ChipSet.KBC.RWREG.PARITY_ERR | ChipSet.KBC.RWREG.REFRESH_BIT) | ((this.cpu.getCycles() & 0x40)? ChipSet.KBC.RWREG.REFRESH_BIT : 0);
@@ -3844,11 +3844,11 @@ ChipSet.prototype.in8042Status = function(port, addrFrom)
* immediately), then checks KBC.STATUS.OUTBUFF_FULL and performs a "flush" on port 0x60 if
* it's set, then waits for KBC.STATUS.OUTBUFF_FULL *again*. Unfortunately, the "flush" throws
* away our response if we respond immediately.
- *
+ *
* So now when out8042InBuffCmd() has a response, it sets KBC.STATUS.OUTBUFF_DELAY instead
* (which is outside the 0xff range of bits we return); when we see KBC.STATUS.OUTBUFF_DELAY,
* we clear it and set KBC.STATUS.OUTBUFF_FULL, which will be returned on the next read.
- *
+ *
* This provides a single poll delay, so that the aforementioned "flush" won't toss our response.
* If longer delays are needed down the road, we may need to set a delay count in the upper (hidden)
* bits of b8042Status, instead of using a single "OUTBUFF_DELAY" bit.
@@ -3877,18 +3877,18 @@ ChipSet.prototype.out8042InBuffCmd = function(port, bOut, addrFrom)
this.messagePort(port, bOut, addrFrom, "8042_INBUFF.CMD", ChipSet.MESSAGE_8042);
Component.assert(!(this.b8042Status & ChipSet.KBC.STATUS.INBUFF_FULL));
this.b8042InBuff = bOut;
-
+
this.b8042Status |= ChipSet.KBC.STATUS.CMD_FLAG;
-
+
var bPulseBits = 0;
if (this.b8042InBuff >= ChipSet.KBC.CMD.PULSE_OUTPORT) {
bPulseBits = (this.b8042InBuff ^ 0xf);
/*
- * Now that we have isolated the bit(s) to pulse, map all pulse commands to KBC.CMD.PULSE_OUTPORT
+ * Now that we have isolated the bit(s) to pulse, map all pulse commands to KBC.CMD.PULSE_OUTPORT
*/
this.b8042InBuff = ChipSet.KBC.CMD.PULSE_OUTPORT;
}
-
+
switch (this.b8042InBuff) {
case ChipSet.KBC.CMD.WRITE_CMD: // 0x60
case ChipSet.KBC.CMD.WRITE_OUTPORT: // 0xD1
@@ -3900,7 +3900,7 @@ ChipSet.prototype.out8042InBuffCmd = function(port, bOut, addrFrom)
case ChipSet.KBC.CMD.READ_INPORT: // 0xC0
this.set8042OutBuff(this.b8042InPort);
break;
-
+
case ChipSet.KBC.CMD.DISABLE_KBD: // 0xAD
this.set8042CmdData(this.b8042CmdData | ChipSet.KBC.DATA.CMD.NO_CLOCK);
if (DEBUG) this.messageDebugger("keyboard disabled", ChipSet.MESSAGE_KBD);
@@ -3927,7 +3927,7 @@ ChipSet.prototype.out8042InBuffCmd = function(port, bOut, addrFrom)
case ChipSet.KBC.CMD.READ_TEST: // 0xE0
this.set8042OutBuff((this.b8042CmdData & ChipSet.KBC.DATA.CMD.NO_CLOCK)? 0 : ChipSet.KBC.TESTPORT.KBD_CLOCK);
break;
-
+
case ChipSet.KBC.CMD.PULSE_OUTPORT: // 0xF0-0xFF
if (bPulseBits & 0x1) {
/*
@@ -3938,7 +3938,7 @@ ChipSet.prototype.out8042InBuffCmd = function(port, bOut, addrFrom)
this.cpu.resetRegs();
}
break;
-
+
default:
if (DEBUG && DEBUGGER && this.dbg) {
this.dbg.message("unrecognized 8042 command: " + str.toHexByte(this.b8042InBuff));
@@ -3965,11 +3965,11 @@ ChipSet.prototype.set8042CmdData = function(b)
* sends ChipSet.KBC.CMD.WRITE_CMD to port 0x64, followed by 0x4D to port 0x60, which clears NO_CLOCK
* and enables the keyboard. The BIOS then waits for OUTBUFF_FULL to be set, at which point it seems
* to be anticipating an 0xAA response in the output buffer.
- *
+ *
* 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.
- *
+ *
* 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
* powered on, it performs the BAT, and then when the clock and data lines go high, the keyboard sends
@@ -4110,9 +4110,9 @@ ChipSet.prototype.outMFGData = function(port, bOut, addrFrom)
/**
* outNMI(port, bOut, addrFrom)
- *
+ *
* This handler is installed only for models before MODEL_5170.
- *
+ *
* @this {ChipSet}
* @param {number} port (0xA0)
* @param {number} bOut
@@ -4131,7 +4131,7 @@ ChipSet.prototype.outNMI = function(port, bOut, addrFrom)
*
* AH
* ----
- * 0x00 Get current clock count in CX:DX
+ * 0x00 Get current clock count in CX:DX
* 0x01 Set current clock count from CX:DX
* 0x02 Get real-time clock using BCD (CH=hours, CL=minutes, DH=seconds)
* 0x03 Set real-time clock using BCD (CH=hours, CL=minutes, DH=seconds, DL=1 if Daylight Savings Time option)
@@ -4162,7 +4162,7 @@ ChipSet.prototype.intBIOSRTC = function(addr)
sResult = " CH(hour)=" + str.toHexWord(CH) + " CL(min)=" + str.toHexByte(CL) + " DH(sec)=" + str.toHexByte(DH);
} else if (AH == 0x04 || AH == 0x05) {
sResult = " CX(year)=" + str.toHexWord(chipset.cpu.regCX) + " DH(month)=" + str.toHexByte(DH) + " DL(day)=" + str.toHexByte(DL);
- }
+ }
chipset.dbg.messageIntReturn(ChipSet.BIOS.INT_RTC, nLevel, nCycles, sResult);
};
}(this, this.cpu.getCycles()));
@@ -4173,7 +4173,7 @@ ChipSet.prototype.intBIOSRTC = function(addr)
/**
* parseSwitches(s, def)
- *
+ *
* @this {ChipSet}
* @param {string|undefined} s describing switch settings (can't simply use parseInt() with a base of 2, because the bit order is reversed, as well as the bit sense)
* @param {number} def is a default value to use if s is undefined
@@ -4192,7 +4192,7 @@ ChipSet.prototype.parseSwitches = function(s, def)
/**
* setSpeaker(fOn)
- *
+ *
* @this {ChipSet}
* @param {boolean} [fOn] true to turn speaker on, false to turn off, otherwise update as appropriate
*/
@@ -4238,7 +4238,7 @@ ChipSet.prototype.setSpeaker = function(fOn)
/**
* messageDebugger(sMessage, bitsMessage, nIRQ)
- *
+ *
* @this {ChipSet}
* @param {string} sMessage is any caller-defined message string
* @param {number} [bitsMessage] is one or more Debugger MESSAGE_* category flag(s)
@@ -4266,7 +4266,7 @@ ChipSet.prototype.messageDebugger = function(sMessage, bitsMessage, nIRQ)
/**
* messagePort(port, bOut, addrFrom, name, bitsMessage, bIn)
- *
+ *
* @this {ChipSet}
* @param {number} port
* @param {number|null} bOut if an output operation
diff --git a/my_modules/pcjs-client/lib/computer.js b/my_modules/pcjs-client/lib/computer.js
index 0c974a790..37e284a90 100644
--- a/my_modules/pcjs-client/lib/computer.js
+++ b/my_modules/pcjs-client/lib/computer.js
@@ -53,11 +53,11 @@
* The PCjs JavaScript files do have some initialization-order dependencies.
* If you load the files individually, it's recommended that you load them in
* the same order that they're compiled.
- *
+ *
* Generally speaking, component.js should be first, computer.js should be
* last (of the files based on component.js), and panel.js should be listed
* early so that the Control Panel is ready as soon as possible.
- *
+ *
* Another recent ordering requirement is that rom.js must be loaded before
* ram.js; this was true before, but now it's required, because I'm starting
* to add ROM BIOS Data Area definitions to rom.js, and since the data area
@@ -67,19 +67,19 @@
"use strict";
if (typeof module !== 'undefined') {
- var str = require("../../shared/lib/strlib");
- var usr = require("../../shared/lib/usrlib");
- var web = require("../../shared/lib/weblib");
- var UserAPI = require("../../shared/lib/userapi");
- var ReportAPI = require("../../shared/lib/reportapi");
- var Component = require("../../shared/lib/component");
- var Bus = require("./bus");
- var State = require("./state");
+ var str = require("../../shared/lib/strlib");
+ var usr = require("../../shared/lib/usrlib");
+ var web = require("../../shared/lib/weblib");
+ var UserAPI = require("../../shared/lib/userapi");
+ var ReportAPI = require("../../shared/lib/reportapi");
+ var Component = require("../../shared/lib/component");
+ var Bus = require("./bus");
+ var State = require("./state");
}
/**
* Computer(parmsComputer, parmsMachine, fSuspended)
- *
+ *
* @constructor
* @extends Component
* @param {Object} parmsComputer
@@ -93,7 +93,7 @@ if (typeof module !== 'undefined') {
* 20 is the minimum (and the default), which implies 8086/8088 real-mode addressing,
* while 24 is required for 80286 protected-mode addressing. This value is passed
* directly through to the Bus component; see that component for more details.
- *
+ *
* resume: one of the Computer.RESUME constants, which are as follows:
* '0' if resume disabled (default)
* '1' if enabled without prompting
@@ -102,7 +102,7 @@ if (typeof module !== 'undefined') {
* or a string containing the path of a predefined JSON-encoded state
*
* state: the path to JSON-encoded state file (see details regarding 'state' below)
- *
+ *
* If a predefined state is supplied AND it's successfully loaded, then resume behavior
* defaults to '1' (ie, resume enabled without prompting).
*
@@ -154,12 +154,12 @@ function Computer(parmsComputer, parmsMachine, fSuspended) {
this.bus = new Bus({'id': this.idMachine + '.bus', 'buswidth': this.nBusWidth}, this.cpu, this.dbg);
/*
- * Iterate through all the components and connect them to the Control Panel, if any
+ * Iterate through all the components and connect them to the Control Panel, if any
*/
var iComponent, component;
var aComponents = Component.getComponents(this.id);
this.panel = Component.getComponentByType("Panel", this.id);
-
+
if (this.panel && this.panel.controlPrint) {
for (iComponent = 0; iComponent < aComponents.length; iComponent++) {
component = aComponents[iComponent];
@@ -198,7 +198,7 @@ function Computer(parmsComputer, parmsMachine, fSuspended) {
* The Computer 'state' property allows a state file to be specified independent of the 'resume' feature;
* previously, you could only use 'resume' to load a state file -- which we still support, but loading a state
* file that way prevents the machine's state from being saved, since we always resume from the 'resume' file.
- *
+ *
* The other wrinkle is on the restore side: we need to IGNORE the 'state' property if a saved state now exists.
* So we have to peek at localStorage, and unfortunately, the only way to "peek" is to actually load the data,
* but we're not ready to use it yet, so powerUp() has been changed to use any existing stateComputer that we've
@@ -210,7 +210,7 @@ function Computer(parmsComputer, parmsMachine, fSuspended) {
*/
var fAllowResume;
var sState = Component.parmsURL && Component.parmsURL['state'] || (fAllowResume = true) && parmsComputer['state'];
-
+
if (sState) {
sStatePath = this.sStatePath = sState;
if (!fAllowResume) {
@@ -229,7 +229,7 @@ function Computer(parmsComputer, parmsMachine, fSuspended) {
/*
* If sStatePath is set, we must use it. But if there's no sStatePath AND resume is set,
- * then we have the option of resuming from a server-side state, assuming a valid USERID.
+ * then we have the option of resuming from a server-side state, assuming a valid USERID.
*/
if (!sStatePath && this.resume) {
sStatePath = this.getServerStatePath();
@@ -241,7 +241,7 @@ function Computer(parmsComputer, parmsMachine, fSuspended) {
} else {
web.loadResource(sStatePath, true, null, this, this.onLoadSetReady);
}
-
+
if (!fSuspended) {
/*
* Power "up" the computer, giving every component the opportunity to reset or restore itself.
@@ -317,7 +317,7 @@ Computer.prototype.getUserID = function()
/**
* onLoadSetReady(sStateFile, sStateData, nErrorCode)
- *
+ *
* @this {Computer}
* @param {string} sStateFile
* @param {string} sStateData
@@ -327,7 +327,7 @@ Computer.prototype.onLoadSetReady = function(sStateFile, sStateData, nErrorCode)
{
if (!nErrorCode) {
this.sStateData = sStateData;
- if (DEBUG) this.messageDebugger("loaded state file " + sStateFile.replace(this.sUserID || "xxx", "xxx"));
+ if (DEBUG) this.messageDebugger("loaded state file " + sStateFile.replace(this.sUserID || "xxx", "xxx"));
} else {
this.sResumePath = null;
this.fServerState = false;
@@ -338,7 +338,7 @@ Computer.prototype.onLoadSetReady = function(sStateFile, sStateData, nErrorCode)
/**
* wait(fn, parms)
- *
+ *
* wait() waits until every component is ready (including ourselves, the last component we check),
* then calls the specified Computer method.
*
@@ -376,7 +376,7 @@ Computer.prototype.wait = function(fn, parms)
* validateState(stateComputer)
*
* NOTE: We clear() stateValidate only when there's no stateComputer.
- *
+ *
* @this {Computer}
* @param {State|null} [stateComputer]
* @return {boolean} true if state passes validation, false if not
@@ -403,7 +403,7 @@ Computer.prototype.validateState = function(stateComputer)
* powerOn(resume)
*
* Power every component "up", applying any previously available state information.
- *
+ *
* @this {Computer}
* @param {number} [resume] is a valid RESUME value; default is this.resume
*/
@@ -455,7 +455,7 @@ Computer.prototype.powerOn = function(resume)
stateComputer.load(sData);
} else {
/*
- * A missing (or not yet created) state file is no cause for alarm, but other errors might be
+ * A missing (or not yet created) state file is no cause for alarm, but other errors might be
*/
if (sCode == UserAPI.CODE.FAIL && sData != UserAPI.FAIL.NOSTATE) {
this.notice("Error: " + sData);
@@ -529,7 +529,7 @@ Computer.prototype.powerOn = function(resume)
/**
* powerRestore(component, stateComputer, fRepower, fRestore)
- *
+ *
* @this {Computer}
* @param {Component} component
* @param {State} stateComputer
@@ -550,7 +550,7 @@ Computer.prototype.powerRestore = function(component, stateComputer, fRepower, f
* This is a hack that makes it possible for a machine whose ID has been
* supplemented with a suffix (a single letter or digit) to find object IDs
* in states created from a machine without the suffix.
- *
+ *
* For example, if a state file was created from a machine with ID "ibm5160"
* but the current machine is "ibm5160a", this attempts a second lookup with
* "ibm5160", enabling us to find objects that match the original machine ID
@@ -565,7 +565,7 @@ Computer.prototype.powerRestore = function(component, stateComputer, fRepower, f
* string comes back, something went wrong. By explicitly eliminating "string" data,
* the Closure Compiler stops complaining that we might be passing strings to our
* powerUp() functions (even though we know we're not).
- *
+ *
* TODO: Determine if there's some way to coerce the Closure Compiler into treating
* data as Object or null, without having to include this runtime check. An assert
* would be a good idea, but this is overkill.
@@ -629,7 +629,7 @@ Computer.prototype.powerRestore = function(component, stateComputer, fRepower, f
* powerFinish(aParms)
*
* This is nothing more than a continuation of powerOn(), giving us the option of calling wait() one more time.
- *
+ *
* @this {Computer}
* @param {Array} aParms containing [stateComputer, resume, fRestore]
*/
@@ -676,7 +676,7 @@ Computer.prototype.powerFinish = function(aParms)
/**
* powerReport(stateComputer)
- *
+ *
* @this {Computer}
* @param {State} stateComputer
*/
@@ -712,7 +712,7 @@ Computer.prototype.powerReport = function(stateComputer)
*
* As it stands, the worst that happens is any manually mounted disk images might have to be manually remounted,
* which doesn't seem like a huge problem.
- *
+ *
* @this {Computer}
* @param {boolean} fSave
* @param {boolean} [fShutdown] is true if the machine is being shut down
@@ -809,9 +809,9 @@ Computer.prototype.powerOff = function(fSave, fShutdown)
sState = stateComputer.toString();
}
}
-
+
if (fShutdown) this.fPowered = false;
-
+
return sState;
};
@@ -819,11 +819,11 @@ Computer.prototype.powerOff = function(fSave, fShutdown)
* reset()
*
* Notify all (other) components with a reset() method that the Computer is being reset.
- *
+ *
* NOTE: We'd like to reset the Bus first (due to the importance of the A20 line), but since we
* allocated the Bus object ourselves, after all the other components were allocated, it ends
* up near the end of Component's list of components. Hence the special case for this.bus below.
- *
+ *
* @this {Computer}
*/
Computer.prototype.reset = function()
@@ -846,10 +846,10 @@ Computer.prototype.reset = function()
* start(ms, nCycles)
*
* Notify all (other) components with a start() method that the CPU has started.
- *
+ *
* Note that we're called by runCPU(), which is why we exclude the CPU component,
* as well as ourselves.
- *
+ *
* @this {Computer}
* @param {number} ms
* @param {number} nCycles
@@ -892,7 +892,7 @@ Computer.prototype.stop = function(ms, nCycles)
/**
* setBinding(sHTMLClass, sHTMLType, sBinding, control)
- *
+ *
* @this {Computer}
* @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")
@@ -942,7 +942,7 @@ Computer.prototype.resetUserID = function()
/**
* queryUserID(fPrompt)
- *
+ *
* @param {boolean} [fPrompt]
* @returns {string|null|undefined}
*/
@@ -968,7 +968,7 @@ Computer.prototype.queryUserID = function(fPrompt)
/**
* verifyUserID(sUserID)
- *
+ *
* @this {Computer}
* @param {string} sUserID
* @return {string} validated user ID, or null if error
@@ -1002,7 +1002,7 @@ Computer.prototype.verifyUserID = function(sUserID)
/**
* getServerStatePath()
- *
+ *
* @this {Computer}
* @return {string|null} sStatePath (null if no localStorage or no USERID stored in localStorage)
*/
@@ -1020,7 +1020,7 @@ Computer.prototype.getServerStatePath = function()
/**
* saveServerState(sUserID, sState)
- *
+ *
* @param {string} sUserID
* @param {string|null} sState
*/
@@ -1054,7 +1054,7 @@ Computer.prototype.saveServerState = function(sUserID, sState)
/**
* storeServerState(sUserID, sState, fSync)
- *
+ *
* @this {Computer}
* @param {string} sUserID
* @param {string} sState
@@ -1095,7 +1095,7 @@ Computer.prototype.storeServerState = function(sUserID, sState, fSync)
/**
* onReset()
- *
+ *
* @this {Computer}
*/
Computer.prototype.onReset = function()
@@ -1117,7 +1117,7 @@ Computer.prototype.onReset = function()
* and rely on all the components to reset themselves to their default state. The components with
* the greatest burden here are FDC and HDC, which must rely on the fReload flag to determine whether
* or not to unload/reload all their original auto-mounted disk images.
- *
+ *
* However, if we started with a predefined state (ie, sStatePath is set), we take this shortcut, because
* we don't (yet) have code in place to gracefully reload the initial state (requires calling loadResource()
* again); alternatively, we could avoid throwing that state away, but it seems better to save the memory.
@@ -1139,7 +1139,7 @@ Computer.prototype.onReset = function()
/**
* getComponentByType(sType, componentPrev)
- *
+ *
* @this {Computer}
* @param {string} sType
* @param {Component} [componentPrev] of previously returned component, if any
@@ -1188,19 +1188,19 @@ Computer.prototype.messageDebugger = function(sMessage, fForce)
Computer.init = function()
{
var aeMachines = Component.getElementsByClass(window.document, PCJSCLASS + "-machine");
-
+
for (var iMachine = 0; iMachine < aeMachines.length; iMachine++) {
-
+
var eMachine = aeMachines[iMachine];
var parmsMachine = Component.getComponentParms(eMachine);
var aeComputers = Component.getElementsByClass(eMachine, PCJSCLASS, "computer");
-
+
for (var iComputer = 0; iComputer < aeComputers.length; iComputer++) {
-
+
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.
@@ -1208,7 +1208,7 @@ Computer.init = function()
var computer = new Computer(parmsComputer, parmsMachine, true);
if (DEBUG) computer.messageDebugger("onInit(" + computer.fPowered + ")");
-
+
/*
* For now, all we support are "reset" and "save" buttons. We may eventually add a "power"
* button to manually suspend/resume the machine. An "erase" button was also considered, but
@@ -1216,7 +1216,7 @@ Computer.init = function()
* might be redundant now.
*/
Component.bindComponentControls(computer, eComputer, PCJSCLASS);
-
+
/*
* Power "up" the computer, giving every component the opportunity to reset or restore itself.
*/
@@ -1238,7 +1238,7 @@ Computer.show = function()
if (computer) {
if (DEBUG) computer.messageDebugger("onShow(" + computer.fInitialized + "," + computer.fPowered + ")");
-
+
if (computer.fInitialized && !computer.fPowered) {
/**
* Repower the computer, notifying every component to continue running as-is.
@@ -1285,7 +1285,7 @@ Computer.exit = function()
if (computer) {
if (DEBUG) computer.messageDebugger("onExit(" + computer.fPowered + ")");
-
+
if (computer.fPowered) {
/**
* Power "down" the computer, giving every component an opportunity to save its state,
diff --git a/my_modules/pcjs-client/lib/cpu.js b/my_modules/pcjs-client/lib/cpu.js
index 4efdf2f08..9f1c0ec77 100644
--- a/my_modules/pcjs-client/lib/cpu.js
+++ b/my_modules/pcjs-client/lib/cpu.js
@@ -34,9 +34,9 @@
"use strict";
if (typeof module !== 'undefined') {
- var str = require("../../shared/lib/strlib");
- var usr = require("../../shared/lib/usrlib");
- var Component = require("../../shared/lib/component");
+ var str = require("../../shared/lib/strlib");
+ var usr = require("../../shared/lib/usrlib");
+ var Component = require("../../shared/lib/component");
}
/**
@@ -46,9 +46,9 @@ if (typeof module !== 'undefined') {
*
* cycles: the machine's base cycles per second; the X86CPU constructor will
* provide us with a default (based on the CPU model) to use as a fallback
- *
+ *
* multiplier: base cycle multiplier; default is 1
- *
+ *
* autoStart: true to automatically start, false to not, or null (default)
* to make the autoStart decision based on whether or not a Debugger is
* installed (if there's no Debugger AND no "Run" button, then auto-start,
@@ -82,7 +82,7 @@ function CPU(parmsCPU, nCyclesDefault)
var nMultiplier = parmsCPU['multiplier'] || 1;
this.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
@@ -113,7 +113,7 @@ function CPU(parmsCPU, nCyclesDefault)
* Get checksum parameters, if any. runCPU() behavior is not affected until fChecksum
* is true, which won't happen until resetChecksum() is called with nCyclesChecksumInterval
* ("csInterval") set to a positive value.
- *
+ *
* As above, any of these parameters can also be set with the Debugger's execution options
* command ("x"); for example, "x cs int 5000" will set nCyclesChecksumInterval to 5000
* and call resetChecksum().
@@ -126,7 +126,7 @@ function CPU(parmsCPU, nCyclesDefault)
var cpu = this;
this.onRunTimeout = function() { cpu.runCPU(); };
-
+
this.setReady();
}
@@ -156,7 +156,7 @@ CPU.STATUS_UPDATES_PER_SECOND = 2;
/**
* initBus(cmp, bus, cpu, dbg)
- *
+ *
* @this {CPU}
* @param {Computer} cmp
* @param {Bus} bus
@@ -170,7 +170,7 @@ CPU.prototype.initBus = function(cmp, bus, cpu, dbg)
this.cmp = cmp;
/*
* Attach the Video component to the CPU, so that the CPU can periodically update
- * the video display via displayVideo(), as cycles permit.
+ * the video display via displayVideo(), as cycles permit.
*/
var video = cmp.getComponentByType("Video");
if (video) {
@@ -184,7 +184,7 @@ CPU.prototype.initBus = function(cmp, bus, cpu, dbg)
/*
* Attach the ChipSet component to the CPU, so that it can obtain the IDT vector number of
* pending hardware interrupts, in response to ChipSet's updateINTR() notifications.
- *
+ *
* We must also call chipset.updateAllTimers() periodically; stepCPU() takes care of that.
*/
this.chipset = cmp.getComponentByType("ChipSet");
@@ -195,7 +195,7 @@ CPU.prototype.initBus = function(cmp, bus, cpu, dbg)
* reset()
*
* This is a placeholder for reset (overridden by the X86CPU component).
- *
+ *
* @this {CPU}
*/
CPU.prototype.reset = function()
@@ -206,7 +206,7 @@ CPU.prototype.reset = function()
* save()
*
* This is a placeholder for save support (overridden by the X86CPU component).
- *
+ *
* @this {CPU}
* @return {Object|null}
*/
@@ -219,7 +219,7 @@ CPU.prototype.save = function()
* restore(data)
*
* This is a placeholder for restore support (overridden by the X86CPU component).
- *
+ *
* @this {CPU}
* @param {Object} data
* @return {boolean} true if restore successful, false if not
@@ -258,7 +258,7 @@ CPU.prototype.powerUp = function(data, fRepower)
* 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.
*/
@@ -273,7 +273,7 @@ CPU.prototype.powerUp = function(data, fRepower)
/**
* powerDown(fSave)
- *
+ *
* @this {CPU}
* @param {boolean} fSave
* @return {Object|boolean}
@@ -286,7 +286,7 @@ CPU.prototype.powerDown = function(fSave)
/**
* autoStart()
- *
+ *
* @this {CPU}
* @return {boolean} true if started, false if not
*/
@@ -335,9 +335,9 @@ CPU.prototype.isRunning = function()
/**
* getChecksum()
- *
+ *
* This will be implemented by the X86CPU component.
- *
+ *
* @this {CPU}
* @return {number} a 32-bit summation of key elements of the current CPU state (used by the CPU checksum code)
*/
@@ -352,7 +352,7 @@ CPU.prototype.getChecksum = function()
* If checksum generation is enabled (fChecksum is true), this resets the running 32-bit checksum and the
* cycle counter that will trigger the next displayChecksum(); called by resetCycles(), which is called whenever
* the CPU is reset or restored.
- *
+ *
* @this {CPU}
* @return {boolean} true if checksum generation enabled, false if not
*/
@@ -378,7 +378,7 @@ CPU.prototype.resetChecksum = function()
* number of cycles (1), effectively limiting execution to a single instruction, and then we're called with
* the exact number cycles that were actually executed. This should give us instruction-granular checksums
* at precise intervals that are 100% repeatable.
- *
+ *
* @this {CPU}
* @param {number} nCycles
*/
@@ -409,11 +409,11 @@ CPU.prototype.updateChecksum = function(nCycles)
/**
* displayChecksum()
- *
+ *
* When checksum generation is enabled (fChecksum is true), this is called to provide a crude log of all
* checksums generated at the specified cycle intervals, as specified by the "csStart" and "csInterval" parmsCPU
* properties).
- *
+ *
* @this {CPU}
*/
CPU.prototype.displayChecksum = function()
@@ -473,7 +473,7 @@ CPU.prototype.displayVideo = function()
/**
* setBinding(sHTMLClass, sHTMLType, sBinding, control)
- *
+ *
* @this {CPU}
* @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")
@@ -539,7 +539,7 @@ CPU.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, control)
* A divisor greater than 1 (the default) does NOT require us to yield more frequently or update the screen
* more frequently; it only means that stepCPU() must be called more frequently, with correspondingly smaller burst
* cycles, because stepCPU() is responsible for updating all the timers ONCE, each time it's called.
- *
+ *
* @this {CPU}
* @param {number} nDivisor
*/
@@ -652,12 +652,12 @@ CPU.prototype.getCycles = function(fScaled)
*
* but that speed will fluctuate somewhat: large fluctuations at first, but increasingly smaller
* fluctuations after each burst of instructions that runCPU() executes.
- *
+ *
* Alternatively, we can scale the cycle count by the multiplier, which is good in that the
* multiplier doesn't vary once the user changes it, but a potential downside is that the
* multiplier might be set too high, resulting in a target speed that's higher than the effective
* speed is able to reach.
- *
+ *
* Also, if multipliers were always limited to a power-of-two, then this could be calculated
* with a simple shift. However, only the "setSpeed" UI binding limits it that way; the Debugger
* interface allows any value, as does the CPU "multiplier" parmsCPU property (from the machine's
@@ -717,9 +717,9 @@ CPU.prototype.getSpeed = function() {
*/
CPU.prototype.getSpeedCurrent = function() {
/*
- * TODO: Has toFixed() been "fixed" in all browsers (eg, IE) to return a rounded value now?
+ * 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.fRunning && this.mhz)? (this.mhz.toFixed(2) + "Mhz") : "Stopped");
};
/**
@@ -730,14 +730,14 @@ CPU.prototype.getSpeedCurrent = function() {
*/
CPU.prototype.getSpeedTarget = function() {
/*
- * TODO: Has toFixed() been "fixed" in all browsers (eg, IE) to return a rounded value now?
+ * TODO: Has toFixed() been "fixed" in all browsers (eg, IE) to return a rounded value now?
*/
return this.mhzTarget.toFixed(2) + "Mhz";
};
/**
* setSpeed(nMultiplier, fOnClick)
- *
+ *
* @this {CPU}
* @param {number} [nMultiplier] is the new proposed multiplier (reverts to 1 if the target was too high)
* @param {boolean} [fOnClick] is true if called from a click handler that might have stolen focus
@@ -774,7 +774,7 @@ CPU.prototype.setSpeed = function(nMultiplier, fOnClick)
/**
* calcSpeed(nCycles, msElapsed)
- *
+ *
* @this {CPU}
* @param {number} nCycles
* @param {number} msElapsed
@@ -793,7 +793,7 @@ CPU.prototype.calcSpeed = function(nCycles, msElapsed)
/**
* calcStartTime()
- *
+ *
* @this {CPU}
*/
CPU.prototype.calcStartTime = function()
@@ -808,22 +808,22 @@ CPU.prototype.calcStartTime = function()
* Try to detect situations where the browser may have throttled us, such as when the user switches
* to a different tab; in those situations, Chrome and Safari may restrict setTimeout() callbacks
* to roughly one per second.
- *
+ *
* Another scenario: the user resizes the browser window. setTimeout() callbacks are not throttled,
* but there can still be enough of a lag between the callbacks that CPU speed will be noticeably
* erratic if we don't compensate for it here.
- *
+ *
* 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.
- *
+ *
* This shouldn't be triggered when the Debugger halts the CPU, because setSpeed() -- which is called
* whenever the CPU starts running again -- zeroes msEndThisRun.
- *
+ *
* This also won't do anything about other internal delays; for example, Debugger message() calls.
* By the time the message() function has called yieldCPU(), the cost of the message has already been
* incurred, so it will be end up being charged against the instruction(s) that triggered them.
- *
+ *
* TODO: Consider calling yieldCPU() sooner from message(), so that it can arrange for the msEndThisRun
* "snapshot" to occur sooner; it's unclear, however, whether that will really improve the CPU's ability
* to hit its target speed, since you would expect any instruction that displays a message to be an
@@ -849,14 +849,14 @@ CPU.prototype.calcStartTime = function()
/**
* calcRemainingTime()
- *
+ *
* @this {CPU}
* @return {number}
*/
CPU.prototype.calcRemainingTime = function()
{
this.msEndThisRun = usr.getTime();
-
+
var msYield = this.msPerYield;
if (this.nCyclesThisRun) {
/*
@@ -906,7 +906,7 @@ CPU.prototype.calcRemainingTime = function()
/*
* Last but not least, update nRecalcCycles, so that when runCPU() starts up again and calls calcStartTime(),
- * it'll be ready to decide if calcCycles() should be called again.
+ * it'll be ready to decide if calcCycles() should be called again.
*/
this.nRecalcCycles += this.nCyclesThisRun;
@@ -920,7 +920,7 @@ CPU.prototype.calcRemainingTime = function()
/**
* runCPU(fOnClick)
- *
+ *
* @this {CPU}
* @param {boolean} [fOnClick] is true if called from a click handler that might have stolen focus
*/
@@ -953,7 +953,7 @@ CPU.prototype.runCPU = function(fOnClick)
try {
do {
var nCyclesPerBurst = this.fChecksum? 1 : Math.round(this.nCyclesPerBurst / this.nBurstDivisor);
-
+
/*
* This is an alternative to ChipSet calling setBurstDivisor(). Unfortunately, this doesn't seem
* to work as well as setBurstDivisor(); for some reason, the smaller bursts that the burst divisor
@@ -965,7 +965,7 @@ CPU.prototype.runCPU = function(fOnClick)
* nCyclesPerBurst = nCyclesTimer0;
* }
*/
-
+
/*
* nCyclesPerBurst is how many cycles we WANT to run on each iteration of stepCPU(), but it may run
* significantly less (or slightly more, since we can't execute partial instructions).
@@ -1015,7 +1015,7 @@ CPU.prototype.runCPU = function(fOnClick)
/**
* setBurstCycles(nCycles)
- *
+ *
* This function is used by the ChipSet component whenever a very low timer count is set,
* in anticipation of the timer requiring an update sooner than the normal nCyclesPerYield
* period in runCPU() would normally provide.
@@ -1046,7 +1046,7 @@ CPU.prototype.setBurstCycles = function(nCycles)
*
* This similar to yieldCPU(), but it doesn't need to zero nCyclesNextYield to break out of runCPU();
* it simply needs to clear fRunning (well, "simply" may be oversimplifying a bit....)
- *
+ *
* @this {CPU}
* @param {boolean} [fComplete]
*/
@@ -1067,7 +1067,7 @@ CPU.prototype.haltCPU = function(fComplete)
/**
* stepCPU(nMinCycles)
- *
+ *
* This will be implemented by the X86CPU component.
*
* @this {CPU}
@@ -1086,7 +1086,7 @@ CPU.prototype.stepCPU = function(nMinCycles)
* stepCPU() -- needed to have more control over when these updates are performed. However, for
* other callers of stepCPU(), such as the Debugger, the combination of stepCPU() + updateCPU()
* provides the old behavior.
- *
+ *
* @this {CPU}
*/
CPU.prototype.updateCPU = function()
@@ -1097,7 +1097,7 @@ CPU.prototype.updateCPU = function()
/**
* yieldCPU()
- *
+ *
* Similar to haltCPU() with regard to how it resets various cycle countdown values, but the CPU
* remains in a "running" state.
*
diff --git a/my_modules/pcjs-client/lib/debugger.js b/my_modules/pcjs-client/lib/debugger.js
index fc8bab5af..f91620ff4 100644
--- a/my_modules/pcjs-client/lib/debugger.js
+++ b/my_modules/pcjs-client/lib/debugger.js
@@ -35,15 +35,15 @@
if (DEBUGGER) {
if (typeof module !== 'undefined') {
- var str = require("../../shared/lib/strlib");
- var usr = require("../../shared/lib/usrlib");
- var web = require("../../shared/lib/weblib");
- var Component = require("../../shared/lib/component");
- var Bus = require("./bus");
- var State = require("./state");
- var CPU = require("./cpu");
- var X86 = require("./x86");
- var X86Seg = require("./x86seg");
+ var str = require("../../shared/lib/strlib");
+ var usr = require("../../shared/lib/usrlib");
+ var web = require("../../shared/lib/weblib");
+ var Component = require("../../shared/lib/component");
+ var Bus = require("./bus");
+ var State = require("./state");
+ var CPU = require("./cpu");
+ var X86 = require("./x86");
+ var X86Seg = require("./x86seg");
}
}
diff --git a/my_modules/pcjs-client/lib/disk.js b/my_modules/pcjs-client/lib/disk.js
index 00b26ac88..134ac2383 100644
--- a/my_modules/pcjs-client/lib/disk.js
+++ b/my_modules/pcjs-client/lib/disk.js
@@ -51,19 +51,19 @@
/*
* Client/Server Disk I/O
- *
+ *
* To support large disks without consuming large amounts of client-side memory, and to push
* client-side disk changes back the server, we need a DiskIO API that can be used in place of
* the DiskDump API.
- *
+ *
* Use of the DiskIO API and any associated disk images must be tightly coupled to per-user
* storage and specific machine configurations, to prevent the disk images from being corrupted
* by inconsistent I/O operations. Our basic User API (userapi.js) already provides some
* per-user storage that we can use to get the design rolling.
- *
+ *
* The DiskIO API must also provide the ability to create new (empty) hard disk images in per-user
* storage and automatically associate them with the machine configurations that requested them.
- *
+ *
* Principles
* ---
* Originally, when the Disk class was given a disk image to load and mount, it would request the
@@ -71,84 +71,84 @@
* for larger disks -- let's just say anything stored on the server as an IMG file -- we'd prefer
* to interact with that disk using "On-Demand I/O". Any IMG file on the same server as the PCjs
* application should be a candidate for on-demand access.
- *
+ *
* On-Demand I/O means that nothing is initially transferred from the server. As sectors are
* requested by the PCjs machine, PCjs requests them from the server, and maintains an MRU cache
* of sectors, periodically discarding the least-used clean sectors above a certain memory limit.
* Dirty sectors (ie, those that the PCjs machine has written to) must be periodically sent
* back to the server and then marked as clean, so that they can be discarded like any other
* sector.
- *
+ *
* We also support "local" init-only disk images, which means that dirty sectors are never sent
* back to the server and are instead retained by the client for the lifetime of the app; such
* images are "read-only" as far as the server is concerned, but "read-write" as far as the client
* is concerned. Reloading/restarting an app with an "local" disk will return the disk to its
- * initial state.
- *
+ * initial state.
+ *
* Practice
* ---
* Let's first look at what we *already* do for the HDC component:
- *
+ *
* 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:
- *
+ *
*
- *
+ *
* and an example of #2 is in /configs/pc/disks/fixed/win101.xml:
- *
+ *
*
*
* The HDC component expects an array of drive entries. Array position determines drive numbering
* (the first entry is drive 0, the second is drive 1, etc), and each entry contains the following
* properties:
- *
+ *
* 'name': user-friendly name for the disk, if any
* 'path': URL of the disk image, if any
* 'type': a drive type
- *
+ *
* Of those properties, only 'type' is required, which provides an index into an HDC "Drive Type"
* table that determines disk geometry and therefore disk size. As we add support for larger disks and
* newer disk controllers, the 'type' parameter will be superseded by either a user-defined 'geometry'
* parameter that will define number of heads, cylinders, tracks, sectors per track, and (max) bytes per
* sector, or perhaps a generic 'size' parameter that leaves geometry choices to the HDC component,
* which will then pass those decisions on to the Disk component.
- *
+ *
* We will enable on-demand I/O for a disk image with a new 'mode' parameter that looks like:
- *
+ *
* 'mode': one of "local", "preload", "demandrw", "demandro"
- *
+ *
* "preload" means the disk image will be completely preloaded, exactly as before; "demandrw" enables
* full on-demand I/O support; and "demandro" enables on-demand I/O for reads only (all writes are retained
* and never written back to the server).
- *
+ *
* "ro" will be the fallback for "rw" unless TWO other important criteria are met: 1) the user has a
* private user key, and therefore per-user storage; and 2) the disk image 'path' contains an asterisk (*)
* that the server can internally remap to a directory in the user's storage; eg:
- *
+ *
* 'path': /10mb.img (path components following the asterisk are optional)
- *
+ *
* If the disk image does not already exist, it will be created (but not formatted).
- *
+ *
* This preserves the promise that EVERYTHING a user does within a PCjs machine is private (ie, not
* visible to any other PCjs users). I don't want to be in the business of saving any user machine
* states or disk changes, but at least those operations are limited to users who have asked for (and
* received) a private user key.
- *
+ *
* Another important consideration at this stage is dealing with multiple machines writing to the same
* disk image; even though we're limiting the "demandrw" mode to per-user images, a single user may still
* inadvertently start up multiple machines that refer to the same disk image.
- *
+ *
* So, every PCjs machine needs to generate a unique token and include that token with every Disk I/O API
* operation, so that the server can revoke a previous machine's "rw" access to a disk image when a new
* machine requests "rw" access to the same disk image.
- *
+ *
* From the client's perspective, revocation can be quietly dealt with by reverting to "demandro" mode;
* that client becomes stuck with all their dirty sectors until they can reclaim "rw" access, which should
* only happen if no intervening writes to the disk image on the server have occurred (if I bother allowing
* reclamation at all).
- *
+ *
* The real challenge here is avoiding revocation of a machine that still has critical changes to commit,
* but since we can't even solve the problem of a user closing their browser at an inopportune time
* and potentially leaving a disk image in an inconsistent state, premature revocation is the least of
@@ -159,12 +159,12 @@
"use strict";
if (typeof module !== 'undefined') {
- var str = require("../../shared/lib/strlib");
- var usr = require("../../shared/lib/usrlib");
- var web = require("../../shared/lib/weblib");
- var DiskAPI = require("../../shared/lib/diskapi");
- var DumpAPI = require("../../shared/lib/dumpapi");
- var Component = require("../../shared/lib/component");
+ var str = require("../../shared/lib/strlib");
+ var usr = require("../../shared/lib/usrlib");
+ var web = require("../../shared/lib/weblib");
+ var DiskAPI = require("../../shared/lib/diskapi");
+ var DumpAPI = require("../../shared/lib/dumpapi");
+ var Component = require("../../shared/lib/component");
}
/**
@@ -177,7 +177,7 @@ if (typeof module !== 'undefined') {
* @property {number} iHead
* @property {number} iModify
* @property {number} cModify
- *
+ *
* Every Sector object (once loaded and fully parsed) should have ALL of the following named properties:
*
* 'sector': sector number
@@ -186,7 +186,7 @@ if (typeof module !== 'undefined') {
* 'pattern': dword pattern to use for empty or partial sectors (or null if sector still needs to be loaded)
*
* initSector() also sets the following properties, to help us quickly identify its location within aDiskData:
- *
+ *
* iCylinder
* iHead
*
@@ -195,7 +195,7 @@ if (typeof module !== 'undefined') {
* iModify: index of first modified dword in sector
* cModify: number of modified dwords in sector
* fDirty: true if sector is dirty, false if clean (or cleaning in progress)
- *
+ *
* fDirty is used in conjunction with "demandrw" disks; it is set to true whenever the sector is modified, and is
* set to false whenever the sector has been sent to the server. If the server write succeeds and fDirty is still
* false, then the sector modifications are removed (cModify is set to zero). If the write succeeds but fDirty was
@@ -203,7 +203,7 @@ if (typeof module !== 'undefined') {
* in place (since we don't keep track of more than one modification range within a sector). And if the write failed,
* then fDirty is set back to true and again all modifications remain in place; the best we can do is schedule another
* write attempt.
- *
+ *
* TODO: Perhaps we should also maintain a failure count and stop trying to write sectors that reach a certain
* threshold. Error-handling, as usual, is the thorniest problem.
*/
@@ -223,7 +223,7 @@ if (typeof module !== 'undefined') {
*
* This means, for example, that all references to "track[iSector].data" must actually appear as
* "track[iSector]['data']".
- *
+ *
* @constructor
* @extends Component
* @param {HDC|FDC} controller
@@ -233,13 +233,13 @@ if (typeof module !== 'undefined') {
function Disk(controller, drive, mode)
{
Component.call(this, "Disk", {'id': controller.idMachine + ".disk" + Disk.nDisks++}, Disk);
-
+
this.controller = controller;
this.cmp = controller.cmp;
this.dbg = controller.dbg;
this.drive = drive;
this.mode = mode;
-
+
/*
* We pull out a number of drive properties that we may or may not need as defaults
*/
@@ -258,11 +258,11 @@ function Disk(controller, drive, mode)
/*
* The following dirty sector and timer properties are used only with fOnDemand disks,
- * assuming fRemote was successfully set.
+ * assuming fRemote was successfully set.
*/
this.aDirtySectors = [];
this.aDirtyTimestamps = []; // this array is parallel to aDirtySectors
- this.timerWrite = null; // REMOTE_WRITE_DELAY timer in effect, if any
+ this.timerWrite = null; // REMOTE_WRITE_DELAY timer in effect, if any
this.msTimerWrite = 0; // the time that the write timer, if any, is set to fire
this.fWriteInProgress = false;
@@ -276,12 +276,12 @@ function Disk(controller, drive, mode)
* @property {number} 2 contains iSector
* @property {number} 3 contains nSectors
* @property {boolean} 4 contains fAsync
- * @property {function(nErrorCode:number,fAsync:boolean)} 5 contains done
+ * @property {function(nErrorCode:number,fAsync:boolean)} 5 contains done
*/
/**
* The default number of milliseconds to wait before writing a dirty sector back to a remote disk image
- *
+ *
* @const {number}
*/
Disk.REMOTE_WRITE_DELAY = 2000; // 2-second delay
@@ -295,7 +295,7 @@ Component.subclass(Component, Disk);
/**
* initBus(cmp, bus, cpu, dbg)
- *
+ *
* We have no real interest in this notification, other than to obtain a reference to the Debugger
* for every disk loaded BEFORE the initBus() phase; any disk loaded AFTER that point will get its Debugger
* reference, if any, from the disk controller passed to the Disk() constructor.
@@ -315,7 +315,7 @@ Disk.prototype.initBus = function(cmp, bus, cpu, dbg) {
*
* As with powerDown(), our sole concern here is for REMOTE disks: if a powerDown() call disconnected an
* "on-demand" disk, we need to get reconnected. Calling our own load() function should get the job done.
- *
+ *
* The HDC component could have triggered this as well, but its powerUp() function only calls autoMount()
* in case of page (ie, application) reload, which is fine for local disks but insufficient for remote disks,
* which have a server connection that must re-established.
@@ -339,14 +339,14 @@ Disk.prototype.powerUp = function(data, fRepower) {
*
* Our sole concern here is for REMOTE disks, making sure any unwritten changes get flushed to
* the server during a shutdown. No local state is ever returned, so fSave is ignored.
- *
+ *
* Local disks are managed by the controller (ie, FDC or HDC) that mounted them; the controller's
* powerDown() handler will take care of calling save() as needed.
- *
+ *
* TODO: Consider taking responsibility for saving the state of local disks as well; the only reason
* the controllers still take care of them is historical, because this component originally didn't
* exist, and even after it was created, it didn't originally receive powerDown() notifications.
- *
+ *
* @this {Disk}
* @param {boolean} fSave
* @param {boolean} [fShutdown]
@@ -385,7 +385,7 @@ Disk.prototype.powerDown = function(fSave, fShutdown)
/**
* create()
- *
+ *
* Initializes the disk contents according to the current drive mode and parameters.
*/
Disk.prototype.create = function()
@@ -407,7 +407,7 @@ Disk.prototype.create = function()
* Now that our read() and write() functions can deal with unallocated data
* arrays, and can read/write the specified pattern on-the-fly, we no longer need
* to pre-allocate and pre-initialize the 'data' array.
- *
+ *
* For "local" disks, we can assume a 'pattern' of 0, but for "demandrw" and "demandro"
* disks, 'pattern' is set to null, as yet another indication that I/O is required to load
* the sector from the server (or to write it back to the server).
@@ -429,12 +429,12 @@ Disk.prototype.create = function()
* TODO: Figure out how we can strongly type fnNotify, because the Closure Compiler has issues with:
*
* param {function(Component,Object,Disk,string,string)} fnNotify
- *
+ *
* Also, while we're at it, learn if there are ways to:
- *
+ *
* 1) declare a function taking NO parameters (ie, generate a warning if any parameters are specified)
* 2) declare a type for a function's return value
- *
+ *
* @this {Disk}
* @param {string} sDiskName
* @param {string} sDiskPath
@@ -443,7 +443,7 @@ Disk.prototype.create = function()
Disk.prototype.load = function(sDiskName, sDiskPath, fnNotify)
{
var sDiskURL = sDiskPath;
-
+
/*
* We could use this.log() as well, but it wouldn't also log which component initiated the load.
*/
@@ -452,7 +452,7 @@ Disk.prototype.load = function(sDiskName, sDiskPath, fnNotify)
this.controller.log(sMessage);
this.messageDebugger(sMessage);
}
-
+
this.sDiskName = sDiskName;
this.sDiskPath = sDiskPath;
this.fnNotify = fnNotify;
@@ -484,16 +484,16 @@ Disk.prototype.load = function(sDiskName, sDiskPath, fnNotify)
* disk BPBs, you'll always get a standard PC XT 10mb disk image, so if the 'file' or 'dir' contains
* more than 10mb of data, the request will fail. Ultimately, I want to honor the controller's
* driveConfig 'size' parm, or to match the capacity required by the driveConfig 'type' parameter.
- *
+ *
* If a 'disk' is specified, we pass mbhd=0, because the actual size will depend on the image.
* However, I don't currently have any .DSK or .IMG files containing hard disk images; those formats
* were really intended for floppy disk images. If I never create any hard disk image files, then
* we can simply eliminate sSizeParm in the 'disk' case.
- *
+ *
* Added more extensions to the list of paths-treated-as-disk-images, so that URLs to files located here:
- *
+ *
* ftp://ftp.oldskool.org/pub/TOPBENCH/dskimage/
- *
+ *
* can be used as-is. TODO: There's a TODO in netlib.getFile() regarding remote support that needs
* to be resolved first; DiskDump relies on that function for its remote requests, and it currently
* supports only HTTP.
@@ -513,10 +513,10 @@ Disk.prototype.load = function(sDiskName, sDiskPath, fnNotify)
/**
* onLoadDisk(sDiskFile, sDiskData, nErrorCode, sDiskPath)
- *
+ *
* This function was originally called mount(). If the mount is successful, we pass the Disk object to the
* caller's fnNotify handler; otherwise, we pass null.
- *
+ *
* @this {Disk}
* @param {string} sDiskFile
* @param {string} sDiskData
@@ -578,18 +578,18 @@ Disk.prototype.onLoadDisk = function(sDiskFile, sDiskData, nErrorCode, sDiskPath
* eval(). In particular, the 10Mb disk image we use for the Windows 1.01 demo config fails in
* IE9 with an "Out of memory" exception. One work-around would be to chop the data into chunks
* (perhaps one track per chunk, using regular expressions) and then manually re-assemble it.
- *
+ *
* However, it turns out that using JSON.parse(sDiskData) instead of eval("(" + sDiskData + ")")
* is a much easier fix. The only drawback is that we must first quote any unquoted property names
* and remove any comments, because while eval() was cool with them, JSON.parse() is more particular;
* the following RegExp replacements take care of those requirements.
- *
+ *
* The use of hex values is something else that eval() was OK with, but JSON.parse() is not, and
* while I've stopped using hex values in DumpAPI responses (at least when "format=json" is specified),
* I can't guarantee they won't show up in "legacy" images, and there's no simple RegExp replacement
* for transforming hex values into decimal values, so I cop out and fall back to eval() if I detect
* any hex prefixes ("0x") in the sequence. Ditto for error messages, which appear like so:
- *
+ *
* ["unrecognized disk path: test.img"]
*/
var aDiskData;
@@ -622,18 +622,18 @@ Disk.prototype.onLoadDisk = function(sDiskFile, sDiskData, nErrorCode, sDiskPath
* aDiskData is an array of cylinders, each of which is an array of heads, each of which
* is an array of sector objects. The format does not impose any limitations on number of
* cylinders, number of heads, or number of bytes in any of the sector object byte-arrays.
- *
+ *
* WARNING: All accesses to sector object properties must be via their string names, not their
* "dot" names, otherwise code will break after it's been processed by the Closure Compiler.
- *
+ *
* Sector object properties include:
- *
+ *
* 'sector' the sector number (1-based, not required to be sequential)
* 'length' the byte-length (ie, formatted length) of the sector
* 'data' the dword-array containing the sector data
* 'pattern' if the dword-array length is less than 'length'/4, this value must be used
* to pad out the sector; if no 'pattern' is specified, it's assumed to be zero
- *
+ *
* We still support the older JSON encoding, where sector data was encoded as an array of 'bytes'
* rather than a dword 'data' array. However, our support is strictly limited to an on-the-fly
* conversion to a forward-compatible 'data' array.
@@ -698,27 +698,27 @@ Disk.prototype.onLoadDisk = function(sDiskFile, sDiskData, nErrorCode, sDiskPath
}
/*
* The current sector should now have ALL the properties of a proper Sector object; ie:
- *
+ *
* 'sector': sector number
* 'length': size of the sector, in bytes
* 'data': array of dwords
* 'pattern': dword pattern to use for empty or partial sectors
- *
+ *
* In addition, we will maintain the following information on a per-sector basis,
* as sectors are modified:
- *
+ *
* iModify: index of first modified dword in sector
* cModify: number of modified dwords in sector
* fDirty: true if sector is dirty, false if clean (or cleaning in progress)
- *
+ *
* And for the disk as a whole, we maintain a checksum of the original unmodified data:
- *
+ *
* dwChecksum: summation of all dwords in all non-empty sectors
*/
this.initSector(sector, iCylinder, iHead);
/*
* Pattern-filling of sectors is deferred until absolutely necessary (eg, when a sector is
- * being written). So all we need to do at this point is checksum all the initial sector data.
+ * being written). So all we need to do at this point is checksum all the initial sector data.
*/
for (var idw = 0; idw < adw.length; idw++) {
dwChecksum = (dwChecksum + adw[idw]) & 0xffffffff;
@@ -741,7 +741,7 @@ Disk.prototype.onLoadDisk = function(sDiskFile, sDiskData, nErrorCode, sDiskPath
/**
* initSector(sector, iCylinder, iHead, iSector, cbSector, dwPattern)
- *
+ *
* @param {Object} sector
* @param {number} iCylinder
* @param {number} iHead
@@ -779,7 +779,7 @@ Disk.prototype.onLoadParseSectors = function(sURLName, sURLData, nErrorCode, sec
var iSector = sectorInfo[2];
var nSectors = sectorInfo[3];
fAsync = sectorInfo[4];
-
+
if (DEBUG) this.messageDebugger("Disk.onLoadParseSectors(" + iCylinder + ":" + iHead + ":" + iSector + ":" + nSectors + ")");
var abData = JSON.parse(sURLData);
@@ -788,10 +788,10 @@ Disk.prototype.onLoadParseSectors = function(sURLName, sURLData, nErrorCode, sec
/*
* We call seek with fWrite == true to prevent seek() from triggering another call
* to readRemoteSectors() and endlessly recursing. That also forces seek() to:
- *
+ *
* 1) zero the sector's 'pattern'
* 2) disable warning about reading an uninitialized sector
- *
+ *
* We KNOW this is an uninitialized sector, because we're about to initialize it.
*/
var sector = this.seek(iCylinder, iHead, iSector, true);
@@ -814,11 +814,11 @@ Disk.prototype.onLoadParseSectors = function(sURLName, sURLData, nErrorCode, sec
/**
* connectRemoteDisk(sDiskPath)
- *
+ *
* Unlike disconnect(), we don't issue the connect request ourselves; instead, we piggyback on the existing
* preload code in load() to establish the connection. That, in turn, will trigger a call to mount(), which
* will check fOnDemand and set fRemote if the connection was successful.
- *
+ *
* @this {Disk}
* @param {string} sDiskPath
* @return {string} is the URL connection string required to connect to sDiskPath
@@ -836,7 +836,7 @@ Disk.prototype.connectRemoteDisk = function(sDiskPath)
/**
* readRemoteSectors(iCylinder, iHead, iSector, nSectors, done)
- *
+ *
* @param {number} iCylinder
* @param {number} iHead
* @param {number} iSector
@@ -847,7 +847,7 @@ Disk.prototype.connectRemoteDisk = function(sDiskPath)
Disk.prototype.readRemoteSectors = function(iCylinder, iHead, iSector, cbSector, nSectors, done)
{
if (DEBUG) this.messageDebugger("Disk.readRemoteSectors(" + iCylinder + ":" + iHead + ":" + iSector + ":" + nSectors + "," + cbSector + ")");
-
+
if (this.fRemote) {
var sParms = DiskAPI.QUERY.ACTION + '=' + DiskAPI.ACTION.READ;
sParms += '&' + DiskAPI.QUERY.VOLUME + '=' + this.sDiskPath;
@@ -868,12 +868,12 @@ Disk.prototype.readRemoteSectors = function(iCylinder, iHead, iSector, cbSector,
* Writes to a remote disk are performed on a timer-driven basis. When a sector is modified for the first time,
* a reference to that sector is "pushed" onto (ie, appended to the end of) aDirtySectors, and if aDirtySectors was
* originally empty, then a REMOTE_WRITE_DELAY timer is set.
- *
+ *
* When the timer fires, the first batch of contiguous sectors is sent off the server, and when the server responds
* (ie, when cleanDirtySectors() is called), if the response indicates success, every sector that was sent is marked
* clean -- unless one or more writes to the sector occurred in the meantime, which we track through a per-sector
- * fDirty flag.
- *
+ * fDirty flag.
+ *
* @param {number} iCylinder
* @param {number} iHead
* @param {number} iSector
@@ -885,7 +885,7 @@ Disk.prototype.readRemoteSectors = function(iCylinder, iHead, iSector, cbSector,
Disk.prototype.writeRemoteSectors = function(iCylinder, iHead, iSector, nSectors, abSectors, fAsync)
{
if (DEBUG) this.messageDebugger("Disk.writeRemoteSectors(" + iCylinder + ":" + iHead + ":" + iSector + ":" + nSectors + ")");
-
+
if (this.fRemote) {
var data = {};
this.fWriteInProgress = true;
@@ -904,7 +904,7 @@ Disk.prototype.writeRemoteSectors = function(iCylinder, iHead, iSector, nSectors
/**
* disconnectRemoteDisk()
- *
+ *
* This is called by our powerDown() notification handler. If fRemote is true, we issue the disconnect request and
* then immediately set fRemote to false; we don't wait for (or test) the response.
*
@@ -928,7 +928,7 @@ Disk.prototype.disconnectRemoteDisk = function()
*
* Mark the specified sector as dirty, add it to the queue (aDirtySectors) if not already added,
* and establish a timeout handler (findDirtySectors) if not already established.
- *
+ *
* A freshly dirtied sector should sit in the queue for a short period of time (eg, 2 seconds)
* before we attempt to write it; that is, a REMOTE_WRITE_DELAY timer should start ticking again
* for any sector that is rewritten. However, there will be exceptions; for example, when a sector
@@ -961,7 +961,7 @@ Disk.prototype.queueDirtySector = function(sector, fAsync)
*
* If a timer is already active, make sure it's still valid (ie, the time the timer is scheduled to fire is
* >= the timestamp of the next dirty sector + REMOTE_WRITE_DELAY); if not, cancel the timer and start a new one.
- *
+ *
* @return {boolean} true if write timer set, false if not
*/
Disk.prototype.updateWriteTimer = function()
@@ -1050,7 +1050,7 @@ Disk.prototype.onWriteCleanSectors = function(sURLName, sURLData, nErrorCode, se
var nSectors = sectorInfo[3];
var fAsync = sectorInfo[4];
this.fWriteInProgress = false;
-
+
if (iCylinder >= 0 && iCylinder < this.aDiskData.length && iHead >= 0 && iHead < this.aDiskData[iCylinder].length) {
for (var i = iSector - 1; nSectors-- > 0 && i >= 0 && i < this.aDiskData[iCylinder][iHead].length; i++) {
var sector = this.aDiskData[iCylinder][iHead][i];
@@ -1071,7 +1071,7 @@ Disk.prototype.onWriteCleanSectors = function(sURLName, sURLData, nErrorCode, se
/**
* info()
- *
+ *
* @this {Disk}
* @return {Array} containing: [nCylinders, nHeads, nSectorsPerTrack, nBytesPerSector]
*/
@@ -1079,7 +1079,7 @@ Disk.prototype.info = function()
{
if (!this.aDiskData.length) {
return [0, 0, 0, 0];
- }
+ }
return [this.aDiskData.length, this.aDiskData[0].length, this.aDiskData[0][0].length, this.aDiskData[0][0][0]['length']];
};
@@ -1091,7 +1091,7 @@ Disk.prototype.info = function()
* Sectors that were initially compressed should remain compressed unless/until they were modified.
*
* TODO: Check sectors (or at least modified sectors) to see if they can be recompressed.
- *
+ *
* @this {Disk}
* @return {string} containing the entire disk image as JSON-encoded data
*/
@@ -1104,7 +1104,7 @@ Disk.prototype.dump = function()
* back again during mount() -- or whenever JSON.parse() is used instead of eval(). But I still remove
* them temporarily, so that any remaining property names (eg, "iModify", "cModify", "fDirty") can
* easily be stripped out, by virtue of their being the only quoted properties left. We then "requote"
- * all the property names that remain.
+ * all the property names that remain.
*/
s = s.replace(/"(sector|length|data|pattern)":/gm, "$1:");
/*
@@ -1124,17 +1124,17 @@ Disk.prototype.dump = function()
* properties. That code used to be in the FDC component, where it was perfectly reasonable
* to access those properties. We need a cleaner interface back to the drive, similar to the
* info() interface we provide to the controller.
- *
+ *
* Whether or not the "dynamic reconfiguration" feature itself is perfectly reasonable is,
* of course, a separate question.
- *
+ *
* @this {Disk}
* @param {number} iCylinder
* @param {number} iHead
* @param {number} iSector
* @param {boolean} [fWrite]
* @param {function(Object,boolean)} [done]
- * @return {Object|null} is the requested sector, or null if not found (or not available yet)
+ * @return {Object|null} is the requested sector, or null if not found (or not available yet)
*/
Disk.prototype.seek = function(iCylinder, iHead, iSector, fWrite, done)
{
@@ -1181,7 +1181,7 @@ Disk.prototype.seek = function(iCylinder, iHead, iSector, fWrite, done)
this.readRemoteSectors(iCylinder, iHead, iSector, drive.cbSector, nSectors, function onReadRemoteComplete(err, fAsync) {
if (err) sector = null;
// noinspection JSReferencingMutableVariableFromClosure
- done(sector, fAsync);
+ done(sector, fAsync);
});
return null;
} else {
@@ -1205,7 +1205,7 @@ Disk.prototype.seek = function(iCylinder, iHead, iSector, fWrite, done)
/**
* fill(sector, ab, off)
- *
+ *
* @param {Object} sector
* @param {*} ab (technically, this should be typed as Array. but I'm having trouble coercing JSON.parse() to that)
* @param {number} off
@@ -1251,7 +1251,7 @@ Disk.prototype.toBytes = function(sector)
/**
* read(sector, ibSector, fCompare)
- *
+ *
* @this {Disk}
* @param {Object} sector (returned from a previous seek)
* @param {number} ibSector a byte index within the given sector
@@ -1261,7 +1261,7 @@ Disk.prototype.toBytes = function(sector)
Disk.prototype.read = function(sector, ibSector, fCompare)
{
var b = -1;
-
+
if (DEBUG && !ibSector && !fCompare) this.messageDebugger("Disk.read(" + this.controller.id + ":" + this.drive.iDrive + "," + sector.iCylinder + ":" + sector.iHead + ":" + sector['sector'] + ")");
if (ibSector < sector['length']) {
@@ -1275,7 +1275,7 @@ Disk.prototype.read = function(sector, ibSector, fCompare)
/**
* write(sector, ibSector, b)
- *
+ *
* @this {Disk}
* @param {Object} sector (returned from a previous seek)
* @param {number} ibSector a byte index within the given sector
@@ -1286,7 +1286,7 @@ Disk.prototype.write = function(sector, ibSector, b)
{
if (this.fWriteProtected)
return false;
-
+
if (DEBUG && !ibSector) this.messageDebugger("Disk.write(" + this.controller.id + ":" + this.drive.iDrive + "," + sector.iCylinder + ":" + sector.iHead + ":" + sector['sector'] + ")");
if (ibSector < sector['length']) {
@@ -1299,7 +1299,7 @@ Disk.prototype.write = function(sector, ibSector, b)
* Ensure every byte up to the specified byte is properly initialized.
*/
for (var i = adw.length; i <= idw; i++) adw[i] = dwPattern;
-
+
if (!sector.cModify) {
sector.iModify = idw;
sector.cModify = 1;
@@ -1330,7 +1330,7 @@ Disk.prototype.write = function(sector, ibSector, b)
* [iCylinder, iHead, iSector, iModify, [...]]
*
* where [...] is an array of modified dword(s) in the corresponding sector.
- *
+ *
* @this {Disk}
* @return {Array} of modified sectors
*/
@@ -1373,7 +1373,7 @@ Disk.prototype.save = function()
* [iCylinder, iHead, iSector, iModify, [...]]
*
* where [...] is an array of modified dword(s) in the corresponding sector.
- *
+ *
* @this {Disk}
* @param {Array} deltas
* @return {number} 0 if no changes applied, -1 if an error occurred, otherwise the number of sectors modified
@@ -1382,7 +1382,7 @@ Disk.prototype.restore = function(deltas)
{
/*
* If deltas is undefined, that's not necessarily an error; the controller may simply be (re)initializing
- * itself (although neither controller should be calling restore() under those conditions anymore).
+ * itself (although neither controller should be calling restore() under those conditions anymore).
*/
var nChanges = 0;
var sReason = "unsupported restore format";
@@ -1426,7 +1426,7 @@ Disk.prototype.restore = function(deltas)
* Note the buried test for write-protection. Yes, an invariant condition should be tested
* outside the loop, not inside, but (a) it's a trivial test, (b) the test should never fail
* because save() should never generate any mods for a write-protected disk, and (c) it
- * centralizes all the failure conditions we're currently checking (which, admittedly, ain't much).
+ * centralizes all the failure conditions we're currently checking (which, admittedly, ain't much).
*/
if (iCylinder >= this.aDiskData.length || iHead >= this.aDiskData[iCylinder].length || iSector >= this.aDiskData[iCylinder][iHead].length) {
sReason = "sector " + iCylinder + ":" + iHead + ":" + iSector + " out of range (" + nChanges + " changes applied)";
@@ -1471,7 +1471,7 @@ Disk.prototype.restore = function(deltas)
* messageDebugger(sMessage)
*
* This is a combination of the Debugger's messageEnabled(MESSAGE_DISK) and message() functions, for convenience.
- *
+ *
* @this {Disk}
* @param {string} sMessage is any caller-defined message string
*/
diff --git a/my_modules/pcjs-client/lib/fdc.js b/my_modules/pcjs-client/lib/fdc.js
index d66dba83d..423a5f3ed 100644
--- a/my_modules/pcjs-client/lib/fdc.js
+++ b/my_modules/pcjs-client/lib/fdc.js
@@ -34,14 +34,14 @@
"use strict";
if (typeof module !== 'undefined') {
- var str = require("../../shared/lib/strlib");
- var web = require("../../shared/lib/weblib");
- var DiskAPI = require("../../shared/lib/diskapi");
- var Component = require("../../shared/lib/component");
- var ChipSet = require("./chipset");
- var Disk = require("./disk");
- var Computer = require("./computer");
- var State = require("./state");
+ var str = require("../../shared/lib/strlib");
+ var web = require("../../shared/lib/weblib");
+ var DiskAPI = require("../../shared/lib/diskapi");
+ var Component = require("../../shared/lib/component");
+ var ChipSet = require("./chipset");
+ var Disk = require("./disk");
+ var Computer = require("./computer");
+ var State = require("./state");
}
/*
@@ -738,6 +738,13 @@ FDC.prototype.initController = function(data)
for (iDrive = 0; iDrive < this.aDrives.length; iDrive++) {
var drive = this.aDrives[iDrive];
if (drive === undefined) {
+ /*
+ * The first time each drive is initialized, obtain its type (from switches or CMOS) and the physical limits
+ * of the drive (ie, max tracks and max sectors/track). As for max heads, initDrive() assumes that all drives
+ * have two heads, and in any case, there's no way to configure/specify a single-sided floppy drive.
+ *
+ * TODO: Provide a configuration option for single-sided drives, in case someone really wants to simulate that.
+ */
drive = this.aDrives[iDrive] = {};
drive.bType = this.chipset.getSWFloppyDriveType(iDrive);
drive.nCylinders = 40;
@@ -823,7 +830,7 @@ FDC.prototype.initDrive = function(drive, iDrive, data)
/*
* Note that when no data is provided (eg, when the controller is being reinitialized), we now take
* care to preserve any drive defaults that initController() already obtained for us, falling back to
- * bare minimums only when all else has failed.
+ * bare minimums only when all else fails.
*/
data[1] = [FDC.DEFAULT_DRIVE_NAME, drive.nCylinders || 40, drive.nHeads || data[3], drive.nSectors || 9, drive.cbSector || 512, data[1]];
}
@@ -845,6 +852,18 @@ FDC.prototype.initDrive = function(drive, iDrive, data)
drive.nSectors = data[i][3]; // sectors/track
drive.cbSector = data[i][4]; // bytes/sector
drive.fRemovable = data[i][5];
+ /*
+ * If we have current media parameters, restore them; otherwise, default to the drive's physical parameters.
+ */
+ if (drive.nDiskCylinders = data[i][6]) {
+ drive.nDiskHeads = data[i][7];
+ drive.nDiskSectors = data[i][8];
+ } else {
+ drive.nDiskCylinders = drive.nCylinders;
+ drive.nDiskHeads = drive.nHeads;
+ drive.nDiskSectors = drive.nSectors;
+
+ }
i++;
/*
@@ -888,11 +907,7 @@ FDC.prototype.initDrive = function(drive, iDrive, data)
drive.nBytes = data[i++];
/*
- * The next group of properties are set by user requests to load/unload diskette images.
- *
- * NOTE: I now avoid reinitializing drive.disk in order to retain any previously mounted diskette across resets.
- *
- * drive.disk = null; // when a "disk" is "inserted" into the "drive", this is a Disk object
+ * We no longer reinitialize drive.disk, in order to retain previously mounted diskette across resets.
*/
/*
@@ -971,7 +986,7 @@ FDC.prototype.saveDrive = function(drive)
var i = 0;
var data = [];
data[i++] = drive.resCode;
- data[i++] = [drive.name, drive.nCylinders, drive.nHeads, drive.nSectors, drive.cbSector, drive.fRemovable];
+ data[i++] = [drive.name, drive.nCylinders, drive.nHeads, drive.nSectors, drive.cbSector, drive.fRemovable, drive.nDiskCylinders, drive.nDiskHeads, drive.nDiskSectors];
data[i++] = drive.bHead;
/*
* We used to store drive.nHeads in the next slot, but now we store bCylinderSeek,
@@ -1170,15 +1185,20 @@ FDC.prototype.loadDiskette = function(iDrive, sDisketteName, sDiskettePath, fAut
*/
FDC.prototype.mountDiskette = function(drive, disk, sDisketteName, sDiskettePath)
{
+ var aDiskInfo;
+
drive.fBusy = false;
- /*
- * We shouldn't mount the diskette unless the drive is able to handle it; for example, DSDD (40-track)
- * drives cannot read DSHD (80-track) diskettes.
- */
- if (disk && disk.aDiskData.length > drive.nCylinders) {
- this.notice("Diskette \"" + sDisketteName + "\" too large for drive " + String.fromCharCode(0x41 + drive.iDrive));
- disk = null;
+ if (disk) {
+ /*
+ * We shouldn't mount the diskette unless the drive is able to handle it; for example, DSDD (40-track)
+ * drives cannot read DSHD (80-track) diskettes.
+ */
+ aDiskInfo = disk.info();
+ if (disk && aDiskInfo[0] > drive.nCylinders || aDiskInfo[1] > drive.nHeads || aDiskInfo[2] > drive.nSectors) {
+ this.notice("Diskette \"" + sDisketteName + "\" too large for drive " + String.fromCharCode(0x41 + drive.iDrive));
+ disk = null;
+ }
}
if (disk) {
@@ -1205,6 +1225,13 @@ FDC.prototype.mountDiskette = function(drive, disk, sDisketteName, sDiskettePath
* and will not match the drive mappings that DOS ultimately uses (ie, for drives beyond B:).
*/
this.notice("Mounted diskette \"" + sDisketteName + "\" in drive " + String.fromCharCode(0x41 + drive.iDrive), drive.fAutoMount);
+
+ /*
+ * Update the drive's current media parameters to match the disk's.
+ */
+ drive.nDiskCylinders = aDiskInfo[0];
+ drive.nDiskHeads = aDiskInfo[1];
+ drive.nDiskSectors = aDiskInfo[2];
}
if (drive.fAutoMount) {
@@ -2141,8 +2168,8 @@ FDC.prototype.writeByte = function(drive, 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
+ * This increments the sector number; when the sector number reaches drive.nDiskSectors on the current track, we
+ * increment drive.bHead and reset drive.bSector, and when drive.bHead reaches drive.nDiskHeads, we reset drive.bHead
* and increment drive.bCylinder.
*
* @this {FDC}
@@ -2150,13 +2177,13 @@ FDC.prototype.writeByte = function(drive, b)
*/
FDC.prototype.advanceSector = function(drive)
{
- Component.assert(drive.bCylinder < drive.nCylinders);
+ Component.assert(drive.bCylinder < drive.nDiskCylinders);
drive.bSector++;
var bSectorStart = 1;
- if (drive.bSector >= drive.nSectors + bSectorStart) {
+ if (drive.bSector >= drive.nDiskSectors + bSectorStart) {
drive.bSector = bSectorStart;
drive.bHead++;
- if (drive.bHead >= drive.nHeads) {
+ if (drive.bHead >= drive.nDiskHeads) {
drive.bHead = 0;
drive.bCylinder++;
}
diff --git a/my_modules/pcjs-client/lib/hdc.js b/my_modules/pcjs-client/lib/hdc.js
index a2dbc96ec..5d435cb90 100644
--- a/my_modules/pcjs-client/lib/hdc.js
+++ b/my_modules/pcjs-client/lib/hdc.js
@@ -34,13 +34,13 @@
"use strict";
if (typeof module !== 'undefined') {
- var str = require("../../shared/lib/strlib");
- var web = require("../../shared/lib/weblib");
- var DiskAPI = require("../../shared/lib/diskapi");
- var Component = require("../../shared/lib/component");
- var ChipSet = require("./chipset");
- var Disk = require("./disk");
- var State = require("./state");
+ var str = require("../../shared/lib/strlib");
+ var web = require("../../shared/lib/weblib");
+ var DiskAPI = require("../../shared/lib/diskapi");
+ var Component = require("../../shared/lib/component");
+ var ChipSet = require("./chipset");
+ var Disk = require("./disk");
+ var State = require("./state");
}
/**
@@ -145,7 +145,7 @@ HDC.aDriveTypes = [
* so aDriveTypes must first be indexed by a controller index (this.iHDC).
*
* The following is a more complete description of the drive types supported by the MODEL_5170, where C is
- * Cylinders, H is Heads, WP is Write Pre-Comp, and LZ is Landing Zone (in practice, we don't need WP or LZ).
+ * Cylinders, H is Heads, WP is Write Pre-Comp, and LZ is Landing Zone (in practice, we don't need WP or LZ).
*
* Type C H WP LZ
* ---- --- -- --- ---
@@ -457,7 +457,7 @@ HDC.BIOS = {
};
/*
- * NOTE: These are useful values for reference, but they're not actually used for anything at the moment.
+ * NOTE: These are useful values for reference, but they're not actually used for anything at the moment.
*/
HDC.BIOS.DISK_CMD = {
RESET: 0x00,
@@ -865,7 +865,7 @@ HDC.prototype.initDrive = function(iDrive, drive, driveConfig, data, fReset)
/*
* The next group of properties are set by user requests to load/unload disk images.
*
- * NOTE: I now avoid reinitializing drive.disk in order to retain any previously mounted disk across resets.
+ * We no longer reinitialize drive.disk, in order to retain previously mounted disk across resets.
*/
if (drive.disk === undefined) {
drive.disk = null;
@@ -1235,7 +1235,7 @@ HDC.prototype.outXTCData = function(port, bOut, addrFrom)
}
if (this.regDataTotal >= cbCmd) {
/*
- * It's essential that XTC.STATUS.IOMODE be set here, at least after the final 8-byte HDC.XTC.DATA.CMD.INIT_DRIVE sequence.
+ * It's essential that XTC.STATUS.IOMODE be set here, at least after the final 8-byte HDC.XTC.DATA.CMD.INIT_DRIVE sequence.
*/
this.regStatus |= HDC.XTC.STATUS.IOMODE;
this.regStatus &= ~HDC.XTC.STATUS.REQ;
@@ -1650,13 +1650,13 @@ HDC.prototype.outATCDrvHd = function(port, bOut, addrFrom)
* of configured hard drives is something other than 2, using INT 0x13/AH=0x10. This in turn calls the
* BIOS "TST_RDY" function, which selects the drive in this register (see DRIVE_MASK), and then immediately
* expects regStatus to reflect success or failure.
- *
+ *
* We were always returning success, because no ATC command was actually issued, and so the user would
* always get a spurious CMOS configuration error: "System Options Not Set-(Run SETUP)".
- *
+ *
* So now we update regStatus here. I'm not sure which status bits are normally set to indicate failure,
* but it should be sufficient to set or clear the READY bit according to whether the drive exists or not.
- *
+ *
* TODO: Dig into the ATC documentation some more, and determine what other situations, if any, regStatus
* needs to be updated.
*/
diff --git a/my_modules/pcjs-client/lib/keyboard.js b/my_modules/pcjs-client/lib/keyboard.js
index 77c144b40..7a19f7410 100644
--- a/my_modules/pcjs-client/lib/keyboard.js
+++ b/my_modules/pcjs-client/lib/keyboard.js
@@ -34,12 +34,12 @@
"use strict";
if (typeof module !== 'undefined') {
- var str = require("../../shared/lib/strlib");
- var web = require("../../shared/lib/weblib");
- var Component = require("../../shared/lib/component");
- var ChipSet = require("./chipset");
- var State = require("./state");
- var CPU = require("./cpu");
+ var str = require("../../shared/lib/strlib");
+ var web = require("../../shared/lib/weblib");
+ var Component = require("../../shared/lib/component");
+ var ChipSet = require("./chipset");
+ var State = require("./state");
+ var CPU = require("./cpu");
}
/**
@@ -57,7 +57,7 @@ if (typeof module !== 'undefined') {
*
* Its main purpose is to receive binding requests for various keyboard events,
* and to use those events to simulate the PC's keyboard hardware.
- *
+ *
* @constructor
* @extends Component
* @param {Object} parmsKbd
@@ -119,11 +119,11 @@ Keyboard.CMD.SETLEDS = 0xED;
Keyboard.CMDRES = {};
Keyboard.CMDRES.OVERRUN = 0x00;
Keyboard.CMDRES.LOADTEST = 0x65; // this is an undocumented "LOAD MANUFACTURING TEST REQUEST" response code
-Keyboard.CMDRES.BATSUCCESS = 0xAA; // Basic Assurance Test (BAT) completed successfully
+Keyboard.CMDRES.BATSUCCESS = 0xAA; // Basic Assurance Test (BAT) completed successfully
Keyboard.CMDRES.ECHO = 0xEE;
Keyboard.CMDRES.BREAKPREFIX = 0xF0;
Keyboard.CMDRES.ACK = 0xFA;
-Keyboard.CMDRES.BATFAIL = 0xFC; // Basic Assurance Test (BAT) failed
+Keyboard.CMDRES.BATFAIL = 0xFC; // Basic Assurance Test (BAT) failed
Keyboard.CMDRES.DIAGFAIL = 0xFD;
Keyboard.CMDRES.RESEND = 0xFE;
@@ -280,7 +280,7 @@ Keyboard.aButtonCodes = {
* For example, Safari on iOS devices will not generate up/down events for shift keys, and for other keys,
* the up/down events are usually generated after the actual press is complete, and in rapid succession,
* which doesn't always give the simulation enough time to detect the key.
- *
+ *
* The other problem (which is more of a problem with keyboards like the C1P than any IBM keyboards) is
* that the shift/modifier state for a character on the "source" keyboard may not match the shift/modifier
* state for the same character on the "target" keyboard. And since this code is inherited from C1Pjs,
@@ -424,7 +424,7 @@ Keyboard.aCharCodes[Keyboard.CHARCODE.CTRLALTDEL]=0x53 + (Keyboard.CHARCODE.CTRL
/**
* setBinding(sHTMLClass, sHTMLType, sBinding, control)
- *
+ *
* @this {Keyboard}
* @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")
@@ -444,7 +444,7 @@ Keyboard.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, contro
*
* However, it's also possible for the keyboard XML definition to define a control that serves
* a similar purpose; eg:
- *
+ *
* Kbd
*
* The latter is purely experimental, while we work on finding ways to trigger the soft keyboard on
@@ -508,7 +508,7 @@ Keyboard.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, contro
/**
* findBinding(bKey, t, fDown)
- *
+ *
* @this {Keyboard}
* @param {number} bKey
* @param {string} t is the type of control (eg, "button" or "key")
@@ -533,7 +533,7 @@ Keyboard.prototype.findBinding = function(bKey, t, fDown)
/**
* initBus(cmp, bus, cpu, dbg)
- *
+ *
* @this {Keyboard}
* @param {Computer} cmp
* @param {Bus} bus
@@ -551,7 +551,7 @@ Keyboard.prototype.initBus = function(cmp, bus, cpu, dbg)
/**
* setModel(nModel)
- *
+ *
* @this {Keyboard}
* @param {number} nModel
*/
@@ -561,7 +561,7 @@ Keyboard.prototype.setModel = function(nModel)
/**
* setReady()
- *
+ *
* @this {Keyboard}
*/
Keyboard.prototype.setReady = function()
@@ -574,7 +574,7 @@ Keyboard.prototype.setReady = function()
/**
* resetDevice()
- *
+ *
* @this {Keyboard}
*/
Keyboard.prototype.resetDevice = function()
@@ -589,12 +589,12 @@ Keyboard.prototype.resetDevice = function()
/**
* setEnable(fData, fClock)
- *
+ *
* This is the ChipSet's primary interface for toggling keyboard "data" and "clock" lines.
* For MODEL_5150 and MODEL_5160 machines, this function is called from the ChipSet's PPI_B
* output handler. For MODEL_5170 machines, this function is called when selected KBC.CMD
* "data bytes" have been written.
- *
+ *
* @this {Keyboard}
* @param {boolean} fData is true if the keyboard simulated data line should be enabled
* @param {boolean} fClock is true if the keyboard's simulated clock line should be enabled
@@ -635,7 +635,7 @@ Keyboard.prototype.setEnable = function(fData, fClock)
*
* This is the ChipSet's primary interface for controlling "Model M" keyboards (ie, those used
* with MODEL_5170 machines). Commands are delivered through the ChipSet's 8042 Keyboard Controller.
- *
+ *
* @this {Keyboard}
* @param {number} bCmd should be one of the Keyboard.CMD.* command codes (Model M keyboards only)
* @return {number} response should be one of the Keyboard.CMDRES.* response codes, or -1 if unrecognized
@@ -656,7 +656,7 @@ Keyboard.prototype.sendCmd = function(bCmd)
/**
* readScanCode(fShift)
- *
+ *
* This is the ChipSet's interface for reading scan codes.
*
* @this {Keyboard}
@@ -676,9 +676,9 @@ Keyboard.prototype.readScanCode = function(fShift)
/**
* shiftScanCode(fFlush)
- *
+ *
* This is the ChipSet's interface to advance (or flush) scan codes.
- *
+ *
* @this {Keyboard}
* @param {boolean} [fFlush] is true to completely flush the keyboard buffer
*/
@@ -736,7 +736,7 @@ Keyboard.prototype.powerUp = function(data, fRepower)
/**
* powerDown(fSave)
- *
+ *
* @this {Keyboard}
* @param {boolean} fSave
* @return {Object|boolean}
@@ -748,7 +748,7 @@ Keyboard.prototype.powerDown = function(fSave)
/**
* reset()
- *
+ *
* @this {Keyboard}
*/
Keyboard.prototype.reset = function()
@@ -801,7 +801,7 @@ Keyboard.prototype.reset = function()
* save()
*
* This implements save support for the Keyboard component.
- *
+ *
* @this {Keyboard}
* @return {Object}
*/
@@ -816,7 +816,7 @@ Keyboard.prototype.save = function()
* restore(data)
*
* This implements restore support for the Keyboard component.
- *
+ *
* @this {Keyboard}
* @param {Object} data
* @return {boolean} true if successful, false if failure
@@ -828,7 +828,7 @@ Keyboard.prototype.restore = function(data)
/**
* initState(data)
- *
+ *
* @this {Keyboard}
* @param {Array} [data]
* @return {boolean} true if successful, false if failure
@@ -844,7 +844,7 @@ Keyboard.prototype.initState = function(data)
/**
* saveState()
- *
+ *
* @this {Keyboard}
* @return {Array}
*/
@@ -859,7 +859,7 @@ Keyboard.prototype.saveState = function()
/**
* setSoftKeyState(control, f)
- *
+ *
* @this {Keyboard}
* @param {Object} control is an HTML control DOM object
* @param {boolean} f is true if the key represented by e should be "on", false if "off"
@@ -877,7 +877,7 @@ Keyboard.prototype.setSoftKeyState = function(control, f)
*
* Just as 0xAA is a special scan code response to a software reset, 0xFF is a special scan code response
* to an internal buffer overrun. I try to simulate both.
- *
+ *
* @this {Keyboard}
* @param {number} bScan
* @param {boolean} [fRepeat]
@@ -917,7 +917,7 @@ Keyboard.prototype.addScanCode = function(bScan, fRepeat)
/**
* calcReleaseDelay(fRepeat)
- *
+ *
* Attempts to scale our default "release" delay appropriately for the current CPU speed.
*
* Note that if the effective CPU speed exceeds 16Mhz, it becomes very difficult to rely on timer-driven key events
@@ -947,7 +947,7 @@ Keyboard.prototype.calcReleaseDelay = function(fRepeat)
/**
* autoClear(notCharCode)
- *
+ *
* @this {Keyboard}
* @param {number} [notCharCode]
*/
@@ -963,7 +963,7 @@ Keyboard.prototype.autoClear = function(notCharCode)
/**
* injectKeys(sKeyCodes, msDelay)
- *
+ *
* @this {Keyboard}
* @param {string} sKeyCodes
* @param {number|undefined} [msDelay] is an optional injection delay (default is msInjectDelay)
@@ -977,7 +977,7 @@ Keyboard.prototype.injectKeys = function(sKeyCodes, msDelay)
/**
* injectKeysFromBuffer(msDelay)
- *
+ *
* @this {Keyboard}
* @param {number} msDelay is the delay between injected keys
*/
@@ -1004,7 +1004,7 @@ Keyboard.prototype.injectKeysFromBuffer = function(msDelay)
/**
* keyEvent(event, fDown)
- *
+ *
* @this {Keyboard}
* @param {Object} event
* @param {boolean} fDown is true if called for a keyDown event, false if called for a keyUp event
@@ -1070,7 +1070,7 @@ Keyboard.prototype.keyEvent = function(event, fDown)
* which also generates "down" and "up" events (LOTS of "down" events for that matter),
* but no "press" event. The C1P has no TAB key, so it's safe to completely ignore,
* hence the code below, but a PC does, so I need to simulate it.
- *
+ *
* fPass = fAutoClear = false;
*
* I don't get keyPress events for ESC (why?) and I never want the browser to act on DELETE
@@ -1117,10 +1117,10 @@ Keyboard.prototype.keyEvent = function(event, fDown)
* "up" events, so that keys will repeat immediately when released/pressed repeatedly (most
* noticeable with the Enter key), or set fAutoClear to false to ensure that polling apps have
* enough time to see every key press.
- *
+ *
* I've decided that the former is more important than the latter, so if polling apps are still
* missing keystrokes, then perhaps nCyclesThreshold needs to be supplemented in some way.
- *
+ *
* fAutoClear = false;
*/
}
@@ -1161,7 +1161,7 @@ Keyboard.prototype.keyEvent = function(event, fDown)
*
* We've stopped relying on keyPress for keyboard emulation purposes, but it's still handy to hook and monitor
* when debugging.
- *
+ *
* @this {Keyboard}
* @param {Object} event
* @return {boolean} true to pass the event along, false to consume it
@@ -1184,12 +1184,12 @@ Keyboard.prototype.keyPress = function(event)
/*
* Unlike Safari and Chrome, Firefox doesn't seem to honor our "consume" request for the "down" DELETE keyEvent,
* so we must ALSO check for the DELETE key here, and again "consume" it. Ditto for TAB.
- *
+ *
* In fact, this is just one example of a larger Firefox problem (see https://bugzilla.mozilla.org/show_bug.cgi?id=501496).
* Basically, Firefox is not honoring our consumption of keyDown events, and generates keyPress events anyway.
* This causes us grief for various CTRL and ALT combinations, resulting in duplicate key presses.
* So, I'm going to try to fix this below, by setting fPass to true if either of those modifier keys is currently down;
- * if they're not, then we'll continue with the original code that sets fPass based on the return value from keyPressSimulate().
+ * if they're not, then we'll continue with the original code that sets fPass based on the return value from keyPressSimulate().
*/
fPass = false;
} else {
@@ -1210,7 +1210,7 @@ Keyboard.prototype.keyPress = function(event)
/**
* keyPressSimulate(charCode)
- *
+ *
* @this {Keyboard}
* @param {number} charCode
* @param {boolean} [fQuickRelease] is true to simulate the press and release immediately
@@ -1232,10 +1232,10 @@ Keyboard.prototype.keyPressSimulate = function(charCode, fQuickRelease)
* and execute a LOT of instructions between delivery of the keyPress event and the "keyTimeout"
* event, and since JavaScript events (including timeouts) are delivered synchronously, it might
* take too long for the "keyTimeout" event to arrive.
- *
+ *
* Why don't we ALWAYS do this? Because at normal CPU speeds, we want to faithfully simulate how
* long a key is held, so that features like auto-repeat work properly.
- *
+ *
* TODO: The above is probably more true for C1Pjs (where some of this code came from) than PCjs,
* so revisit these assumptions. The fact that I had to add the fQuickRelease parameter suggests
* that it's time to review/overhaul this code.
@@ -1265,7 +1265,7 @@ Keyboard.prototype.keyPressSimulate = function(charCode, fQuickRelease)
/**
* keyEventSimulate(charCode, fDown, simCode)
- *
+ *
* @this {Keyboard}
* @param {number} charCode
* @param {boolean} fDown
@@ -1353,7 +1353,7 @@ Keyboard.prototype.keyEventSimulate = function(charCode, fDown, simCode)
* messageDebugger(sMessage, fPort)
*
* This is a combination of the Debugger's messageEnabled(MESSAGE_KBD) and message() functions, for convenience.
- *
+ *
* @this {Keyboard}
* @param {string} sMessage is any caller-defined message string
* @param {boolean} [fPort] is true if the message is port-related, false if not
diff --git a/my_modules/pcjs-client/lib/mem.js b/my_modules/pcjs-client/lib/mem.js
index 638800d51..b56b33ebf 100644
--- a/my_modules/pcjs-client/lib/mem.js
+++ b/my_modules/pcjs-client/lib/mem.js
@@ -50,8 +50,8 @@
"use strict";
if (typeof module !== 'undefined') {
- var str = require("../../shared/lib/strlib");
- var Component = require("../../shared/lib/component");
+ var str = require("../../shared/lib/strlib");
+ var Component = require("../../shared/lib/component");
}
/**
* @class DataView
@@ -70,7 +70,7 @@ if (typeof module !== 'undefined') {
* block-granular starting address and an address range equal to bus.blockSize; however,
* the size of any given Memory object's underlying buffer can be either zero or bus.blockSize;
* memory read/write functions for empty (buffer-less) blocks are mapped to readNone/writeNone.
- *
+ *
* The Bus allocates empty blocks for the entire address space during initialization, so that
* any reads/writes to undefined addresses will have no effect. Later, the ROM and RAM
* components will ask the Bus to allocate memory for specific ranges, and the Bus will allocate
@@ -90,7 +90,7 @@ if (typeof module !== 'undefined') {
* consumption. Using TYPEDARRAYS is probably best, although not all JavaScript implementations
* support them (IE9 is probably the only real outlier: it lacks typed arrays but otherwise has
* all the necessary HTML5 support).
- *
+ *
* @constructor
* @param {number} addr of block (must be some multiple of bus.blockSize)
* @param {number} [size] of block's buffer in bytes (0 for none); must be a multiple of 4
@@ -107,13 +107,13 @@ function Memory(addr, size, fReadOnly, controller) {
/*
* For empty memory blocks, all we need to do is ensure all access functions
- * are mapped to "none" handlers.
+ * are mapped to "none" handlers.
*/
if (!size) {
this.setAccess();
return;
}
-
+
/*
* When a controller is specified, the controller must provide a buffer,
* via getMemoryBuffer(), and memory access functions, via getMemoryAccess().
@@ -126,7 +126,7 @@ function Memory(addr, size, fReadOnly, controller) {
this.setAccess(controller.getMemoryAccess());
return;
}
-
+
/*
* This is the normal case: allocate a buffer that provides 8 bits of data per address;
* no controller is required because our default memory access functions (see afnMemory)
@@ -161,7 +161,7 @@ Memory.prototype = {
constructor: Memory,
/**
* readNone(off)
- *
+ *
* @this {Memory}
* @param {number} off
* @return {number}
@@ -174,7 +174,7 @@ Memory.prototype = {
},
/**
* writeNone(off, v)
- *
+ *
* @this {Memory}
* @param {number} off
* @param {number} v (could be either a byte or word value, since we use the same handler for both kinds of accesses)
@@ -186,7 +186,7 @@ Memory.prototype = {
},
/**
* readByteTypedArray(off)
- *
+ *
* @this {Memory}
* @param {number} off
* @return {number}
@@ -197,7 +197,7 @@ Memory.prototype = {
},
/**
* readWordTypedArray(off)
- *
+ *
* @this {Memory}
* @param {number} off
* @return {number}
@@ -208,7 +208,7 @@ Memory.prototype = {
},
/**
* writeByteTypedArray(off, b)
- *
+ *
* @this {Memory}
* @param {number} off
* @param {number} b
@@ -220,7 +220,7 @@ Memory.prototype = {
},
/**
* writeWordTypedArray(off, w)
- *
+ *
* @this {Memory}
* @param {number} off
* @param {number} w
@@ -232,7 +232,7 @@ Memory.prototype = {
},
/**
* readByteMemory(off)
- *
+ *
* @this {Memory}
* @param {number} off
* @return {number}
@@ -246,7 +246,7 @@ Memory.prototype = {
},
/**
* readWordMemory(off)
- *
+ *
* @this {Memory}
* @param {number} off
* @return {number}
@@ -269,7 +269,7 @@ Memory.prototype = {
},
/**
* writeByteMemory(off, b)
- *
+ *
* @this {Memory}
* @param {number} off
* @param {number} b
@@ -287,7 +287,7 @@ Memory.prototype = {
},
/**
* writeWordMemory(off, w)
- *
+ *
* @this {Memory}
* @param {number} off
* @param {number} w
@@ -312,7 +312,7 @@ Memory.prototype = {
},
/**
* readByteVerify(off)
- *
+ *
* @this {Memory}
* @param {number} off
* @return {number}
@@ -323,7 +323,7 @@ Memory.prototype = {
},
/**
* readWordVerify(off)
- *
+ *
* @this {Memory}
* @param {number} off
* @return {number}
@@ -336,7 +336,7 @@ Memory.prototype = {
},
/**
* writeByteVerify(off, b)
- *
+ *
* @this {Memory}
* @param {number} off
* @param {number} b
@@ -347,7 +347,7 @@ Memory.prototype = {
},
/**
* writeWordVerify(off, w)
- *
+ *
* @this {Memory}
* @param {number} off
* @param {number} w
@@ -366,7 +366,7 @@ Memory.prototype = {
*
* Memory blocks with custom memory controllers do NOT save their contents;
* that's the responsibility of the controller component.
- *
+ *
* @this {Memory}
* @return {Array|Int32Array|null}
*/
@@ -389,7 +389,7 @@ Memory.prototype = {
* but we can't be sure of the "endianness" of an Int32Array -- which would be OK if the array
* was always saved/restored on the same machine, but there's no guarantee of that, either.
* So we use getInt32() and require little-endian values.
- *
+ *
* Moreover, an Int32Array isn't treated by JSON.stringify() and JSON.parse() exactly like
* a normal array; it's serialized as an Object rather than an Array, so it lacks a "length"
* property and causes problems for State.store() and State.parse().
@@ -411,7 +411,7 @@ Memory.prototype = {
* used by Bus.restoreMemory(), which is called by X86CPU.restore(), after all other
* components have been restored and thus all Memory blocks have been allocated
* by their respective components.
- *
+ *
* @this {Memory}
* @param {Array|null} adw
* @return {boolean} true if successful, false if block size mismatch
@@ -445,7 +445,7 @@ Memory.prototype = {
},
/**
* setAccess(afn)
- *
+ *
* @this {Memory}
* @param {Array.} [afn]
* @param {boolean} [fDirect]
@@ -458,7 +458,7 @@ Memory.prototype = {
},
/**
* setReadAccess(afn, fDirect)
- *
+ *
* @this {Memory}
* @param {Array.} afn
* @param {boolean} [fDirect]
@@ -473,7 +473,7 @@ Memory.prototype = {
},
/**
* setWriteAccess(afn, fDirect)
- *
+ *
* @this {Memory}
* @param {Array.} afn
* @param {boolean} [fDirect]
@@ -488,7 +488,7 @@ Memory.prototype = {
},
/**
* resetReadAccess()
- *
+ *
* @this {Memory}
*/
resetReadAccess: function() {
@@ -497,7 +497,7 @@ Memory.prototype = {
},
/**
* resetWriteAccess()
- *
+ *
* @this {Memory}
*/
resetWriteAccess: function() {
@@ -506,7 +506,7 @@ Memory.prototype = {
},
/**
* setDebugInfo(cpu, dbg, addr, size)
- *
+ *
* @this {Memory}
* @param {X86CPU|Component} cpu
* @param {Debugger|Component} dbg
@@ -524,7 +524,7 @@ Memory.prototype = {
},
/**
* addBreakpoint(off, fWrite)
- *
+ *
* @this {Memory}
* @param {number} off
* @param {boolean} fWrite
@@ -547,7 +547,7 @@ Memory.prototype = {
},
/**
* removeBreakpoint(off, fWrite)
- *
+ *
* @this {Memory}
* @param {number} off
* @param {boolean} fWrite
diff --git a/my_modules/pcjs-client/lib/mouse.js b/my_modules/pcjs-client/lib/mouse.js
index 3dac0db5c..6561e3154 100644
--- a/my_modules/pcjs-client/lib/mouse.js
+++ b/my_modules/pcjs-client/lib/mouse.js
@@ -34,11 +34,11 @@
"use strict";
if (typeof module !== 'undefined') {
- var str = require("../../shared/lib/strlib");
- var web = require("../../shared/lib/weblib");
- var Component = require("../../shared/lib/component");
- var SerialPort = require("./serial");
- var State = require("./state");
+ var str = require("../../shared/lib/strlib");
+ var web = require("../../shared/lib/weblib");
+ var Component = require("../../shared/lib/component");
+ var SerialPort = require("./serial");
+ var State = require("./state");
}
/**
@@ -64,7 +64,7 @@ if (typeof module !== 'undefined') {
* TODO: Just out of curiosity, verify that the Microsoft Bus Mouse used ports 0x23D and 0x23F,
* because I saw Windows v1.01 probing those ports immediately prior to probing COM2 (and then COM1)
* for a serial mouse.
- *
+ *
* @constructor
* @extends Component
* @param {Object} parmsMouse
@@ -83,14 +83,14 @@ function Mouse(parmsMouse) {
/*
* From http://paulbourke.net/dataformats/serialmouse:
- *
+ *
* The old MicroSoft serial mouse, while no longer in general use, can be employed to provide a low cost input device,
* for example, coupling the internal mechanism to other moving objects. The serial protocol for the mouse is:
*
* 1200 baud, 7 bit, 1 stop bit, no parity.
*
* The pinout of the connector follows the standard serial interface, as shown below:
- *
+ *
* Pin Abbr Description
* 1 DCD Data Carrier Detect
* 2 RD Receive Data [serial data from mouse to host]
@@ -101,7 +101,7 @@ function Mouse(parmsMouse) {
* 7 RTS Request To Send [used to provide positive voltage to mouse]
* 8 CTS Clear To Send
* 9 RI Ring
- *
+ *
* Every time the mouse changes state (moved or button pressed) a three byte "packet" is sent to the serial interface.
* For reasons known only to the engineers, the data is arranged as follows, most notably the two high order bits for the
* x and y coordinates share the first byte with the button status.
@@ -110,16 +110,16 @@ function Mouse(parmsMouse) {
* 1st byte 1 LB RB Y7 Y6 X7 X6
* 2nd byte 0 X5 X4 X3 X2 X1 X0
* 3rd byte 0 Y5 Y4 Y3 Y2 Y1 Y0
- *
+ *
* where:
- *
+ *
* LB is the state of the left button, 1 = pressed, 0 = released.
* RB is the state of the right button, 1 = pressed, 0 = released
* X0-7 is movement of the mouse in the X direction since the last packet. Positive movement is toward the right.
* Y0-7 is movement of the mouse in the Y direction since the last packet. Positive movement is back, toward the user.
- *
+ *
* From http://www.kryslix.com/nsfaq/Q.12.html:
- *
+ *
* The Microsoft serial mouse is the most popular 2-button mouse. It is supported by all major operating systems.
* The maximum tracking rate for a Microsoft mouse is 40 reports/second * 127 counts per report, in other words, 5080 counts
* per second. The most common range for mice is is 100 to 400 CPI (counts per inch) but can be up to 1000 CPI. A 100 CPI mouse
@@ -141,12 +141,12 @@ function Mouse(parmsMouse) {
* (0x4D, ASCII 'M').
*
* Serial data parameters: 1200bps, 7 data bits, 1 stop bit
- *
+ *
* Data is sent in 3 byte packets for each event (a button is pressed or released, or the mouse moves):
- *
+ *
* D7 D6 D5 D4 D3 D2 D1 D0
* Byte 1 X 1 LB RB Y7 Y6 X7 X6
- * Byte 2 X 0 X5 X4 X3 X2 X1 X0
+ * Byte 2 X 0 X5 X4 X3 X2 X1 X0
* Byte 3 X 0 Y5 Y4 Y3 Y2 Y1 Y0
*
* LB is the state of the left button (1 means down).
@@ -161,7 +161,7 @@ Component.subclass(Component, Mouse);
/**
* initBus(cmp, bus, cpu, dbg)
- *
+ *
* @this {Mouse}
* @param {Computer} cmp
* @param {Bus} bus
@@ -180,7 +180,7 @@ Mouse.prototype.initBus = function(cmp, bus, cpu, dbg) {
/**
* isActive()
- *
+ *
* @this {Mouse}
* @return {boolean} true if active, false if not
*/
@@ -214,10 +214,10 @@ Mouse.prototype.powerUp = function(data, fRepower) {
* on the adapter's state, which is why I envisioned a subsequent syncMouse() call. And you would want
* to do that as a separate call, not as part of attachMouse(), because componentAdapter isn't
* set until attachMouse() returns.
- *
+ *
* However, syncMouse() seems unnecessary, given that SerialPort initializes its MCR to an "inactive"
* state, and even when restoring a previous state, if we've done our job properly, both SerialPort and Mouse
- * should be restored in sync, making any explicit attempt at sync'ing unnecessary (or so I hope).
+ * should be restored in sync, making any explicit attempt at sync'ing unnecessary (or so I hope).
*/
// this.componentAdapter.syncMouse();
break;
@@ -242,7 +242,7 @@ Mouse.prototype.powerUp = function(data, fRepower) {
/**
* powerDown(fSave)
- *
+ *
* @this {Mouse}
* @param {boolean} fSave
* @return {Object|boolean}
@@ -253,7 +253,7 @@ Mouse.prototype.powerDown = function(fSave) {
/**
* reset()
- *
+ *
* @this {Mouse}
*/
Mouse.prototype.reset = function() {
@@ -264,7 +264,7 @@ Mouse.prototype.reset = function() {
* save()
*
* This implements save support for the Mouse component.
- *
+ *
* @this {Mouse}
* @return {Object}
*/
@@ -278,7 +278,7 @@ Mouse.prototype.save = function() {
* restore(data)
*
* This implements restore support for the Mouse component.
- *
+ *
* @this {Mouse}
* @param {Object} data
* @return {boolean} true if successful, false if failure
@@ -289,7 +289,7 @@ Mouse.prototype.restore = function(data) {
/**
* initState(data)
- *
+ *
* @this {Mouse}
* @param {Array} [data]
* @return {boolean} true if successful, false if failure
@@ -310,7 +310,7 @@ Mouse.prototype.initState = function(data) {
/**
* saveState()
- *
+ *
* @this {Mouse}
* @return {Array}
*/
@@ -333,7 +333,7 @@ Mouse.prototype.saveState = function() {
*
* NOTE: addEventListener() wasn't supported in IE until IE9, but that's OK, because IE9 is the
* oldest IE we support anyway (since older versions of IE lacked complete HTML5/canvas support).
- *
+ *
* @this {Mouse}
* @param {Object} control from the HTML DOM (eg, the canvas for the simulated screen)
*/
@@ -365,13 +365,13 @@ Mouse.prototype.captureMouse = function(control) {
this.fCaptured = true;
}
/*
- * None of these tricks seemed to work for IE10, so I'm giving up hiding the browser's mouse pointer in IE for now.
+ * None of these tricks seemed to work for IE10, so I'm giving up hiding the browser's mouse pointer in IE for now.
*
* control['style']['cursor'] = "url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjbQg61aAAAADUlEQVQYV2P4//8/IwAI/QL/+TZZdwAAAABJRU5ErkJggg=='), url('/versions/images/current/blank.cur'), none";
- *
+ *
* Setting the cursor style to "none" may not be a standard, but it works in Safari, Firefox and Chrome, so that's pretty
* good for a non-standard!
- *
+ *
* TODO: The reference to '/versions/images/current/blank.cur' is also problematic for anyone who might want
* to run this app from a different server, so think about that as well.
*/
@@ -385,7 +385,7 @@ Mouse.prototype.captureMouse = function(control) {
* TODO: Use removeEventListener() if fCaptured, to clean up our handlers; since I'm currently using
* anonymous functions, and since I'm not seeing any compelling reason to remove the handlers once they've
* been established, it's less code to leave them in place.
- *
+ *
* @this {Mouse}
* @param {Object} control from the HTML DOM
*/
@@ -408,7 +408,7 @@ Mouse.prototype.releaseMouse = function(control) {
* but I don't think they're available in all browsers. screenX and screenY would work as well.
*
* Anyway, all I care about are deltas. For now.
- *
+ *
* @this {Mouse}
* @param {Object} event object from a 'mousemove' event (specifically, a MouseEvent object)
*/
@@ -430,7 +430,7 @@ Mouse.prototype.moveMouse = function(event) {
/**
* clickMouse(iButton, fDown)
- *
+ *
* @this {Mouse}
* @param {number} iButton is 0 for fButton1 (the LEFT button), 2 for fButton2 (the RIGHT button)
* @param {boolean} fDown
@@ -470,7 +470,7 @@ Mouse.prototype.clickMouse = function(iButton, fDown) {
* Byte 1 X 1 LB RB Y7 Y6 X7 X6
* Byte 2 X 0 X5 X4 X3 X2 X1 X0
* Byte 3 X 0 Y5 Y4 Y3 Y2 Y1 Y0
- *
+ *
* @this {Mouse}
* @param {string|null} [sDiag] diagnostic message
* @param {number} [xDiag] original x-coordinate (optional; for diagnostic use only)
@@ -499,7 +499,7 @@ Mouse.prototype.sendPacket = function(sDiag, xDiag, yDiag) {
* sitting in the RBR), and then writes 0x0B to the MCR (DTR on, RTS on). This last step is consistent with making
* the mouse "active", but it is NOT consistent with "toggling DTR", so I conclude that a reset is ALSO sufficient
* for sending the identification byte. Right or wrong, this gets the ball rolling for Windows v1.01.
- *
+ *
* @this {Mouse}
* @param {number} bMCR
*/
@@ -532,7 +532,7 @@ Mouse.prototype.notifyMCR = function(bMCR) {
* At the very least, Windows will have (re)masked the serial port's IRQ, so what does it matter? Not much,
* I just would have preferred that fActive properly reflect whether we should continue dispatching mouse
* events, displaying MESSAGE_MOUSE messages, etc.
- *
+ *
* We could ask the ChipSet component to notify the SerialPort component whenever its IRQ is masked/unmasked,
* and then have the SerialPort pass that notification on to us, but I'm assuming that in the real world,
* a mouse device that's still powered may still send event data to the serial port, and if there was software
@@ -550,7 +550,7 @@ Mouse.prototype.notifyMCR = function(bMCR) {
* messageDebugger(sMessage)
*
* This is a combination of the Debugger's messageEnabled(MESSAGE_MOUSE) and message() functions, for convenience.
- *
+ *
* @this {Mouse}
* @param {string} sMessage is any caller-defined message string
*/
diff --git a/my_modules/pcjs-client/lib/panel.js b/my_modules/pcjs-client/lib/panel.js
index 6297eb620..689e0278a 100644
--- a/my_modules/pcjs-client/lib/panel.js
+++ b/my_modules/pcjs-client/lib/panel.js
@@ -4,7 +4,7 @@
* @version 1.0
* @suppress {missingProperties}
* Created 2012-Jun-19
- *
+ *
* Copyright © 2012-2014 Jeff Parsons
*
* This file is part of PCjs, which is part of the JavaScript Machines Project (aka JSMachines)
@@ -34,15 +34,15 @@
"use strict";
if (typeof module !== 'undefined') {
- var web = require("../../shared/lib/weblib");
- var Component = require("../../shared/lib/component");
+ var web = require("../../shared/lib/weblib");
+ var Component = require("../../shared/lib/component");
}
/**
* Panel(parmsPanel)
*
* The Panel component has no required (parmsPanel) properties.
- *
+ *
* @constructor
* @extends Component
* @param {Object} parmsPanel
@@ -55,7 +55,7 @@ Component.subclass(Component, Panel);
/**
* setBinding(sHTMLClass, sHTMLType, sBinding, control)
- *
+ *
* The Panel doesn't have any bindings of its own; it passes along all binding requests to
* the Computer, CPU, Keyboard and Debugger components. The order shouldn't matter, since any
* component that doesn't recognize the specified binding should simply ignore it.
@@ -95,7 +95,7 @@ Panel.prototype.initBus = function(cmp, bus, cpu, dbg)
/**
* powerUp(data, fRepower)
- *
+ *
* @this {Panel}
* @param {Object|null} data
* @param {boolean} [fRepower]
@@ -111,7 +111,7 @@ Panel.prototype.powerUp = function(data, fRepower)
/**
* powerDown(fSave)
- *
+ *
* @this {Panel}
* @param {boolean} fSave
* @return {Object|boolean}
@@ -123,19 +123,19 @@ Panel.prototype.powerDown = function(fSave)
/**
* Panel.init()
- *
+ *
* This function operates on every element (e) of class "panel", and initializes
* all the necessary HTML to construct the Panel module(s) as spec'ed.
*
* Note that each element (e) of class "panel" is expected to have a "data-value"
* attribute containing the same JSON-encoded parameters that the Panel constructor
* expects.
- *
+ *
* NOTE: Unlike most other component init() functions, this one is designed to be
* called multiple times: once at load time, so that we can binding our print()
* function to the panel's output control ASAP, and again when the Computer component
* is verifying that all components are ready and invoking their setPower() functions.
- *
+ *
* Our setPower() method gives us a second opportunity to notify any components that
* that might care (eg, CPU, Keyboard, and Debugger) that we have some controls they
* might want to use.
diff --git a/my_modules/pcjs-client/lib/ram.js b/my_modules/pcjs-client/lib/ram.js
index 785a7b27c..f6c9dcd09 100644
--- a/my_modules/pcjs-client/lib/ram.js
+++ b/my_modules/pcjs-client/lib/ram.js
@@ -34,9 +34,9 @@
"use strict";
if (typeof module !== 'undefined') {
- var web = require("../../shared/lib/weblib");
- var Component = require("../../shared/lib/component");
- var ROM = require("./rom");
+ var web = require("../../shared/lib/weblib");
+ var Component = require("../../shared/lib/component");
+ var ROM = require("./rom");
}
/**
@@ -49,7 +49,7 @@ if (typeof module !== 'undefined') {
*
* NOTE: We make a note of the specified size, but no memory is initially allocated
* for the RAM until the Computer component calls setPower().
- *
+ *
* @constructor
* @extends Component
* @param {Object} parmsRAM
@@ -69,7 +69,7 @@ Component.subclass(Component, RAM);
/**
* initBus(cmp, bus, cpu, dbg)
- *
+ *
* @this {RAM}
* @param {Computer} cmp
* @param {Bus} bus
@@ -113,7 +113,7 @@ RAM.prototype.powerUp = function(data, fRepower) {
/**
* powerDown(fSave)
- *
+ *
* @this {RAM}
* @param {boolean} fSave
* @return {Object|boolean}
@@ -146,7 +146,7 @@ RAM.prototype.powerDown = function(fSave) {
* object was not given a specific size (see fInstalled). If there are other RAM objects in the system,
* they must necessarily specify a non-conflicting, non-zero start address, in which case their sizeRAM
* value will never be affected by the ChipSet settings.
- *
+ *
* @this {RAM}
*/
RAM.prototype.reset = function() {
diff --git a/my_modules/pcjs-client/lib/rom.js b/my_modules/pcjs-client/lib/rom.js
index 1717bdfc1..2d055adcb 100644
--- a/my_modules/pcjs-client/lib/rom.js
+++ b/my_modules/pcjs-client/lib/rom.js
@@ -34,10 +34,10 @@
"use strict";
if (typeof module !== 'undefined') {
- var str = require("../../shared/lib/strlib");
- var web = require("../../shared/lib/weblib");
- var DumpAPI = require("../../shared/lib/dumpapi");
- var Component = require("../../shared/lib/component");
+ var str = require("../../shared/lib/strlib");
+ var web = require("../../shared/lib/weblib");
+ var DumpAPI = require("../../shared/lib/dumpapi");
+ var Component = require("../../shared/lib/component");
}
/**
@@ -56,7 +56,7 @@ if (typeof module !== 'undefined') {
*
* Also, while the size parameter may seem redundant, I consider it useful to confirm that the ROM you received
* is the ROM you expected.
- *
+ *
* @constructor
* @extends Component
* @param {Object} parmsROM
@@ -109,11 +109,11 @@ ROM.BIOS.RESET_FLAG_WARMBOOT = 0x1234; // value stored at ROM.BIOS.RESET_FLAG t
/*
* NOTE: There's currently no need for this component to have a reset() function, since
* once the ROM data is loaded, it can't be changed, so there's nothing to reinitialize.
- *
+ *
* OK, well, I take that back, because the Debugger, if installed, has the ability to modify
* ROM contents, so in that case, having a reset() function that restores the original ROM data
* might be useful; then again, it might not, depending on what you're trying to debug.
- *
+ *
* If we do add reset(), then we'll want to change copyROM() to hang onto the original
* ROM data; currently, we release it after copying it into the read-only memory allocated
* via bus.addMemory().
@@ -121,7 +121,7 @@ ROM.BIOS.RESET_FLAG_WARMBOOT = 0x1234; // value stored at ROM.BIOS.RESET_FLAG t
/**
* initBus(cmp, bus, cpu, dbg)
- *
+ *
* @this {ROM}
* @param {Computer} cmp
* @param {Bus} bus
@@ -166,7 +166,7 @@ ROM.prototype.powerUp = function(data, fRepower)
* this function. But it doesn't hurt anything, and maybe we'll use our state to save something
* useful down the road, like user-defined symbols (ie, symbols that the Debugger may have
* created, above and beyond those symbols we automatically loaded, if any, along with the ROM).
- *
+ *
* @this {ROM}
* @param {boolean} fSave
* @return {Object|boolean}
@@ -178,7 +178,7 @@ ROM.prototype.powerDown = function(fSave)
/**
* onLoadROM(sROMFile, sROMData, nErrorCode)
- *
+ *
* @this {ROM}
* @param {string} sROMFile
* @param {string} sROMData
@@ -198,7 +198,7 @@ ROM.prototype.onLoadROM = function(sROMFile, sROMData, nErrorCode)
var rom = eval("(" + sROMData + ")");
var ab = rom['bytes'];
var adw = rom['data'];
-
+
if (ab) {
this.abROM = ab;
}
@@ -304,7 +304,7 @@ ROM.prototype.copyROM = function()
/**
* addROM(addr)
- *
+ *
* If addr is null or undefined, then it's presumably an unused addrROMAlias, which we simply ignore (it's not
* considered a failure condition).
*
diff --git a/my_modules/pcjs-client/lib/serial.js b/my_modules/pcjs-client/lib/serial.js
index a337794c8..00c894703 100644
--- a/my_modules/pcjs-client/lib/serial.js
+++ b/my_modules/pcjs-client/lib/serial.js
@@ -34,10 +34,10 @@
"use strict";
if (typeof module !== 'undefined') {
- var web = require("../../shared/lib/weblib");
- var Component = require("../../shared/lib/component");
- var ChipSet = require("./chipset");
- var State = require("./state");
+ var web = require("../../shared/lib/weblib");
+ var Component = require("../../shared/lib/component");
+ var ChipSet = require("./chipset");
+ var State = require("./state");
}
/**
@@ -57,7 +57,7 @@ if (typeof module !== 'undefined') {
*
* DOS typically names the Primary adapter "COM1" and the Secondary adapter "COM2", but I prefer
* to stick to adapter numbers, since not all operating systems follow those naming conventions.
- *
+ *
* @constructor
* @extends Component
* @param {Object} parmsSerial
@@ -82,7 +82,7 @@ function SerialPort(parmsSerial) {
/**
* controlIOBuffer is a DOM element, if any, bound to the port (currently for output purposes only; see echoByte())
- *
+ *
* @type {Object}
*/
this.controlIOBuffer = null;
@@ -98,12 +98,12 @@ function SerialPort(parmsSerial) {
* property {number} portBase
* property {number} nIRQ
* property {Object} controlIOBuffer is a DOM element, if any, bound to the port (for rudimentary output; see echoByte())
- *
+ *
* NOTE: This class declaration started as a way of informing the code inspector of the controlIOBuffer property,
* which remained undefined until a setBinding() call set it later, but I've since decided that explicitly
* initializing such properties in the constructor is a better way to go -- even though it's more code -- because
* JavaScript compilers are supposed to be happier when the underlying object structures aren't constantly changing.
- *
+ *
* Besides, I'm not sure I want to get into documenting every property this way, for this or any/every other class,
* let alone getting into which ones should be considered private or protected, because PCjs isn't really a library
* for third-party apps.
@@ -113,10 +113,10 @@ Component.subclass(Component, SerialPort);
/*
* Internal name used for the I/O buffer control, if any, that we bind to the SerialPort.
- *
+ *
* Alternatively, if SerialPort wants to use another component's control (eg, the Panel's
* "print" control), it can specify the name of that control with the 'binding' property.
- *
+ *
* For that binding to succeed, we also need to know the target component; for now, that's
* been hard-coded to "Panel", in part because that's one of the few components we can rely
* upon initializing before we do, but it would be a simple matter to include a component type
@@ -126,11 +126,11 @@ SerialPort.sIOBuffer = "buffer";
/*
* 8250 I/O register offsets (add these to a I/O base address to obtain an I/O port address)
- *
+ *
* NOTE: DLL.REG and DLM.REG form a 16-bit divisor into a clock input frequency of 1.8432Mhz. The following
* values should be used for the corresponding baud rates. Rates above 9600 are discouraged by the IBM Tech Ref,
* but rates as high as 128000 are listed on the NS8250A data sheet.
- *
+ *
* Divisor Rate Percent Error
* 0x0900 50
* 0x0600 75
@@ -142,7 +142,7 @@ SerialPort.sIOBuffer = "buffer";
* 0x0060 1200
* 0x0040 1800
* 0x003A 2000 0.69%
- * 0x0030 2400
+ * 0x0030 2400
* 0x0020 3600
* 0x0018 4800
* 0x0010 7200
@@ -173,7 +173,7 @@ SerialPort.IER.UNUSED = 0xF0; // always zero
/*
* Interrupt ID Register (IIR.REG, offset 2)
- *
+ *
* All interrupt conditions cleared by reading the corresponding register (or, in the case of IRR_INT_THR, writing a new value to THR.REG)
*/
SerialPort.IIR = {};
@@ -216,7 +216,7 @@ SerialPort.MCR.UNUSED = 0xE0; // always zero
/*
* Line Status Register (LSR.REG, offset 5)
- *
+ *
* NOTE: I've seen different specs for the LSR_TSRE. I'm following the IBM Tech Ref's lead here, but the data sheet I have calls it TEMT
* instead of TSRE, and claims that it is set whenever BOTH the THR and TSR are empty, and clear whenever EITHER the THR or TSR contain data.
*/
@@ -247,7 +247,7 @@ SerialPort.MSR.RLSD = 0x80; // complement of the RLSD (Received Line
/**
* attachMouse(id, mouse)
- *
+ *
* @this {SerialPort}
* @param {string} id
* @param {Mouse} mouse component
@@ -265,7 +265,7 @@ SerialPort.prototype.attachMouse = function(id, mouse) {
* syncMouse()
*
* NOTE: This is probably obsolete, but the Mouse component still might discover a need for it. See Mouse.powerUp().
- *
+ *
* @this {SerialPort}
*
SerialPort.prototype.syncMouse = function() {
@@ -275,7 +275,7 @@ SerialPort.prototype.syncMouse = function() {
/**
* setBinding(sHTMLClass, sHTMLType, sBinding, control)
- *
+ *
* @this {SerialPort}
* @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")
@@ -291,7 +291,7 @@ SerialPort.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, cont
/*
* By establishing an onkeypress handler here, we make it possible for DOS commands like
* "CTTY COM1" to more or less work (use "CTTY CON" to restore control to the DOS console).
- *
+ *
* WARNING: This isn't really a supported feature yet; very much a work-in-progress.
*/
control.onkeydown = function onKeyDownSerial(event) {
@@ -316,7 +316,7 @@ SerialPort.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, cont
serial.sendRBR([charCode]);
};
return true;
-
+
default:
break;
}
@@ -325,7 +325,7 @@ SerialPort.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, cont
/**
* initBus(cmp, bus, cpu, dbg)
- *
+ *
* @this {SerialPort}
* @param {Computer} cmp
* @param {Bus} bus
@@ -347,7 +347,7 @@ SerialPort.prototype.initBus = function(cmp, bus, cpu, dbg) {
/**
* powerUp(data, fRepower)
- *
+ *
* @this {SerialPort}
* @param {Object|null} data
* @param {boolean} [fRepower]
@@ -366,7 +366,7 @@ SerialPort.prototype.powerUp = function(data, fRepower) {
/**
* powerDown(fSave)
- *
+ *
* @this {SerialPort}
* @param {boolean} fSave
* @return {Object|boolean}
@@ -377,7 +377,7 @@ SerialPort.prototype.powerDown = function(fSave) {
/**
* reset()
- *
+ *
* @this {SerialPort}
*/
SerialPort.prototype.reset = function() {
@@ -388,7 +388,7 @@ SerialPort.prototype.reset = function() {
* save()
*
* This implements save support for the SerialPort component.
- *
+ *
* @this {SerialPort}
* @return {Object}
*/
@@ -402,7 +402,7 @@ SerialPort.prototype.save = function() {
* restore(data)
*
* This implements restore support for the SerialPort component.
- *
+ *
* @this {SerialPort}
* @param {Object} data
* @return {boolean} true if successful, false if failure
@@ -413,7 +413,7 @@ SerialPort.prototype.restore = function(data) {
/**
* initState(data)
- *
+ *
* @this {SerialPort}
* @param {Array} [data]
* @return {boolean} true if successful, false if failure
@@ -454,7 +454,7 @@ SerialPort.prototype.initState = function(data) {
/**
* saveRegisters()
- *
+ *
* @this {SerialPort}
* @return {Array}
*/
@@ -476,7 +476,7 @@ SerialPort.prototype.saveRegisters = function() {
/**
* sendRBR(ab)
- *
+ *
* @this {SerialPort}
* @param {Array} ab is an array of bytes to propagate to the bRBR (Receiver Buffer Register)
*/
@@ -487,7 +487,7 @@ SerialPort.prototype.sendRBR = function(ab) {
/**
* advanceRBR()
- *
+ *
* @this {SerialPort}
*/
SerialPort.prototype.advanceRBR = function() {
@@ -500,7 +500,7 @@ SerialPort.prototype.advanceRBR = function() {
/**
* inRBR(port, addrFrom)
- *
+ *
* @this {SerialPort}
* @param {number} port (0x3F8 or 0x2F8)
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
@@ -516,7 +516,7 @@ SerialPort.prototype.inRBR = function(port, addrFrom) {
/**
* inIER(port, addrFrom)
- *
+ *
* @this {SerialPort}
* @param {number} port (0x3F9 or 0x2F9)
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
@@ -530,7 +530,7 @@ SerialPort.prototype.inIER = function(port, addrFrom) {
/**
* inIIR(port, addrFrom)
- *
+ *
* @this {SerialPort}
* @param {number} port (0x3FA or 0x2FA)
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
@@ -544,7 +544,7 @@ SerialPort.prototype.inIIR = function(port, addrFrom) {
/**
* inLCR(port, addrFrom)
- *
+ *
* @this {SerialPort}
* @param {number} port (0x3FB or 0x2FB)
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
@@ -558,7 +558,7 @@ SerialPort.prototype.inLCR = function(port, addrFrom) {
/**
* inMCR(port, addrFrom)
- *
+ *
* @this {SerialPort}
* @param {number} port (0x3FC or 0x2FC)
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
@@ -572,7 +572,7 @@ SerialPort.prototype.inMCR = function(port, addrFrom) {
/**
* inLSR(port, addrFrom)
- *
+ *
* @this {SerialPort}
* @param {number} port (0x3FD or 0x2FD)
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
@@ -586,7 +586,7 @@ SerialPort.prototype.inLSR = function(port, addrFrom) {
/**
* inMSR(port, addrFrom)
- *
+ *
* @this {SerialPort}
* @param {number} port (0x3FE or 0x2FE)
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
@@ -600,7 +600,7 @@ SerialPort.prototype.inMSR = function(port, addrFrom) {
/**
* outTHR(port, bOut, addrFrom)
- *
+ *
* @this {SerialPort}
* @param {number} port (0x3F8 or 0x2F8)
* @param {number} bOut
@@ -624,7 +624,7 @@ SerialPort.prototype.outTHR = function(port, bOut, addrFrom) {
/**
* outIER(port, bOut, addrFrom)
- *
+ *
* @this {SerialPort}
* @param {number} port (0x3F9 or 0x2F9)
* @param {number} bOut
@@ -641,7 +641,7 @@ SerialPort.prototype.outIER = function(port, bOut, addrFrom) {
/**
* outLCR(port, bOut, addrFrom)
- *
+ *
* @this {SerialPort}
* @param {number} port (0x3FB or 0x2FB)
* @param {number} bOut
@@ -654,7 +654,7 @@ SerialPort.prototype.outLCR = function(port, bOut, addrFrom) {
/**
* outMCR(port, bOut, addrFrom)
- *
+ *
* @this {SerialPort}
* @param {number} port (0x3FC or 0x2FC)
* @param {number} bOut
@@ -671,7 +671,7 @@ SerialPort.prototype.outMCR = function(port, bOut, addrFrom) {
/**
* updateIRR()
- *
+ *
* @this {SerialPort}
*/
SerialPort.prototype.updateIRR = function() {
@@ -691,7 +691,7 @@ SerialPort.prototype.updateIRR = function() {
/**
* echoByte(b)
- *
+ *
* @this {SerialPort}
* @param {number} b
* @return {boolean} true if echoed, false if not
@@ -715,7 +715,7 @@ SerialPort.prototype.echoByte = function(b) {
* messageDebugger(sMessage)
*
* This is a combination of the Debugger's messageEnabled(MESSAGE_SERIAL) and message() functions, for convenience.
- *
+ *
* @this {SerialPort}
* @param {string} sMessage is any caller-defined message string
*/
@@ -731,7 +731,7 @@ SerialPort.prototype.messageDebugger = function(sMessage) {
* messagePort(port, bOut, addrFrom, name, bIn)
*
* This is an internal version of the Debugger's messagePort() function, for convenience.
- *
+ *
* @this {SerialPort}
* @param {number} port
* @param {number|null} bOut if an output operation
diff --git a/my_modules/pcjs-client/lib/video.js b/my_modules/pcjs-client/lib/video.js
index 41c15e35c..f00ebfc02 100644
--- a/my_modules/pcjs-client/lib/video.js
+++ b/my_modules/pcjs-client/lib/video.js
@@ -96,13 +96,13 @@
"use strict";
if (typeof module !== 'undefined') {
- var str = require("../../shared/lib/strlib");
- var web = require("../../shared/lib/weblib");
- var DumpAPI = require("../../shared/lib/dumpapi");
- var Component = require("../../shared/lib/component");
- var ChipSet = require("./chipset");
- var Keyboard = require("./keyboard");
- var State = require("./state");
+ var str = require("../../shared/lib/strlib");
+ var web = require("../../shared/lib/weblib");
+ var DumpAPI = require("../../shared/lib/dumpapi");
+ var Component = require("../../shared/lib/component");
+ var ChipSet = require("./chipset");
+ var Keyboard = require("./keyboard");
+ var State = require("./state");
}
/**
@@ -130,9 +130,9 @@ if (typeof module !== 'undefined') {
* charRows: number of character rows
* fontROM: path to .rom file (or a JSON representation) that defines the character set
* screenColor: background color of the screen window (default is black)
- *
+ *
* An EGA may specify the following additional properties:
- *
+ *
* switches: string representing EGA switches (see "SW1-SW4" documentation below)
* memory: the size of the EGA's on-board memory (overrides EGA's Video.cardSpecs)
*
@@ -175,7 +175,7 @@ function Video(parmsVideo, canvas, context, textarea)
*/
this.model = parmsVideo['model'];
this.cbMemory = 0;
-
+
if (this.model == "ega") {
this.sEGASW = parmsVideo['switches'];
this.cbMemory = parmsVideo['memory'] || 0; // zero means fallback to the cardSpec's default size
@@ -215,7 +215,7 @@ function Video(parmsVideo, canvas, context, textarea)
this.fDoubleFont = Math.round(this.cxScreen / this.nDefaultCols) >= 12;
this.fTouchScreen = parmsVideo['touchScreen'];
-
+
this.canvasScreen = canvas;
this.contextScreen = context;
this.textareaScreen = textarea;
@@ -229,13 +229,13 @@ function Video(parmsVideo, canvas, context, textarea)
*/
this.addrBuffer = this.sizeBuffer = 0;
- /*
+ /*
* aFonts is an array of font objects (ie, arrays) indexed by FONT ID. Font characters are
* arranged in 16x16 grids, with one grid per canvas object in the aCanvas array of each font object.
- *
+ *
* Each element is a Font object that describes the font size and provides bitmaps for all the font
* color permutations. aFonts.length will be non-zero if ANY fonts are loaded, but do NOT assume
- * that EVERY font has been loaded; check for the existence of a font by checking for its unique ID
+ * that EVERY font has been loaded; check for the existence of a font by checking for its unique ID
* within this sparse array.
*/
this.aFonts = [];
@@ -249,10 +249,10 @@ function Video(parmsVideo, canvas, context, textarea)
/*
* Since I've not found clear documentation on a reliable way to check whether a particular DOM element
* (other than the BODY element) has focus at any given time, I've added onfocus() and onblur() handlers
- * to the canvas to maintain my own focus state.
+ * to the canvas to maintain my own focus state.
*/
this.fHasFocus = false;
-
+
var video = this;
if (this.canvasScreen) {
this.canvasScreen.onfocus = function onFocusCanvas() {
@@ -298,11 +298,11 @@ function Video(parmsVideo, canvas, context, textarea)
Component.subclass(Component, Video);
-Video.TRAPALL = true; // monitor all I/O by default (not just deltas)
+Video.TRAPALL = true; // monitor all I/O by default (not just deltas)
/*
* Supported Cards
- *
+ *
* Note that we choose IDs that match the default font ID for each card as well, just for consistency.
*/
Video.CARDS = {};
@@ -312,22 +312,22 @@ Video.CARDS.EGA = 5;
/*
* Supported Monitors
- *
+ *
* The MDA monitor displays 350 lines of vertical resolution, 720 lines of horizontal resolution, and refreshes
* at ~50Hz. The CGA monitor displays 200 lines vertically, 640 horizontally, and refreshes at ~60Hz.
- *
+ *
* Based on actual MDA timings (see http://diylab.atwebpages.com/pressureDev.htm), the total horizontal
* period (drawing a line and retracing) is ~54.25uSec (1000000uSec / 18432) and the horizontal retrace interval
* is about 15% of that, or ~8.14uSec. Vertical sync occurs once every 370 horizontal periods. Of those 370,
* only 354 represent actively drawn lines (and of those, only 350 are visible); the remaining 16 horizontal
- * periods, or 4% of the 370 total, represent the vertical retrace interval.
- *
+ * periods, or 4% of the 370 total, represent the vertical retrace interval.
+ *
* I don't have similar numbers for the CGA or EGA, so for now, I assume similar percentages; ie, 15% of
* the horizontal period will represent horizontal retrace, and 4% of the vertical pixel maximum (262) will
* represent vertical retrace. However, 24% of the CGA's 262 vertical maximum represents non-visible lines,
* whereas only 5% of the MDA's 370 maximum represents non-visible lines; is there really that much "overscan"
* on the CGA?
- *
+ *
* For each monitor type, there's a Video.monitorSpecs object that describes the horizontal and vertical
* timings, along with my assumptions about the percentage of time that drawing is "active" within those periods,
* and then based on the selected monitor type, I compute the number of CPU cycles that each period lasts,
@@ -335,7 +335,7 @@ Video.CARDS.EGA = 5;
* retrace status flags can be quickly calculated.
*
* For reference, here are some important numbers to know (from https://github.com/reenigne/reenigne/blob/master/8088/cga/register_values.txt):
- *
+ *
* CGA MDA
* Pixel clock 14.318 MHz 16.257 MHz (aka "maximum video bandwidth", as IBM Tech Refs sometimes call it)
* Horizontal 15.700 KHz 18.432 KHz (aka "horizontal drive", as IBM Tech Refs sometimes call it)
@@ -405,22 +405,22 @@ Video.monitorSpecs[ChipSet.MONITOR.EGACOLOR] = {
/*
* EGA Miscellaneous ports and SW1-Sw4
- *
+ *
* The Card.MISC.CLK_SELECT bits determine which of the EGA board's 4 configuration switches are
* returned via Card.STATUS0.SWSENSE (when SWSENSE is zero, the switch is closed):
- *
+ *
* 0xC: return SW1
* 0x8: return SW2
* 0x4: return SW3
* 0x0: return SW4
- *
+ *
* These 4 bits are also copied to the byte at 40:88h by the EGA BIOS, where bit 0 is SW1, bit 1 is SW2,
* bit 2 is SW3 and bit 3 is SW4. Our switch settings come from bEGASW, which in turn comes from sEGASW,
* which in turn comes from the "switches" property passed to the Video component, if any.
- *
+ *
* As usual, the switch settings are reversed in both direction and sense from the switch settings; the
* good news, however, is that we can use the parseSwitches() method in the ChipSet component to parse them.
- *
+ *
* The set of valid EGA switch values, after conversion, is stored in the table below. For each value,
* there is an array that defines the corresponding monitor type(s) for the EGA adapter and any secondary
* adapter. The third value is a boolean indicating whether the EGA is the primary adapter.
@@ -442,7 +442,7 @@ Video.aEGAMonitorSwitches = {
/*
* Supported Modes
- *
+ *
* Although this component is designed to be a video hardware emulation, not a "BIOS simulation", we DO
* look for changes to the hardware state that correspond to standard BIOS mode settings, so our internal
* mode setting will normally match the current BIOS mode. Since 99.9% of applications use only standard
@@ -450,7 +450,7 @@ Video.aEGAMonitorSwitches = {
* we simply use common, familiar values wherever it makes sense to do so. We do have some "BIOS awareness",
* (eg, when we look for a ROM-based font, or when we're trying to ensure all the BIOS diagnostics pass),
* but for the most part, we are treating the BIOS as just another (ROM-based) application.
- *
+ *
* As we expand support to include more programmable cards like the EGA, it becomes quite easy for the card
* to enter a "mode" that has no BIOS counterpart (eg, non-standard combinations of frame buffer address,
* memory access modes, fonts, display regions, etc). Our hardware emulation routines will cope with those
@@ -475,23 +475,23 @@ Video.MODES.UNKNOWN = 0xFF;
/*
* Supported Fonts
- *
+ *
* Once we've finished loading the standard 8K font file, aFonts[] should contain one or more of the
* fonts listed below. For the standard MDA/CGA font ROM, the first (MDA) font resides in the first 4K,
* and the second and third (CGA) fonts reside in the two 2K halves of the second 4K.
- *
+ *
* It may seem odd that the cell size for FONT_CGAD is *larger* than the cell size for FONT_CGA,
* since 40-column mode is actually lower resolution, but since we don't shrink the window when we shrink
* the mode, the characters must be drawn larger, and they look better if we don't have to scale them.
- *
+ *
* From the IBM EGA Manual (p.5):
- *
+ *
* "In alphanumeric modes, characters are formed from one of two ROM (Read Only Memory) character
* generators on the adapter. One character generator defines 7x9 characters in a 9x14 character box.
* For Enhanced Color Display support, the 9x14 character set is modified to provide an 8x14 character set.
* The second character generator defines 7x7 characters in an 8x8 character box. These generators contain
* dot patterns for 256 different characters. The character sets are identical to those provided by the
- * IBM Monochrome Display Adapter and the IBM Color/Graphics Monitor Adapter."
+ * IBM Monochrome Display Adapter and the IBM Color/Graphics Monitor Adapter."
*/
Video.FONTS = {};
Video.FONTS.MDA = 1; // 9x14 monochrome font
@@ -503,19 +503,19 @@ Video.FONTS.EGAD = 10; // 18x28 color font (this is the 9x14 EGA font d
/*
* For each video mode, we need to know the following pieces of information:
- *
+ *
* 0: # of columns (nCols)
* 1: # of rows (nRows)
* 2: # cells per word (nCellsPerWord: # of characters or pixels per word)
* 3: # bytes of visible screen padding, if any (used for CGA graphics modes only)
* 4: font ID (nFont: undefined if graphics mode)
- *
+ *
* By calculating ([0] * [1]) / [2], we obtain the number of 16-bit words that mode actively displays;
* for example, the amount of visible memory used by mode 0x04 is (320 * 200) / 4, or 16000.
- *
+ *
* The MODES.CGA_40X25 modes specify FONT_CGA instead of FONT_CGAD because we don't automatically
* load the FONT_CGAD unless the screen is large enough to accommodate it (see the fDoubleFont calculation).
- *
+ *
* To compensate, we have code in setDimensions() that automatically switches to FONT_CGAD if it's loaded AND
* the cell size warrants the larger font. We could hard-code FONT_CGAD here, but then we'd always load it,
* and it might not always be the best fit.
@@ -527,8 +527,8 @@ Video.aModeParms[Video.MODES.CGA_320X200] = [320, 200, 8, 192];
Video.aModeParms[Video.MODES.CGA_640X200] = [640, 200, 16, 192]; // 0x06
Video.aModeParms[Video.MODES.MDA_80X25] = [ 80, 25, 1, 0, Video.FONTS.MDA]; // 0x07
Video.aModeParms[Video.MODES.EGA_320X200] = [320, 200, 16]; // 0x0D
-Video.aModeParms[Video.MODES.EGA_640X200] = [640, 200, 16]; // 0x0E
-Video.aModeParms[Video.MODES.EGA_640X350_MONO] = [640, 350, 16]; // 0x0F
+Video.aModeParms[Video.MODES.EGA_640X200] = [640, 200, 16]; // 0x0E
+Video.aModeParms[Video.MODES.EGA_640X350_MONO] = [640, 350, 16]; // 0x0F
Video.aModeParms[Video.MODES.EGA_640X350] = [640, 350, 16]; // 0x10
Video.aModeParms[Video.MODES.CGA_40X25_BW] = Video.aModeParms[Video.MODES.CGA_40X25]; // 0x01
@@ -537,13 +537,13 @@ Video.aModeParms[Video.MODES.CGA_320X200_BW] = Video.aModeParms[Video.MODES.C
/*
* MDA attribute byte definitions
- *
+ *
* For MDA, only the following group of ATTR definitions are supported; any FGND/BGND value combinations
* outside this group will be treated as "normal" (ATTR_FGND_WHITE | ATTR_BGND_BLACK).
- *
+ *
* NOTE: Assuming MDA.MODE.BLINK_ENABLE is set (which the ROM BIOS sets by default), ATTR_BGND_BLINK will
* cause the *foreground* element of the cell to blink, even though it is part of the *background* attribute bits.
- *
+ *
* Regarding blink rate, characters are supposed to blink every 16 vertical frames, which amounts to .26667 blinks
* per second, assuming a 60Hz vertical refresh rate. So roughly every 267ms, we need to take care of any blinking
* characters. updateScreen() maintains a global count (cBlinkVisible) of blinking characters, to simplify the
@@ -564,7 +564,7 @@ Video.ATTRS.DRAW_CURSOR = 0x200; // this is an internal attribute bit, in
/*
* Here's a "cheat sheet" for attribute byte combinations that the IBM MDA could have supported. The original (Aug 1981)
* IBM Tech Ref is very terse and implies that only those marked with * are actually supported.
- *
+ *
* *0x00: non-display ATTR_FGND_BLACK | ATTR_BGND_BLACK
* *0x01: underline ATTR_FGND_ULINE | ATTR_BGND_BLACK
* *0x07: normal (white on black) ATTR_FGND_WHITE | ATTR_BGND_BLACK
@@ -576,29 +576,29 @@ Video.ATTRS.DRAW_CURSOR = 0x200; // this is an internal attribute bit, in
* 0x89: blinking bright underline ATTR_FGND_ULINE | ATTR_FGND_BRIGHT | ATTR_BGND_BLINK (or dim background if blink disabled)
* **0x8F: blinking bold ATTR_FGND_WHITE | ATTR_FGND_BRIGHT | ATTR_BGND_BLINK (or dim background if blink disabled)
* **0xF0: blinking reverse ATTR_FGND_WHITE | ATTR_FGND_BRIGHT | ATTR_BGND_BLINK (or bright background if blink disabled)
- *
+ *
* Unsupported attributes reportedly display as "normal" (ATTR_FGND_WHITE | ATTR_BGND_BLACK). However, precisely which
* attributes are unsupported on the MDA varies depending on the source. Some sources (eg, the IBM Tech Ref) imply that
* only those marked by * are supported, while others (eg, some--but not all--Peter Norton guides) include those marked
* by **, and still others include ALL the combinations listed above.
- *
+ *
* Furthermore, according to http://www.seasip.info/VintagePC/mda.html:
- *
+ *
* Attributes 0x00, 0x08, 0x80 and 0x88 display as black space;
* Attribute 0x78 displays as dark green on green; depending on the monitor, there may be a green "halo" where the dark and bright bits meet;
* Attribute 0xF0 displays as a blinking version of 0x70 if blink enabled, and black on bright green otherwise;
* Attribute 0xF8 displays as a blinking version of 0x78 if blink enabled, and as dark green on bright green otherwise.
- *
+ *
* However, I'm rather skeptical about supporting 0x78 and 0xF8, until I see some evidence that "bright black" actually
* produced dark green on IBM equipment; it also doesn't sound like a combination many people would have used. I'll probably
* treat all of 0x08, 0x80 and 0x88 the same as 0x00, only because it seems logical (they're all "black on black" combinations
* with only BRIGHT and/or BLINK bits set). Beyond that, I'll likely treat any other combination not listed in the above cheat
* sheet as "normal".
- *
+ *
* All the discrepancies/disagreements I've found are probably due in part to the proliferation of IBM and non-IBM MDA
* cards, combined with IBM and non-IBM monochrome monitors, and people assuming that their non-IBM card and/or monitor
* behaved exactly like the original IBM equipment, which probably wasn't true in all cases.
- *
+ *
* I would like to limit my MDA display support to EXACTLY everything that the IBM MDA supported and nothing more, but
* since there will be combinations that will logically "fall out" unless I specifically exclude them, it's very likely
* this implementation will end up being a superset.
@@ -697,9 +697,9 @@ Video.aEGADWToByte[0x80808080] = 0xf;
*
* Creates an object representing an initial video card state;
* can also restore a video card from state data created by saveCard().
- *
+ *
* See new Card().
- *
+ *
* @constructor
* @param {Video} [video]
* @param {number} [iCard] (see Video.CARDS.*)
@@ -713,14 +713,14 @@ function Card(video, iCard, data, cbMemory)
* so we need to detect that case and continue indicating that the card is not present.
*/
if (iCard !== undefined && (!data || data.length)) {
-
+
var specs = Video.cardSpecs[iCard];
var nMonitorType = video.nMonitorType || specs[5];
if (!data || data.length < 6) {
data = [false, 0, null, null, 0, new Array(Card.CRTC.TOTAL_REGS)];
}
-
+
/*
* If a Debugger is present, we want to stash a bit more info in each Card.
*/
@@ -729,11 +729,11 @@ function Card(video, iCard, data, cbMemory)
this.type = specs[0];
this.port = specs[1];
}
-
+
this.iCard = iCard;
this.addrBuffer = specs[2]; // default (physical) frame buffer address
this.sizeBuffer = specs[3]; // default frame buffer length (this is the total size, not the current visible size; this.cbScreen is calculated on the fly to reflect the latter)
-
+
/*
* If no memory size is specified, then setMode() will use addMemory() to automatically add enough
* memory blocks to cover the frame buffer specified above; otherwise, it instructs addMemory() to call
@@ -742,16 +742,16 @@ function Card(video, iCard, data, cbMemory)
* the underlying memory.
*/
this.cbMemory = cbMemory || specs[4];
-
+
/*
* All of our cardSpec frame buffer sizes are based on the default text mode (eg, 4Kb for an MDA, 16Kb for
* a CGA), but for a card with 64Kb or more of memory (ie, any EGA card), the default text mode frame buffer
- * size should be dynamically recalculated as the smaller of: cbMemory divided by 4, or 32Kb.
+ * size should be dynamically recalculated as the smaller of: cbMemory divided by 4, or 32Kb.
*/
if (this.cbMemory >= 0x10000 && this.addrBuffer >= 0xB0000) {
this.sizeBuffer = Math.min(this.cbMemory >> 2, 0x8000);
}
-
+
this.fActive = data[0];
this.modeReg = data[1]; // see MDA.MODE* or CGA.MODE_* (use (MDA.MODE.HIRES | MDA.MODE.VIDEO_ENABLE | MDA.MODE.BLINK_ENABLE) if you want to test blinking immediately after the initial power-on reset)
this.colorReg = data[2]; // see CGA.COLOR.* (undefined on MDA)
@@ -761,15 +761,15 @@ function Card(video, iCard, data, cbMemory)
this.aCRTCRegs = data[5];
this.nCRTCRegs = Card.CRTC.TOTAL_REGS;
this.asCRTCRegs = DEBUGGER? Card.CRTC.REGS : [];
-
+
if (iCard == Video.CARDS.EGA) {
this.nCRTCRegs = Card.CRTC.EGA.TOTAL_REGS;
this.asCRTCRegs = DEBUGGER? Card.CRTC.EGA_REGS : [];
this.initEGA(data[6], nMonitorType);
}
-
+
var monitorSpecs = Video.monitorSpecs[nMonitorType] || Video.monitorSpecs[ChipSet.MONITOR.MONO];
-
+
var nCyclesPerSecond = video.cpu.getCyclesPerSecond(); // eg, 4772727
this.nCyclesHorzPeriod = (nCyclesPerSecond / monitorSpecs.nHorzPeriodsPerSec) | 0;
this.nCyclesHorzActive = (this.nCyclesHorzPeriod * monitorSpecs.percentHorzActive / 100) | 0;
@@ -850,12 +850,12 @@ Card.CGA.PRESET_PEN.PORT = 0x3DC;
/*
* Common CRT hardware registers, accessed via Card.XXA.CRTC.INDX.PORT and Card.XXA.CRTC.DATA.PORT
- *
+ *
* NOTE: In this implementation, because we have to make at least two of the registers readable (CURSOR_ADDR_HI and CURSOR_ADDR_LO),
* we end up making ALL the registers readable, otherwise we would have to explicitly block any register marked write-only. I don't
* think making the CRT registers fully readable presents any serious compatibility issues, and it actually offers some benefits
* (eg, improved debugging).
- *
+ *
* However, some things are broken: the (readable) light pen registers on the EGA are overloaded as (writable) vertical retrace
* registers, so the vertical retrace registers cannot actually be read that way. I'm sure the VGA solved that problem, but I haven't
* looked into it yet.
@@ -877,7 +877,7 @@ Card.CRTC.CURSOR_START.INDX = 0x0A;
Card.CRTC.CURSOR_START.MASK = 0x1F;
/*
* I don't entirely understand these cursor blink control bits. Here's what the MC6845 datasheet says:
- *
+ *
* Bit 5 is the blink timing control. When bit 5 is low, the blink frequency is 1/16 of the vertical field rate,
* and when bit 5 is high, the blink frequency is 1/32 of the vertical field rate. Bit 6 is used to enable a blink.
*/
@@ -902,12 +902,12 @@ Card.CRTC.EGA.VERT_BLANK_START = 0x15;
Card.CRTC.EGA.VERT_BLANK_END = 0x16;
Card.CRTC.EGA.MODE_CTRL = {};
Card.CRTC.EGA.MODE_CTRL.INDX = 0x17;
-Card.CRTC.EGA.MODE_CTRL.CMS = 0x01; // Compatibility Mode Support (CGA A13 control)
+Card.CRTC.EGA.MODE_CTRL.CMS = 0x01; // Compatibility Mode Support (CGA A13 control)
Card.CRTC.EGA.MODE_CTRL.SRSC = 0x02; // Select Row Scan Counter
Card.CRTC.EGA.MODE_CTRL.HRS = 0x04; // Horizontal Retrace Select
Card.CRTC.EGA.MODE_CTRL.CBT = 0x08; // Count By Two
Card.CRTC.EGA.MODE_CTRL.OC = 0x10; // Output Control
-Card.CRTC.EGA.MODE_CTRL.AW = 0x20; // Address Wrap (in Word mode, 1 maps A15 to A0 and 0 maps A13; use the latter when only 64Kb is installed)
+Card.CRTC.EGA.MODE_CTRL.AW = 0x20; // Address Wrap (in Word mode, 1 maps A15 to A0 and 0 maps A13; use the latter when only 64Kb is installed)
Card.CRTC.EGA.MODE_CTRL.BM = 0x40; // Byte Mode (1 selects Byte Mode; 0 selects Word Mode)
Card.CRTC.EGA.MODE_CTRL.HR = 0x80; // Hardware Reset
Card.CRTC.EGA.LINE_COMPARE = 0x18;
@@ -933,7 +933,7 @@ Card.STATUS1 = {};
Card.STATUS1.PORT = 0x3DA;
/*
* STATUS1 diagnostic bits 5 and 4 are set according to the Card.ATC.PLANES.MUX bits:
- *
+ *
* MUX Bit 5 Bit 4
* --- ---- ----
* 00: Red Blue
@@ -945,12 +945,12 @@ Card.STATUS1.DIAGNOSTIC = 0x30; // these bits are controlled by the Card
/*
* EGA Attribute Controller (ATC) ports
- *
+ *
* The current ATC INDX value is stored in cardEGA.iATCReg (including the Card.ATC.INDX_ENABLE bit), and the
* ATC DATA values are stored in cardEGA.aATCRegs. Also, the state of the ATC INDX/DATA flip-flop is stored in fATCData.
- *
+ *
* Note that the ATC palette registers (0x0-0xf) all use the following 6 bit assignments, with bits 6 and 7 unused:
- *
+ *
* 0: Blue
* 1: Green
* 2: Red
@@ -1003,7 +1003,7 @@ Card.MISC.VERT_POLARITY = 0x80; // 0 selects positive vertical retrace
/*
* The EGA BIOS writes 0x1 to Card.FEAT_CTRL.BITS and reads Card.STATUS0.FEAT, then writes 0x2 to
* Card.FEAT_CTRL.BITS and reads Card.STATUS0.FEAT. The bits from the first and second reads are shifted
- * into the high nibble of the byte at 40:88h.
+ * into the high nibble of the byte at 40:88h.
*/
Card.FEAT_CTRL = {};
Card.FEAT_CTRL.PORT = 0x3DA; // or 0x3BA; write-only (other than the two bits below, the rest are reserved and/or unused)
@@ -1098,7 +1098,7 @@ Card.GRC.MODE.EVENODD = 0x10;
Card.GRC.MODE.SHIFT = 0x20;
Card.GRC.MISC = {};
Card.GRC.MISC.INDX = 0x06; // MISCELLANEOUS
-Card.GRC.MISC.GRAPHICS = 0x01; // set for graphics mode addressing, clear for text mode addressing
+Card.GRC.MISC.GRAPHICS = 0x01; // set for graphics mode addressing, clear for text mode addressing
Card.GRC.MISC.CHAIN = 0x02; // set for odd/even planes selected with odd/even values of the processor AO bit
Card.GRC.MISC.MAPMEM = 0x0C; //
Card.GRC.MISC.MAPA0128 = 0x00; //
@@ -1115,18 +1115,18 @@ if (DEBUGGER) Card.GRC.REGS = ["SRESET","ESRESET","COLRCMP","DATAROT","READMAP",
/*
* EGA Memory Access Functions
- *
+ *
* Here's where we define all the getMemoryAccess() functions that know how to deal with "planar" EGA memory,
* which consists of 32-bit values for every byte of address space, allowing us to internally store plane 0
- * bytes in bits 0-7, plane 1 bytes in bits 8-15, plane 2 bytes in bits 16-23, and plane 3 bytes in bits 24-31.
- *
+ * bytes in bits 0-7, plane 1 bytes in bits 8-15, plane 2 bytes in bits 16-23, and plane 3 bytes in bits 24-31.
+ *
* All our functions have slightly more overhead than the standard Bus memory access functions, because the
* offset (off) parameter is block-relative, which we must transform into a buffer-relative offset. Fortunately,
* all our Memory objects know this and have already recorded their buffer-relative offset in "this.offset".
*
* Also, the EGA includes a set of latches, one for each plane, which must be updated on most reads/writes;
* we rely on the Memory object's "this.controller" property to give us access to the Card's state.
- *
+ *
* And we take a little extra time to conditionally set fDirty on writes, meaning if a write did not actually
* change the value of the memory, we will not set fDirty. The default write functions in mem.js don't take that
* performance hit, but here, it may be worthwhile, because if it results in fewer dirty blocks, display updates
@@ -1135,10 +1135,10 @@ if (DEBUGGER) Card.GRC.REGS = ["SRESET","ESRESET","COLRCMP","DATAROT","READMAP",
* Note that we don't have to worry about dealing with word accesses that straddle block boundaries, because
* the Bus component automatically breaks those accesses into separate byte requests. Similarly, byte and word
* values for the write functions have already been pre-masked by the Bus component to 8 and 16 bits, respectively.
- *
+ *
* My motto: Be paranoid, but also be careful not to do any more work than you absolutely have to.
*
- *
+ *
* CGA Emulation on the EGA
*
* Modes 4/5 (320x200 low-res graphics) emulate the same buffer format that the CGA uses. To recap: 1 byte contains
@@ -1146,27 +1146,27 @@ if (DEBUGGER) Card.GRC.REGS = ["SRESET","ESRESET","COLRCMP","DATAROT","READMAP",
* Moreover, all even rows are stored in the first 8K of the frame buffer (at 0xB8000), and all odd rows are stored
* in the second 8K (at 0xBA000). Of each 8K, only 8000 (0x1F40) bytes are used (80 bytes X 100 rows); the remaining
* 192 bytes of each 8K are unused.
- *
+ *
* For these modes, the EGA's GRC.MODE is programmed with 0x30: Card.GRC.MODE.EVENODD and Card.GRC.MODE.SHIFT.
* The latter claims to work by forming each 2-bit pixel with even bits from plane 0 and odd bits from plane 1;
* however, I'm unclear how that works if even bytes are only written to plane 0 and odd bytes are only written to
* plane 1, as Card.GRC.MODE.EVENODD implies, because plane 0 would never have any bits for the odd bytes, and
* plane 1 would never have any bits for the even bytes. Clearly, I'm missing something.
*
- *
+ *
* Even/Odd Memory Access Functions
- *
+ *
* The "EVENODD" functions deal with the EGA's default text-mode addressing, where every EVEN address is mapped to
* plane 0 (and plane 2) and every ODD address is mapped to plane 1 (and plane 3). This occurs when SEQ.MODE.SEQUENTIAL
* is clear (and GRC.MODE.EVENODD is set), turning address bit 0 (A0) into a "plane select" bit. Whether A0 is
* also used as a memory address bit depends on CRTC.MODE_CTRL.BM: if it's set, then we're in "Byte Mode" and A0 is
* used as-is; if it's clear, then we're in "Word Mode", and either A15 (when CRTC.MODE_CTRL.AW is set) or A13
* (when CRTC.MODE_CTRL.AW is clear, typically when only 64Kb of EGA memory is installed) is substituted for A0.
- *
+ *
* Note that A13 remains clear until addresses reach 8K, at which point we've spanned 32Kb of EGA memory, so it makes
* sense to propagate A13 to A0 at that point, so that the next 8K of addresses start using ODD instead of EVEN bytes,
* and no memory is wasted on a 64Kb EGA card.
- *
+ *
* These functions, however, don't yet deal with all those subtleties: A0 is currently used only as a "plane select"
* bit and set to zero for addressing purposes, meaning that only the EVEN bytes in EGA memory will ever be used.
*/
@@ -1251,7 +1251,7 @@ Card.ACCESS.readByteMode0EvenOdd = function readByteMode0EvenOdd(off)
/**
* readByteMode1(off)
- *
+ *
* @this {Memory}
* @param {number} off
* @return {number}
@@ -1531,25 +1531,25 @@ Card.ACCESS.afn[Card.ACCESS.WRITE.MODE2XOR] = Card.ACCESS.writeByteMode2Xor;
/**
* initEGA(data)
- *
+ *
* Another one of my frustrations with JSON is that it encodes empty arrays with non-zero lengths as
* arrays of nulls, which means that any uninitialized register arrays whose elements were all originally
* undefined come back via the JSON round-trip as *initialized* arrays whose elements are now all null.
- *
+ *
* I'm a bit surprised, because Crockford would want us to always use the '===' operator to determine whether
* an element is initialized (eg, 'aReg[i] === undefined'), but because of this JSON stupidity, I would have
- * to change all such tests to 'aReg[i] === undefined || aReg[i] === null'. Great.
- *
+ * to change all such tests to 'aReg[i] === undefined || aReg[i] === null'. Great.
+ *
* The solution is to change such comparisons to 'aReg[i] == null' because undefined is coerced to null but
* numeric values are not. Crockford refers to '==' as an "evil" operator, but yet it's OK for JSON to
* effectively treat 'undefined' the same as 'null'? Give me a break!
- *
+ *
* [What do I mean by "another" frustration? Let me talk to you some day about disallowing hex constants,
* or insisting that property names be quoted, for starters. I think it's fine for JSON.stringify() to
* produce output that adheres to those rules by default -- although some stringify() options to control
* how "portable" the output is would be nice -- but refusing to let JSON.parse() parse objects that are,
* in fact, perfectly parseable, is just JSON being a dick.]
- *
+ *
* @this {Card}
* @param {Array|undefined} data
* @param {number} nMonitorType
@@ -1596,7 +1596,7 @@ Card.prototype.initEGA = function(data, nMonitorType)
this.asATCRegs = DEBUGGER? Card.ATC.REGS : [];
this.status0 = data[3]; // aka STATUS0 (not to be confused with this.statusReg, which the EGA refers to as STATUS1)
this.miscReg = data[4];
- this.featReg = data[5]; // for feature control bits, see Card.FEAT_CTRL.BITS; for feature status bits, see Card.STATUS0.FEAT
+ this.featReg = data[5]; // for feature control bits, see Card.FEAT_CTRL.BITS; for feature status bits, see Card.STATUS0.FEAT
this.iSEQReg = data[6];
this.aSEQRegs = data[7];
this.asSEQRegs = DEBUGGER? Card.SEQ.REGS : [];
@@ -1613,14 +1613,14 @@ Card.prototype.initEGA = function(data, nMonitorType)
this.adwMemory = State.decompressEvenOdd(this.adwMemory, cdw);
}
this.setMemoryAccess(data[15]);
-
+
/*
* nReadMapShift must perfectly track how the GRC.READMAP register is programmed, so that Card.ACCESS.READ.MODE0
* memory read functions read the appropriate plane. This default is not terribly critical, unless Card.ACCESS.WRITE.MODE0
* is chosen as our default AND you want the screen randomizer to work.
*/
this.nReadMapShift = data[16];
-
+
/*
* Similarly, nWriteMapMask must perfectly track how the SEQ.MAPMASK register is programmed, so that memory write
* functions write the appropriate plane(s). Again, this default is not terribly critical, unless Card.ACCESS.WRITE.MODE0
@@ -1638,7 +1638,7 @@ Card.prototype.initEGA = function(data, nMonitorType)
/**
* saveCard()
- *
+ *
* @this {Card}
* @return {Array}
*/
@@ -1662,7 +1662,7 @@ Card.prototype.saveCard = function()
/**
* saveEGA()
- *
+ *
* @this {Card}
* @return {Array}
*/
@@ -1709,16 +1709,16 @@ Card.prototype.dumpCard = function()
* Start with registers that are common to all cards....
*/
this.dumpRegs("CRTC", this.iCRTCReg, this.aCRTCRegs, this.asCRTCRegs);
-
+
if (this.iCard == Video.CARDS.MDA || this.iCard == Video.CARDS.CGA) {
this.dumpRegs(" MODEREG", this.modeReg);
this.dumpRegs(" STATUS1", this.statusReg);
}
-
+
if (this.iCard == Video.CARDS.CGA) {
this.dumpRegs(" COLOR", this.colorReg);
}
-
+
if (this.iCard == Video.CARDS.EGA) {
this.dbg.message(" ATCDATA: " + this.fATCData);
this.dumpRegs(" ATC", this.iATCReg, this.aATCRegs, this.asATCRegs);
@@ -1773,7 +1773,7 @@ Card.prototype.dumpBuffer = function(sParm)
*
* Since we don't pre-allocate the register arrays (eg, ATC, CRTC, GRC, etc) on a Card, we can't
* rely on their array length, so we instead rely on the number of register names supplied in asRegs.
- *
+ *
* @this {Card}
* @param {string} sName
* @param {number} iReg
@@ -1819,7 +1819,7 @@ Card.prototype.getMemoryBuffer = function(addr)
* getMemoryAccess()
*
* Return the last set of memory access functions recorded by setMemoryAccess().
- *
+ *
* @this {Card}
* @return {Array.}
*/
@@ -1834,7 +1834,7 @@ Card.prototype.getMemoryAccess = function()
* This transforms the memory access value that getAccess() returns into the best available set of
* memory access functions, which are then returned via getMemoryAccess() to any memory blocks we allocate
* or modify.
- *
+ *
* @this {Card}
* @param {number|undefined} nAccess
*/
@@ -1869,26 +1869,26 @@ Card.prototype.setMemoryAccess = function(nAccess)
/*
* Card Specifications
- *
+ *
* We support dynamically switching between MDA and CGA cards by simply flipping switches on
* the virtual SW1 switch block and resetting the machine. However, I'm not sure I'll support
* dynamically switching the EGA card the same way; there's certainly no UI for it at this point.
- *
+ *
* For each supported card, there is a cardSpec array that the Card class uses to initialize the
* card's defaults:
- *
+ *
* [0]: card descriptor
* [1]: default CRTC port address
* [2]: default frame buffer address
* [3]: default frame buffer size
* [4]: total on-board memory (if no "memory" parm was specified)
* [5]: default monitor type
- *
+ *
* If total on-board memory is zero, then addMemory() will simply add the specified frame buffer
* to the address space; otherwise, we will allocate an internal buffer (adwMemory) and tell addMemory()
* to map it to the frame buffer address. The latter approach gives us total control over the buffer;
* refer to getMemoryAccess().
- *
+ *
* TODO: Consider allocating our own buffer for all video cards, not just EGA. For MDA/CGA, I'm not sure
* it would offer any benefits, other than allowing our internal update functions, like updateScreen(),
* to access the buffer directly, instead of going through the Bus memory interface.
@@ -1907,10 +1907,10 @@ Video.BIOS = {
/**
* initBus(cmp, bus, cpu, dbg)
- *
+ *
* This is a notification issued by the Computer component, after all the other components (notably the CPU)
* have had a chance to initialize.
- *
+ *
* @this {Video}
* @param {Computer} cmp
* @param {Bus} bus
@@ -1922,15 +1922,15 @@ Video.prototype.initBus = function(cmp, bus, cpu, dbg)
this.bus = bus;
this.cpu = cpu;
this.dbg = dbg;
-
+
bus.addPortInputTable(this, Video.aPortInput);
bus.addPortOutputTable(this, Video.aPortOutput);
-
+
if (this.model == "ega") {
bus.addPortInputTable(this, Video.aEGAPortInput);
bus.addPortOutputTable(this, Video.aEGAPortOutput);
}
-
+
if (DEBUGGER && dbg) {
var video = this;
this.cpu.addIntNotify(Video.BIOS.INT_VIDEO, this, this.intBIOSVideo);
@@ -1938,7 +1938,7 @@ Video.prototype.initBus = function(cmp, bus, cpu, dbg)
video.dumpVideo(sParm);
});
}
-
+
/*
* If we have an associated keyboard, then ensure that the keyboard will be notified whenever
* the canvas gets focus and receives input.
@@ -1947,13 +1947,13 @@ Video.prototype.initBus = function(cmp, bus, cpu, dbg)
if (this.kbd && this.canvasScreen) {
this.kbd.setBinding("input", this.textareaScreen? "textarea" : "canvas", "kbd", this.textareaScreen || this.canvasScreen);
}
-
+
this.bEGASW = 0x9; // our default "switches" setting (see aEGAMonitorSwitches)
this.chipset = cmp.getComponentByType("ChipSet");
if (this.chipset && this.sEGASW) {
this.bEGASW = this.chipset.parseSwitches(this.sEGASW, this.bEGASW);
}
-
+
if (this.kbd && this.fTouchScreen) this.captureTouch();
};
@@ -2018,9 +2018,9 @@ Video.prototype.setFocus = function()
/**
* getCanvas()
- *
+ *
* This is an interface used by the Mouse component, so that it can invoke capture/release mouse events from the screen element.
- *
+ *
* @this {Video}
* @return {Object|undefined}
*/
@@ -2031,7 +2031,7 @@ Video.prototype.getCanvas = function()
/**
* captureTouch()
- *
+ *
* @this {Video}
*/
Video.prototype.captureTouch = function()
@@ -2080,7 +2080,7 @@ Video.prototype.captureTouch = function()
/**
* onFocusChange(fFocus)
- *
+ *
* @this {Video}
* @param {boolean} fFocus is true if gaining focus, false if losing it
*/
@@ -2098,7 +2098,7 @@ Video.prototype.releaseTouch = function()
/**
* onTouchStart(event)
- *
+ *
* @this {Video}
* @param {Event} event object from a 'touch' event
*/
@@ -2110,7 +2110,7 @@ Video.prototype.onTouchStart = function(event)
/**
* onTouchMove(event)
- *
+ *
* @this {Video}
* @param {Event} event object from a 'touch' event
*/
@@ -2122,7 +2122,7 @@ Video.prototype.onTouchMove = function(event)
/**
* onTouchEnd(event)
- *
+ *
* @this {Video}
* @param {Event} event object from a 'touch' event
*/
@@ -2133,7 +2133,7 @@ Video.prototype.onTouchEnd = function(event)
/**
* processTouchEvent(event, fStart)
- *
+ *
* @this {Video}
* @param {Event} event object from a 'touch' event
* @param {boolean} fStart if this is a 'touchstart' event
@@ -2145,7 +2145,7 @@ Video.prototype.processTouchEvent = function(event, fStart)
* My thinking here is that if the canvas does NOT yet have focus, then we should actually SKIP
* the usual preventDefault() call, so that everything the user has come to expect (eg, activation of
* the soft keyboard) will work as before.
- *
+ *
* The process of touching the canvas means it should ultimately receive focus, and as long as it
* retains focus, preventDefault() will always be called.
*/
@@ -2153,7 +2153,7 @@ Video.prototype.processTouchEvent = function(event, fStart)
/*
* Touch coordinates (that is, the pageX and pageY properties) are relative to the page, so to make
* them relative to the canvas, we must subtract the canvas's left and top positions. This Apple web page:
- *
+ *
* https://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/HTML-canvas-guide/AddingMouseandTouchControlstoCanvas/AddingMouseandTouchControlstoCanvas.html
*
* makes it sound simple, but it turns out we have to walk the canvas' entire "parentage" of DOM elements
@@ -2203,7 +2203,7 @@ Video.prototype.processTouchEvent = function(event, fStart)
/**
* powerUp(data, fRepower)
- *
+ *
* @this {Video}
* @param {Object|null} data
* @param {boolean} [fRepower]
@@ -2223,10 +2223,10 @@ Video.prototype.powerUp = function(data, fRepower)
/**
* powerDown(fSave)
- *
+ *
* This is where we might add some method of blanking the display, without the disturbing the video
* buffer contents, and blocking all further updates to the display.
- *
+ *
* @this {Video}
* @param {boolean} fSave
* @return {Object|boolean}
@@ -2238,14 +2238,14 @@ Video.prototype.powerDown = function(fSave)
/**
* reset()
- *
+ *
* @this {Video}
*/
Video.prototype.reset = function()
{
var fRandomize = true;
var nMonitorType = ChipSet.MONITOR.NONE;
-
+
/*
* We'll ask the ChipSet what SW1 indicates for monitor type, but we may override it if a specific
* video card model is set. For EGA, SW1 is supposed to be set to indicate NO monitor, and we rely
@@ -2302,7 +2302,7 @@ Video.prototype.reset = function()
* We need to call buildFonts() *after* the card(s) are initialized but *before* setMode() is called.
*/
this.buildFonts();
-
+
this.nMode = null;
this.nModeDefault = (nMonitorType == ChipSet.MONITOR.MONO? Video.MODES.MDA_80X25 : Video.MODES.CGA_80X25);
@@ -2318,18 +2318,18 @@ Video.prototype.reset = function()
* as a way of testing whether our font(s) were successfully loaded. It's assumed
* that our default display mode is a text mode, and that since this is a reset,
* the CRTC.START_ADDR registers are zero as well.
- *
+ *
* If this is an MDA device, then the buffer should reside at 0xB0000 through 0xB0FFF,
* for a total length of 4Kb (0x1000), where every even byte contains a character code,
* and every odd byte contains an attribute code. See the ATTR bit definitions above for
* applicable color, intensity, and blink values. On a CGA device, the buffer resides
* at 0xB8000 through 0xBBFFF, for a total length of 16Kb.
- *
+ *
* Note that the only valid MDA display mode (7) is the 80x25 text mode, which uses 4000
* bytes (2000 character bytes + 2000 attribute bytes), not all 4096 bytes; addrScreenLimit
* reflects the visible limit, not the physical limit. Also, as noted in updateScreen(),
* this simplistic calculation of the extent of visible screen memory is valid only for
- * text modes; in general, it's safer to use cardActive.sizeBuffer as the extent.
+ * text modes; in general, it's safer to use cardActive.sizeBuffer as the extent.
*/
var addrScreenLimit = this.cardActive.addrBuffer + this.cbScreen;
for (var addrScreen = this.cardActive.addrBuffer; addrScreen < addrScreenLimit; addrScreen += 2) {
@@ -2365,7 +2365,7 @@ Video.prototype.enableEGA = function()
{
if (!(this.cardEGA.miscReg & Card.MISC.IO_SELECT)) {
this.cardMono = this.cardEGA;
- this.cardColor = this.cardCGA; // this is done mainly to siphon away any CGA I/O
+ this.cardColor = this.cardCGA; // this is done mainly to siphon away any CGA I/O
} else {
this.cardMono = this.cardMDA; // similarly, this is done to siphon away any MDA I/O
this.cardColor = this.cardEGA;
@@ -2374,9 +2374,9 @@ Video.prototype.enableEGA = function()
/**
* save()
- *
+ *
* This implements save support for the Video component.
- *
+ *
* @this {Video}
* @return {Object}
*/
@@ -2392,9 +2392,9 @@ Video.prototype.save = function()
/**
* restore(data)
- *
+ *
* This implements restore support for the Video component.
- *
+ *
* @this {Video}
* @param {Object} data
* @return {boolean} true if successful, false if failure
@@ -2409,7 +2409,7 @@ Video.prototype.restore = function(data)
this.cardActive = null;
this.cardMono = this.cardMDA = new Card(this, Video.CARDS.MDA, data[0]);
this.cardColor = this.cardCGA = new Card(this, Video.CARDS.CGA, data[1]);
-
+
/*
* If no EGA was originally initialized, then cardEGA will remain uninitialized.
*/
@@ -2426,10 +2426,10 @@ Video.prototype.restore = function(data)
* setMode() will also take care of mapping the appropriate video buffer. So, after restore() has
* finished, we call checkMode(), because the current video mode (nMode) is determined by the
* active card state.
- *
+ *
* Unfortunately, that creates a chicken-and-egg problem, since I just said I didn't want to select
* the active card here.
- *
+ *
* So, we'll add some "cop-out" code to checkMode(): if there's no active card, then fall-back
* to the last known video mode (nMode) and force a call to setMode().
*
@@ -2476,7 +2476,7 @@ Video.prototype.onLoadSetFonts = function(sFontFile, sFontData, nErrorCode)
if (abFontData.length == 8192) {
/*
* Here are the first few rows of MDA font data, at the 0K and 2K boundaries:
- *
+ *
* 00000000 00 00 00 00 00 00 00 00 00 00 7e 81 a5 81 81 bd |..........~.....|
* 00000010 00 00 7e ff db ff ff c3 00 00 00 36 7f 7f 7f 7f |..~........6....|
* ...
@@ -2485,7 +2485,7 @@ Video.prototype.onLoadSetFonts = function(sFontFile, sFontData, nErrorCode)
*
* 8 bytes of data from a row in each of the 2K chunks are combined to form a 8-bit wide character with
* a maximum height of 16 bits. Assembling the bits for character 0x01 (a happy face), we observe the following:
- *
+ *
* 0 0 0 0 0 0 0 0 <== 00 from offset 0x0008
* 0 0 0 0 0 0 0 0 <== 00 from offset 0x0009
* 0 1 1 1 1 1 1 0 <== 7e from offset 0x000A
@@ -2505,24 +2505,24 @@ Video.prototype.onLoadSetFonts = function(sFontFile, sFontData, nErrorCode)
*
* In the second 2K chunk, we observe that the last two bytes of every font cell definition are zero;
* this confirms our understanding that MDA font cell size is 8x14.
- *
+ *
* Finally, there's the issue of screen cell size, which is actually 9x14 on the MDA. We compensate for that
* by building a 9x14 font, even though there's only 8x14 bits of data. As http://www.seasip.info/VintagePC/mda.html
* explains:
- *
+ *
* "For characters C0h-DFh, the ninth pixel column is a duplicate of the eighth; for others, it's blank."
- *
+ *
* This last point is confirmed by "The IBM Personal Computer From The Inside Out", p.295:
- *
+ *
* "Another unique feature of the monochrome adapter is a set of line-drawing and area-fill characters that give
* continuous lines and filled areas. This is unusual for a display with a 9x14 character box because the character
* generator provides a row only eight dots wide. On most displays, a blank 9th dot is then inserted between characters.
* On the monochrome display, there is circuitry that duplicates the 8th dot into the 9th dot position for characters
* whose ASCII codes are 0xB0 through 0xDF."
- *
+ *
* The only question is: is the range actually 0xC0-0xDF, or 0xB0-0xDF??? I'll assume the latter, since 0xB0 is where
* the line-drawing/area-fill characters appear to begin.
- *
+ *
* The CGA font is part of the same ROM. In fact, there are TWO CGA fonts in the ROM: a thin 5x7 "single dot" font
* located at offset 0x1000, and a thick 7x7 "double dot" font at offset 0x1800. The latter is the default font,
* unless overridden by a jumper setting on the CGA card, so it is our default CGA font as well (although someday we
@@ -2591,7 +2591,7 @@ Video.prototype.onROMLoad = function(abROM)
/**
* getCardColors(nBitsPerPixel)
- *
+ *
* @param {number} [nBitsPerPixel]
* @returns {Array}
*/
@@ -2605,22 +2605,22 @@ Video.prototype.getCardColors = function(nBitsPerPixel)
this.aRGB[1] = Video.aCGAColors[Video.ATTRS.FGND_WHITE];
return this.aRGB;
}
-
+
if (nBitsPerPixel == 2) {
/*
* Of the 4 colors returned, the first color comes from colorReg and the other 3 come from one of
* the two hard-coded CGA color sets:
- *
+ *
* Color Set 1 Color Set 2
* ----------- -----------
* Background (0x00) Background (0x00)
* Green (0x12) Cyan (0x13)
* Red (0x14) Magenta (0x15)
* Brown (0x16) White (0x17)
- *
+ *
* The numbers in parentheses are the EGA ATC palette register values that the EGA BIOS uses for each
* color set; on an EGA, I synthesize a fake CGA colorReg value, until I figure out exactly how the EGA
- * simulates the CGA color palette. TODO: Figure it out.
+ * simulates the CGA color palette. TODO: Figure it out.
*/
var colorReg = this.cardActive.colorReg;
if (this.cardActive === this.cardEGA) {
@@ -2636,7 +2636,7 @@ Video.prototype.getCardColors = function(nBitsPerPixel)
}
return this.aRGB;
}
-
+
if (this.cardColor === this.cardCGA) {
/*
* There's no need to update this.aRGB if we simply want to return a hard-coded set of 16 colors.
@@ -2645,7 +2645,7 @@ Video.prototype.getCardColors = function(nBitsPerPixel)
}
Component.assert(this.cardColor === this.cardEGA);
-
+
var aRegs = (this.cardEGA.aATCRegs[15] != null? this.cardEGA.aATCRegs : Video.aEGAPalDef);
for (var i = 0; i < this.aRGB.length; i++) {
var b = aRegs[i] || 0;
@@ -2662,11 +2662,11 @@ Video.prototype.getCardColors = function(nBitsPerPixel)
*
* To support partial font rebuilds (required for the EGA), we now preserve the original font data (abFontData),
* font offsets (aFontOffsets), and font character width (8 for the EGA, undefined for the MDA/CGA).
- *
+ *
* TODO: Ultimately, we want to have exactly one dedicated font for the EGA, the data for which we'll read directly
* from plane 2 of video memory, instead of relying on the original font data in ROM. Relying on the ROM data was
* originally just a crutch to help get EGA support bootstrapped.
- *
+ *
* Also, for the MDA/CGA, we should be discarding the font data after the first buildFonts() call, because we
* should not need to ever rebuild the fonts for those cards (both their font patterns and colors were hard-coded).
*
@@ -2684,57 +2684,57 @@ Video.prototype.setFontData = function(abFontData, aFontOffsets, cxFontChar)
/**
* buildFonts()
- *
+ *
* buildFonts() is called whenever the Video component is reset or restored; we used to build the fonts as soon
* as the ROM containing them was loaded, and then throw away the underlying font data, but with the EGA's ability
* to change the color of any font, font building must now be deferred until the reset or restore notifications,
* ensuring we have access to all the colors the card is currently programmed to use.
- *
+ *
* We're also called whenever EGA palette registers are modified, since one or more fonts will likely need
* to be rebuilt (this is because our fonts contain pre-rendered images of all glyphs for all 16 active colors).
* Calls to buildFonts() should not be expensive though: the underlying createFont() function rebuilds a font only
* if its color has actually changed.
- *
+ *
* TODO: We should avoid rebuilding fonts when palette registers change in graphics modes. More importantly, our
* font code is still written with the assumption that, like the MDA/CGA, the underlying font data never changes.
* The EGA, however, stores its fonts in plane 2, which means fonts are dynamic; this needs to be fixed.
- *
+ *
* Supporting dynamic EGA fonts should not be hard though. We can get rid of abFontData and simply build a
* temporary snapshot of all the font bytes in plane 2 of the EGA's video buffer (adwMemory), and pass that on to
* buildFont() instead. We'll also need to either invalidate the existing font's color (to trigger a rebuild) or
* pass a new "force rebuild" flag.
- *
+ *
* Once that's done, an added benefit will be that we can build just the font(s) that have been loaded into plane 2,
* instead of the multitude of fonts that we now build on a just-in-case basis (eg, the MDA font, the 8x8 CGA font
* for 43-line mode, and so on).
- *
+ *
* @this {Video}
* @return {boolean} true if any or all fonts were (re)built, false if nothing changed
*/
Video.prototype.buildFonts = function()
{
var fChanges = false;
-
+
/*
* There's no point building any fonts if (a) we're in a non-windowed (eg, command-line) environment or
* (b) no font data was loaded.
*/
if (window && this.abFontData) {
-
+
var offSplit = this.cxFontChar? 0 : 0x0800;
var cxChar = this.cxFontChar? this.cxFontChar : 9;
-
+
if (this.buildFont(Video.FONTS.MDA, this.aFontOffsets[0], offSplit, cxChar, 14, this.abFontData, Video.aMDAColors, Video.aMDAColorMap)) {
fChanges = true;
}
-
+
var aRGBColors = this.getCardColors();
offSplit = 0x0000;
cxChar = this.cxFontChar? this.cxFontChar : 8;
if (this.buildFont(Video.FONTS.CGA, this.aFontOffsets[1], offSplit, cxChar, 8, this.abFontData, aRGBColors)) {
fChanges = true;
}
-
+
if (this.cxFontChar) {
if (this.buildFont(Video.FONTS.EGA, this.aFontOffsets[0], 0, this.cxFontChar, 14, this.abFontData, aRGBColors)) {
fChanges = true;
@@ -2748,7 +2748,7 @@ Video.prototype.buildFonts = function()
* buildFont(nFont, offData, offSplit, cxChar, cyChar, abFontData, aRGBColors, aColorMap)
*
* This is a wrapper for createFont() which also takes care loading double-size fonts when fDoubleFont is set.
- *
+ *
* @this {Video}
* @param {number} nFont
* @param {number} offData is the offset of the font data
@@ -2848,17 +2848,17 @@ Video.prototype.createFontColor = function(font, iColor, rgbColor, nDouble, offD
/*
* Now we're ready to create a 16x16 character grid for the specified color. Note that all
* the character bits are opaque (alpha=0xff) while all the surrounding bits are transparent
- * (alpha=0x00, as specified in the 4th byte of rgbOff).
+ * (alpha=0x00, as specified in the 4th byte of rgbOff).
*
* Originally, I created 256 ImageData objects, using context.createImageData(cxChar,cyChar),
* then setting its pixels to match those of an individual character, and then drawing characters
* with contextFont.putImageData(). But putImageData() is relatively slow....
- *
+ *
* Now I create a new canvas, with dimensions that allow me to arrange all 256 characters in an
* 16x16 grid -- much like the "chargen.png" bitmap used in the C1Pjs version of the Video component.
* Then drawing becomes much the same as before, because it turns out that drawImage() accepts either
* an image object OR a canvas object.
- *
+ *
* This also yields better performance, since drawImage() is much faster than putImageData().
* We still have to use putImageData() to build the font canvas, but that's a one-time operation.
*/
@@ -2927,7 +2927,7 @@ Video.prototype.createFontColor = function(font, iColor, rgbColor, nDouble, offD
this.contextScreen.drawImage(canvasFont, 0, iColor*(font.cyCell<<4), canvasFont.width>>2, font.cyCell<<4, iColor*(font.cxCell<<2), 0, canvasFont.width>>2, font.cyCell<<4);
}
*/
-
+
font.aCanvas[iColor] = canvasFont;
};
@@ -2968,15 +2968,15 @@ Video.prototype.checkBlink = function()
* At this point, we can either fire up our own timer (doBlink), or rely on updateScreen()
* being called by the CPU at a regular rate (eg, CPU.VIDEO_UPDATES_PER_SECOND = 60) and advance
* cBlinks at the start of updateScreen() accordingly.
- *
+ *
* doBlink() wants to increment cBlinks every 266ms. On the other hand, if updateScreen() is being
* called 60 times per second, that's about once every 16ms, so if every 16th updateScreen() increments
* cBlinks, cBlinks should advance at the same rate.
- *
+ *
* The only downside to relying on the CPU driving our blink count is that whenever the CPU is halted
* (eg, by the PCjs debugger) all blinking stops -- all characters with the blink attribute AND the cursor.
- *
- * But we can simply say that when we halt, we mean "halt everything" (ie, call it a feature).
+ *
+ * But we can simply say that when we halt, we mean "halt everything" (ie, call it a feature).
*
* this.doBlink(true);
*/
@@ -3008,7 +3008,7 @@ Video.prototype.checkBlink = function()
Video.prototype.checkCursor = function()
{
/*
- * The "hardware cursor" is never visible in graphics modes.
+ * The "hardware cursor" is never visible in graphics modes.
*/
if (!this.nFont) return false;
@@ -3036,7 +3036,7 @@ Video.prototype.checkCursor = function()
* One way of disabling the cursor is to set bit 5 (Card.CRTC.CURSOR_START.BLINKOFF) of the CRTC.CURSOR_START flags;
* another way is setting bCursorStart > bCursorEnd (unless it's an EGA, in which case we must actually draw a
* "split block" cursor instead).
- *
+ *
* TODO: Verify whether the second test (bCursorStart > bCursorMax) should also result in a hidden cursor;
* ThinkTank sets both start and end values to 0x0f, which doesn't make sense on a CGA, where the max is 0x07.
*/
@@ -3058,7 +3058,7 @@ Video.prototype.checkCursor = function()
/*
* yCursor and cyCursor are no longer scaled at this point, because the necessary scaling will depend on whether we're
* drawing the cursor to the on-screen or off-screen buffer, and updateChar() is in the best position to determine that.
- *
+ *
* We also record cyCursorCell, the hardware cell height, since we'll need to know what the yCursor and cyCursor values
* are relative to when it's time to scale them.
*/
@@ -3193,11 +3193,11 @@ Video.prototype.setAccess = function(nAccess)
{
var card = this.cardActive;
if (nAccess != null && card && nAccess != card.nAccess) {
-
+
if (DEBUG) this.messageDebugger("setAccess(0x" + str.toHexWord(nAccess) + ")");
-
+
card.setMemoryAccess(nAccess);
-
+
/*
* Note that setMemoryAccess() can fail, in which case it will an report error, indicating either a
* misconfiguration or some sort of internal inconsistency; in any case, there's not much we can do about
@@ -3211,7 +3211,7 @@ Video.prototype.setAccess = function(nAccess)
/**
* setDimensions()
- *
+ *
* @this {Video}
*/
Video.prototype.setDimensions = function()
@@ -3234,9 +3234,9 @@ Video.prototype.setDimensions = function()
* When an EGA is connected to a CGA monitor, the old aModeParms table is correct: we must
* use the hard-coded 8x8 "CGA_80" font. But when it's connected to an EGA monitor, we want
* to use the 9x14 "EGA" color font instead.
- *
+ *
* TODO: Can an EGA with a monochrome monitor be programmed for 43-line mode as well? If so,
- * then we'll need to load another MDA font variation, because we only load an 9x14 font for MDA.
+ * then we'll need to load another MDA font variation, because we only load an 9x14 font for MDA.
*/
if (this.cardActive === this.cardEGA && this.nFont == Video.FONTS.CGA) {
if (this.cardEGA.aCRTCRegs[Card.CRTC.MAX_SCAN_LINE] == 7) {
@@ -3269,7 +3269,7 @@ Video.prototype.setDimensions = function()
* If no fonts were successfully loaded, there's no point in initializing the remaining drawing parameters.
*/
if (!this.aFonts.length) return;
-
+
this.cxScreenCell = Math.floor(this.cxScreen / this.nCols);
this.cyScreenCell = Math.floor(this.cyScreen / this.nRows);
@@ -3279,17 +3279,17 @@ Video.prototype.setDimensions = function()
* fScaleFont setting: if it's false, we draw the characters as-is, with a border if the characters
* are smaller than the cells; and if fScaleFont is true, we simply tell drawImage to draw the
* characters to fit.
- *
+ *
* WARNING: The only problem with fScaleFont is that any stretching or shrinking tends to be accompanied
* by subpixel artifacts along the boundaries of the font images. Definitely annoying, and apparently
* there are no standard mechanisms for turning that behavior off. So, for now, I've "neutered" the
* fScaleFont test slightly, by adding the "nCols == 80" test that prevents scaling from kicking in for
* 40-column modes.
- *
+ *
* Also, whether scaling or not, if it makes sense to use a "doubled" font, we'll switch the font as
* well. Note that the doubled font for any existing font also has an ID that is double the existing ID,
* making it easy to check for the existence of a font's "double" (shift the ID left by 1).
- *
+ *
* TODO: Since we now use an off-screen buffer for ALL modes, both text and graphics, we should
* revisit changes that were made to work around subpixel artifacts; those should no longer be an issue.
*/
@@ -3318,12 +3318,12 @@ Video.prototype.setDimensions = function()
this.cyScreenCell = font.cyCell;
}
}
-
+
/*
* In text modes, we have the option of setting all the *ScreenBuffer variables to null instead of
* allocating them, because updateChar(), as currently written, is capable of writing characters to
* either an off-screen or on-screen context.
- *
+ *
* this.imageScreenBuffer = this.canvasScreenBuffer = this.contextScreenBuffer = null;
*/
this.cxBuffer = this.cyBuffer = 0;
@@ -3336,10 +3336,10 @@ Video.prototype.setDimensions = function()
* CGA graphics modes have their "cells" (pixels) split evenly across two halves of the video buffer, with
* EVEN scan lines in the first half and ODD scan lines in the second half, so unlike text modes, we can't set a
* limit of what's visible on-screen to "columns * rows", so the screen limit is set to match the buffer limit.
- *
+ *
* In addition, updateScreen() requires an off-screen imageData buffer that matches the size of the entire screen,
* so that updateScreen() can set all pixels that have changed and then update the screen with a single drawImage().
- *
+ *
* An alternative approach, with a smaller footprint, would be to allocate an off-screen buffer large enough for a
* single scan line, and redraw one scan line at a time, but given how EVEN and ODD scan lines are spread across the
* entire buffer, it's not clear there would be enough unchanged scan lines on average to make that approach faster.
@@ -3366,7 +3366,7 @@ Video.prototype.setDimensions = function()
this.xScreenOffset = this.yScreenOffset = 0;
this.cxScreenOffset = this.cxScreen;
this.cyScreenOffset = this.cyScreen;
-
+
var cxBorder = this.cxScreen - (this.nCols * this.cxScreenCell);
var cyBorder = this.cyScreen - (this.nRows * this.cyScreenCell);
if (cxBorder > 0) {
@@ -3417,7 +3417,7 @@ Video.prototype.checkMode = function(fForce)
* The sizeBuffer we choose reflects the amount of physical address space that all 4 planes
* of EGA memory normally span, NOT the total amount of EGA memory. So for a 64Kb EGA card,
* we would set card.sizeBuffer to 16Kb (0x4000).
- *
+ *
* TODO: Need to take into account modes that "chain" planes together (eg, mode 0x0F, and
* presumably mode 0x10, on an EGA card with only 64Kb).
*/
@@ -3484,7 +3484,7 @@ Video.prototype.checkMode = function(fForce)
/*
* NOTE: For the CGA, we precondition any mode change on CGA.MODE.VIDEO_ENABLE being set, otherwise
* we'll get spoofed by the ROM BIOS scroll code, which waits for vertical retrace and then turns CGA.MODE.VIDEO_ENABLE
- * off, using a hard-coded mode value (0x25) that does NOT necessarily match the the CGA video mode currently in effect.
+ * off, using a hard-coded mode value (0x25) that does NOT necessarily match the the CGA video mode currently in effect.
*/
if (!(card.modeReg & Card.CGA.MODE.GRAPHIC_SEL)) {
nMode = ((card.modeReg & Card.CGA.MODE._80X25)? Video.MODES.CGA_80X25 : Video.MODES.CGA_40X25);
@@ -3502,7 +3502,7 @@ Video.prototype.checkMode = function(fForce)
* changes will be moot until the setAccess() call that follows. Basically, whenever both memory mapping AND access
* functions are changing, the memory will be in an inconsistent state until both setMode() and setAccess() are
* finished.
- *
+ *
* The setMode() call takes precedence; if we called setAccess() first, it might attempt to modify memory access
* functions based on the card's addrBuffer setting, and if that doesn't match what's currently mapped, assertions
* will be triggered (probably not fatal, but it would defeat the point of the assertions).
@@ -3516,10 +3516,10 @@ Video.prototype.checkMode = function(fForce)
/**
* setMode(nMode, fForce)
- *
+ *
* Set fForce to true to update the mode regardless of previous mode, or false to perform a normal update
* that bypasses updateScreen() but still calls initCellCache().
- *
+ *
* @this {Video}
* @param {number|null} nMode
* @param {boolean|undefined} [fForce] is set when checkMode() wants to force a mode update
@@ -3528,29 +3528,29 @@ Video.prototype.checkMode = function(fForce)
Video.prototype.setMode = function(nMode, fForce)
{
if (nMode != null && (nMode != this.nMode || fForce)) {
-
+
if (DEBUG) this.messageDebugger("setMode(0x" + str.toHexWord(nMode) + (fForce? ",force" : "") + ")");
-
+
this.cUpdates = 0; // count updateScreen() calls as a means of driving blink updates
this.nMode = nMode;
-
+
/*
* On an EGA, it's CRITICAL that a reset() invalidate cardActive, to ensure that the code below
* releases the previous frame buffer and installs a new one, even if there was no change in the
* frame buffer address or size, because otherwise the Memory blocks installed at the frame buffer
* address may still be using blocks of the EGA's previous memory buffer.
- *
+ *
* When the EGA is reinitialized, a new memory buffer (adwMemory) is allocated (see initEGA()), and
* this is where the mapping of that EGA memory buffer to the frame buffer occurs. Other cards
* (MDA or CGA) don't allocate/manage their own memory buffer, but even then, it's still a good idea
* to always force this operation (eg, in case a switch setting changed the active video card).
*/
var card = this.cardActive || (nMode == Video.MODES.MDA_80X25? this.cardMono : this.cardColor);
-
+
if (card != this.cardActive || card.addrBuffer != this.addrBuffer || card.sizeBuffer != this.sizeBuffer) {
-
+
this.removeCursor();
-
+
if (this.addrBuffer) {
if (!this.bus.removeMemory(this.addrBuffer, this.sizeBuffer)) {
/*
@@ -3560,13 +3560,13 @@ Video.prototype.setMode = function(nMode, fForce)
}
if (this.cardActive) this.cardActive.fActive = false;
}
-
+
this.cardActive = card;
card.fActive = true;
-
+
this.addrBuffer = card.addrBuffer;
this.sizeBuffer = card.sizeBuffer;
-
+
var controller = (card === this.cardEGA? card : null);
if (!this.bus.addMemory(card.addrBuffer, card.sizeBuffer, false, controller)) {
/*
@@ -3575,9 +3575,9 @@ Video.prototype.setMode = function(nMode, fForce)
return false;
}
}
-
+
this.setDimensions();
-
+
if (fForce !== false) {
this.updateScreen(true);
} else {
@@ -3589,7 +3589,7 @@ Video.prototype.setMode = function(nMode, fForce)
/**
* setPixel(imageData, x, y, rgb)
- *
+ *
* Worker function used by createFontColor() and updateScreen() (graphics modes only).
*
* @this {Video}
@@ -3609,7 +3609,7 @@ Video.prototype.setPixel = function(imageData, x, y, rgb)
/**
* initCellCache(fNew)
- *
+ *
* Invalidates the contents of our internal cell cache.
*
* @this {Video}
@@ -3631,16 +3631,16 @@ Video.prototype.initCellCache = function(fNew)
for (var iCell = 0; iCell < nCells; iCell++) {
this.aCellCache[iCell] = -1; // invalidate every cell of our internal cell cache (-1 is an invalid cell value)
}
- this.cBlinkVisible = -1; // also invalidate the visible blinking character count, to force updateScreen() to recount
+ this.cBlinkVisible = -1; // also invalidate the visible blinking character count, to force updateScreen() to recount
};
/**
* doBlink()
- *
+ *
* This function is obsolete, now that the checkBlink() function is called on every updateScreen()
* and checkCursor() call. updateScreen() is driven by the CPU timer, so piggy-backing on that to
- * drive blink updates seems preferable to having another active timer in the system.
- *
+ * drive blink updates seems preferable to having another active timer in the system.
+ *
* @this {Video}
* @param {boolean} [fStart]
*
@@ -3686,7 +3686,7 @@ Video.prototype.initCellCache = function(fNew)
Video.prototype.updateChar = function(col, row, data, context)
{
/*
- * The caller MUST promise this.nFont is defined, and that the font in this.aFonts[this.nFont] has been loaded.
+ * The caller MUST promise this.nFont is defined, and that the font in this.aFonts[this.nFont] has been loaded.
*/
var bChar = data & 0xff;
var bAttr = data >> 8;
@@ -3748,12 +3748,12 @@ Video.prototype.updateChar = function(col, row, data, context)
* this.contextScreen.moveTo(xDst, yDst + this.yCursor);
* this.contextScreen.lineTo(xDst + this.cxScreenCell, yDst + this.yCursor);
* this.contextScreen.stroke();
- *
+ *
* Also, note that we're scaling the yCursor and cyCursor values here, instead of in checkCursor(), because
* this is where we have all the required information: in the first case (off-screen buffer), the scaling must
* be based on the font cell size (cxCell, cyCell), whereas in the second case (on-screen buffer), the scaling
* must be based on the screen cell size (cxScreenCell,cyScreenCell).
- *
+ *
* yCursor and cyCursor are actual hardware values, both relative to another hardware value: cyCursorCell.
*/
var yCursor = this.yCursor;
@@ -3778,7 +3778,7 @@ Video.prototype.updateChar = function(col, row, data, context)
/**
* updateScreen(fForce)
- *
+ *
* Propagates the video buffer to the cell cache and updates the window with any changes. Forced updates
* are generally internal updates triggered by an I/O operation or other state change, while non-forced updates
* are the periodic updates coming from the CPU.
@@ -3796,7 +3796,7 @@ Video.prototype.updateScreen = function(fForce)
* The Computer component maintains an fPowered setting on our behalf, so we use it.
*/
if (!this.fPowered) return;
-
+
/*
* If the card's video signal is disabled (eg, during a mode change), then skip the update,
* unless fForce is set.
@@ -3810,9 +3810,9 @@ Video.prototype.updateScreen = function(fForce)
if (this.cardActive.modeReg & Card.CGA.MODE.VIDEO_ENABLE) fEnabled = true;
}
}
-
+
if (!fEnabled && !fForce) return;
-
+
if (fForce) {
this.initCellCache(true);
}
@@ -3827,7 +3827,7 @@ Video.prototype.updateScreen = function(fForce)
/*
* If cBlinks is "enabled" (ie, >= 0), then advance it once every 16 updateScreen() calls
* (assuming an updateScreen() frequency of 60 per second; see CPU.VIDEO_UPDATES_PER_SECOND).
- *
+ *
* We assume that the CPU is calling us whenever fForce is undefined.
*/
var fBlinkUpdate = false;
@@ -3843,19 +3843,19 @@ Video.prototype.updateScreen = function(fForce)
* Calculate the VISIBLE start of screen memory (addrScreen), not merely the PHYSICAL start,
* as well as the extent of it (cbScreen) and use those values for all addressing operations
* to follow. FYI, in these calculations, offScreen does not refer to "off-screen" memory,
- * but rather the "offset" of the start of visible screen memory.
+ * but rather the "offset" of the start of visible screen memory.
*/
var addrScreen = this.cardActive.addrBuffer;
var addrScreenLimit = addrScreen + this.cardActive.sizeBuffer;
var offScreen = (this.cardActive.aCRTCRegs[Card.CRTC.START_ADDR_HI] << 8) + this.cardActive.aCRTCRegs[Card.CRTC.START_ADDR_LO];
-
+
/*
* Any screen (aka "page") offset must be doubled for text modes, due to the attribute bytes.
*
* TODO: Come up with a more robust method of deciding when any screen offset should be doubled.
*/
if (this.nFont) offScreen <<= 1;
-
+
addrScreen += offScreen;
var cbScreen = this.cbScreen;
if (addrScreen + cbScreen > addrScreenLimit) {
@@ -3876,7 +3876,7 @@ Video.prototype.updateScreen = function(fForce)
* AND there are no visible blinking characters (as of the last updateScreen) AND there is
* no visible cursor, then we're done; simply return. Otherwise, if there's only a blinking
* cursor, then update JUST that one cell.
- *
+ *
* When dealing with blinking characters, note that we need to run through the entire buffer
* ONLY if the low bits of the blink count just transitioned to 2 or 0; hence, we could return if
* the blink count was ODD. But we'd still have to worry about the cursor, so it's simpler to blow
@@ -3893,7 +3893,7 @@ Video.prototype.updateScreen = function(fForce)
}
// else if (this.cBlinks & 0x1) return;
}
-
+
if (this.nFont) {
/*
* This is the text-mode update case. We're required to FIRST verify that the current font
@@ -3914,7 +3914,7 @@ Video.prototype.updateScreen = function(fForce)
/**
* updateScreenText(addrScreen, addrScreenLimit, iCell, nCells)
- *
+ *
* @param addrScreen
* @param addrScreenLimit
* @param iCell
@@ -3923,14 +3923,14 @@ Video.prototype.updateScreen = function(fForce)
Video.prototype.updateScreenText = function(addrScreen, addrScreenLimit, iCell, nCells)
{
var addr, data, dataCache, cUpdated = 0;
-
+
/*
* If MDA.MODE.BLINK_ENABLE is set and a cell's blink bit is set, then if (cBlinks & 0x2) != 0,
* we want the foreground element of the cell to be drawn; otherwise we don't. So every 16-bit
* data word we pull from the video buffer will be supplemented with our own special attribute bit
* (ATTRS.DRAW_FGND = 0x100) accordingly; and to simplify the drawing code, we will also mask the
* blink bit from the cell's attribute bits.
- *
+ *
* If MDA.MODE.BLINK_ENABLE is clear, then we always set ATTRS.DRAW_FGND and never mask the blink
* bit in a cell's attributes bits, since it's actually an intensity bit in that case.
*/
@@ -3973,7 +3973,7 @@ Video.prototype.updateScreenText = function(addrScreen, addrScreenLimit, iCell,
/**
* updateScreenGraphicsCGA(addrScreen, addrScreenLimit)
- *
+ *
* @param addrScreen
* @param addrScreenLimit
*/
@@ -3990,7 +3990,7 @@ Video.prototype.updateScreenGraphicsCGA = function(addrScreen, addrScreenLimit)
var wPixelMask = (nPixelsPerCell == 16? 0x10000 : 0x30000);
var nPixelShift = (nPixelsPerCell == 16? 1 : 2);
var aPixelColors = this.getCardColors(nPixelShift);
-
+
var x = 0, y = 0;
var xDirty = this.nCols, xMaxDirty = 0, yDirty = this.nRows, yMaxDirty = 0;
while (addr < addrScreenLimit) {
@@ -4068,7 +4068,7 @@ Video.prototype.updateScreenGraphicsEGA = function(addrScreen, addrScreenLimit)
var iCell = 0, nPixelsPerCell = 8;
var aPixelColors = this.getCardColors();
var adwMemory = this.cardActive.adwMemory;
-
+
var x = 0, y = 0;
var xDirty = this.nCols, xMaxDirty = 0, yDirty = this.nRows, yMaxDirty = 0;
while (addr < addrScreenLimit) {
@@ -4116,7 +4116,7 @@ Video.prototype.updateScreenGraphicsEGA = function(addrScreen, addrScreenLimit)
}
}
/*
- * For a fascinating discussion of the best way to update the screen canvas at this point, see updateScreenGraphicsCGA().
+ * For a fascinating discussion of the best way to update the screen canvas at this point, see updateScreenGraphicsCGA().
*/
if (xDirty < this.nCols) {
var cxDirty = xMaxDirty - xDirty;
@@ -4297,7 +4297,7 @@ Video.prototype.inStatus0 = function(port, addrFrom)
var iBit = 3 - ((this.cardEGA.miscReg & Card.MISC.CLK_SELECT) >> 2); // this is the desired SW # (0-3)
var bSWBit = (this.bEGASW & (1 << iBit)) << (Card.STATUS0.SWSENSE_SHIFT - iBit);
var b = ((this.cardEGA.status0 & ~Card.STATUS0.SWSENSE) | bSWBit);
- /*
+ /*
* TODO: Figure out where Card.STATUS0.FEAT bits should come from....
*/
this.cardEGA.status0 = b;
@@ -4529,7 +4529,7 @@ Video.prototype.outGRCData = function(port, bOut, addrFrom)
break;
case Card.GRC.MISC.INDX:
this.checkMode(false);
- break;
+ break;
case Card.GRC.COLRDC.INDX:
this.cardEGA.nColorDontCare = Video.aEGAByteToDW[(bOut & 0xf) ^ 0xf] & 0x80808080;
break;
@@ -4733,7 +4733,7 @@ Video.prototype.outCRTCData = function(card, bOut, addrFrom)
* During mode changes on the EGA, all the CRTC regs are typically programmed in sequence,
* and if that's all that's happening with Card.CRTC.MAX_SCAN_LINE, then we don't want to treat
* it special; let the mode change be detected normally (eg, when the GRC regs are written later).
- *
+ *
* On the other hand, if this was an out-of-sequence write to Card.CRTC.MAX_SCAN_LINE, then
* yes, we want to force setMode() to call setDimensions(), which is key to setting the proper
* number of screen rows.
@@ -4819,26 +4819,26 @@ Video.prototype.inCardStatus = function(card, addrFrom)
if (card === this.cardEGA) {
/*
* STATUS1 diagnostic bits 5 and 4 are set according to the Card.ATC.PLANES.MUX bits:
- *
+ *
* MUX Bit 5 Bit 4
* --- ---- ----
* 00: Red Blue
* 01: SecBlue Green
* 10: SecRed SecGreen
* 11: unused unused
- *
+ *
* Depending on where we are in the horizontal and vertical periods (which can be inferred from the
* same elapsed cycle count that we used to simulate the retrace bits above), we could extract 4 bits
* from a corresponding region of the video buffer, "and" them with Card.ATC.PLANES.MASK, use
* that to index into the palette registers (cardEGA.aATCRegs), and use the resulting palette register
* bits to set these diagnostics bits. However, that's all rather tedious, and the process of extracting
* 4 appropriate bits from the video buffer varies depending on the video mode.
- *
+ *
* Why are we even considering this? Because the EGA BIOS diagnostic code draws a bright reverse-video
* line of text blocks across the top of the screen, writes 0x3F to palette register 0x0f, and then
* monitors the STATUS1 diagnostic bits, waiting for those palette bits to show up. It turns out, however,
* that we can easily fool the EGA BIOS by simply toggling the diagnostic bits. So we take the easy way out.
- *
+ *
* TODO: Faithful emulation of these bits is certainly doable, so consider doing it at some point.
*/
b |= ((card.statusReg & Card.STATUS1.DIAGNOSTIC) ^ Card.STATUS1.DIAGNOSTIC);
@@ -4852,7 +4852,7 @@ Video.prototype.inCardStatus = function(card, addrFrom)
/*
* On the MDA/CGA, to satisfy ROM BIOS testing ("TEST.10"), it's sufficient to do a simple toggle of
* bits 0 and 3 on every read.
- *
+ *
* Also, according to http://www.seasip.info/VintagePC/mda.html, on an MDA, bits 7-4 are always ON and bits 2-1
* are always OFF, hence the "OR" of 0xf0.
*/
@@ -4889,7 +4889,7 @@ Video.prototype.dumpVideo = function(sParm)
* messageDebugger(sMessage)
*
* This is a combination of the Debugger's messageEnabled(MESSAGE_VIDEO) and message() functions, for convenience.
- *
+ *
* @this {Video}
* @param {boolean} [fForce] to display the message regardless of the MESSAGE_VIDEO setting, provided the Debugger is loaded
* @param {string} sMessage is any caller-defined message string
@@ -4907,7 +4907,7 @@ Video.prototype.messageDebugger = function(sMessage, fForce)
* messagePort(port, bOut, addrFrom, name, bIn)
*
* This is an internal version of the Debugger's messagePort() function, for convenience.
- *
+ *
* @this {Video}
* @param {number} port
* @param {number|null} bOut if an output operation
@@ -4924,7 +4924,7 @@ Video.prototype.messagePort = function(port, bOut, addrFrom, name, bIn)
/*
* Port input/output notification tables
- *
+ *
* TODO: I added some "duplicate" entries for the MDA because, according to docs I'd read, MDA ports are
* decoded at multiple addresses. However, if this is important, then it should be verified and implemented
* consistently (eg, for CGA as well). For now, I'm decoding only the standard port addresses.
@@ -4975,7 +4975,7 @@ Video.aEGAPortInput = {
Video.aEGAPortOutput = {
0x3BA: Video.prototype.outFeat,
0x3C0: Video.prototype.outATC,
- 0x3C1: Video.prototype.outATC, // the EGA BIOS writes to this port (see C000:0416), implying that 0x3C0 and 0x3C1 both decode the same register
+ 0x3C1: Video.prototype.outATC, // the EGA BIOS writes to this port (see C000:0416), implying that 0x3C0 and 0x3C1 both decode the same register
0x3C2: Video.prototype.outMisc, // FYI, since this overlaps with STATUS0.PORT, there's currently no way for the Debugger to read the Misc register
0x3C4: Video.prototype.outSEQIndx,
0x3C5: Video.prototype.outSEQData,
@@ -5002,17 +5002,17 @@ Video.init = function()
for (var iVideo = 0; iVideo < aeVideo.length; iVideo++) {
var eVideo = aeVideo[iVideo];
var parmsVideo = Component.getComponentParms(eVideo);
-
+
var eCanvas = window.document.createElement("canvas");
if (eCanvas === undefined) {
eVideo.innerHTML = "
Missing <canvas> support; try a new web browser.";
return;
}
-
+
eCanvas.setAttribute("class", PCJSCLASS + "-canvas");
eCanvas.setAttribute("width", parmsVideo['screenWidth']);
eCanvas.setAttribute("height", parmsVideo['screenHeight']);
-
+
/*
* As noted in keyboard.js, the keyboard on an iOS device pops up with the SHIFT key depressed,
* which is not the initial keyboard state that the Keyboard component expects. I originally tried
@@ -5029,12 +5029,12 @@ Video.init = function()
* HACK: A canvas style of "auto" provides for excellent responsive canvas scaling in EVERY browser
* except IE9/IE10, so I recalculate the appropriate CSS height every time the parent DIV is resized;
* IE11 works without this hack, so we take advantage of the fact that IE11 doesn't report itself as "MSIE".
- *
+ *
* Also, make sure the parent DIV also has a style of "auto"; normally, it has no explicit height, but
* sometimes we'll preset it to a height (eg, "350px") for design purposes.
*/
eCanvas.style.height = eVideo.style.height = "auto";
-
+
if (web.getUserAgent().indexOf("MSIE") >= 0) {
eCanvas.style.height = (((eVideo.clientWidth * parmsVideo['screenHeight']) / parmsVideo['screenWidth']) | 0) + "px";
eVideo.onresize = function(eParent, eChild, cx, cy) {
@@ -5044,23 +5044,23 @@ Video.init = function()
}(eVideo, eCanvas, parmsVideo['screenWidth'], parmsVideo['screenHeight']); // jshint ignore:line
}
eVideo.appendChild(eCanvas);
-
+
/*
* HACK: Android-based browsers (eg, the Kindle Fire browser, the Chrome browser) don't honor the
* "contenteditable" attribute; that is, when the canvas receives focus, they don't activate the on-screen
* keyboard. So my fallback is to create a transparent textarea on top of the canvas.
- *
+ *
* We depend upon the containing DIV (and/or its parent DIV) to have a style of "position:relative" (which
* all elements of class "pcjs-container" should have) so that we can position the textarea using absolute
* coordinates. Also, we don't want the textarea to be visible, but we must use "opacity:0" instead of
* "visibility:hidden", because the latter prevents the element from receiving events.
- *
+ *
* 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.
- *
+ *
* See this Chromium issue for more information: https://code.google.com/p/chromium/issues/detail?id=118639
*
var eTextArea = window.document.createElement("textarea");
@@ -5069,13 +5069,13 @@ Video.init = function()
*
* The following test failed as well. You can clearly see the overlaid semi-transparent password-enabled
* input field, but none of the input characters are passed along, with the exception of the "Go" (Enter) key.
- *
+ *
var eInput = window.document.createElement("input");
eInput.setAttribute("type", "password");
eInput.setAttribute("style", "position:absolute; left:0; top:0; width:100%; height:100%; opacity:0.5");
eVideo.appendChild(eInput);
*/
-
+
/*
* Now we can create the Video object, record it, and wire it up to the associated document elements.
*/
@@ -5084,7 +5084,7 @@ Video.init = function()
/*
* Bind any video-specific controls (eg, the Refresh button). There are no essential controls, however;
- * even the "Refresh" button is just a diagnostic tool, to ensure that the screen contents are up-to-date.
+ * even the "Refresh" button is just a diagnostic tool, to ensure that the screen contents are up-to-date.
*/
Component.bindComponentControls(video, eVideo, PCJSCLASS);
}
diff --git a/my_modules/pcjs-client/lib/x86cpu.js b/my_modules/pcjs-client/lib/x86cpu.js
index d5f710425..4facf0e0e 100644
--- a/my_modules/pcjs-client/lib/x86cpu.js
+++ b/my_modules/pcjs-client/lib/x86cpu.js
@@ -34,19 +34,19 @@
"use strict";
if (typeof module !== 'undefined') {
- var str = require("../../shared/lib/strlib");
- var web = require("../../shared/lib/weblib");
- var Component = require("../../shared/lib/component");
- var Bus = require("./bus");
- var State = require("./state");
- var CPU = require("./cpu");
- var X86 = require("./x86");
- var X86Seg = require("./x86seg");
- var X86Grps = require("./x86grps");
- var X86Help = require("./x86help");
- var X86Mods = require("./x86mods");
- var X86OpXX = require("./x86opxx");
- var X86Op0F = require("./x86op0f");
+ var str = require("../../shared/lib/strlib");
+ var web = require("../../shared/lib/weblib");
+ var Component = require("../../shared/lib/component");
+ var Bus = require("./bus");
+ var State = require("./state");
+ var CPU = require("./cpu");
+ var X86 = require("./x86");
+ var X86Seg = require("./x86seg");
+ var X86Grps = require("./x86grps");
+ var X86Help = require("./x86help");
+ var X86Mods = require("./x86mods");
+ var X86OpXX = require("./x86opxx");
+ var X86Op0F = require("./x86op0f");
}
/**
diff --git a/my_modules/pcjs-client/lib/x86grps.js b/my_modules/pcjs-client/lib/x86grps.js
index 68e40f246..fd122ca27 100644
--- a/my_modules/pcjs-client/lib/x86grps.js
+++ b/my_modules/pcjs-client/lib/x86grps.js
@@ -34,9 +34,9 @@
"use strict";
if (typeof module !== 'undefined') {
- var X86 = require("./x86");
- var X86Help = require("./x86help");
- var Debugger = require("./debugger");
+ var X86 = require("./x86");
+ var X86Help = require("./x86help");
+ var Debugger = require("./debugger");
}
var X86Grps = {
@@ -66,7 +66,7 @@ var X86Grps = {
/**
* NOTE: Notice that some of the simpler math functions could get away with updating resultSize before
* the calculation, but here the calculation depends on the incoming carry value.
- *
+ *
* @this {X86CPU}
* @param {number} dst
* @param {number} src
@@ -82,7 +82,7 @@ var X86Grps = {
/**
* NOTE: Notice that some of the simpler math functions could get away with updating resultSize before
* the calculation, but here the calculation depends on the incoming carry value.
- *
+ *
* @this {X86CPU}
* @param {number} dst
* @param {number} src
@@ -169,7 +169,7 @@ var X86Grps = {
/**
* NOTE: Notice that some of the simpler math functions could get away with updating resultSize before
* the calculation, but here the calculation depends on the incoming carry value.
- *
+ *
* @this {X86CPU}
* @param {number} dst
* @param {number} src
@@ -185,7 +185,7 @@ var X86Grps = {
/**
* NOTE: Notice that some of the simpler math functions could get away with updating resultSize before
* the calculation, but here the calculation depends on the incoming carry value.
- *
+ *
* @this {X86CPU}
* @param {number} dst
* @param {number} src
@@ -296,7 +296,7 @@ var X86Grps = {
* operand size of the last operation. And since only 2 of the 6 arithmetic flags need to change, that tips the scales
* in favor of leaving resultSize alone. However, the previous code that worked so hard to update resultSize is still
* here, commented out; it works, but it's less efficient.
- *
+ *
* @this {X86CPU}
* @param {number} result (untruncated, so that we can inspect it for CARRY and OVERFLOW)
* @param {number} size
@@ -497,7 +497,7 @@ var X86Grps = {
* and/or code that depends on them, I'll continue setting PS_AF and PS_OF "normally".
*
* See also: AND, OR, TEST, and XOR (those instructions leave AUXCARRY "undefined" as well).
- *
+ *
* @this {X86CPU}
* @param {number} dst
* @param {number} src (1 or CL, or an immediate byte for 80186/80188 and up)
@@ -522,7 +522,7 @@ var X86Grps = {
* AUXCARRY (PS_AF), AUXCARRY isn't properly set on a real 8086/8088; its value is
* documented as "undefined." Similarly, OVERFLOW (PS_OF) is documented as "undefined"
* for shifts > 1. See opGrpSHLb() for more details.
- *
+ *
* @this {X86CPU}
* @param {number} dst
* @param {number} src (1 or CL, or an immediate byte for 80186/80188 and up)
@@ -547,7 +547,7 @@ var X86Grps = {
* AUXCARRY (PS_AF), AUXCARRY isn't properly set on a real 8086/8088; its value is
* documented as "undefined." Similarly, OVERFLOW (PS_OF) is documented as "undefined"
* for shifts > 1. See opGrpSHLb() for more details.
- *
+ *
* @this {X86CPU}
* @param {number} dst
* @param {number} src (1 or CL, or an immediate byte for 80186/80188 and up)
@@ -572,7 +572,7 @@ var X86Grps = {
* AUXCARRY (PS_AF), AUXCARRY isn't properly set on a real 8086/8088; its value is
* documented as "undefined." Similarly, OVERFLOW (PS_OF) is documented as "undefined"
* for shifts > 1. See opGrpSHLb() for more details.
- *
+ *
* @this {X86CPU}
* @param {number} dst
* @param {number} src (1 or CL, or an immediate byte for 80186/80188 and up)
@@ -597,7 +597,7 @@ var X86Grps = {
* AUXCARRY (PS_AF), AUXCARRY isn't properly set on a real 8086/8088; its value is
* documented as "undefined." Similarly, OVERFLOW (PS_OF) is documented as "undefined"
* for shifts > 1. See opGrpSHLb() for more details.
- *
+ *
* @this {X86CPU}
* @param {number} dst
* @param {number} src (1 or CL, or an immediate byte for 80186/80188 and up)
@@ -623,7 +623,7 @@ var X86Grps = {
* AUXCARRY (PS_AF), AUXCARRY isn't properly set on a real 8086/8088; its value is
* documented as "undefined." Similarly, OVERFLOW (PS_OF) is documented as "undefined"
* for shifts > 1. See opGrpSHLb() for more details.
- *
+ *
* @this {X86CPU}
* @param {number} dst
* @param {number} src (1 or CL, or an immediate byte for 80186/80188 and up)
@@ -739,7 +739,7 @@ var X86Grps = {
}
/*
* Multiply/divide instructions specify only a single operand, which the decoders pass to us
- * via the dst parameter, so we set src to the other implied operand (either AX or DX:AX).
+ * via the dst parameter, so we set src to the other implied operand (either AX or DX:AX).
* However, src is technically an output, and dst is merely an input (which is why we must return
* dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src.
*/
@@ -783,7 +783,7 @@ var X86Grps = {
}
/*
* Multiply/divide instructions specify only a single operand, which the decoders pass to us
- * via the dst parameter, so we set src to the other implied operand (either AX or DX:AX).
+ * via the dst parameter, so we set src to the other implied operand (either AX or DX:AX).
* However, src is technically an output, and dst is merely an input (which is why we must return
* dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src.
*/
@@ -822,7 +822,7 @@ var X86Grps = {
this.resultSize = X86.RESULT.SIZE_BYTE;
/*
* Multiply/divide instructions specify only a single operand, which the decoders pass to us
- * via the dst parameter, so we set src to the other implied operand (either AX or DX:AX).
+ * via the dst parameter, so we set src to the other implied operand (either AX or DX:AX).
* However, src is technically an output, and dst is merely an input (which is why we must return
* dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src.
*/
@@ -836,7 +836,7 @@ var X86Grps = {
* @param {number} dst
* @param {number} src (null)
* @return {number} (we return dst unchanged, since it's actually AX that's modified)
- *
+ *
* TODO: Implement the following difference, from "AP-186: Introduction to the 80186 Microprocessor, March 1983":
*
* "The 8086 will cause a divide error whenever the absolute value of the quotient is greater then 7FFFH
@@ -869,7 +869,7 @@ var X86Grps = {
this.resultSize = X86.RESULT.SIZE_BYTE;
/*
* Multiply/divide instructions specify only a single operand, which the decoders pass to us
- * via the dst parameter, so we set src to the other implied operand (either AX or DX:AX).
+ * via the dst parameter, so we set src to the other implied operand (either AX or DX:AX).
* However, src is technically an output, and dst is merely an input (which is why we must return
* dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src.
*/
@@ -900,7 +900,7 @@ var X86Grps = {
}
/*
* Multiply/divide instructions specify only a single operand, which the decoders pass to us
- * via the dst parameter, so we set src to the other implied operand (either AX or DX:AX).
+ * via the dst parameter, so we set src to the other implied operand (either AX or DX:AX).
* However, src is technically an output, and dst is merely an input (which is why we must return
* dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src.
*/
@@ -914,15 +914,15 @@ var X86Grps = {
* lower 16 bits (carry clear) and when the upper 16 bits contain significant bits (carry set). The latter
* will occur whenever a positive result is > 32767 (0x00007fff) and whenever a negative result is < -32768
* (0xffff8000).
- *
+ *
* Example 1: 256 * 64 = 16384 (0x00004000): carry is clear
* Example 2: 256 * 128 = 32768 (0x00008000): carry is set (the sign bit no longer fits in the lower 16 bits)
* Example 3: 256 * -128 (0xff80) = -32768 (0xffff8000): carry is clear (the sign bit *still* fits in the lower 16 bits)
* Example 4: 256 * -256 (0xff00) = -65536 (0xffff0000): carry is set (the sign bit no longer fits in the lower 16 bits)
- *
+ *
* An earlier version of this function assumed it simply needed to check bit 15 of the result to determine carry,
* which was completely broken.
- *
+ *
* @this {X86CPU}
* @param {number} dst
* @param {number} src (null)
@@ -945,7 +945,7 @@ var X86Grps = {
}
/*
* Multiply/divide instructions specify only a single operand, which the decoders pass to us
- * via the dst parameter, so we set src to the other implied operand (either AX or DX:AX).
+ * via the dst parameter, so we set src to the other implied operand (either AX or DX:AX).
* However, src is technically an output, and dst is merely an input (which is why we must return
* dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src.
*/
@@ -970,7 +970,7 @@ var X86Grps = {
}
/*
* Detect small divisor (quotient overflow)
- *
+ *
* WARNING: We CANNOT simply do "src = (this.regDX << 16) | this.regAX", because if bit 15 of DX
* is set, JavaScript will create a negative 32-bit number. So we instead use non-bit-wise operators
* to force JavaScript to create a floating-point value that won't suffer from 32-bit-math side-effects.
@@ -990,7 +990,7 @@ var X86Grps = {
this.resultSize = X86.RESULT.SIZE_WORD;
/*
* Multiply/divide instructions specify only a single operand, which the decoders pass to us
- * via the dst parameter, so we set src to the other implied operand (either AX or DX:AX).
+ * via the dst parameter, so we set src to the other implied operand (either AX or DX:AX).
* However, src is technically an output, and dst is merely an input (which is why we must return
* dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src.
*/
@@ -1040,7 +1040,7 @@ var X86Grps = {
this.resultSize = X86.RESULT.SIZE_WORD;
/*
* Multiply/divide instructions specify only a single operand, which the decoders pass to us
- * via the dst parameter, so we set src to the other implied operand (either AX or DX:AX).
+ * via the dst parameter, so we set src to the other implied operand (either AX or DX:AX).
* However, src is technically an output, and dst is merely an input (which is why we must return
* dst unchanged). So, to make traceLog() more consistent, we reverse the order of dst and src.
*/
@@ -1258,7 +1258,7 @@ var X86Grps = {
/*
* A word (or two) on instruction groups (eg, GRP1, GRP2), which are groups of instructions that
* use a mod/reg/rm byte, where the reg field of that byte selects a function rather than a register.
- *
+ *
* I start with the groupings used by Intel's "Pentium Processor User's Manual (Volume 3: Architecture
* and Programming Manual)", but I deviate slightly, mostly by subdividing their groups with the use
* of suffixes:
@@ -1275,7 +1275,7 @@ var X86Grps = {
* 0x0F,0x01 Grp7 GRP7 (SGDT, SIDT, LGDT, LIDT, SMSW, LMSW, INVLPG) Group G
* 0x0F,0xBA Grp8 GRP8 (BT, BTS, BTR, BTC) Group H
* 0x0F,0xC7 Grp9 GRP9 (CMPXCH) (N/A, 80386 and up?)
- *
+ *
* My only serious deviation is Grp5, which I refer to as GRP4w, because it contains word forms of
* the INC and DEC instructions found in GRP4b. Granted, GRP4w also contains versions of the CALL,
* JMP and PUSH instructions, which are not in GRP4b, but there's nothing in GRP4b that conflicts with
diff --git a/my_modules/pcjs-client/lib/x86help.js b/my_modules/pcjs-client/lib/x86help.js
index 06793df3f..633849e69 100644
--- a/my_modules/pcjs-client/lib/x86help.js
+++ b/my_modules/pcjs-client/lib/x86help.js
@@ -34,8 +34,8 @@
"use strict";
if (typeof module !== 'undefined') {
- var X86 = require("./x86");
- var Debugger = require("./debugger");
+ var X86 = require("./x86");
+ var Debugger = require("./debugger");
}
var X86Help = {
@@ -127,14 +127,14 @@ var X86Help = {
* @param {number} dst
* @param {number} src
* @return {number}
- *
+ *
* 80286_and_80287_Programmers_Reference_Manual_1987.pdf, p.B-44 (p.254) notes that:
- *
+ *
* "The low 16 bits of the product of a 16-bit signed multiply are the same as those of an
* unsigned multiply. The three operand IMUL instruction can be used for unsigned operands as well."
- *
+ *
* However, we still sign-extend the operands before multiplying, making it easier to range-check the result.
- *
+ *
* (80186/80188 and up)
*/
opHelpIMUL16: function(dst, src) {
@@ -237,8 +237,8 @@ var X86Help = {
if (wIndex < wLower || wIndex > wUpper) {
/*
* The INT 0x05 handler must be called with CS:IP pointing to the BOUND instruction.
- *
- * TODO: Determine the cycle impact when a BOUND exception is triggered, over and above nOpCyclesBound.
+ *
+ * TODO: Determine the cycle impact when a BOUND exception is triggered, over and above nOpCyclesBound.
*/
this.setIP(this.opEA - this.segCS.base);
X86Help.opHelpINT.call(this, X86.EXCEPTION.BOUND_ERR, null, 0);
@@ -273,7 +273,7 @@ var X86Help = {
/*
* 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.
- *
+ *
* TODO: This instruction's 80286 documentation does not discuss conforming code segments; determine
* if we need a special check for them.
*/
@@ -297,7 +297,7 @@ var X86Help = {
/*
* 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.
- *
+ *
* TODO: LSL is explicitly documented as ALSO requiring a non-null selector, so we check X86.SEL.MASK;
* are there any other instructions that were, um, less explicit but also require a non-null selector?
*/
diff --git a/my_modules/pcjs-client/lib/x86mods.js b/my_modules/pcjs-client/lib/x86mods.js
index 5c67b66c1..b980b0f8f 100644
--- a/my_modules/pcjs-client/lib/x86mods.js
+++ b/my_modules/pcjs-client/lib/x86mods.js
@@ -34,7 +34,7 @@
"use strict";
if (typeof module !== 'undefined') {
- var X86 = require("./x86");
+ var X86 = require("./x86");
}
var X86Mods = {
@@ -15350,7 +15350,7 @@ var X86Mods = {
* mod=11 (reg:dst) reg=110 (afnGrp[6]) r/m=100 (SP)
*/
opModGrpWordF4: function(afnGrp, fnSrc) {
- this.opFlags |= X86.OPFLAG.PUSHSP; // we limit this hack to the only ModRM function that calls opGrpPUSHw() with SP
+ this.opFlags |= X86.OPFLAG.PUSHSP; // we limit this hack to the only ModRM function that calls opGrpPUSHw() with SP
this.regSP = afnGrp[6].call(this, this.regSP, fnSrc.call(this));
},
/**
diff --git a/my_modules/pcjs-client/lib/x86op0f.js b/my_modules/pcjs-client/lib/x86op0f.js
index 86160f68f..18516f613 100644
--- a/my_modules/pcjs-client/lib/x86op0f.js
+++ b/my_modules/pcjs-client/lib/x86op0f.js
@@ -34,10 +34,10 @@
"use strict";
if (typeof module !== 'undefined') {
- var X86 = require("./x86");
- var X86Grps = require("./x86grps");
- var X86Help = require("./x86help");
- var X86Mods = require("./x86mods");
+ var X86 = require("./x86");
+ var X86Grps = require("./x86grps");
+ var X86Help = require("./x86help");
+ var X86Mods = require("./x86mods");
}
var X86Op0F = {
@@ -149,10 +149,10 @@ var X86Op0F = {
/*
* For VERR, if the code segment is readable and conforming, the descriptor privilege level
* (DPL) can be any value.
- *
+ *
* 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.
*/
@@ -187,7 +187,7 @@ 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.
*/
@@ -261,8 +261,8 @@ var X86Op0F = {
* opLIDT(dst, src)
*
* The 80286 LIDT instruction expects a 40-bit operand: a 16-bit limit, followed by a 24-bit address;
- * the ModRM decoder has already supplied the first word of the operand (in dst), which corresponds to the
- * limit, so we must fetch the remaining 24 bits ourselves.
+ * the ModRM decoder has already supplied the first word of the operand (in dst), which corresponds to the
+ * limit, so we must fetch the remaining 24 bits ourselves.
*
* @this {X86CPU}
* @param {number} dst
@@ -273,7 +273,7 @@ var X86Op0F = {
if (this.regEA < 0) {
X86Help.opInvalid.call(this);
} else {
- this.addrIDT = this.getWord(this.regEA + 2) | (this.getByte(this.regEA + 4) << 16);
+ 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;
this.nStepCycles -= 12;
@@ -389,7 +389,7 @@ X86Op0F.aOps0F = [
* the instructions in GRP6 and GRP7 only read their dst operand (eg, LLDT), which means the ModRM helper function
* must insure that setEAWord() is disabled, while others only write their dst operand (eg, SLDT), which means that
* getEAWord() should be disabled *prior* to calling the ModRM helper function. This latter case requires that
- * we decode the reg field of the ModRM byte before dispatching.
+ * we decode the reg field of the ModRM byte before dispatching.
*/
X86Op0F.aOpGRP6Prot = [
X86Op0F.opSLDT, X86Op0F.opSTR, X86Op0F.opLLDT, X86Op0F.opLTR, // 0x0F,0x00(reg=0x0-0x3)
diff --git a/my_modules/pcjs-client/lib/x86opxx.js b/my_modules/pcjs-client/lib/x86opxx.js
index fff2720a5..4737f7277 100644
--- a/my_modules/pcjs-client/lib/x86opxx.js
+++ b/my_modules/pcjs-client/lib/x86opxx.js
@@ -34,12 +34,12 @@
"use strict";
if (typeof module !== 'undefined') {
- var Component = require("../../shared/lib/component");
- var X86 = require("./x86");
- var X86Grps = require("./x86grps");
- var X86Help = require("./x86help");
- var X86Mods = require("./x86mods");
- var X86Op0F = require("./x86op0f");
+ var Component = require("../../shared/lib/component");
+ var X86 = require("./x86");
+ var X86Grps = require("./x86grps");
+ var X86Help = require("./x86help");
+ var X86Mods = require("./x86mods");
+ var X86Op0F = require("./x86op0f");
}
var X86OpXX = {
@@ -1194,14 +1194,14 @@ var X86OpXX = {
opINSb: function() {
var nReps = 1;
var nDelta = 0;
-
+
/*
* NOTE: 5 + 4n is the cycle time for the 80286; the 80186/80188 has different values: 14 cycles for
* an unrepeated INS, and 8 + 8n for a repeated INS. However, accurate cycle times for the 80186/80188 is
* low priority.
*/
var nCycles = 5;
-
+
/*
* The (normal) REP prefix, if used, is REPNZ (0xf2), but either one works....
*/
@@ -1210,7 +1210,7 @@ var X86OpXX = {
nDelta = 1;
if (this.opPrefixes & X86.OPFLAG.REPEAT) nCycles = 4;
}
-
+
if (nReps--) {
var b = this.bus.checkPortInputNotify(this.regDX, this.regEIP - nDelta - 1);
this.setSOByte(this.segES, this.regDI, b);
@@ -1240,7 +1240,7 @@ var X86OpXX = {
opINSw: function() {
var nReps = 1;
var nDelta = 0;
-
+
/*
* NOTE: 5 + 4n is the cycle time for the 80286; the 80186/80188 has different values: 14 cycles for
* an unrepeated INS, and 8 + 8n for a repeated INS. However, accurate cycle times for the 80186/80188 is
@@ -1278,13 +1278,13 @@ var X86OpXX = {
* @this {X86CPU}
*
* NOTE: Segment overrides are ignored for this instruction, so we must use segDS instead of segData.
- *
+ *
* op=0x6E (outsb) (80186/80188 and up)
*/
opOUTSb: function() {
var nReps = 1;
var nDelta = 0;
-
+
/*
* NOTE: 5 + 4n is the cycle time for the 80286; the 80186/80188 has different values: 14 cycles for
* an unrepeated INS, and 8 + 8n for a repeated INS. However, accurate cycle times for the 80186/80188 is
@@ -1327,7 +1327,7 @@ var X86OpXX = {
opOUTSw: function() {
var nReps = 1;
var nDelta = 0;
-
+
/*
* NOTE: 5 + 4n is the cycle time for the 80286; the 80186/80188 has different values: 14 cycles for
* an unrepeated INS, and 8 + 8n for a repeated INS. However, accurate cycle times for the 80186/80188 is
@@ -1647,15 +1647,15 @@ var X86OpXX = {
* If the second operand is a register, then the ModeRegByte decoder must use separate "get" and
* "set" assignments, otherwise instructions like "XCHG DH,DL" will end up using a stale DL instead of
* our updated DL.
- *
+ *
* To be clear, a single assignment like this will fail:
- *
+ *
* opModeRegByteF2: function(fn) {
* this.regDX = (this.regDX & 0xff) | (fn.call(this, this.regDX >> 8, this.regDX & 0xff) << 8);
* }
*
* which is why all affected decoders now use separate assignments; eg:
- *
+ *
* opModeRegByteF2: function(fn) {
* var b = fn.call(this, this.regDX >> 8, this.regDX & 0xff);
* this.regDX = (this.regDX & 0xff) | (b << 8);
@@ -1981,7 +1981,7 @@ var X86OpXX = {
},
/**
* @this {X86CPU}
- *
+ *
* op=0x9B (wait)
*/
opWAIT: function() {
@@ -2019,7 +2019,7 @@ var X86OpXX = {
opSAHF: function() {
/*
* NOTE: While it make LOOK more efficient to do this:
- *
+ *
* this.setPS((this.getPS() & ~X86.PS.SAHF) | ((this.regAX >> 8) & X86.PS.SAHF));
*
* the call to getPS() forces all the "indirect" flags to be resolved first, and then the call
@@ -2729,7 +2729,7 @@ var X86OpXX = {
* @this {X86CPU}
*
* Here's the pseudo-code from http://www.pcjs.org/pubs/pc/reference/intel/80286/progref, p.B-40 (p.250):
- *
+ *
* LEVEL := LEVEL MOD 32
* Push BP
* Set a temporary value FRAME_PTR := SP
@@ -2742,7 +2742,7 @@ var X86OpXX = {
* End if
* BP := FRAME_PTR
* SP := SP - first operand
- *
+ *
* TODO: Verify that this pseudo-code is identical on the 80186/80188 (eg, is LEVEL MOD 32 performed in both instances?)
*
* op=0xC8 (enter imm16,imm8) (80186/80188 and up)
@@ -2771,7 +2771,7 @@ var X86OpXX = {
},
/**
* @this {X86CPU}
- *
+ *
* Set SP to BP, then pop BP
*
* op=0xC9 (leave) (80186/80188 and up)
@@ -3359,7 +3359,7 @@ var X86OpXX = {
/*
* This 256-entry array of opcode functions is at the heart of the CPU engine: stepCPU(n).
- *
+ *
* It might be worth trying a switch() statement instead, to see how the performance compares,
* but I suspect that would vary quite a bit across JavaScript engines; for now, I'm putting my
* money on array lookup.
@@ -3405,7 +3405,7 @@ X86OpXX.aOps = [
/*
* On all processors, opcode groups 0x80 and 0x82 perform identically (0x82 opcodes sign-extend their
* immediate data, but since both 0x80 and 0x82 are byte operations, the sign extension has no effect).
- *
+ *
* WARNING: Intel's "Pentium Processor User's Manual (Volume 3: Architecture and Programming Manual)" refers
* to opcode 0x82 as a "reserved" instruction, but also cryptically refers to it as "MOVB AL,imm". This is
* assumed to be an error in the manual, because as far as I know, 0x82 has always mirrored 0x80.
diff --git a/my_modules/pcjs-client/lib/x86seg.js b/my_modules/pcjs-client/lib/x86seg.js
index 145cac651..a92cff952 100644
--- a/my_modules/pcjs-client/lib/x86seg.js
+++ b/my_modules/pcjs-client/lib/x86seg.js
@@ -34,17 +34,17 @@
"use strict";
if (typeof module !== 'undefined') {
- var X86 = require("./x86");
- var X86Help = require("./x86help");
+ var X86 = require("./x86");
+ var X86Help = require("./x86help");
}
/**
* X86Seg(cpu, sName)
- *
+ *
* @constructor
* @param {X86CPU} cpu
* @param {string} [sName] segment name
- * @param {boolean} [fProt] true if segment register used exclusively in protected-mode
+ * @param {boolean} [fProt] true if segment register used exclusively in protected-mode
*/
function X86Seg(cpu, sName, fProt)
{
@@ -64,7 +64,7 @@ function X86Seg(cpu, sName, fProt)
/**
* loadReal(sel, fSuppress)
- *
+ *
* This is the default real-mode load() function.
*
* @this {X86Seg}
@@ -84,7 +84,7 @@ X86Seg.loadReal = function loadReal(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.
- *
+ *
* 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:
*
@@ -92,7 +92,7 @@ X86Seg.loadReal = function loadReal(sel, fSuppress)
* 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}
@@ -115,23 +115,23 @@ X86Seg.loadProt = function loadProt(sel, fSuppress)
if (offDT + 7 <= addrDTLimit) {
this.checkRead = X86Seg.checkReadProtEnabled;
this.checkWrite = X86Seg.checkWriteProtEnabled;
-
+
/*
* 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;
-
+
/*
* TODO: Use (direct) Bus memory interfaces instead of (indirect) CPU memory interfaces here?
*/
var limit = this.cpu.getWord(offDT + X86.DESC.LIMIT.OFFSET);
var acc = this.cpu.getWord(offDT + X86.DESC.ACC.OFFSET);
var base = this.cpu.getWord(offDT + X86.DESC.BASE.OFFSET) | ((acc & X86.DESC.ACC.BASE1623) << 16);
-
+
Component.assert(this.cpu.getWord(offDT + 0x06) == 0);
-
+
/*
* For LSL (which uses fSuppress), we must support X86.DESC.ACC.TYPE.SEG as well as TSS and LDT.
*/
@@ -271,7 +271,7 @@ X86Seg.checkWriteProtDisabled = function checkWriteProtDisabled(off, cb, fSuppre
*
* 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}
* @return {Array}
*/
@@ -285,7 +285,7 @@ X86Seg.prototype.save = function()
*
* 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
*/
@@ -305,12 +305,12 @@ X86Seg.prototype.restore = function(a)
/**
* setBase(addr)
- *
+ *
* This is used in unusual situations where the base must be set independently; normally, the base
* is set according to the selector provided to load(), but there are a few cases where setBase() is
* required (eg, in resetRegs() where the 80286 wants the real-mode CS selector to be 0xF000 but the
* CS base must be 0xFF0000, and LOADALL).
- *
+ *
* @this {X86Seg}
* @param {number} addr
*/
diff --git a/versions/pcjs/1.15.5/pc-dbg.js b/versions/pcjs/1.15.5/pc-dbg.js
index 8002cd557..1aae29aaf 100644
--- a/versions/pcjs/1.15.5/pc-dbg.js
+++ b/versions/pcjs/1.15.5/pc-dbg.js
@@ -8,95 +8,95 @@ n.send(q)}else n.open("GET",a,b),n.send();a=[];b||(h=n.responseText,200!=n.statu
function va(a){if(window){var b=window?window.navigator.userAgent:"";return"iOS"==a&&b.match(/(iPod|iPhone|iPad)/)&&b.match(/AppleWebKit/)||"MSIE"==a&&b.match(/(MSIE|Trident)/)||0<=b.indexOf(a)?!0:!1}return!1}function wa(a,b,c){function d(){a-=1;0<=a&&(b()||(a=0));0=this.cg?12:14;this.ec=1<>2;this.eb=this.ec-1;this.Zg=(this.ue+this.ec)/this.ec|0;this.ye=this.Zg-1;this.rd=[];this.sd=[];this.Zf=this.$f=!1;this.Li();this.Ta()}y(x,Va);
-Va.prototype.Li=function(){this.Aa=Array(this.Zg);for(var a=0;a>a.rb;0>this.rb;0>a.rb;0>a.rb].tg(b&a.eb)}
-function cb(a,b){var c=b&a.eb,d=(b&a.Ib)>>a.rb;return c!=a.eb?a.Aa[d].Oj(c):a.Aa[d++].tg(c)|a.Aa[d&a.ye].tg(0)<<8}function db(a,b,c){a.Aa[(b&a.Ib)>>a.rb].Bg(b&a.eb,c&255)}function eb(a,b,c){var d=b&a.eb;b=(b&a.Ib)>>a.rb;d!=a.eb?a.Aa[b].Xj(d,c&65535):(a.Aa[b++].Bg(d,c&255),a.Aa[b&a.ye].Bg(0,c>>8&255))}
-function fb(a){for(var b=0,c=[],d=0;d=this.cg?12:14;this.fc=1<>2;this.eb=this.fc-1;this.Zg=(this.ue+this.fc)/this.fc|0;this.ye=this.Zg-1;this.rd=[];this.sd=[];this.Zf=this.$f=!1;this.Ni();this.Ta()}y(x,Va);
+Va.prototype.Ni=function(){this.Aa=Array(this.Zg);for(var a=0;a>a.rb;0>this.rb;0>a.rb;0>a.rb].tg(b&a.eb)}
+function cb(a,b){var c=b&a.eb,d=(b&a.Ib)>>a.rb;return c!=a.eb?a.Aa[d].Rj(c):a.Aa[d++].tg(c)|a.Aa[d&a.ye].tg(0)<<8}function db(a,b,c){a.Aa[(b&a.Ib)>>a.rb].Bg(b&a.eb,c&255)}function eb(a,b,c){var d=b&a.eb;b=(b&a.Ib)>>a.rb;d!=a.eb?a.Aa[b].$j(d,c&65535):(a.Aa[b++].Bg(d,c&255),a.Aa[b&a.ye].Bg(0,c>>8&255))}
+function fb(a){for(var b=0,c=[],d=0;d>2);for(d=0;d>2]>>>((a&3)<<3)&255},hp:function(a){var b=a>>2;a=(a&3)<<3;var c=this.ra[b]>>>a;return 24>a?c&65535:c&255|(this.ra[b+1]&255)<<8},pp:function(a,b){var c=a>>
-2,d=(a&3)<<3;this.ra[c]=this.ra[c]&~(255<>2,d=(a&3)<<3;24>d?this.ra[c]=this.ra[c]&~(65535<>8);this.mb=!0},gp:function(a){qb(this.X,this.Wd+a);return this.tg(a)},ip:function(a){qb(this.X,this.Wd+a)||qb(this.X,this.Wd+a+1);return this.Oj(a)},qp:function(a,b){rb(this.X,this.Wd+a);this.Bg(a,b)},sp:function(a,b){rb(this.X,this.Wd+a)||rb(this.X,this.Wd+a+1);this.Xj(a,b)},save:function(){return this.ia?
-null:this.ra},restore:function(a){return this.ia?null===a:this.zm==a.length<<2?(this.ra=a,this.mb=!0):!1},Pe:function(a,b){a||(a=[]);void 0===b&&(b=!0);sb(this,a,b);tb(this,a,b)},Vd:function(a,b){b?0===this.qk++&&tb(this,ub):0===this.pk++&&sb(this,ub)}};function wb(a,b){b?0===--a.qk&&(a.Dc=a.mh?a.xf:a.Bg,a.im=a.mh?a.xf:a.Xj):0===--a.pk&&(a.sc=a.tg,a.Wl=a.Oj)}function Wa(a,b,c,d,e){a.S=b;a.X=c;a.Wd=d;a.pk=a.qk=0;a.X&&xb(a.X,d,e)}
-function tb(a,b,c){a.Dc=b[2]&&!a.mh?b[2]:a.xf;a.im=b[3]&&!a.mh?b[3]:a.xf;c&&(a.Bg=b[2]?b[2]:a.xf,a.Xj=b[3]?b[3]:a.xf)}function sb(a,b,c){a.sc=b[0]?b[0]:a.Ih;a.Wl=b[1]?b[1]:a.Ih;c&&(a.tg=b[0]?b[0]:a.Ih,a.Oj=b[1]?b[1]:a.Ih)}var pb=[Xa.prototype.fp,Xa.prototype.hp,Xa.prototype.pp,Xa.prototype.rp],ub=[Xa.prototype.gp,Xa.prototype.ip,Xa.prototype.qp,Xa.prototype.sp];
-function yb(a,b){x.call(this,"CPU",a,yb);var c=a.multiplier||1;this.Hd=a.cycles||b;this.Gd=c;this.wh=Math.round(this.Hd/1E4)/100;this.Ge=this.wh*this.Gd;this.Ob=this.Nb=!1;this.ui=a.autoStart;c=Fa.autostart;void 0!==c&&(this.ui="true"==c?!0:"false"==c?!1:null);this.cf=!1;this.dg=this.mf=0;this.fg=a.csStart;this.lf=a.csInterval;this.nf=a.csStop;var d=this;this.jo=function(){d.Ne()};this.Ta()}y(x,yb);k=yb.prototype;
-k.nc=function(a,b,c,d){this.na=b;this.X=d;this.Da=a;var e=C(a,"Video");e&&(this.pi=function(){zb(e)},this.Md=function(){e.Md()});this.ka=C(a,"ChipSet");this.Ta()};k.reset=function(){};k.save=function(){return null};k.restore=function(){return!1};k.$b=function(a,b){if(!b){if(a&&this.restore){Ab(this);if(!this.restore(a))return!1;Bb(this)}else this.reset();this.X?this.X.Ln():this.ca("No debugger detected")}this.Nb=!0;!Cb(this)&&this.X&&Db(this.X);Eb(this);return!0};
-k.Wb=function(a){this.Nb=!1;return a&&this.save?this.save():!0};function Cb(a){return!0===a.ui||null===a.ui&&!a.X&&void 0===a.sa.run?(a.Ne(),!0):!1}k.Md=function(){};k.Dk=function(){return 0};function Bb(a){void 0===a.fg&&(a.fg=0);void 0===a.lf&&(a.lf=-1);void 0===a.nf&&(a.nf=-1);a.cf=0<=a.fg&&0=a.mf&&(a.mf+=a.lf,c=!0);0<=a.nf&&a.nf<=F(a)&&(a.lf=a.nf=-1,Bb(a),a.Ab(),c=!0);c&&a.ca(F(a)+" cycles: checksum="+p(a.dg))}}function G(a,b,c,d){void 0!==a.sa[b]&&(void 0===d&&(d=4),void 0===c&&(Sa(a,"Register "+b+" is invalid"),a.Ab()),c=p(c,d),a.sa[b].innerHTML!=c&&(a.sa[b].innerHTML=c))}k.eh=function(){};k.pi=function(){};
+function nb(a,b,c,d){var e=a.sd[b];void 0!==e?(e[1]&&e[1].call(e[0],b,c,d),a.X&&a.$f!=e[2]&&ob(a.X,b,c)):a.X&&(a.X.ba(a,b,c,d),a.$f&&ob(a.X,b,c))}function $a(a,b,c){w("Memory block error ("+a+","+p(b)+","+p(c)+")");return!1}function Xa(a,b,c,d){this.Cm=b;this.ra=null;this.offset=0;this.mh=c;this.ia=null;this.lb=this.zk=!1;if(b)if(d)this.ia=d,a=[d.ed,a-d.cb],this.ra=a[0],this.offset=a[1],this.Pe(d.Jf);else{this.ra=Array(b>>2);for(d=0;d>2]>>>((a&3)<<3)&255},kp:function(a){var b=a>>2;a=(a&3)<<3;var c=this.ra[b]>>>a;return 24>a?c&65535:c&255|(this.ra[b+1]&255)<<8},sp:function(a,b){var c=a>>
+2,d=(a&3)<<3;this.ra[c]=this.ra[c]&~(255<>2,d=(a&3)<<3;24>d?this.ra[c]=this.ra[c]&~(65535<>8);this.lb=!0},jp:function(a){qb(this.X,this.Wd+a);return this.tg(a)},lp:function(a){qb(this.X,this.Wd+a)||qb(this.X,this.Wd+a+1);return this.Rj(a)},tp:function(a,b){rb(this.X,this.Wd+a);this.Bg(a,b)},vp:function(a,b){rb(this.X,this.Wd+a)||rb(this.X,this.Wd+a+1);this.$j(a,b)},save:function(){return this.ia?
+null:this.ra},restore:function(a){return this.ia?null===a:this.Cm==a.length<<2?(this.ra=a,this.lb=!0):!1},Pe:function(a,b){a||(a=[]);void 0===b&&(b=!0);sb(this,a,b);tb(this,a,b)},Vd:function(a,b){b?0===this.tk++&&tb(this,ub):0===this.sk++&&sb(this,ub)}};function wb(a,b){b?0===--a.tk&&(a.Dc=a.mh?a.xf:a.Bg,a.lm=a.mh?a.xf:a.$j):0===--a.sk&&(a.sc=a.tg,a.Zl=a.Rj)}function Wa(a,b,c,d,e){a.S=b;a.X=c;a.Wd=d;a.sk=a.tk=0;a.X&&xb(a.X,d,e)}
+function tb(a,b,c){a.Dc=b[2]&&!a.mh?b[2]:a.xf;a.lm=b[3]&&!a.mh?b[3]:a.xf;c&&(a.Bg=b[2]?b[2]:a.xf,a.$j=b[3]?b[3]:a.xf)}function sb(a,b,c){a.sc=b[0]?b[0]:a.Kh;a.Zl=b[1]?b[1]:a.Kh;c&&(a.tg=b[0]?b[0]:a.Kh,a.Rj=b[1]?b[1]:a.Kh)}var pb=[Xa.prototype.ip,Xa.prototype.kp,Xa.prototype.sp,Xa.prototype.up],ub=[Xa.prototype.jp,Xa.prototype.lp,Xa.prototype.tp,Xa.prototype.vp];
+function yb(a,b){x.call(this,"CPU",a,yb);var c=a.multiplier||1;this.Hd=a.cycles||b;this.Gd=c;this.wh=Math.round(this.Hd/1E4)/100;this.Ge=this.wh*this.Gd;this.Ob=this.Nb=!1;this.wi=a.autoStart;c=Fa.autostart;void 0!==c&&(this.wi="true"==c?!0:"false"==c?!1:null);this.cf=!1;this.dg=this.mf=0;this.fg=a.csStart;this.lf=a.csInterval;this.nf=a.csStop;var d=this;this.mo=function(){d.Ne()};this.Ta()}y(x,yb);k=yb.prototype;
+k.pc=function(a,b,c,d){this.na=b;this.X=d;this.Da=a;var e=C(a,"Video");e&&(this.ri=function(){zb(e)},this.Md=function(){e.Md()});this.ka=C(a,"ChipSet");this.Ta()};k.reset=function(){};k.save=function(){return null};k.restore=function(){return!1};k.ac=function(a,b){if(!b){if(a&&this.restore){Ab(this);if(!this.restore(a))return!1;Bb(this)}else this.reset();this.X?this.X.On():this.ca("No debugger detected")}this.Nb=!0;!Cb(this)&&this.X&&Db(this.X);Eb(this);return!0};
+k.Wb=function(a){this.Nb=!1;return a&&this.save?this.save():!0};function Cb(a){return!0===a.wi||null===a.wi&&!a.X&&void 0===a.sa.run?(a.Ne(),!0):!1}k.Md=function(){};k.Gk=function(){return 0};function Bb(a){void 0===a.fg&&(a.fg=0);void 0===a.lf&&(a.lf=-1);void 0===a.nf&&(a.nf=-1);a.cf=0<=a.fg&&0=a.mf&&(a.mf+=a.lf,c=!0);0<=a.nf&&a.nf<=F(a)&&(a.lf=a.nf=-1,Bb(a),a.Ab(),c=!0);c&&a.ca(F(a)+" cycles: checksum="+p(a.dg))}}function G(a,b,c,d){void 0!==a.sa[b]&&(void 0===d&&(d=4),void 0===c&&(Sa(a,"Register "+b+" is invalid"),a.Ab()),c=p(c,d),a.sa[b].innerHTML!=c&&(a.sa[b].innerHTML=c))}k.eh=function(){};k.ri=function(){};
k.xb=function(a,b,c,d){var e=this;a=!1;switch(c){case "run":this.sa[c]=d;d.onclick=function(){e.Ob?e.Ab(!0):e.Ne(!0)};a=!0;break;case "reset":this.sa[c]=d;d.onclick=function(){e.Da&&Gb(e.Da)};a=!0;break;case "speed":this.sa[c]=d;a=!0;break;case "setSpeed":this.sa[c]=d,d.onclick=function(){Hb(e,e.Gd<<1,!0)},d.innerHTML=this.Ge.toFixed(2)+"Mhz",a=!0}return a};function Ib(a,b,c){a.Ke+=b;c&&(a.Oc=a.A=0)}
-function Jb(a,b){var c=30;60>c&&(c=60);2>c&&(c=2);var d=1;b&&1a.wh&&(c=Math.round(c/a.Gd));return c}function Ab(a){a.ld=0;a.zh=1;a.Ke=a.ke=a.Oc=a.A=0;Bb(a);Hb(a,1)}
+function Jb(a,b){var c=30;60>c&&(c=60);2>c&&(c=2);var d=1;b&&1a.wh&&(c=Math.round(c/a.Gd));return c}function Ab(a){a.ld=0;a.zh=1;a.Ke=a.ke=a.Oc=a.A=0;Bb(a);Hb(a,1)}
function Hb(a,b,c){void 0!==b&&(0.8>a.ld/a.Ge&&(b=1),a.Gd=b,b=a.wh*a.Gd,a.Ge!=b&&(a.Ge=b,b=a.Ge.toFixed(2)+"Mhz",a.sa.setSpeed&&(a.sa.setSpeed.innerHTML=b),a.ca("target speed: "+b)),c&&a.Md());Ib(a,a.ke);a.ke=0;a.kf=oa();a.He=0;Jb(a)}
-k.Ne=function(a){if(Pa(this,!0)){this.Ob||(Hb(this),this.Da&&this.Da.start(this.kf,F(this)),this.Ob=!0,this.ka&&Kb(this.ka),this.sa.run&&(this.sa.run.innerHTML="Halt"),a&&this.Md());this.Hj>=this.Hd&&Jb(this,!0);this.ig=0;this.xh=oa();this.He&&(a=this.xh-this.He,a>this.Kk&&(this.kf+=a,this.kf>this.xh&&(this.kf=this.xh)));try{do{this.wf(this.cf?1:Math.round(this.$n/this.zh));var b=this.Oc-this.A;this.ke+=b;this.ig+=b;Ib(this,0,!0);Fb(this,b);this.hg-=b;0>=this.hg&&(this.hg+=this.Ok,this.pi());this.gg-=
-b;0>=this.gg&&(this.gg+=this.Nk,this.eh());this.of-=b;if(0>=this.of){this.of+=this.Si;break}}while(this.Ob)}catch(c){this.Ab();Eb(this);this.Da&&this.Da.stop(oa(),F(this));Pa(this,!1);Sa(this,c.message);return}b=setTimeout;a=this.jo;this.He=oa();var d=this.Kk;this.ig&&(d=Math.round(d*this.ig/this.Si));var d=d-(this.He-this.xh),e=this.He-this.kf;e&&(this.ld=Math.round(this.ke/(10*e))/100,864E5<=e&&(this.Ke=0,this.ka&&Lb(this.ka,!0),Hb(this)));if(0>d||this.ld=this.Hd&&Jb(this,!0);this.ig=0;this.xh=oa();this.He&&(a=this.xh-this.He,a>this.Nk&&(this.kf+=a,this.kf>this.xh&&(this.kf=this.xh)));try{do{this.wf(this.cf?1:Math.round(this.co/this.zh));var b=this.Oc-this.A;this.ke+=b;this.ig+=b;Ib(this,0,!0);Fb(this,b);this.hg-=b;0>=this.hg&&(this.hg+=this.Rk,this.ri());this.gg-=
+b;0>=this.gg&&(this.gg+=this.Qk,this.eh());this.of-=b;if(0>=this.of){this.of+=this.Ui;break}}while(this.Ob)}catch(c){this.Ab();Eb(this);this.Da&&this.Da.stop(oa(),F(this));Pa(this,!1);Sa(this,c.message);return}b=setTimeout;a=this.mo;this.He=oa();var d=this.Nk;this.ig&&(d=Math.round(d*this.ig/this.Ui));var d=d-(this.He-this.xh),e=this.He-this.kf;e&&(this.ld=Math.round(this.ke/(10*e))/100,864E5<=e&&(this.Ke=0,this.ka&&Lb(this.ka,!0),Hb(this)));if(0>d||this.ld>13;return this.Ua=e}if(b&&768>=b)return this.oa=a,this.Nc=c,this.ab=d,this.Mc=(d&24576)>>13,this.Ua=e}return-1}function Wb(a){return this.Ua+a}
function Xb(a){return this.Ua+a}function Sb(a,b,c){return a+b<=this.Nc?this.Ua+a:Ub.call(this,0,0,c)}function Ub(a,b,c){c||Yb.call(this.S,13,0);return-1}function Tb(a,b,c){return a+b<=this.Nc?this.Ua+a:Vb.call(this,0,0,c)}function Vb(a,b,c){c||Yb.call(this.S,13,0);return-1}Nb.prototype.save=function(){return[this.oa,this.Ua,this.Nc,this.ab,this.Mc,this.xg]};Nb.prototype.restore=function(a){"number"==typeof a?this.load(a):(this.oa=a[0],this.Ua=a[1],this.Nc=a[2],this.ab=a[3],this.Mc=a[4],this.xg=a[5])};
function Pb(a,b){void 0===b&&(b=!!(a.S.ad&1));b?(a.load=Rb,a.Wc=Sb,a.Yb=Tb):(a.load=Qb,a.Wc=Wb,a.Yb=Xb)}
-function Zb(a){this.Fa=a.model||8088;var b=0;switch(this.Fa){default:case 8088:b=4772727;break;case 80286:b=6E6}yb.call(this,a,b);this.dk=61442;this.Jg=4;this.pf=255;this.Ij=4;this.aa=5;this.ta=6;this.fa=7;this.ga=8;this.P=9;this.V=11;this.W=12;this.Ie=4;this.Qk=60;this.Rk=83;this.Tb=3;this.sb=9;this.gc=16;this.Ch=1;this.Vk=19;this.Xk=28;this.Zk=16;this.Yk=21;this.Wk=37;this.Tk=2;this.aj=9;this.Uk=5;this.Sk=33;this.cj=10;this.bj=8;this.mg=3;this.lg=15;this.ml=51;this.nl=1;this.ol=2;this.pl=4;this.ll=
-32;this.rl=this.dj=15;this.Ub=16;this.Vb=4;this.tl=11;this.sl=18;this.ql=24;this.Cb=4;this.ul=2;this.ej=16;this.vl=17;this.jj=18;this.wl=19;this.ij=5;this.kj=6;this.Bl=2;this.Al=8;this.yl=9;this.mj=this.lj=this.xl=this.zl=10;this.al=80;this.cl=144;this.$k=86;this.bl=154;this.el=101;this.gl=165;this.dl=107;this.fl=171;this.Dl=70;this.Fl=113;this.Cl=76;this.El=124;this.il=80;this.kl=128;this.hl=86;this.jl=134;this.og=3;this.ng=16;this.rj=10;this.qj=8;this.Gl=51;this.hc=8;this.Hl=17;this.Il=36;this.pc=
-11;this.Jl=16;this.pg=10;this.Pb=2;this.Yi=18;this.Zi=9-this.Pb;this.$i=17-this.Pb;this.fj=12;this.gj=9-this.Pb;this.hj=13-this.Pb;this.nj=18;this.oj=9-this.Pb;this.pj=17-this.Pb;this.sj=15;this.tj=9-this.Pb;this.uj=15-this.Pb;this.yj=11;this.zj=9-this.Pb;this.Aj=10-this.Pb;this.Kl=8;this.Nl=12;this.Ll=18;this.Ml=17;this.Ol=15;this.wj=8;this.vj=20;this.xj=2;this.Dj=3;this.qg=9;this.Cj=5;this.Bj=11;this.Fj=4;this.Ej=17;this.Pl=11;this.Sa=$b.slice();80186<=this.Fa&&(this.pf=31,this.Sa[15]=ac,this.Sa[96]=
-bc,this.Sa[97]=cc,this.Sa[98]=dc,this.Sa[99]=ac,this.Sa[100]=ac,this.Sa[101]=ac,this.Sa[102]=ac,this.Sa[103]=ac,this.Sa[104]=ec,this.Sa[105]=fc,this.Sa[106]=gc,this.Sa[107]=hc,this.Sa[108]=ic,this.Sa[109]=jc,this.Sa[110]=kc,this.Sa[111]=lc,this.Sa[192]=mc,this.Sa[193]=nc,this.Sa[200]=oc,this.Sa[201]=pc,this.Sa[241]=qc,rc[7]=sc,tc[7]=sc,80286<=this.Fa&&(this.dk=2,this.Jg=0,this.Sa[15]=uc,this.Sa[99]=vc,this.Sa[84]=wc,this.P=this.ga=this.fa=this.ta=this.aa=this.Ij=0,this.W=this.V=1,this.Ie=3,this.Qk=
-14,this.Rk=16,this.Tb=2,this.gc=this.sb=7,this.Ch=0,this.Vk=7,this.Xk=13,this.Zk=7,this.Yk=11,this.Wk=16,this.Tk=3,this.aj=6,this.Uk=2,this.Sk=13,this.bj=this.cj=5,this.mg=2,this.lg=7,this.ml=23,this.nl=0,this.ol=1,this.pl=3,this.ll=17,this.dj=7,this.rl=11,this.Ub=7,this.Vb=3,this.tl=7,this.sl=11,this.ql=15,this.Cb=2,this.ul=3,this.ej=7,this.wl=this.jj=this.vl=8,this.kj=this.ij=4,this.Bl=2,this.Al=3,this.yl=5,this.zl=2,this.xl=3,this.lj=5,this.mj=3,this.al=14,this.cl=22,this.$k=17,this.bl=25,this.el=
-17,this.gl=25,this.dl=20,this.fl=28,this.Dl=13,this.Fl=21,this.Cl=16,this.El=24,this.il=13,this.kl=21,this.hl=16,this.jl=24,this.og=2,this.ng=7,this.qj=this.rj=5,this.Gl=19,this.Hl=this.hc=5,this.Il=17,this.pc=3,this.Jl=5,this.pg=3,this.Pb=0,this.Yi=8,this.Zi=5,this.$i=9,this.gj=this.fj=5,this.hj=4,this.oj=this.nj=5,this.pj=4,this.sj=7,this.tj=5,this.uj=8,this.yj=3,this.zj=4,this.Aj=3,this.Nl=this.Kl=11,this.Ml=this.Ll=15,this.Ol=7,this.wj=5,this.vj=8,this.xj=0,this.Dj=2,this.qg=6,this.Cj=3,this.Bj=
-6,this.Fj=3,this.Pl=this.Ej=5));this.Lg=[];this.Mg=[];this.Oc=this.ah=0;this.kh=this.yi=!1;this.Aa=[];this.ue=this.Ib=this.rb=this.eb=this.ye=0;this.T=this.Jm;this.U=this.Km;this.N=this.Rn;this.O=this.Sn;this.Q=this.np;this.R=this.op;xc(this)}y(yb,Zb);k=Zb.prototype;k.Li=function(a,b,c,d,e){this.Aa=a;this.ue=this.Ib=b;this.rb=c;this.eb=d;this.ye=e};k.reset=function(){this.Ob&&this.Ab();xc(this);Ab(this);this.jd=!1};
-function xc(a){a.G=0;a.B=0;a.I=0;a.J=0;a.Y=0;a.H=0;a.F=0;a.D=0;a.ad=65520;a.dd=0;a.te=1023;a.Jc={Jj:0,oa:0,ab:0,vh:-1};a.ua=new Nb(a,"CS");a.Eb=new Nb(a,"DS");a.wb=new Nb(a,"SS");a.Za=new Nb(a,"ES");a.fm=new Nb(a,"ZERO");yc(a,0,65535);80286<=a.Fa&&(a.Sc=a.Ye=0,a.Ld=new Nb(a,"LDT",!0),a.Ag=new Nb(a,"TSS",!0),a.Qb=new Nb(a,"VER",!0),yc(a,65520,61440),a.ua.Ua=16711680);zc(a,0);Ac(a);a.nb=0;a.Db=a.ug=-1;a.Ug=0;a.ha=a.Ka=-1;a.C=a.Eb;a.M=a.wb;a.$=a.wa=0}
-k.Dk=function(){var a=this.G+this.B+this.I+this.J+this.Y+this.H+this.F+this.D|0;return a=a+this.qa+this.ua.oa+this.Eb.oa+this.wb.oa+this.Za.oa+Bc(this)|0};function Cc(a,b,c,d){void 0!==d&&(void 0===a.Lg[b]&&(a.Lg[b]=[]),a.Lg[b].push([c,d]))}function Dc(a,b){a.yi&&E(a.X,a.X.$j)&&(Ec(a.X,b,a.Ba),Fc(a,a.Ba,function(a,c){return function(d){Gc(a.X,b,d,F(a)-c)}}(a,F(a))));var c=a.Lg[b];if(void 0!==c)for(var d=0;d>1?128:0}
function Zc(a){return(a.ja^a.ma^a.ja>>1)&a.da>>1?2048:0}function $c(a){a.Z&=~a.da}function ad(a){a.ma=a.ja&16|a.ma&-17}function bd(a){a.Z|=a.da-1}function cd(a){Yc(a)&&(a.ja^=a.da>>1|a.da>>2,a.ma^=32896)}function dd(a){a.ja&=~a.da;a.ma=a.ja&32896|a.ma&-32897}function ed(a){a.Z|=a.da}function fd(a){a.ma=~(a.ja&16)&16|a.ma&-17}function gd(a){a.Z&=~(a.da-1)}function hd(a){Yc(a)||(a.ja^=a.da>>1|a.da>>2,a.ma^=32896)}function id(a){a.ja|=a.da;a.ma=a.ja&32896|a.ma&-32897}
-function Bc(a){return a.xa&-2262|Uc(a)|Vc(a)|Wc(a)|Xc(a)|Yc(a)|Zc(a)}function zc(a,b){a.da=256;a.Z=a.ja=a.ma=0;b&1&&ed(a);b&4||(a.ja|=1);b&16&&(a.ma|=16);b&64||bd(a);b&128&&hd(a);b&2048&&id(a);a.xa=a.xa&-1793|b&1792|a.dk;a.xa&256&&(a.nb|=2,a.$|=4)}
+function Bc(a){return a.xa&-2262|Uc(a)|Vc(a)|Wc(a)|Xc(a)|Yc(a)|Zc(a)}function zc(a,b){a.da=256;a.Z=a.ja=a.ma=0;b&1&&ed(a);b&4||(a.ja|=1);b&16&&(a.ma|=16);b&64||bd(a);b&128&&hd(a);b&2048&&id(a);a.xa=a.xa&-1793|b&1792|a.gk;a.xa&256&&(a.mb|=2,a.$|=4)}
k.xb=function(a,b,c,d){var e=!1;switch(c){case "AX":case "BX":case "CX":case "DX":case "SP":case "BP":case "SI":case "DI":case "CS":case "DS":case "SS":case "ES":case "IP":case "PC":case "PS":case "C":case "P":case "A":case "Z":case "S":case "T":case "I":case "D":case "O":this.sa[c]=d;e=!0;break;default:e=yb.prototype.xb.call(this,a,b,c,d)}return e};k.ub=function(a){return this.Aa[(a&this.Ib)>>this.rb].sc(a&this.eb)};
-k.Ia=function(a){var b=a&this.eb;a=(a&this.Ib)>>this.rb;this.A-=this.Ij;return b!=this.eb?this.Aa[a].Wl(b):this.Aa[a++].sc(b)|this.Aa[a&this.ye].sc(0)<<8};k.bd=function(a,b){this.Aa[(a&this.Ib)>>this.rb].Dc(a&this.eb,b&255)};k.Nd=function(a,b){var c=a&this.eb,d=(a&this.Ib)>>this.rb;this.A-=this.Ij;c!=this.eb?this.Aa[d].im(c,b&65535):(this.Aa[d++].Dc(c,b&255),this.Aa[d&this.ye].Dc(0,b>>8&255))};k.Jm=function(a,b){this.zg=a;this.ha=a.Wc(this.rg=b,0);return this.$&1?0:this.ub(this.ha)};
-k.Km=function(a,b){this.zg=a;this.ha=a.Wc(this.rg=b,1);return this.$&1?0:this.Ia(this.ha)};k.Rn=function(a,b){this.zg=a;this.Ka=this.ha=a.Wc(this.rg=b,0);return this.$&1?0:this.ub(this.ha)};k.Sn=function(a,b){this.zg=a;this.Ka=this.ha=a.Wc(this.rg=b,1);return this.$&1?0:this.Ia(this.ha)};k.np=function(a){this.$&2||this.bd(this.zg.Yb(this.rg,1),a)};k.op=function(a){this.$&2||this.Nd(this.zg.Yb(this.rg,2),a)};k.ea=function(){var a=this.ub(this.Ba);this.Ba=this.ua.Ua+(this.qa=this.qa+1&65535);return a};
+k.Ia=function(a){var b=a&this.eb;a=(a&this.Ib)>>this.rb;this.A-=this.Lj;return b!=this.eb?this.Aa[a].Zl(b):this.Aa[a++].sc(b)|this.Aa[a&this.ye].sc(0)<<8};k.bd=function(a,b){this.Aa[(a&this.Ib)>>this.rb].Dc(a&this.eb,b&255)};k.Nd=function(a,b){var c=a&this.eb,d=(a&this.Ib)>>this.rb;this.A-=this.Lj;c!=this.eb?this.Aa[d].lm(c,b&65535):(this.Aa[d++].Dc(c,b&255),this.Aa[d&this.ye].Dc(0,b>>8&255))};k.Mm=function(a,b){this.zg=a;this.ha=a.Wc(this.rg=b,0);return this.$&1?0:this.ub(this.ha)};
+k.Nm=function(a,b){this.zg=a;this.ha=a.Wc(this.rg=b,1);return this.$&1?0:this.Ia(this.ha)};k.Un=function(a,b){this.zg=a;this.Ka=this.ha=a.Wc(this.rg=b,0);return this.$&1?0:this.ub(this.ha)};k.Vn=function(a,b){this.zg=a;this.Ka=this.ha=a.Wc(this.rg=b,1);return this.$&1?0:this.Ia(this.ha)};k.qp=function(a){this.$&2||this.bd(this.zg.Yb(this.rg,1),a)};k.rp=function(a){this.$&2||this.Nd(this.zg.Yb(this.rg,2),a)};k.ea=function(){var a=this.ub(this.Ba);this.Ba=this.ua.Ua+(this.qa=this.qa+1&65535);return a};
k.L=function(){var a=this.ub(this.Ba)<<24>>24;this.Ba=this.ua.Ua+(this.qa=this.qa+1&65535);return a&65535};k.K=function(){var a=this.Ia(this.Ba);this.Ba=this.ua.Ua+(this.qa=this.qa+2&65535);return a};k.Ja=function(){var a=this.Y;this.Y=this.Y+2&65535;return this.Ia(this.wb.Wc(a,1))};function K(a,b){var c=a.Y=a.Y-2&65535;a.Nd(a.wb.Yb(c,1),b)}
k.eh=function(){G(this,"AX",this.G);G(this,"BX",this.B);G(this,"CX",this.I);G(this,"DX",this.J);G(this,"SP",this.Y);G(this,"BP",this.H);G(this,"SI",this.F);G(this,"DI",this.D);G(this,"CS",this.ua.oa);G(this,"DS",this.Eb.oa);G(this,"SS",this.wb.oa);G(this,"ES",this.Za.oa);G(this,"IP",this.qa);var a=Bc(this);G(this,"PS",a);G(this,"C",a&1?1:0,1);G(this,"P",a&4?1:0,1);G(this,"A",a&16?1:0,1);G(this,"Z",a&64?1:0,1);G(this,"S",a&128?1:0,1);G(this,"T",a&256?1:0,1);G(this,"I",a&512?1:0,1);G(this,"D",a&1024?
1:0,1);G(this,"O",a&2048?1:0,1);this.sa.speed&&(this.sa.speed.innerHTML=this.Ob&&this.ld?this.ld.toFixed(2)+"Mhz":"Stopped")};
-k.wf=function(a){this.kh=!0;this.yi=a&&this.X&&jd(this.X);this.Oc=this.A=a;this.ka&&Lb(this.ka);a||!this.X||E(this.X,this.X.Te)||(this.$|=4);do{var b=this.$&240;if(b)this.wa|=b;else if(this.Fh=this.Ba,this.ha=this.Ka=-1,this.C=this.Eb,this.M=this.wb,this.wa=this.$&256,this.nb){a:{if(!(this.$&4))if(this.nb&1&&this.xa&512){if(b=kd(this.ka),-1<=b&&(this.nb&=-2,0<=b)){this.nb&=-5;ld.call(this,b,null,11);b=!0;break a}}else if(this.nb&2){this.nb&=-3;ld.call(this,1,null,11);b=!0;break a}if(b=this.nb&8){for(var b=
-this.ka,c=!1,d=0;dthis.Ka?0>this.ha?this.Tb:this.sb:this.gc;return(this.Z=this.ja=a+b)&255}function pd(a,b){this.da=256;this.A-=0>this.Ka?0>this.ha?this.Tb:this.sb:this.gc;return(this.Z=this.ja=this.ma=a|b)&255}
-function qd(a,b){this.ma=a^b;this.Z=this.ja=a+b+(this.Z&this.da?1:0);this.da=256;this.A-=0>this.Ka?0>this.ha?this.Tb:this.sb:this.gc;return this.Z&255}function rd(a,b){this.ma=a^b;this.Z=this.ja=a-b-(this.Z&this.da?1:0);this.da=256;this.A-=0>this.Ka?0>this.ha?this.Tb:this.sb:this.gc;return this.Z&255}function sd(a,b){this.da=256;this.A-=0>this.Ka?0>this.ha?this.Tb:this.sb:this.gc;return(this.Z=this.ja=this.ma=a&b)&255}
-function td(a,b){this.ma=a^b;this.da=256;this.A-=0>this.Ka?0>this.ha?this.Tb:this.sb:this.gc;return(this.Z=this.ja=a-b)&255}function ud(a,b){this.da=256;this.A-=0>this.Ka?0>this.ha?this.Tb:this.sb:this.gc;return(this.Z=this.ja=this.ma=a^b)&255}function vd(a,b){this.ma=a^b;this.da=256;this.Z=this.ja=a-b;this.A-=0>this.Ka?0>this.ha?this.Tb:this.aj:this.sb;this.$|=2;return a}
-function wd(a,b){this.ma=a^b;this.da=65536;this.A-=0>this.Ka?0>this.ha?this.Tb:this.sb:this.gc;return(this.Z=this.ja=a+b)&65535}function xd(a,b){this.da=65536;this.A-=0>this.Ka?0>this.ha?this.Tb:this.sb:this.gc;return(this.Z=this.ja=this.ma=a|b)&65535}function yd(a,b){this.ma=a^b;this.Z=this.ja=a+b+(this.Z&this.da?1:0);this.da=65536;this.A-=0>this.Ka?0>this.ha?this.Tb:this.sb:this.gc;return this.Z&65535}
-function zd(a,b){this.ma=a^b;this.Z=this.ja=a-b-(this.Z&this.da?1:0);this.da=65536;this.A-=0>this.Ka?0>this.ha?this.Tb:this.sb:this.gc;return this.Z&65535}function Ad(a,b){this.da=65536;this.A-=0>this.Ka?0>this.ha?this.Tb:this.sb:this.gc;return(this.Z=this.ja=this.ma=a&b)&65535}function Bd(a,b){this.ma=a^b;this.da=65536;this.A-=0>this.Ka?0>this.ha?this.Tb:this.sb:this.gc;return(this.Z=this.ja=a-b)&65535}
-function Cd(a,b){this.da=65536;this.A-=0>this.Ka?0>this.ha?this.Tb:this.sb:this.gc;return(this.Z=this.ja=this.ma=a^b)&65535}function Dd(a,b){this.ma=a^b;this.da=65536;this.Z=this.ja=a-b;this.A-=0>this.Ka?0>this.ha?this.Tb:this.aj:this.sb;this.$|=2;return a}function Ed(a,b){this.Z=this.Z&this.da-1|(a&b?this.da:0);(a^a>>1)&b>>1?id(this):dd(this)}function Fd(a,b){var c=a;if(b){var d,e=b&7;e?c=(d=a<>8-e)&255:d=a<<8;Ed.call(this,d,256)}return c}
+k.wf=function(a){this.kh=!0;this.Ai=a&&this.X&&jd(this.X);this.Oc=this.A=a;this.ka&&Lb(this.ka);a||!this.X||E(this.X,this.X.Te)||(this.$|=4);do{var b=this.$&240;if(b)this.wa|=b;else if(this.Hh=this.Ba,this.ha=this.Ka=-1,this.C=this.Eb,this.M=this.wb,this.wa=this.$&256,this.mb){a:{if(!(this.$&4))if(this.mb&1&&this.xa&512){if(b=kd(this.ka),-1<=b&&(this.mb&=-2,0<=b)){this.mb&=-5;ld.call(this,b,null,11);b=!0;break a}}else if(this.mb&2){this.mb&=-3;ld.call(this,1,null,11);b=!0;break a}if(b=this.mb&8){for(var b=
+this.ka,c=!1,d=0;dthis.Ka?0>this.ha?this.Tb:this.sb:this.hc;return(this.Z=this.ja=a+b)&255}function pd(a,b){this.da=256;this.A-=0>this.Ka?0>this.ha?this.Tb:this.sb:this.hc;return(this.Z=this.ja=this.ma=a|b)&255}
+function qd(a,b){this.ma=a^b;this.Z=this.ja=a+b+(this.Z&this.da?1:0);this.da=256;this.A-=0>this.Ka?0>this.ha?this.Tb:this.sb:this.hc;return this.Z&255}function rd(a,b){this.ma=a^b;this.Z=this.ja=a-b-(this.Z&this.da?1:0);this.da=256;this.A-=0>this.Ka?0>this.ha?this.Tb:this.sb:this.hc;return this.Z&255}function sd(a,b){this.da=256;this.A-=0>this.Ka?0>this.ha?this.Tb:this.sb:this.hc;return(this.Z=this.ja=this.ma=a&b)&255}
+function td(a,b){this.ma=a^b;this.da=256;this.A-=0>this.Ka?0>this.ha?this.Tb:this.sb:this.hc;return(this.Z=this.ja=a-b)&255}function ud(a,b){this.da=256;this.A-=0>this.Ka?0>this.ha?this.Tb:this.sb:this.hc;return(this.Z=this.ja=this.ma=a^b)&255}function vd(a,b){this.ma=a^b;this.da=256;this.Z=this.ja=a-b;this.A-=0>this.Ka?0>this.ha?this.Tb:this.dj:this.sb;this.$|=2;return a}
+function wd(a,b){this.ma=a^b;this.da=65536;this.A-=0>this.Ka?0>this.ha?this.Tb:this.sb:this.hc;return(this.Z=this.ja=a+b)&65535}function xd(a,b){this.da=65536;this.A-=0>this.Ka?0>this.ha?this.Tb:this.sb:this.hc;return(this.Z=this.ja=this.ma=a|b)&65535}function yd(a,b){this.ma=a^b;this.Z=this.ja=a+b+(this.Z&this.da?1:0);this.da=65536;this.A-=0>this.Ka?0>this.ha?this.Tb:this.sb:this.hc;return this.Z&65535}
+function zd(a,b){this.ma=a^b;this.Z=this.ja=a-b-(this.Z&this.da?1:0);this.da=65536;this.A-=0>this.Ka?0>this.ha?this.Tb:this.sb:this.hc;return this.Z&65535}function Ad(a,b){this.da=65536;this.A-=0>this.Ka?0>this.ha?this.Tb:this.sb:this.hc;return(this.Z=this.ja=this.ma=a&b)&65535}function Bd(a,b){this.ma=a^b;this.da=65536;this.A-=0>this.Ka?0>this.ha?this.Tb:this.sb:this.hc;return(this.Z=this.ja=a-b)&65535}
+function Cd(a,b){this.da=65536;this.A-=0>this.Ka?0>this.ha?this.Tb:this.sb:this.hc;return(this.Z=this.ja=this.ma=a^b)&65535}function Dd(a,b){this.ma=a^b;this.da=65536;this.Z=this.ja=a-b;this.A-=0>this.Ka?0>this.ha?this.Tb:this.dj:this.sb;this.$|=2;return a}function Ed(a,b){this.Z=this.Z&this.da-1|(a&b?this.da:0);(a^a>>1)&b>>1?id(this):dd(this)}function Fd(a,b){var c=a;if(b){var d,e=b&7;e?c=(d=a<>8-e)&255:d=a<<8;Ed.call(this,d,256)}return c}
function Gd(a,b){var c=a;if(b){var d,e=b&15;e?c=(d=a<>16-e)&65535:d=a<<16;Ed.call(this,d,65536)}return c}function Hd(a,b){var c=a;if(b){var d,c=b&7,c=d=(a>>c|a<<8-c)&255;d&128&&(d|=256);Ed.call(this,d,256)}return c}function Id(a,b){var c=a;if(b){var d,c=b&15,c=d=(a>>c|a<<16-c)&65535;d&32768&&(d|=65536);Ed.call(this,d,65536)}return c}
function Jd(a,b){var c=a;if(b){var d;(d=(b&this.pf)%9)?(d=a<>9-d,c=d&255):d=a|(this.Z&this.da?1:0)<<8;Ed.call(this,d,256)}return c}function Kd(a,b){var c=a;if(b){var d;(d=(b&this.pf)%17)?(d=a<>17-d,c=d&65535):d=a|(this.Z&this.da?1:0)<<16;Ed.call(this,d,65536)}return c}function Ld(a,b){var c=a;b&&(c=(b&this.pf)%9,c=a>>c|(this.Z&this.da?1:0)<<8-c|a<<9-c,Ed.call(this,c,256),c&=255);return c}
function Md(a,b){var c=a;b&&(c=(b&this.pf)%17,c=a>>c|(this.Z&this.da?1:0)<<16-c|a<<17-c,Ed.call(this,c,65536),c&=65535);return c}function Nd(a,b){var c=a;b&&(c=8>b-1;this.Z=this.ja=c>>1;this.Z=c&1?this.Z|256:this.Z&-257;this.ma=a^this.Z;this.da=256;a=this.Z}return a&255}function Qd(a,b){if(b){var c=16>b-1;this.Z=this.ja=c>>1;this.Z=c&1?this.Z|65536:this.Z&-65537;this.ma=a^this.Z;this.da=65536;a=this.Z}return a&65535}function Rd(a,b){if(b){8>24>>b-1;this.Z=this.ja=c>>1;this.Z=c&1?this.Z|256:this.Z&-257;this.ma=a^this.Z;this.da=256;a=this.Z}return a&255}
-function Sd(a,b){if(b){16>16>>b-1;this.Z=this.ja=c>>1;this.Z=c&1?this.Z|65536:this.Z&-65537;this.ma=a^this.Z;this.da=65536;a=this.Z}return a&65535}function Td(){this.A-=0>this.ha?2:this.Ol;return 1}function Ud(){var a=this.I&this.pf;this.A-=(0>this.ha?this.wj:this.vj)+(a<this.ha?this.wj:this.vj)+(a<>16>>b-1;this.Z=this.ja=c>>1;this.Z=c&1?this.Z|65536:this.Z&-65537;this.ma=a^this.Z;this.da=65536;a=this.Z}return a&65535}function Td(){this.A-=0>this.ha?2:this.Rl;return 1}function Ud(){var a=this.I&this.pf;this.A-=(0>this.ha?this.zj:this.yj)+(a<this.ha?this.zj:this.yj)+(a<this.Ka?this.hc:this.Hl;return b},$d,$d,$d,$d,$d,$d,$d],de=[function(a,b){this.A-=0>this.Ka?this.zl:this.xl;return b},L,L,L,L,L,L,L],ee=[Fd,Hd,Jd,Ld,Nd,Pd,L,Rd],fe=[Gd,Id,Kd,Md,Od,Qd,L,Sd],he=[function(a,b){b=this.ea();this.Z=this.ja=this.ma=a&b;this.da=256;this.A-=0>this.ha?this.Cj:this.Bj;this.$|=2;return a},L,function(a){this.A-=0>this.ha?this.og:this.ng;return a^255},function(a,b){b=0;this.ma=a^b;this.da=
-256;this.A-=0>this.ha?this.og:this.ng;return(this.Z=this.ja=b-a)&255},function(a){this.G=this.Db=(this.Z=(this.G&255)*a)&65535;this.ma=this.ja=this.Z;this.da=256;this.G&65280?(ed(this),id(this)):($c(this),dd(this));this.A-=0>this.ha?this.Dl:this.Cl;this.$|=2;return a},function(a){var b=(this.G<<24>>24)*(a<<24>>24);this.G=this.Db=b&65535;this.Z=this.ma=this.ja=b;this.da=256;127b?(ed(this),id(this)):($c(this),dd(this));this.A-=0>this.ha?this.il:this.hl;this.$|=2;return a},function(a){if(!a)return ge.call(this),
-a;var b=this.G/a;if(255this.ha?this.al:this.$k;this.$|=2;return a},function(a){if(!a)return ge.call(this),a;var b=(this.G<<16>>16)/(a<<24>>24);if(b>b<<24>>24&65535)return ge.call(this),a;this.Db=this.G=b&255|((this.G<<16>>16)%(a<<24>>24)&255)<<8;this.ja=this.ma=this.Z=b|256;this.da=256;this.A-=0>this.ha?this.el:this.dl;this.$|=2;return a}],ie=[function(a,b){b=this.K();this.Z=this.ja=
-this.ma=a&b;this.da=65536;this.A-=0>this.ha?this.Cj:this.Bj;this.$|=2;return a},L,function(a){this.A-=0>this.ha?this.og:this.ng;return a^65535},function(a,b){b=0;this.ma=a^b;this.da=65536;this.A-=0>this.ha?this.og:this.ng;return(this.Z=this.ja=b-a)&65535},function(a){this.Db=this.G=(this.Z=this.G*a)&65535;this.ug=this.J=this.Z>>16&65535;this.ma=this.ja=this.Z;this.da=65536;this.J?(ed(this),id(this)):($c(this),dd(this));this.A-=0>this.ha?this.Fl:this.El;this.$|=2;return a},function(a){var b=(this.G<<
-16>>16)*(a<<16>>16);this.G=this.Db=b&65535;this.J=this.ug=b>>16&65535;this.Z=this.ma=this.ja=b;this.da=65536;32767b?(ed(this),id(this)):($c(this),dd(this));this.A-=0>this.ha?this.kl:this.jl;this.$|=2;return a},function(a,b){if(!a)return ge.call(this),a;b=this.G+65536*this.J;var c=Math.floor(b/a);if(65536<=c)return ge.call(this),a;this.Db=this.G=c&65535;this.ug=this.J=b%a&65535;this.ja=this.ma=this.Z=c|65536;this.da=65536;this.A-=0>this.ha?this.cl:this.bl;this.$|=2;return a},function(a,
-b){if(!a)return ge.call(this),a;var c=a<<16>>16;b=this.J<<16|this.G;var d=Math.floor(b/c);if(d!=(d&65535)<<16>>16)return ge.call(this),a;this.Db=this.G=d&65535;this.ug=this.J=b%c&65535;this.ja=this.ma=this.Z=d|65536;this.da=65536;this.A-=0>this.ha?this.gl:this.fl;this.$|=2;return a}],rc=[function(a){this.ma=a;a=(this.ja=a+1)&255;this.Z=a|(this.Z&this.da?1:0)<<8;this.da=256;this.A-=0>this.ha?this.mg:this.lg;return a},function(a){this.ma=a;a=(this.ja=a-1)&255;this.Z=a|(this.Z&this.da?1:0)<<8;this.da=
-256;this.A-=0>this.ha?this.mg:this.lg;return a},L,L,L,L,L,L],tc=[function(a){this.ma=a;a=(this.ja=a+1)&65535;this.Z=a|(this.Z&this.da?1:0)<<16;this.da=65536;this.A-=0>this.ha?this.mg:this.lg;return a},function(a){this.ma=a;a=(this.ja=a-1)&65535;this.Z=a|(this.Z&this.da?1:0)<<16;this.da=65536;this.A-=0>this.ha?this.mg:this.lg;return a},function(a){K(this,this.qa);I(this,a);this.A-=0>this.ha?this.Zk:this.Yk;this.$|=2;return a},function(a){if(0>this.ha)return L.call(this,a);K(this,this.ua.oa);K(this,
-this.qa);yc(this,a,this.Ia(this.ha+2));this.A-=this.Wk;this.$|=2;return a},function(a){I(this,a);this.A-=0>this.ha?this.tl:this.sl;this.$|=2;return a},function(a){if(0>this.ha)return L.call(this,a);yc(this,a,this.Ia(this.ha+2));this.A-=this.ql;this.$|=2;return a},function(a){var b=a;this.$&512&&(a=a-2&65535,80286>this.Fa&&(b=a));K(this,b);this.A-=0>this.ha?this.pc:this.Jl;this.$|=2;return a},$d],je=[Fd,Hd,Jd,Ld,Nd,Pd,L,Rd],ke=[Gd,Id,Kd,Md,Od,Qd,L,Sd];
-function le(a,b){this.A-=0>this.Ka?0>this.ha?this.Bl:this.Al:this.yl;return b}function me(){return le.call(this,0,this.Db)}function ne(a,b){this.Z=this.ja=this.ma=a&b;this.da=256;this.A-=0>this.Ka?0>this.ha?this.Dj:this.qg:this.qg;this.$|=2;return a}function oe(a,b){this.Z=this.ja=this.ma=a&b;this.da=65536;this.A-=0>this.Ka?0>this.ha?this.Dj:this.qg:this.qg;this.$|=2;return a}
-function pe(a,b){var c=(b<<16>>16)*(this.ea()<<24>>24);this.Z=this.ma=this.ja=c;this.da=256;32767c?(ed(this),id(this)):($c(this),dd(this));this.A-=0>this.ha?21:24;return c&65535}function qe(a,b){var c=(b<<16>>16)*(this.K()<<16>>16);this.Z=this.ma=this.ja=c;this.da=65536;32767c?(ed(this),id(this)):($c(this),dd(this));this.A-=0>this.ha?21:24;return c&65535}function re(a){return a}function se(a){if(0>this.ha)return M.call(this),a;this.A-=this.ul;return this.ha}
-function te(a,b){if(0>this.ha)return M.call(this),a;Oc(this,this.Ia(this.ha+2));this.A-=this.ej;return b}function ue(a,b){if(0>this.ha)return M.call(this),a;Tc(this,this.Ia(this.ha+2));this.A-=this.ej;return b}function ve(a){if(0>this.ha)return ac.call(this),a;var b=a<<16>>16,c=this.Ia(this.ha)<<16>>16,d=this.Ia(this.ha+2)<<16>>16;this.A-=this.Sk;if(bd)I(this,this.Fh-this.ua.Ua),ld.call(this,5,null,0);this.$|=2;return a}
+var ae=[od,pd,qd,rd,sd,td,ud,vd],be=[wd,xd,yd,zd,Ad,Bd,Cd,Dd],ce=[function(a,b){this.A-=0>this.Ka?this.ic:this.Kl;return b},$d,$d,$d,$d,$d,$d,$d],de=[function(a,b){this.A-=0>this.Ka?this.Cl:this.Al;return b},L,L,L,L,L,L,L],ee=[Fd,Hd,Jd,Ld,Nd,Pd,L,Rd],fe=[Gd,Id,Kd,Md,Od,Qd,L,Sd],he=[function(a,b){b=this.ea();this.Z=this.ja=this.ma=a&b;this.da=256;this.A-=0>this.ha?this.Fj:this.Ej;this.$|=2;return a},L,function(a){this.A-=0>this.ha?this.og:this.ng;return a^255},function(a,b){b=0;this.ma=a^b;this.da=
+256;this.A-=0>this.ha?this.og:this.ng;return(this.Z=this.ja=b-a)&255},function(a){this.G=this.Db=(this.Z=(this.G&255)*a)&65535;this.ma=this.ja=this.Z;this.da=256;this.G&65280?(ed(this),id(this)):($c(this),dd(this));this.A-=0>this.ha?this.Gl:this.Fl;this.$|=2;return a},function(a){var b=(this.G<<24>>24)*(a<<24>>24);this.G=this.Db=b&65535;this.Z=this.ma=this.ja=b;this.da=256;127b?(ed(this),id(this)):($c(this),dd(this));this.A-=0>this.ha?this.ll:this.kl;this.$|=2;return a},function(a){if(!a)return ge.call(this),
+a;var b=this.G/a;if(255this.ha?this.dl:this.cl;this.$|=2;return a},function(a){if(!a)return ge.call(this),a;var b=(this.G<<16>>16)/(a<<24>>24);if(b>b<<24>>24&65535)return ge.call(this),a;this.Db=this.G=b&255|((this.G<<16>>16)%(a<<24>>24)&255)<<8;this.ja=this.ma=this.Z=b|256;this.da=256;this.A-=0>this.ha?this.hl:this.gl;this.$|=2;return a}],ie=[function(a,b){b=this.K();this.Z=this.ja=
+this.ma=a&b;this.da=65536;this.A-=0>this.ha?this.Fj:this.Ej;this.$|=2;return a},L,function(a){this.A-=0>this.ha?this.og:this.ng;return a^65535},function(a,b){b=0;this.ma=a^b;this.da=65536;this.A-=0>this.ha?this.og:this.ng;return(this.Z=this.ja=b-a)&65535},function(a){this.Db=this.G=(this.Z=this.G*a)&65535;this.ug=this.J=this.Z>>16&65535;this.ma=this.ja=this.Z;this.da=65536;this.J?(ed(this),id(this)):($c(this),dd(this));this.A-=0>this.ha?this.Il:this.Hl;this.$|=2;return a},function(a){var b=(this.G<<
+16>>16)*(a<<16>>16);this.G=this.Db=b&65535;this.J=this.ug=b>>16&65535;this.Z=this.ma=this.ja=b;this.da=65536;32767b?(ed(this),id(this)):($c(this),dd(this));this.A-=0>this.ha?this.nl:this.ml;this.$|=2;return a},function(a,b){if(!a)return ge.call(this),a;b=this.G+65536*this.J;var c=Math.floor(b/a);if(65536<=c)return ge.call(this),a;this.Db=this.G=c&65535;this.ug=this.J=b%a&65535;this.ja=this.ma=this.Z=c|65536;this.da=65536;this.A-=0>this.ha?this.fl:this.el;this.$|=2;return a},function(a,
+b){if(!a)return ge.call(this),a;var c=a<<16>>16;b=this.J<<16|this.G;var d=Math.floor(b/c);if(d!=(d&65535)<<16>>16)return ge.call(this),a;this.Db=this.G=d&65535;this.ug=this.J=b%c&65535;this.ja=this.ma=this.Z=d|65536;this.da=65536;this.A-=0>this.ha?this.jl:this.il;this.$|=2;return a}],rc=[function(a){this.ma=a;a=(this.ja=a+1)&255;this.Z=a|(this.Z&this.da?1:0)<<8;this.da=256;this.A-=0>this.ha?this.mg:this.lg;return a},function(a){this.ma=a;a=(this.ja=a-1)&255;this.Z=a|(this.Z&this.da?1:0)<<8;this.da=
+256;this.A-=0>this.ha?this.mg:this.lg;return a},L,L,L,L,L,L],tc=[function(a){this.ma=a;a=(this.ja=a+1)&65535;this.Z=a|(this.Z&this.da?1:0)<<16;this.da=65536;this.A-=0>this.ha?this.mg:this.lg;return a},function(a){this.ma=a;a=(this.ja=a-1)&65535;this.Z=a|(this.Z&this.da?1:0)<<16;this.da=65536;this.A-=0>this.ha?this.mg:this.lg;return a},function(a){K(this,this.qa);I(this,a);this.A-=0>this.ha?this.bl:this.al;this.$|=2;return a},function(a){if(0>this.ha)return L.call(this,a);K(this,this.ua.oa);K(this,
+this.qa);yc(this,a,this.Ia(this.ha+2));this.A-=this.Zk;this.$|=2;return a},function(a){I(this,a);this.A-=0>this.ha?this.wl:this.vl;this.$|=2;return a},function(a){if(0>this.ha)return L.call(this,a);yc(this,a,this.Ia(this.ha+2));this.A-=this.tl;this.$|=2;return a},function(a){var b=a;this.$&512&&(a=a-2&65535,80286>this.Fa&&(b=a));K(this,b);this.A-=0>this.ha?this.qc:this.Ml;this.$|=2;return a},$d],je=[Fd,Hd,Jd,Ld,Nd,Pd,L,Rd],ke=[Gd,Id,Kd,Md,Od,Qd,L,Sd];
+function le(a,b){this.A-=0>this.Ka?0>this.ha?this.El:this.Dl:this.Bl;return b}function me(){return le.call(this,0,this.Db)}function ne(a,b){this.Z=this.ja=this.ma=a&b;this.da=256;this.A-=0>this.Ka?0>this.ha?this.Gj:this.qg:this.qg;this.$|=2;return a}function oe(a,b){this.Z=this.ja=this.ma=a&b;this.da=65536;this.A-=0>this.Ka?0>this.ha?this.Gj:this.qg:this.qg;this.$|=2;return a}
+function pe(a,b){var c=(b<<16>>16)*(this.ea()<<24>>24);this.Z=this.ma=this.ja=c;this.da=256;32767c?(ed(this),id(this)):($c(this),dd(this));this.A-=0>this.ha?21:24;return c&65535}function qe(a,b){var c=(b<<16>>16)*(this.K()<<16>>16);this.Z=this.ma=this.ja=c;this.da=65536;32767c?(ed(this),id(this)):($c(this),dd(this));this.A-=0>this.ha?21:24;return c&65535}function re(a){return a}function se(a){if(0>this.ha)return M.call(this),a;this.A-=this.xl;return this.ha}
+function te(a,b){if(0>this.ha)return M.call(this),a;Oc(this,this.Ia(this.ha+2));this.A-=this.hj;return b}function ue(a,b){if(0>this.ha)return M.call(this),a;Tc(this,this.Ia(this.ha+2));this.A-=this.hj;return b}function ve(a){if(0>this.ha)return ac.call(this),a;var b=a<<16>>16,c=this.Ia(this.ha)<<16>>16,d=this.Ia(this.ha+2)<<16>>16;this.A-=this.Vk;if(bd)I(this,this.Hh-this.ua.Ua),ld.call(this,5,null,0);this.$|=2;return a}
function we(a,b){this.A-=10+(0>this.ha?0:1);if((a&3)<(b&3))return a=a&-4|b&3,gd(this),a;bd(this);return a}function xe(a,b){this.A-=14+(0>this.ha?0:2);if(0<=this.Qb.load(b,!0)&&this.Qb.Mc>=(this.ua.oa&3)&&this.Qb.Mc>=(b&3))return gd(this),this.Qb.ab&65280;bd(this);return a}function ye(a,b){this.A-=14+(0>this.ha?0:2);if(b&65528&&0<=this.Qb.load(b,!0)&&(3072==(this.Qb.ab&3072)||this.Qb.Mc>=(this.ua.oa&3))&&this.Qb.Mc>=(b&3))return gd(this),this.Qb.Nc;bd(this);return a}
-function ze(a,b){if(0>this.ha){switch(this.Ug&7){case 0:this.G=this.G&-256|a;break;case 1:this.I=this.I&-256|a;break;case 2:this.J=this.J&-256|a;break;case 3:this.B=this.B&-256|a;break;case 4:this.G=this.G&255|a<<8;break;case 5:this.I=this.I&255|a<<8;break;case 6:this.J=this.J&255|a<<8;break;case 7:this.B=this.B&255|a<<8}this.A-=this.Fj}else this.Ka=this.ha,this.Q(a),this.A-=this.Ej;return b}
-function Ae(a,b){if(0>this.ha){switch(this.Ug&7){case 0:this.G=a;break;case 1:this.I=a;break;case 2:this.J=a;break;case 3:this.B=a;break;case 4:this.Y=a;break;case 5:this.H=a;break;case 6:this.F=a;break;case 7:this.D=a}this.A-=this.Fj}else this.Ka=this.ha,this.R(a),this.A-=this.Ej;return b}function ld(a,b,c){Mc(this,a)&&(K(this,Bc(this)),this.xa&=this.Jc.vh,K(this,this.ua.oa),K(this,this.qa),null!=b&&K(this,b),yc(this,this.Jc.Jj,this.Jc.oa),this.A-=this.ml+c)}
-function ge(){I(this,this.Fh-this.ua.Ua);ld.call(this,0,null,2)}function Yb(a,b){this.X&&E(this.X,this.X.nm)&&this.X.message("Fault 0x"+r(a)+(null!=b?" (0x"+u(b)+")":"")+" on opcode 0x"+r(bb(this.na,this.Ba))+" at "+da(this.qa,this.ua.oa));80186<=this.Fa&&(I(this,this.Fh-this.ua.Ua),ld.call(this,a,b,0))}function ac(){Yb.call(this,6);this.Ab()}function M(){I(this,this.Fh-this.ua.Ua);Sa(this,"Undefined opcode 0x"+r(bb(this.na,this.Ba))+" at "+da(this.qa,this.ua.oa));this.Ab()}
+function ze(a,b){if(0>this.ha){switch(this.Ug&7){case 0:this.G=this.G&-256|a;break;case 1:this.I=this.I&-256|a;break;case 2:this.J=this.J&-256|a;break;case 3:this.B=this.B&-256|a;break;case 4:this.G=this.G&255|a<<8;break;case 5:this.I=this.I&255|a<<8;break;case 6:this.J=this.J&255|a<<8;break;case 7:this.B=this.B&255|a<<8}this.A-=this.Ij}else this.Ka=this.ha,this.Q(a),this.A-=this.Hj;return b}
+function Ae(a,b){if(0>this.ha){switch(this.Ug&7){case 0:this.G=a;break;case 1:this.I=a;break;case 2:this.J=a;break;case 3:this.B=a;break;case 4:this.Y=a;break;case 5:this.H=a;break;case 6:this.F=a;break;case 7:this.D=a}this.A-=this.Ij}else this.Ka=this.ha,this.R(a),this.A-=this.Hj;return b}function ld(a,b,c){Mc(this,a)&&(K(this,Bc(this)),this.xa&=this.Jc.vh,K(this,this.ua.oa),K(this,this.qa),null!=b&&K(this,b),yc(this,this.Jc.Mj,this.Jc.oa),this.A-=this.pl+c)}
+function ge(){I(this,this.Hh-this.ua.Ua);ld.call(this,0,null,2)}function Yb(a,b){this.X&&E(this.X,this.X.qm)&&this.X.message("Fault 0x"+r(a)+(null!=b?" (0x"+u(b)+")":"")+" on opcode 0x"+r(bb(this.na,this.Ba))+" at "+da(this.qa,this.ua.oa));80186<=this.Fa&&(I(this,this.Hh-this.ua.Ua),ld.call(this,a,b,0))}function ac(){Yb.call(this,6);this.Ab()}function M(){I(this,this.Hh-this.ua.Ua);Sa(this,"Undefined opcode 0x"+r(bb(this.na,this.Ba))+" at "+da(this.qa,this.ua.oa));this.Ab()}
function Be(a){a=a.call(this,this.G&255,this.G&255);this.G=this.G&-256|a}function Ce(a){a=a.call(this,this.G&255,this.I&255);this.G=this.G&-256|a}function De(a){a=a.call(this,this.G&255,this.J&255);this.G=this.G&-256|a}function Ee(a){a=a.call(this,this.G&255,this.B&255);this.G=this.G&-256|a}function Fe(a){a=a.call(this,this.G&255,this.G>>8);this.G=this.G&-256|a}function Ge(a){a=a.call(this,this.G&255,this.I>>8);this.G=this.G&-256|a}
function He(a){a=a.call(this,this.G&255,this.J>>8);this.G=this.G&-256|a}function Ie(a){a=a.call(this,this.G&255,this.B>>8);this.G=this.G&-256|a}function Je(a){a=a.call(this,this.I&255,this.G&255);this.I=this.I&-256|a}function Ke(a){a=a.call(this,this.I&255,this.I&255);this.I=this.I&-256|a}function Le(a){a=a.call(this,this.I&255,this.J&255);this.I=this.I&-256|a}function Me(a){a=a.call(this,this.I&255,this.B&255);this.I=this.I&-256|a}
function Ne(a){a=a.call(this,this.I&255,this.G>>8);this.I=this.I&-256|a}function Oe(a){a=a.call(this,this.I&255,this.I>>8);this.I=this.I&-256|a}function Pe(a){a=a.call(this,this.I&255,this.J>>8);this.I=this.I&-256|a}function Qe(a){a=a.call(this,this.I&255,this.B>>8);this.I=this.I&-256|a}function Re(a){a=a.call(this,this.J&255,this.G&255);this.J=this.J&-256|a}function Se(a){a=a.call(this,this.J&255,this.I&255);this.J=this.J&-256|a}
@@ -374,22 +374,22 @@ b){this.B=a[7].call(this,this.B,b.call(this))},function(a,b){this.Y=a[7].call(th
M,M,M,M,M,M,M,ac,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,M,
M,M],Jc=[function(){this.A-=2+(0>this.ha?0:1);return this.Ld.oa},function(){this.A-=2+(0>this.ha?0:1);return this.Ag.oa},function(a){this.$|=2;this.Ld.load(a);this.A-=17+(0>this.ha?0:2);return a},function(a){this.$|=2;this.Ag.load(a);this.A-=17+(0>this.ha?0:2);return a},function(a){this.$|=2;this.A-=14+(0>this.ha?0:2);if(0<=this.Qb.load(a,!0)&&2048!=(this.Qb.ab&2560)&&(3072==(this.Qb.ab&3072)||this.Qb.Mc>=(this.ua.oa&3)&&this.Qb.Mc>=(a&3)))return gd(this),a;bd(this);return a},function(a){this.$|=
2;this.A-=14+(0>this.ha?0:2);if(0<=this.Qb.load(a,!0)&&512==(this.Qb.ab&2560)&&this.Qb.Mc>=(this.ua.oa&3)&&this.Qb.Mc>=(a&3))return gd(this),a;bd(this);return a},L,L],Kc=[sc,sc,sc,sc,sc,sc,L,L],Ic=Kc,ch=[function(a){0>this.ha?ac.call(this):(this.Nd(this.ha+2,this.Sc),this.bd(this.ha+4,this.Sc>>16),a=this.Ye-this.Sc,this.A-=11);return a},function(a){0>this.ha?ac.call(this):(this.Nd(this.ha+2,this.dd),this.bd(this.ha+4,this.dd>>16),a=this.te-this.dd,this.A-=12);return a},function(a){0>this.ha?ac.call(this):
-(this.Sc=this.Ia(this.ha+2)|this.ub(this.ha+4)<<16,this.Ye=this.Sc+a,this.$|=2,this.A-=11);return a},function(a){0>this.ha?ac.call(this):(this.dd=this.Ia(this.ha+2)|this.ub(this.ha+4)<<16,this.te=this.dd+a,this.$|=2,this.A-=12);return a},function(){this.A-=2+(0>this.ha?0:1);return this.ad},L,function(a){this.ad=this.ad&65520|a&-65521;this.A-=3+(0>this.ha?0:3);this.ad&1&&Ac(this,!0);this.$|=2;return a},L];function uc(){dh[this.ea()].call(this)}function wc(){K(this,this.Y);this.A-=this.pc}
-function bc(){var a=this.Y;K(this,this.G);K(this,this.I);K(this,this.J);K(this,this.B);K(this,a);K(this,this.H);K(this,this.F);K(this,this.D);this.A-=this.Il}function cc(){this.D=this.Ja();this.F=this.Ja();this.H=this.Ja();this.Y+=2;this.B=this.Ja();this.J=this.Ja();this.I=this.Ja();this.G=this.Ja();this.A-=this.Gl}function dc(){N[this.ea()].call(this,ve)}function vc(){Zg[this.ea()].call(this,we)}function ec(){K(this,this.K());this.A-=this.pc}function fc(){N[this.ea()].call(this,qe)}
-function gc(){K(this,this.ea());this.A-=this.pc}function hc(){N[this.ea()].call(this,pe)}function ic(){var a=1,b=0,c=5;this.wa&192&&(a=this.I,b=1,this.wa&256&&(c=4));if(a--){var d=jb(this.na,this.J,this.Ba-b-1);this.bd(this.Za.Yb(this.D,0),d);this.D=this.D+(this.xa&1024?-1:1)&65535;this.A-=c;this.I-=b;a&&(J(this,-2),this.$|=256)}}
+(this.Sc=this.Ia(this.ha+2)|this.ub(this.ha+4)<<16,this.Ye=this.Sc+a,this.$|=2,this.A-=11);return a},function(a){0>this.ha?ac.call(this):(this.dd=this.Ia(this.ha+2)|this.ub(this.ha+4)<<16,this.te=this.dd+a,this.$|=2,this.A-=12);return a},function(){this.A-=2+(0>this.ha?0:1);return this.ad},L,function(a){this.ad=this.ad&65520|a&-65521;this.A-=3+(0>this.ha?0:3);this.ad&1&&Ac(this,!0);this.$|=2;return a},L];function uc(){dh[this.ea()].call(this)}function wc(){K(this,this.Y);this.A-=this.qc}
+function bc(){var a=this.Y;K(this,this.G);K(this,this.I);K(this,this.J);K(this,this.B);K(this,a);K(this,this.H);K(this,this.F);K(this,this.D);this.A-=this.Ll}function cc(){this.D=this.Ja();this.F=this.Ja();this.H=this.Ja();this.Y+=2;this.B=this.Ja();this.J=this.Ja();this.I=this.Ja();this.G=this.Ja();this.A-=this.Jl}function dc(){N[this.ea()].call(this,ve)}function vc(){Zg[this.ea()].call(this,we)}function ec(){K(this,this.K());this.A-=this.qc}function fc(){N[this.ea()].call(this,qe)}
+function gc(){K(this,this.ea());this.A-=this.qc}function hc(){N[this.ea()].call(this,pe)}function ic(){var a=1,b=0,c=5;this.wa&192&&(a=this.I,b=1,this.wa&256&&(c=4));if(a--){var d=jb(this.na,this.J,this.Ba-b-1);this.bd(this.Za.Yb(this.D,0),d);this.D=this.D+(this.xa&1024?-1:1)&65535;this.A-=c;this.I-=b;a&&(J(this,-2),this.$|=256)}}
function jc(){var a=1,b=0,c=5;this.wa&192&&(a=this.I,b=1,this.wa&256&&(c=4));if(a--){var d=this.Ba-b-1,d=jb(this.na,this.J,d)|jb(this.na,this.J,d)<<8;this.Nd(this.Za.Yb(this.D,1),d);this.D=this.D+(this.xa&1024?-2:2)&65535;this.A-=c;this.I-=b;a&&(J(this,-2),this.$|=256)}}
function kc(){var a=1,b=0,c=5;this.wa&192&&(a=this.I,b=1,this.wa&256&&(c=4));if(a--){var d=this.ub(this.Eb.Wc(this.F,0));this.F=this.F+(this.xa&1024?-1:1)&65535;this.A-=c;this.I-=b;nb(this.na,this.J,d,this.Ba-b-1);a&&(J(this,-2),this.$|=256)}}
function lc(){var a=1,b=0,c=5;this.wa&192&&(a=this.I,b=1,this.wa&256&&(c=4));if(a--){var d=this.Ia(this.Eb.Wc(this.F,1));this.F=this.F+(this.xa&1024?-2:2)&65535;this.A-=c;this.I-=b;b=this.Ba-b-1;nb(this.na,this.J,d&255,b);nb(this.na,this.J,d>>8,b);a&&(J(this,-2),this.$|=256)}}function eh(){var a=this.L();Zc(this)?(I(this,this.qa+a),this.A-=this.Ub):this.A-=this.Vb}function fh(){var a=this.L();Zc(this)?this.A-=this.Vb:(I(this,this.qa+a),this.A-=this.Ub)}
function gh(){var a=this.L();Uc(this)?(I(this,this.qa+a),this.A-=this.Ub):this.A-=this.Vb}function hh(){var a=this.L();Uc(this)?this.A-=this.Vb:(I(this,this.qa+a),this.A-=this.Ub)}function ih(){var a=this.L();Xc(this)?(I(this,this.qa+a),this.A-=this.Ub):this.A-=this.Vb}function jh(){var a=this.L();Xc(this)?this.A-=this.Vb:(I(this,this.qa+a),this.A-=this.Ub)}function kh(){var a=this.L();Uc(this)||Xc(this)?(I(this,this.qa+a),this.A-=this.Ub):this.A-=this.Vb}
function lh(){var a=this.L();Uc(this)||Xc(this)?this.A-=this.Vb:(I(this,this.qa+a),this.A-=this.Ub)}function mh(){var a=this.L();Yc(this)?(I(this,this.qa+a),this.A-=this.Ub):this.A-=this.Vb}function nh(){var a=this.L();Yc(this)?this.A-=this.Vb:(I(this,this.qa+a),this.A-=this.Ub)}function oh(){var a=this.L();Vc(this)?(I(this,this.qa+a),this.A-=this.Ub):this.A-=this.Vb}function ph(){var a=this.L();Vc(this)?this.A-=this.Vb:(I(this,this.qa+a),this.A-=this.Ub)}
function qh(){var a=this.L();!Yc(this)!=!Zc(this)?(I(this,this.qa+a),this.A-=this.Ub):this.A-=this.Vb}function rh(){var a=this.L();!Yc(this)==!Zc(this)?(I(this,this.qa+a),this.A-=this.Ub):this.A-=this.Vb}function sh(){var a=this.L();Xc(this)||!Yc(this)!=!Zc(this)?(I(this,this.qa+a),this.A-=this.Ub):this.A-=this.Vb}function th(){var a=this.L();Xc(this)||!Yc(this)!=!Zc(this)?this.A-=this.Vb:(I(this,this.qa+a),this.A-=this.Ub)}
-function uh(){ah[this.ea()].call(this,ae,this.ea);this.A-=0>this.Ka?1:this.Ch}function mc(){ah[this.ea()].call(this,je,Vd)}function nc(){bh[this.ea()].call(this,ke,Vd)}function vh(){var a=this.K();I(this,this.Ja());this.Y=this.Y+a&65535;this.A-=this.Nl}function wh(){I(this,this.Ja());this.A-=this.Kl}
-function oc(){var a=this.K(),b=this.ea()&31;this.A-=11;K(this,this.H);var c=this.Y;if(0this.Ka?1:this.Eh}function mc(){ah[this.ea()].call(this,je,Vd)}function nc(){bh[this.ea()].call(this,ke,Vd)}function vh(){var a=this.K();I(this,this.Ja());this.Y=this.Y+a&65535;this.A-=this.Ql}function wh(){I(this,this.Ja());this.A-=this.Nl}
+function oc(){var a=this.K(),b=this.ea()&31;this.A-=11;K(this,this.H);var c=this.Y;if(0>8,c,d=Wc(this);9<(a&15)||d?(a=a+6&15,b=b+1&255,c=d=!0):c=d=!1;this.G=b<<8|(this.Z=a);this.da=65536;c&&(this.Z|=this.da);d?fd(this):ad(this);this.A-=this.Ie},function(){Yg[this.ea()].call(this,vd)},function(){Zg[this.ea()].call(this,Dd)},function(){$g[this.ea()].call(this,vd)},function(){N[this.ea()].call(this,Dd)},function(){this.G=this.G&-256|vd.call(this,this.G&255,this.ea());this.A--},function(){this.G=Dd.call(this,this.G,this.K());this.A--},function(){this.$|=
@@ -397,250 +397,251 @@ this.Pb},function(){var a=this.G&255,b=this.G>>8,c,d=Wc(this);9<(a&15)||d?(a=a+6
this.J=(this.ja=this.J+1)&65535;this.Z=this.J|(this.Z&this.da?1:0)<<16;this.da=65536;this.A-=2},function(){this.ma=this.B;this.B=(this.ja=this.B+1)&65535;this.Z=this.B|(this.Z&this.da?1:0)<<16;this.da=65536;this.A-=2},function(){this.ma=this.Y;this.Y=(this.ja=this.Y+1)&65535;this.Z=this.Y|(this.Z&this.da?1:0)<<16;this.da=65536;this.A-=2},function(){this.ma=this.H;this.H=(this.ja=this.H+1)&65535;this.Z=this.H|(this.Z&this.da?1:0)<<16;this.da=65536;this.A-=2},function(){this.ma=this.F;this.F=(this.ja=
this.F+1)&65535;this.Z=this.F|(this.Z&this.da?1:0)<<16;this.da=65536;this.A-=2},function(){this.ma=this.D;this.D=(this.ja=this.D+1)&65535;this.Z=this.D|(this.Z&this.da?1:0)<<16;this.da=65536;this.A-=2},function(){this.ma=this.G;this.G=(this.ja=this.G-1)&65535;this.Z=this.G|(this.Z&this.da?1:0)<<16;this.da=65536;this.A-=2},function(){this.ma=this.I;this.I=(this.ja=this.I-1)&65535;this.Z=this.I|(this.Z&this.da?1:0)<<16;this.da=65536;this.A-=2},function(){this.ma=this.J;this.J=(this.ja=this.J-1)&65535;
this.Z=this.J|(this.Z&this.da?1:0)<<16;this.da=65536;this.A-=2},function(){this.ma=this.B;this.B=(this.ja=this.B-1)&65535;this.Z=this.B|(this.Z&this.da?1:0)<<16;this.da=65536;this.A-=2},function(){this.ma=this.Y;this.Y=(this.ja=this.Y-1)&65535;this.Z=this.Y|(this.Z&this.da?1:0)<<16;this.da=65536;this.A-=2},function(){this.ma=this.H;this.H=(this.ja=this.H-1)&65535;this.Z=this.H|(this.Z&this.da?1:0)<<16;this.da=65536;this.A-=2},function(){this.ma=this.F;this.F=(this.ja=this.F-1)&65535;this.Z=this.F|
-(this.Z&this.da?1:0)<<16;this.da=65536;this.A-=2},function(){this.ma=this.D;this.D=(this.ja=this.D-1)&65535;this.Z=this.D|(this.Z&this.da?1:0)<<16;this.da=65536;this.A-=2},function(){K(this,this.G);this.A-=this.pc},function(){K(this,this.I);this.A-=this.pc},function(){K(this,this.J);this.A-=this.pc},function(){K(this,this.B);this.A-=this.pc},function(){K(this,this.Y-2&65535);this.A-=this.pc},function(){K(this,this.H);this.A-=this.pc},function(){K(this,this.F);this.A-=this.pc},function(){K(this,this.D);
-this.A-=this.pc},function(){this.G=this.Ja();this.A-=this.hc},function(){this.I=this.Ja();this.A-=this.hc},function(){this.J=this.Ja();this.A-=this.hc},function(){this.B=this.Ja();this.A-=this.hc},function(){this.Y=this.Ja();this.A-=this.hc},function(){this.H=this.Ja();this.A-=this.hc},function(){this.F=this.Ja();this.A-=this.hc},function(){this.D=this.Ja();this.A-=this.hc},eh,fh,gh,hh,ih,jh,kh,lh,mh,nh,oh,ph,qh,rh,sh,th,eh,fh,gh,hh,ih,jh,kh,lh,mh,nh,oh,ph,qh,rh,sh,th,uh,function(){bh[this.ea()].call(this,
-be,this.K);this.A-=0>this.Ka?1:this.Ch},uh,function(){bh[this.ea()].call(this,be,this.L);this.A-=0>this.Ka?1:this.Ch},function(){Yg[this.ea()].call(this,ne)},function(){Zg[this.ea()].call(this,oe)},function(){$g[this.Ug=this.ea()].call(this,ze)},function(){N[this.Ug=this.ea()].call(this,Ae)},function(){this.$|=1;Yg[this.ea()].call(this,le)},function(){this.$|=1;Zg[this.ea()].call(this,le)},function(){$g[this.ea()].call(this,le)},function(){N[this.ea()].call(this,le)},function(){var a=this.ea();switch((a&
-56)>>3){case 0:this.Db=this.Za.oa;break;case 1:this.Db=this.ua.oa;break;case 2:this.Db=this.wb.oa;break;case 3:this.Db=this.Eb.oa;break;default:M.call(this);return}this.$|=1;Zg[a].call(this,me)},function(){this.$|=1;this.C=this.M=this.fm;N[this.ea()].call(this,se)},function(){var a,b=this.ea(),c=(b&56)>>3;switch(c){case 0:a=this.G;break;case 2:a=this.J;break;case 3:a=this.B;break;default:if(80286<=this.Fa){ac.call(this);return}switch(c){case 1:a=this.I;break;case 4:a=this.Y;break;case 5:a=this.H;
+(this.Z&this.da?1:0)<<16;this.da=65536;this.A-=2},function(){this.ma=this.D;this.D=(this.ja=this.D-1)&65535;this.Z=this.D|(this.Z&this.da?1:0)<<16;this.da=65536;this.A-=2},function(){K(this,this.G);this.A-=this.qc},function(){K(this,this.I);this.A-=this.qc},function(){K(this,this.J);this.A-=this.qc},function(){K(this,this.B);this.A-=this.qc},function(){K(this,this.Y-2&65535);this.A-=this.qc},function(){K(this,this.H);this.A-=this.qc},function(){K(this,this.F);this.A-=this.qc},function(){K(this,this.D);
+this.A-=this.qc},function(){this.G=this.Ja();this.A-=this.ic},function(){this.I=this.Ja();this.A-=this.ic},function(){this.J=this.Ja();this.A-=this.ic},function(){this.B=this.Ja();this.A-=this.ic},function(){this.Y=this.Ja();this.A-=this.ic},function(){this.H=this.Ja();this.A-=this.ic},function(){this.F=this.Ja();this.A-=this.ic},function(){this.D=this.Ja();this.A-=this.ic},eh,fh,gh,hh,ih,jh,kh,lh,mh,nh,oh,ph,qh,rh,sh,th,eh,fh,gh,hh,ih,jh,kh,lh,mh,nh,oh,ph,qh,rh,sh,th,uh,function(){bh[this.ea()].call(this,
+be,this.K);this.A-=0>this.Ka?1:this.Eh},uh,function(){bh[this.ea()].call(this,be,this.L);this.A-=0>this.Ka?1:this.Eh},function(){Yg[this.ea()].call(this,ne)},function(){Zg[this.ea()].call(this,oe)},function(){$g[this.Ug=this.ea()].call(this,ze)},function(){N[this.Ug=this.ea()].call(this,Ae)},function(){this.$|=1;Yg[this.ea()].call(this,le)},function(){this.$|=1;Zg[this.ea()].call(this,le)},function(){$g[this.ea()].call(this,le)},function(){N[this.ea()].call(this,le)},function(){var a=this.ea();switch((a&
+56)>>3){case 0:this.Db=this.Za.oa;break;case 1:this.Db=this.ua.oa;break;case 2:this.Db=this.wb.oa;break;case 3:this.Db=this.Eb.oa;break;default:M.call(this);return}this.$|=1;Zg[a].call(this,me)},function(){this.$|=1;this.C=this.M=this.im;N[this.ea()].call(this,se)},function(){var a,b=this.ea(),c=(b&56)>>3;switch(c){case 0:a=this.G;break;case 2:a=this.J;break;case 3:a=this.B;break;default:if(80286<=this.Fa){ac.call(this);return}switch(c){case 1:a=this.I;break;case 4:a=this.Y;break;case 5:a=this.H;
break;case 6:a=this.F;break;case 7:a=this.D}}N[b].call(this,le);switch(c){case 0:Tc(this,this.G);this.G=a;break;case 1:Nc(this,this.I);this.I=a;break;case 2:Pc(this,this.J);this.J=a;break;case 3:Oc(this,this.B);this.B=a;break;case 4:Tc(this,this.Y);this.Y=a;break;case 5:Nc(this,this.H);this.H=a;break;case 6:Pc(this,this.F);this.F=a;break;case 7:Oc(this,this.D),this.D=a}},function(){this.$|=1;bh[this.ea()].call(this,ce,this.Ja)},function(){this.A-=3},function(){var a=this.G;this.G=this.I;this.I=a;
-this.A-=3},function(){var a=this.G;this.G=this.J;this.J=a;this.A-=3},function(){var a=this.G;this.G=this.B;this.B=a;this.A-=3},function(){var a=this.G;this.G=this.Y;this.Y=a;this.A-=3},function(){var a=this.G;this.G=this.H;this.H=a;this.A-=3},function(){var a=this.G;this.G=this.F;this.F=a;this.A-=3},function(){var a=this.G;this.G=this.D;this.D=a;this.A-=3},function(){this.G=this.G<<24>>24&65535;this.A-=2},function(){this.J=this.G&32768?65535:0;this.A-=this.Uk},function(){var a=this.K(),b=this.K();
-K(this,this.ua.oa);K(this,this.qa);yc(this,a,b);this.A-=this.Xk},function(){M.call(this)},function(){K(this,Bc(this));this.A-=this.pc},function(){zc(this,this.Ja());this.A-=this.hc},function(){var a=this.G>>8;a&1?ed(this):$c(this);a&4?Vc(this)||(this.ja^=1):Vc(this)&&(this.ja^=1);a&16?fd(this):ad(this);a&64?gd(this):bd(this);a&128?hd(this):cd(this);this.A-=this.Cb},function(){this.G=this.G&255|(Bc(this)&213)<<8;this.A-=this.Cb},function(){this.G=this.G&-256|this.T(this.C,this.K());this.A-=this.lj},
-function(){this.G=this.U(this.C,this.K());this.A-=this.lj},function(){var a=this.K(),b=this.G;this.bd(this.C.Yb(a,0),b);this.A-=this.mj},function(){var a=this.K(),b=this.G;this.Nd(this.C.Yb(a,1),b);this.A-=this.mj},function(){var a=1,b=0,c=this.nj;this.wa&192&&(a=this.I,b=1,c=this.pj,this.wa&256||(this.A-=this.oj));if(a--){var d=this.xa&1024?-1:1,e=this.T(this.C,this.F);this.bd(this.Za.Yb(this.D,0),e);this.F=this.F+d&65535;this.D=this.D+d&65535;this.A-=c;this.I-=b;a&&(J(this,this.wa&16?-3:-2),this.$|=
-256)}},function(){var a=1,b=0,c=this.nj;this.wa&192&&(a=this.I,b=1,c=this.pj,this.wa&256||(this.A-=this.oj));if(a--){var d=this.xa&1024?-2:2,e=this.U(this.C,this.F);this.Nd(this.Za.Yb(this.D,1),e);this.F=this.F+d&65535;this.D=this.D+d&65535;this.A-=c;this.I-=b;a&&(J(this,this.wa&16?-3:-2),this.$|=256)}},function(){var a=1,b=0,c=this.Yi;this.wa&192&&(a=this.I,b=1,c=this.$i,this.wa&256||(this.A-=this.Zi));if(a--){var d=this.xa&1024?-1:1,e=this.T(this.C,this.F),f=this.N(this.Za,this.D);vd.call(this,
-e,f);this.F=this.F+d&65535;this.D=this.D+d&65535;this.A-=c-this.sb;this.I-=b;a&&Xc(this)==(this.wa&64)&&(J(this,this.wa&16?-3:-2),this.$|=256)}},function(){var a=1,b=0,c=this.Yi;this.wa&192&&(a=this.I,b=1,c=this.$i,this.wa&256||(this.A-=this.Zi));if(a--){var d=this.xa&1024?-2:2,e=this.U(this.C,this.F),f=this.O(this.Za,this.D);Dd.call(this,e,f);this.F=this.F+d&65535;this.D=this.D+d&65535;this.A-=c-this.sb;this.I-=b;a&&Xc(this)==(this.wa&64)&&(J(this,this.wa&16?-3:-2),this.$|=256)}},function(){this.Z=
-this.ja=this.ma=this.G&255&this.ea();this.da=256;this.A-=this.Ie},function(){this.Z=this.ja=this.ma=this.G&this.K();this.da=65536;this.A-=this.Ie},function(){var a=1,b=0,c=this.yj;this.wa&192&&(a=this.I,b=1,c=this.Aj,this.wa&256||(this.A-=this.zj));if(a--){var d=this.G;this.bd(this.Za.Yb(this.D,0),d);this.D=this.D+(this.xa&1024?-1:1)&65535;this.A-=c;this.I-=b;a&&(J(this,-2),this.$|=256)}},function(){var a=1,b=0,c=this.yj;this.wa&192&&(a=this.I,b=1,c=this.Aj,this.wa&256||(this.A-=this.zj));if(a--){var d=
-this.G;this.Nd(this.Za.Yb(this.D,1),d);this.D=this.D+(this.xa&1024?-2:2)&65535;this.A-=c;this.I-=b;a&&(J(this,-2),this.$|=256)}},function(){var a=1,b=0,c=this.fj;this.wa&192&&(a=this.I,b=1,c=this.hj,this.wa&256||(this.A-=this.gj));a--&&(this.G=this.G&-256|this.T(this.C,this.F),this.F=this.F+(this.xa&1024?-1:1)&65535,this.A-=c,this.I-=b,a&&(J(this,this.wa&16?-3:-2),this.$|=256))},function(){var a=1,b=0,c=this.fj;this.wa&192&&(a=this.I,b=1,c=this.hj,this.wa&256||(this.A-=this.gj));a--&&(this.G=this.U(this.C,
-this.F),this.F=this.F+(this.xa&1024?-2:2)&65535,this.A-=c,this.I-=b,a&&(J(this,this.wa&16?-3:-2),this.$|=256))},function(){var a=1,b=0,c=this.sj;this.wa&192&&(a=this.I,b=1,c=this.uj,this.wa&256||(this.A-=this.tj));a--&&(vd.call(this,this.G&255,this.N(this.Za,this.D)),this.D=this.D+(this.xa&1024?-1:1)&65535,this.A-=c-this.sb,this.I-=b,a&&Xc(this)==(this.wa&64)&&(J(this,-2),this.$|=256))},function(){var a=1,b=0,c=this.sj;this.wa&192&&(a=this.I,b=1,c=this.uj,this.wa&256||(this.A-=this.tj));a--&&(Dd.call(this,
+this.A-=3},function(){var a=this.G;this.G=this.J;this.J=a;this.A-=3},function(){var a=this.G;this.G=this.B;this.B=a;this.A-=3},function(){var a=this.G;this.G=this.Y;this.Y=a;this.A-=3},function(){var a=this.G;this.G=this.H;this.H=a;this.A-=3},function(){var a=this.G;this.G=this.F;this.F=a;this.A-=3},function(){var a=this.G;this.G=this.D;this.D=a;this.A-=3},function(){this.G=this.G<<24>>24&65535;this.A-=2},function(){this.J=this.G&32768?65535:0;this.A-=this.Xk},function(){var a=this.K(),b=this.K();
+K(this,this.ua.oa);K(this,this.qa);yc(this,a,b);this.A-=this.$k},function(){M.call(this)},function(){K(this,Bc(this));this.A-=this.qc},function(){zc(this,this.Ja());this.A-=this.ic},function(){var a=this.G>>8;a&1?ed(this):$c(this);a&4?Vc(this)||(this.ja^=1):Vc(this)&&(this.ja^=1);a&16?fd(this):ad(this);a&64?gd(this):bd(this);a&128?hd(this):cd(this);this.A-=this.Cb},function(){this.G=this.G&255|(Bc(this)&213)<<8;this.A-=this.Cb},function(){this.G=this.G&-256|this.T(this.C,this.K());this.A-=this.oj},
+function(){this.G=this.U(this.C,this.K());this.A-=this.oj},function(){var a=this.K(),b=this.G;this.bd(this.C.Yb(a,0),b);this.A-=this.pj},function(){var a=this.K(),b=this.G;this.Nd(this.C.Yb(a,1),b);this.A-=this.pj},function(){var a=1,b=0,c=this.qj;this.wa&192&&(a=this.I,b=1,c=this.sj,this.wa&256||(this.A-=this.rj));if(a--){var d=this.xa&1024?-1:1,e=this.T(this.C,this.F);this.bd(this.Za.Yb(this.D,0),e);this.F=this.F+d&65535;this.D=this.D+d&65535;this.A-=c;this.I-=b;a&&(J(this,this.wa&16?-3:-2),this.$|=
+256)}},function(){var a=1,b=0,c=this.qj;this.wa&192&&(a=this.I,b=1,c=this.sj,this.wa&256||(this.A-=this.rj));if(a--){var d=this.xa&1024?-2:2,e=this.U(this.C,this.F);this.Nd(this.Za.Yb(this.D,1),e);this.F=this.F+d&65535;this.D=this.D+d&65535;this.A-=c;this.I-=b;a&&(J(this,this.wa&16?-3:-2),this.$|=256)}},function(){var a=1,b=0,c=this.aj;this.wa&192&&(a=this.I,b=1,c=this.cj,this.wa&256||(this.A-=this.bj));if(a--){var d=this.xa&1024?-1:1,e=this.T(this.C,this.F),f=this.N(this.Za,this.D);vd.call(this,
+e,f);this.F=this.F+d&65535;this.D=this.D+d&65535;this.A-=c-this.sb;this.I-=b;a&&Xc(this)==(this.wa&64)&&(J(this,this.wa&16?-3:-2),this.$|=256)}},function(){var a=1,b=0,c=this.aj;this.wa&192&&(a=this.I,b=1,c=this.cj,this.wa&256||(this.A-=this.bj));if(a--){var d=this.xa&1024?-2:2,e=this.U(this.C,this.F),f=this.O(this.Za,this.D);Dd.call(this,e,f);this.F=this.F+d&65535;this.D=this.D+d&65535;this.A-=c-this.sb;this.I-=b;a&&Xc(this)==(this.wa&64)&&(J(this,this.wa&16?-3:-2),this.$|=256)}},function(){this.Z=
+this.ja=this.ma=this.G&255&this.ea();this.da=256;this.A-=this.Ie},function(){this.Z=this.ja=this.ma=this.G&this.K();this.da=65536;this.A-=this.Ie},function(){var a=1,b=0,c=this.Bj;this.wa&192&&(a=this.I,b=1,c=this.Dj,this.wa&256||(this.A-=this.Cj));if(a--){var d=this.G;this.bd(this.Za.Yb(this.D,0),d);this.D=this.D+(this.xa&1024?-1:1)&65535;this.A-=c;this.I-=b;a&&(J(this,-2),this.$|=256)}},function(){var a=1,b=0,c=this.Bj;this.wa&192&&(a=this.I,b=1,c=this.Dj,this.wa&256||(this.A-=this.Cj));if(a--){var d=
+this.G;this.Nd(this.Za.Yb(this.D,1),d);this.D=this.D+(this.xa&1024?-2:2)&65535;this.A-=c;this.I-=b;a&&(J(this,-2),this.$|=256)}},function(){var a=1,b=0,c=this.ij;this.wa&192&&(a=this.I,b=1,c=this.kj,this.wa&256||(this.A-=this.jj));a--&&(this.G=this.G&-256|this.T(this.C,this.F),this.F=this.F+(this.xa&1024?-1:1)&65535,this.A-=c,this.I-=b,a&&(J(this,this.wa&16?-3:-2),this.$|=256))},function(){var a=1,b=0,c=this.ij;this.wa&192&&(a=this.I,b=1,c=this.kj,this.wa&256||(this.A-=this.jj));a--&&(this.G=this.U(this.C,
+this.F),this.F=this.F+(this.xa&1024?-2:2)&65535,this.A-=c,this.I-=b,a&&(J(this,this.wa&16?-3:-2),this.$|=256))},function(){var a=1,b=0,c=this.vj;this.wa&192&&(a=this.I,b=1,c=this.xj,this.wa&256||(this.A-=this.wj));a--&&(vd.call(this,this.G&255,this.N(this.Za,this.D)),this.D=this.D+(this.xa&1024?-1:1)&65535,this.A-=c-this.sb,this.I-=b,a&&Xc(this)==(this.wa&64)&&(J(this,-2),this.$|=256))},function(){var a=1,b=0,c=this.vj;this.wa&192&&(a=this.I,b=1,c=this.xj,this.wa&256||(this.A-=this.wj));a--&&(Dd.call(this,
this.G,this.O(this.Za,this.D)),this.D=this.D+(this.xa&1024?-2:2)&65535,this.A-=c-this.sb,this.I-=b,a&&Xc(this)==(this.wa&64)&&(J(this,-2),this.$|=256))},function(){this.G=this.G&-256|this.ea();this.A-=this.Cb},function(){this.I=this.I&-256|this.ea();this.A-=this.Cb},function(){this.J=this.J&-256|this.ea();this.A-=this.Cb},function(){this.B=this.B&-256|this.ea();this.A-=this.Cb},function(){this.G=this.G&255|this.ea()<<8;this.A-=this.Cb},function(){this.I=this.I&255|this.ea()<<8;this.A-=this.Cb},function(){this.J=
this.J&255|this.ea()<<8;this.A-=this.Cb},function(){this.B=this.B&255|this.ea()<<8;this.A-=this.Cb},function(){this.G=this.K();this.A-=this.Cb},function(){this.I=this.K();this.A-=this.Cb},function(){this.J=this.K();this.A-=this.Cb},function(){this.B=this.K();this.A-=this.Cb},function(){this.Y=this.K();this.A-=this.Cb},function(){this.H=this.K();this.A-=this.Cb},function(){this.F=this.K();this.A-=this.Cb},function(){this.D=this.K();this.A-=this.Cb},vh,wh,vh,wh,function(){N[this.ea()].call(this,ue)},
-function(){N[this.ea()].call(this,te)},function(){this.$|=1;ah[this.ea()].call(this,de,this.ea)},function(){this.$|=1;bh[this.ea()].call(this,de,this.K)},xh,yh,xh,yh,function(){ld.call(this,3,null,this.nl)},function(){var a=this.ea();Dc(this,a)?ld.call(this,a,null,0):this.A--},function(){Zc(this)?ld.call(this,4,null,this.ol):this.A-=this.pl},function(){yc(this,this.Ja(),this.Ja());zc(this,this.Ja());this.ah&&Hc(this,this.Ba);this.A-=this.ll},function(){ah[this.ea()].call(this,ee,Td)},function(){bh[this.ea()].call(this,
-fe,Td)},function(){ah[this.ea()].call(this,ee,Ud)},function(){bh[this.ea()].call(this,fe,Ud)},function(){var a=this.ea(),b=this.G&255;this.G=(b/a&255)<<8|b%a;this.da=256;this.Z=this.ja=b;this.A-=this.Rk},function(){var a=this.ea();this.Z=this.ja=this.G=(this.G>>8)*a+this.G&255;this.da=256;this.A-=this.Qk},function(){this.G=this.G&-256|(Uc(this)?255:0);this.A-=2},function(){this.G=this.G&-256|this.T(this.C,this.B+(this.G&255)&65535);this.A-=this.Pl},zh,zh,zh,zh,zh,zh,zh,zh,function(){var a=this.L();
-(this.I=this.I-1&65535)&&this.Z&this.da-1?(I(this,this.qa+a),this.A-=this.wl):this.A-=this.ij},function(){var a=this.L();!(this.I=this.I-1&65535)||this.Z&this.da-1?this.A-=this.kj:(I(this,this.qa+a),this.A-=this.jj)},function(){var a=this.L();(this.I=this.I-1&65535)?(I(this,this.qa+a),this.A-=this.vl):this.A-=this.ij},function(){var a=this.L();this.I?this.A-=this.kj:(I(this,this.qa+a),this.A-=this.jj)},function(){var a=this.ea();this.G=this.G&-256|jb(this.na,a,this.Ba-2);this.A-=this.cj},function(){var a=
-this.ea();this.G=jb(this.na,a,this.Ba-1)|jb(this.na,a+1&65535,this.Ba-2)<<8;this.A-=this.cj},function(){var a=this.ea();nb(this.na,a,this.G&255,this.Ba-2);this.A-=this.rj},function(){var a=this.ea();nb(this.na,a,this.G&255,this.Ba-2);nb(this.na,a+1&65535,this.G>>8,this.Ba-2);this.A-=this.rj},function(){var a=this.K();K(this,this.qa);I(this,this.qa+a);this.A-=this.Vk},function(){var a=this.K();I(this,this.qa+a);this.A-=this.dj},function(){yc(this,this.K(),this.K());this.A-=this.rl},function(){var a=
-this.L();I(this,this.qa+a);this.A-=this.dj},function(){this.G=this.G&-256|jb(this.na,this.J,this.Ba-1);this.A-=this.bj},function(){this.G=jb(this.na,this.J,this.Ba-1)|jb(this.na,this.J+1&65535,this.Ba-1)<<8;this.A-=this.bj},function(){nb(this.na,this.J,this.G&255,this.Ba-1);this.A-=this.qj},function(){nb(this.na,this.J,this.G&255,this.Ba-1);nb(this.na,this.J+1&65535,this.G>>8,this.Ba-1);this.A-=this.qj},Ah,Ah,function(){this.$|=132;this.A-=this.Pb},function(){this.$|=68;this.A-=this.Pb},function(){this.nb|=
-4;this.A-=2;this.X&&jd(this.X)?(J(this,-1),this.Ab()):this.xa&512||(this.X&&J(this,-1),this.Ab())},function(){Uc(this)?$c(this):ed(this);this.A-=2},function(){this.Db=-1;ah[this.ea()].call(this,he,Wd);0<=this.Db&&(this.G=this.Db)},function(){this.Db=-1;bh[this.ea()].call(this,ie,Wd);0<=this.Db&&(this.G=this.Db,this.J=this.ug)},function(){this.Z&=~this.da;this.A-=2},function(){this.Z|=this.da;this.A-=2},function(){this.xa&=-513;this.A-=this.Tk},function(){this.xa|=512;this.$|=4;this.A-=2},function(){this.xa&=
+function(){N[this.ea()].call(this,te)},function(){this.$|=1;ah[this.ea()].call(this,de,this.ea)},function(){this.$|=1;bh[this.ea()].call(this,de,this.K)},xh,yh,xh,yh,function(){ld.call(this,3,null,this.ql)},function(){var a=this.ea();Dc(this,a)?ld.call(this,a,null,0):this.A--},function(){Zc(this)?ld.call(this,4,null,this.rl):this.A-=this.sl},function(){yc(this,this.Ja(),this.Ja());zc(this,this.Ja());this.ah&&Hc(this,this.Ba);this.A-=this.ol},function(){ah[this.ea()].call(this,ee,Td)},function(){bh[this.ea()].call(this,
+fe,Td)},function(){ah[this.ea()].call(this,ee,Ud)},function(){bh[this.ea()].call(this,fe,Ud)},function(){var a=this.ea(),b=this.G&255;this.G=(b/a&255)<<8|b%a;this.da=256;this.Z=this.ja=b;this.A-=this.Uk},function(){var a=this.ea();this.Z=this.ja=this.G=(this.G>>8)*a+this.G&255;this.da=256;this.A-=this.Tk},function(){this.G=this.G&-256|(Uc(this)?255:0);this.A-=2},function(){this.G=this.G&-256|this.T(this.C,this.B+(this.G&255)&65535);this.A-=this.Sl},zh,zh,zh,zh,zh,zh,zh,zh,function(){var a=this.L();
+(this.I=this.I-1&65535)&&this.Z&this.da-1?(I(this,this.qa+a),this.A-=this.zl):this.A-=this.lj},function(){var a=this.L();!(this.I=this.I-1&65535)||this.Z&this.da-1?this.A-=this.nj:(I(this,this.qa+a),this.A-=this.mj)},function(){var a=this.L();(this.I=this.I-1&65535)?(I(this,this.qa+a),this.A-=this.yl):this.A-=this.lj},function(){var a=this.L();this.I?this.A-=this.nj:(I(this,this.qa+a),this.A-=this.mj)},function(){var a=this.ea();this.G=this.G&-256|jb(this.na,a,this.Ba-2);this.A-=this.fj},function(){var a=
+this.ea();this.G=jb(this.na,a,this.Ba-1)|jb(this.na,a+1&65535,this.Ba-2)<<8;this.A-=this.fj},function(){var a=this.ea();nb(this.na,a,this.G&255,this.Ba-2);this.A-=this.uj},function(){var a=this.ea();nb(this.na,a,this.G&255,this.Ba-2);nb(this.na,a+1&65535,this.G>>8,this.Ba-2);this.A-=this.uj},function(){var a=this.K();K(this,this.qa);I(this,this.qa+a);this.A-=this.Yk},function(){var a=this.K();I(this,this.qa+a);this.A-=this.gj},function(){yc(this,this.K(),this.K());this.A-=this.ul},function(){var a=
+this.L();I(this,this.qa+a);this.A-=this.gj},function(){this.G=this.G&-256|jb(this.na,this.J,this.Ba-1);this.A-=this.ej},function(){this.G=jb(this.na,this.J,this.Ba-1)|jb(this.na,this.J+1&65535,this.Ba-1)<<8;this.A-=this.ej},function(){nb(this.na,this.J,this.G&255,this.Ba-1);this.A-=this.tj},function(){nb(this.na,this.J,this.G&255,this.Ba-1);nb(this.na,this.J+1&65535,this.G>>8,this.Ba-1);this.A-=this.tj},Ah,Ah,function(){this.$|=132;this.A-=this.Pb},function(){this.$|=68;this.A-=this.Pb},function(){this.mb|=
+4;this.A-=2;this.X&&jd(this.X)?(J(this,-1),this.Ab()):this.xa&512||(this.X&&J(this,-1),this.Ab())},function(){Uc(this)?$c(this):ed(this);this.A-=2},function(){this.Db=-1;ah[this.ea()].call(this,he,Wd);0<=this.Db&&(this.G=this.Db)},function(){this.Db=-1;bh[this.ea()].call(this,ie,Wd);0<=this.Db&&(this.G=this.Db,this.J=this.ug)},function(){this.Z&=~this.da;this.A-=2},function(){this.Z|=this.da;this.A-=2},function(){this.xa&=-513;this.A-=this.Wk},function(){this.xa|=512;this.$|=4;this.A-=2},function(){this.xa&=
-1025;this.A-=2},function(){this.xa|=1024;this.A-=2},function(){ah[this.ea()].call(this,rc,Wd)},function(){bh[this.ea()].call(this,tc,Wd)}];
-function O(a){x.call(this,"ChipSet",a,O);this.Fa=a.model;this.Fa=void 0!==this.Fa?parseInt(this.Fa,10):Bh;this.Xb=0;var b=a.sw1;if(b)this.Xb=Ch(b,Dh|Eh.vm);else if(b=a.fdrives||2,this.Xb|=Fh.Uh,b--,this.Xb|=(b&3)<=Gh&&(this.Pf=this.Qf=2);this.oh=a.scaleTimers||!1;this.mp=a.rtcDate;this.Ak=!1;a.sound&&window&&"webkitAudioContext"in window&&
-(this.mi=new webkitAudioContext);this.reset();this.Ta()}y(x,O);var Bh=5150,Gh=5170,Hh={none:0,tv:1,color:2,mono:3,ega:0},Fh={Uh:1,ONE:0,Rp:64,Pp:128,yp:192,Bf:192,Df:6},Dh=12,Eh={Qp:16,tp:32,vm:48,Bf:48,Df:4};k=O.prototype;
+function O(a){x.call(this,"ChipSet",a,O);this.Fa=a.model;this.Fa=void 0!==this.Fa?parseInt(this.Fa,10):Bh;this.Xb=0;var b=a.sw1;if(b)this.Xb=Ch(b,Dh|Eh.ym);else if(b=a.fdrives||2,this.Xb|=Fh.Wh,b--,this.Xb|=(b&3)<=Gh&&(this.Pf=this.Qf=2);this.oh=a.scaleTimers||!1;this.pp=a.rtcDate;this.Dk=!1;a.sound&&window&&"webkitAudioContext"in window&&
+(this.oi=new webkitAudioContext);this.reset();this.Ta()}y(x,O);var Bh=5150,Gh=5170,Hh={none:0,tv:1,color:2,mono:3,ega:0},Fh={Wh:1,ONE:0,Up:64,Sp:128,Bp:192,Bf:192,Df:6},Dh=12,Eh={Tp:16,wp:32,ym:48,Bf:48,Df:4};k=O.prototype;
k.xb=function(a,b,c,d){switch(c){case "sw1":return this.sa[c]=d,Ih(this,c,d,this.Xb,{0:this.Fa==Bh?"Bootable Floppy Drive":"Loop on POST",1:this.Fa==Bh?"Reserved":"Coprocessor",2:"Base Memory Size",4:"Monitor Type",6:"Number of Floppy Drives"}),!0;case "sw2":if(this.Fa==Bh)return this.sa[c]=d,Ih(this,c,d,this.pe,{0:"Expansion Memory Size",4:"Reserved"}),!0;break;case "swdesc":return this.sa[c]=d,!0}return!1};
-k.nc=function(a,b,c,d){this.na=b;this.S=c;this.X=d;this.Da=a;this.bb=C(a,"Keyboard");this.Ql=Math.round(c.Hd/1193181);ib(b,this,Jh);mb(b,this,Kh);this.Fab;b++){var c=13>=b?Sh(e,b):e.pa[b];a&&(a+="\n");a+="CMOS[0x"+r(b)+"]: 0x"+r(c)}e.X.message(a)})}Cc(c,26,this,this.Nn)};k.$b=function(a,b){if(!b)if(!a)this.reset(!0);else if(!this.restore(a))return!1;return!0};k.Wb=function(a){return a&&this.save?this.save():!0};
-k.reset=function(a){var b;this.cd=this.Xb;this.Qe=this.pe;Th(this);this.$a=Array(this.Pf);for(b=0;b=Gh){this.kb=16;this.ud=0;this.Xd=16;this.Rg=0;this.ve=160;512<=Xh(this)&&(this.ve|=16);3==Yh(this)&&(this.ve|=64);this.fi=3;this.Mf=0;this.Ng=Array(7);this.we=0;a||(this.pa=Array(64));
-Zh(this,this.mp);for(a=14;46>a;a++)void 0===this.pa[a]&&(this.pa[a]=0);this.pa[20]=this.cd&(Eh.Bf|2|Fh.Uh|Fh.Bf);this.pa[16]=$h(this,0)<<4|$h(this,1);ai(this)}};
+k.pc=function(a,b,c,d){this.na=b;this.S=c;this.X=d;this.Da=a;this.bb=C(a,"Keyboard");this.Tl=Math.round(c.Hd/1193181);ib(b,this,Jh);mb(b,this,Kh);this.Fab;b++){var c=13>=b?Sh(e,b):e.pa[b];a&&(a+="\n");a+="CMOS[0x"+r(b)+"]: 0x"+r(c)}e.X.message(a)})}Cc(c,26,this,this.Qn)};k.ac=function(a,b){if(!b)if(!a)this.reset(!0);else if(!this.restore(a))return!1;return!0};k.Wb=function(a){return a&&this.save?this.save():!0};
+k.reset=function(a){var b;this.cd=this.Xb;this.Qe=this.pe;Th(this);this.$a=Array(this.Pf);for(b=0;b=Gh){this.jb=16;this.ud=0;this.Xd=16;this.Rg=0;this.ve=160;512<=Xh(this)&&(this.ve|=16);3==Yh(this)&&(this.ve|=64);this.hi=3;this.Mf=0;this.Ng=Array(7);this.we=0;a||(this.pa=Array(64));
+Zh(this,this.pp);for(a=14;46>a;a++)void 0===this.pa[a]&&(this.pa[a]=0);this.pa[20]=this.cd&(Eh.Bf|2|Fh.Wh|Fh.Bf);this.pa[16]=$h(this,0)<<4|$h(this,1);ai(this)}};
function Zh(a,b){var c=b?new Date(b):new Date;"[object Date]"!==Object.prototype.toString.call(c)||isNaN(c.getTime())?(c=new Date,a.ca("CMOS date invalid ("+b+"), using "+c)):b&&a.ca("CMOS date: "+c);a.pa[0]=c.getSeconds();a.pa[1]=0;a.pa[2]=c.getMinutes();a.pa[3]=0;a.pa[4]=c.getHours();a.pa[5]=0;a.pa[6]=c.getDay()+1;a.pa[7]=c.getDate();a.pa[8]=c.getMonth()+1;c=c.getFullYear();a.pa[9]=c%100;c/=100;a.pa[50]=c%10|c/10<<4;a.eg=-1;a.pa[10]=38;a.pa[11]=2;a.pa[12]=0;a.pa[13]=128}
function Sh(a,b){var c=a.pa[b];if(10>b){var d=!1;4!=b&&5!=b||a.pa[11]&2||(c=12>c?c?c:12:(c-=12)?c+128:140,d=!0);a.pa[11]&4||(d&&128c;c++)b+=a.pa[c];a.pa[47]=b&255;a.pa[46]=b>>8}
-k.save=function(){var a=new H(this);a.set(0,[this.Xb,this.pe,this.cd,this.Qe]);for(var b=[],c=0;c=Gh&&(a.set(5,[this.kb,this.ud,this.Xd,this.Rg,this.ve,this.fi]),a.set(6,[this.Mf,this.Ng,this.we,this.pa,this.eg]));return a.data()};
-k.restore=function(a){var b,c;b=a[0];this.Xb=b[0];this.pe=b[1];this.cd=b[2];this.Qe=b[3];b=a[1];this.$a=Array(this.Pf);for(c=0;c>2)+1)*a.Qn+32*((b?a.pe:a.Qe)&15)}function di(a,b){var c=b?a.Xb:a.cd;return a.Fa!=Bh||c&Fh.Uh?((c&Fh.Bf)>>Fh.Df)+1:0}function $h(a,b){return b>Eh.Df}
+k.save=function(){var a=new H(this);a.set(0,[this.Xb,this.pe,this.cd,this.Qe]);for(var b=[],c=0;c=Gh&&(a.set(5,[this.jb,this.ud,this.Xd,this.Rg,this.ve,this.hi]),a.set(6,[this.Mf,this.Ng,this.we,this.pa,this.eg]));return a.data()};
+k.restore=function(a){var b,c;b=a[0];this.Xb=b[0];this.pe=b[1];this.cd=b[2];this.Qe=b[3];b=a[1];this.$a=Array(this.Pf);for(c=0;c>2)+1)*a.Tn+32*((b?a.pe:a.Qe)&15)}function di(a,b){var c=b?a.Xb:a.cd;return a.Fa!=Bh||c&Fh.Wh?((c&Fh.Bf)>>Fh.Df)+1:0}function $h(a,b){return b>Eh.Df}
function Ih(a,b,c,d,e){for(var f="",g=1;8>=g;g++){var h="pcjs-bitCell";g||(h+=" pcjs-bitCellLeft");f+=''+g+"\n"}c.innerHTML=f;b=B(c,"pcjs-bitCell");c=null;for(g=0;g>2].Gb[b&3],c,d,e)}function mi(a,b,c){b=a.$a[b>>2].Gb[b&3];b.dh&&b.Gi&&b.Eh?(c&&(b.fh=c),b.Fd||md(a,b,!0)):c&&c(!0)}
-function md(a,b,c){c&&(b.count=b.Zb[1]<<8|b.Zb[0],b.jm=b.mode&12,b.Bk=b.jd=!1);for(var d=!1;0<=b.count&&(c=b.Xg<<16|b.Rb[1]<<8|b.Rb[0],4==b.jm?(d=!0,function(c){b.Gi.call(b.dh,b.Eh,-1,function(f,g){0>f&&(b.Bk||(b.Bk=!0),f=255);b.Fd||db(a.na,c,f);(d=g)&&setTimeout(function(){ti(b)||md(a,b)},0)})}(c)):8==b.jm?(c=bb(a.na,c),0>b.Gi.call(b.dh,b.Eh,c)&&(b.jd=!0)):b.jd=!0),!d&&!ti(b););}
-function ti(a){if(!a.jd&&0<=--a.count&&(a.mode&32?(a.Rb[0]--,0>a.Rb[0]&&(a.Rb[0]=255,a.Rb[1]--,0>a.Rb[1]&&(a.Rb[1]=255))):(a.Rb[0]++,255>2].Gb[b&3],c,d,e)}function mi(a,b,c){b=a.$a[b>>2].Gb[b&3];b.dh&&b.Ii&&b.Gh?(c&&(b.fh=c),b.Fd||md(a,b,!0)):c&&c(!0)}
+function md(a,b,c){c&&(b.count=b.Zb[1]<<8|b.Zb[0],b.mm=b.mode&12,b.Ek=b.jd=!1);for(var d=!1;0<=b.count&&(c=b.Xg<<16|b.Rb[1]<<8|b.Rb[0],4==b.mm?(d=!0,function(c){b.Ii.call(b.dh,b.Gh,-1,function(f,g){0>f&&(b.Ek||(b.Ek=!0),f=255);b.Fd||db(a.na,c,f);(d=g)&&setTimeout(function(){ti(b)||md(a,b)},0)})}(c)):8==b.mm?(c=bb(a.na,c),0>b.Ii.call(b.dh,b.Gh,c)&&(b.jd=!0)):b.jd=!0),!d&&!ti(b););}
+function ti(a){if(!a.jd&&0<=--a.count&&(a.mode&32?(a.Rb[0]--,0>a.Rb[0]&&(a.Rb[0]=255,a.Rb[1]--,0>a.Rb[1]&&(a.Rb[1]=255))):(a.Rb[0]++,255>3,e=a.tb[d];e.Jb|=1<<(b&7);e.jg=c||0;1==d&&(a.tb[0].Jb|=4);wi(a,d)}
+function yi(a,b,c,d){var e=a.tb[b];a.ba(e.port+1,c,d,"PIC"+b,O.Te);e.Id>3,e=a.tb[d];e.Jb|=1<<(b&7);e.jg=c||0;1==d&&(a.tb[0].Jb|=4);wi(a,d)}
function Ai(a,b){var c=b>>3,d=a.tb[c],e=1<<(b&7);d.Jb&e&&(d.Jb&=~e,1!=c||d.Jb||(a.tb[0].Jb&=-5),wi(a,c))}function kd(a,b){void 0===b&&(b=0);var c=-1,d=a.tb[b];if(d.jg)c=-2,d.jg--;else for(var e=d.Jb&((d.Fc|d.vd)^255),f=d.xe+1;;){var f=f&7,g=1<>6;if(3!=a){c=b&1;var d=b&14;if(b&=48){var e=this.Hb[a];e.vg=b;e.mode=d;e.nk=c;e.Ic=[0,0];e.Zb=[0,0];e.Vf=[0,0];e.kd=!1;e.Yf=!1;e.df=!1;Ci(this,a);0==a&&Ai(this,0);2==a&&255==this.tb[0].vd&&77==this.Ac&&(a=this.Hb[0],a.Yc[0]=a.Ic[0],a.Yc[1]=a.Ic[1],a.me=F(this.S,this.oh))}else Rh(this,a),b=this.Hb[a],b.Vf[0]=b.Zb[0],b.Vf[1]=b.Zb[1],b.Yf=!0,Ci(this,a)}};
+function Di(a,b,c,d){a.ba(64+b,c,d,"TIMER"+b,O.Ue);d=a.Hb[b];d.de==d.gd&&Ci(a,b);d.Ic[d.de++]=c;if(d.de==d.gd){d.df&&0!=d.mode&&8!=d.mode||(d.Yf=!1,d.Zb[0]=d.Yc[0]=d.Ic[0],d.Zb[1]=d.Yc[1]=d.Ic[1],d.me=F(a.S,a.oh),d.df=!0,d.kd=0!=d.mode,0==b&&Ai(a,0));2==b&&Kb(a);if(0==b){var e=Ei(a,0);2048<=e&&(a.S.zh=Math.round(65536/e))}0==b&&0==d.mode&&16==d.vg&&(b=a.S,b.Ob&&(a=b.A-c*a.Tl,b.A-=a,b.Oc-=a))}}k.Kn=function(a,b){this.ba(a,null,b,"TIMER_CTRL",O.Ue);return null};
+k.bp=function(a,b,c){this.ba(a,b,c,"TIMER_CTRL",O.Ue);this.li=b;a=(b&192)>>6;if(3!=a){c=b&1;var d=b&14;if(b&=48){var e=this.Hb[a];e.vg=b;e.mode=d;e.qk=c;e.Ic=[0,0];e.Zb=[0,0];e.Vf=[0,0];e.kd=!1;e.Yf=!1;e.df=!1;Ci(this,a);0==a&&Ai(this,0);2==a&&255==this.tb[0].vd&&77==this.Ac&&(a=this.Hb[0],a.Yc[0]=a.Ic[0],a.Yc[1]=a.Ic[1],a.me=F(this.S,this.oh))}else Rh(this,a),b=this.Hb[a],b.Vf[0]=b.Zb[0],b.Vf[1]=b.Zb[1],b.Yf=!0,Ci(this,a)}};
function Ei(a,b){var c=a.Hb[b],d=c.Ic[1]<<8|c.Ic[0];d||(d=1==c.gd?256:65536);return d}function Ci(a,b){var c=a.Hb[b];c.de=32==c.vg?1:0;c.gd=48==c.vg?2:1}
-function Rh(a,b,c){var d=a.Hb[b];if(d.df&&(2!=b||a.Ac&1)){var e=F(a.S,a.oh),f=(e-d.me)/a.Ql|0;0>f&&(d.me=e,f=0);var g=Ei(a,b),h=a.Hb[b],m=h.Yc[1]<<8|h.Yc[0];m||(m=1==h.gd?256:65536);h=m-f;0==d.mode?(0>=h&&(h=0),h||(d.kd=!0,d.df=!1,b||zi(a,0))):4==d.mode?(d.kd=1!=h,0>=h&&(h=g+h,0>=h&&(h=g),d.Yc[0]=h&255,d.Yc[1]=h>>8,d.me=e,!b&&d.kd&&zi(a,0))):6==d.mode&&(h-=f,0>=h&&(d.kd=!d.kd,h=g+h,0>=h&&(h=g),d.Yc[0]=h&255,d.Yc[1]=h>>8,d.me=e,!b&&d.kd&&zi(a,0)));d.Zb[0]=h&255;d.Zb[1]=h>>8;c&&(a.me=0)}return d}
+function Rh(a,b,c){var d=a.Hb[b];if(d.df&&(2!=b||a.Ac&1)){var e=F(a.S,a.oh),f=(e-d.me)/a.Tl|0;0>f&&(d.me=e,f=0);var g=Ei(a,b),h=a.Hb[b],m=h.Yc[1]<<8|h.Yc[0];m||(m=1==h.gd?256:65536);h=m-f;0==d.mode?(0>=h&&(h=0),h||(d.kd=!0,d.df=!1,b||zi(a,0))):4==d.mode?(d.kd=1!=h,0>=h&&(h=g+h,0>=h&&(h=g),d.Yc[0]=h&255,d.Yc[1]=h>>8,d.me=e,!b&&d.kd&&zi(a,0))):6==d.mode&&(h-=f,0>=h&&(d.kd=!d.kd,h=g+h,0>=h&&(h=g),d.Yc[0]=h&255,d.Yc[1]=h>>8,d.me=e,!b&&d.kd&&zi(a,0)));d.Zb[0]=h&255;d.Zb[1]=h>>8;c&&(a.me=0)}return d}
function Lb(a,b){for(var c=0;c=Gh){var c=0,d=a.S.Hd,e=F(a.S,a.oh);if(0<=a.eg&&(c=e-a.eg,Math.floor(c/d)&&60<=++a.pa[0]&&(a.pa[0]=0,60<=++a.pa[2]&&(a.pa[2]=0,24<=++a.pa[4])))){a.pa[4]=0;a.pa[6]=a.pa[6]%7+1;var f=a.pa[9],g=qa[a.pa[8]-1];28==g&&0===f%4&&(f%100||0===f%400)&&g++;++a.pa[7]>g&&(a.pa[7]=1,12<++a.pa[8]&&(a.pa[8]=1,a.pa[9]=(a.pa[9]+1)%100))}a.eg=e-c%d}}
-k.zn=function(a,b){var c=this.Wg;this.Of&16&&(this.Ac&128?c=this.cd:this.bb&&(c=Fi(this.bb)));this.ba(a,null,b,"PPI_A",O.uc,c);return c};k.So=function(a,b,c){this.ba(a,b,c,"PPI_A",O.uc);this.Wg=b};k.An=function(a,b){var c=this.Ac;this.ba(a,null,b,"PPI_B",O.uc,c);return c};k.To=function(a,b,c){this.ba(a,b,c,"PPI_B",O.uc);Gi(this,b);this.bb&&Hi(this.bb,b&128?!1:!0,b&64?!0:!1)};function Gi(a,b){var c=!!(b&2),d=!!(a.Ac&2);a.Ac=b;c!=d&&Kb(a,c)}
-k.Bn=function(a,b){var c=0,c=this.Fa==Bh?this.Ac&4?c|this.Qe&15:c|this.Qe>>4&1:this.Ac&8?c|this.cd>>4:c|this.cd&15;this.Ac&1&&Rh(this,2).kd&&(c=this.Ac&2?c|32:c|16);this.ba(a,null,b,"PPI_C",O.uc|O.Fg,c);return c};k.Uo=function(a,b,c){this.ba(a,b,c,"PPI_C",O.uc);this.hi=b};k.Cn=function(a,b){var c=this.Of;this.ba(a,null,b,"PPI_CTRL",O.uc,c);return c};k.Vo=function(a,b,c){this.ba(a,b,c,"PPI_CTRL",O.uc);this.Of=b};
-k.Pm=function(a,b){var c=this.Rg;this.ba(a,null,b,"8042_OUTBUFF",O.Se,c);this.kb&=-258;var d=this.bb&&Fi(this.bb,!0);d&&Ii(this,d);return c};k.mo=function(a,b,c){this.ba(a,b,c,"8042_INBUF.DATA",O.Se);if(this.kb&8)switch(this.ud){case 96:Ji(this,b);break;case 209:Ki(this,b);break;default:if(Ji(this,this.Xd&-17),this.bb){a=-1;switch(b){case 255:a=250,Li(this.bb)}Ii(this,a)}}this.ud=b;this.kb&=-9};k.Qm=function(a,b){var c=this.Ac&-209|(F(this.S)&64?16:0);this.ba(a,null,b,"8042_RWREG",O.Se|O.rm,c);return c};
-k.no=function(a,b,c){this.ba(a,b,c,"8042_RWREG",O.Se);Gi(this,b)};k.Rm=function(a,b){this.ba(a,null,b,"8042_STATUS",O.Se,this.kb);var c=this.kb&255;this.kb&256&&(this.kb|=1,this.kb&=-257);return c};
-k.lo=function(a,b,c){this.ba(a,b,c,"8042_INBUFF.CMD",O.Se);this.ud=b;this.kb|=8;a=0;240<=this.ud&&(a=this.ud^15,this.ud=240);switch(this.ud){case 192:Ii(this,this.ve);break;case 173:Ji(this,this.Xd|16);break;case 174:Ji(this,this.Xd&-17);break;case 170:this.bb&&Mi(this.bb,!0);Ji(this,this.Xd|16);Ii(this,85);Ki(this,3);break;case 224:Ii(this,this.Xd&16?0:1);break;case 240:a&1&&xc(this.S)}};function Ji(a,b){a.Xd=b;a.kb=a.kb&-5|b&4;a.bb&&Hi(a.bb,!!(b&8),!(b&16))&&Ii(a,Fi(a.bb,!0))}
-function Ii(a,b){0<=b&&(a.Rg=b,a.kb&=-2,a.kb|=256)}function Ki(a,b){a.fi=b;Ya(a.na,!!(b&2));b&1||xc(a.S)}k.en=function(a,b){this.ba(a,null,b,"CMOS_ADDR",O.Cf,this.we);return this.we};k.Ao=function(a,b,c){this.ba(a,b,c,"CMOS_ADDR",O.Cf);this.we=b;this.Vg=b&128?0:128};k.fn=function(a,b){var c=this.we&63,d=13>=c?Sh(this,c):this.pa[c];this.ba(a,null,b,"CMOS_DATA["+r(c)+"]",O.Cf,d);return d};
-k.Bo=function(a,b,c){var d=this.we&63;this.ba(a,b,c,"CMOS_DATA["+r(d)+"]",O.Cf);a=this.pa;13>=d&&10>d&&(c=!1,this.pa[11]&4||(b=10*(b>>4)+(b&15),c=!0),4==d||5==d)&&(c&&12=b?b=12==b?0:b:(b-=116,b=24==b?12:b)));a[d]=b};k.xn=function(a,b){this.ba(a,null,b,"MFG_DATA",O.uc,this.Mf);return this.Mf};k.Po=function(a,b,c){this.ba(a,b,c,"MFG_DATA",O.uc);this.Mf=b};k.Ro=function(a,b,c){this.ba(a,b,c,"NMI",O.uc);this.Vg=b};
-k.Nn=function(a){var b=this.S.G>>8;this.X&&E(this.X,O.tm)&&(Ec(this.X,26,a),Fc(this.S,a,function(a,d){return function(e){d=F(a.S)-d;var f,g=a.S.J&255,h=a.S.J>>8,m=a.S.J&255,n=a.S.J>>8;if(2==b||3==b)f=" CH(hour)="+u(h)+" CL(min)="+r(g)+" DH(sec)="+r(n);else if(4==b||5==b)f=" CX(year)="+u(a.S.I)+" DH(month)="+r(n)+" DL(day)="+r(m);Gc(a.X,26,e,d,f)}}(this,F(this.S))));return!0};function Ch(a,b){if(void 0===a)return b;for(var c=0,d=1,e=0;ec||2E4>4&1:this.Ac&8?c|this.cd>>4:c|this.cd&15;this.Ac&1&&Rh(this,2).kd&&(c=this.Ac&2?c|32:c|16);this.ba(a,null,b,"PPI_C",O.uc|O.Fg,c);return c};k.Xo=function(a,b,c){this.ba(a,b,c,"PPI_C",O.uc);this.ji=b};k.Fn=function(a,b){var c=this.Of;this.ba(a,null,b,"PPI_CTRL",O.uc,c);return c};k.Yo=function(a,b,c){this.ba(a,b,c,"PPI_CTRL",O.uc);this.Of=b};
+k.Sm=function(a,b){var c=this.Rg;this.ba(a,null,b,"8042_OUTBUFF",O.Se,c);this.jb&=-258;var d=this.bb&&Fi(this.bb,!0);d&&Ii(this,d);return c};k.po=function(a,b,c){this.ba(a,b,c,"8042_INBUF.DATA",O.Se);if(this.jb&8)switch(this.ud){case 96:Ji(this,b);break;case 209:Ki(this,b);break;default:if(Ji(this,this.Xd&-17),this.bb){a=-1;switch(b){case 255:a=250,Li(this.bb)}Ii(this,a)}}this.ud=b;this.jb&=-9};k.Tm=function(a,b){var c=this.Ac&-209|(F(this.S)&64?16:0);this.ba(a,null,b,"8042_RWREG",O.Se|O.um,c);return c};
+k.qo=function(a,b,c){this.ba(a,b,c,"8042_RWREG",O.Se);Gi(this,b)};k.Um=function(a,b){this.ba(a,null,b,"8042_STATUS",O.Se,this.jb);var c=this.jb&255;this.jb&256&&(this.jb|=1,this.jb&=-257);return c};
+k.oo=function(a,b,c){this.ba(a,b,c,"8042_INBUFF.CMD",O.Se);this.ud=b;this.jb|=8;a=0;240<=this.ud&&(a=this.ud^15,this.ud=240);switch(this.ud){case 192:Ii(this,this.ve);break;case 173:Ji(this,this.Xd|16);break;case 174:Ji(this,this.Xd&-17);break;case 170:this.bb&&Mi(this.bb,!0);Ji(this,this.Xd|16);Ii(this,85);Ki(this,3);break;case 224:Ii(this,this.Xd&16?0:1);break;case 240:a&1&&xc(this.S)}};function Ji(a,b){a.Xd=b;a.jb=a.jb&-5|b&4;a.bb&&Hi(a.bb,!!(b&8),!(b&16))&&Ii(a,Fi(a.bb,!0))}
+function Ii(a,b){0<=b&&(a.Rg=b,a.jb&=-2,a.jb|=256)}function Ki(a,b){a.hi=b;Ya(a.na,!!(b&2));b&1||xc(a.S)}k.hn=function(a,b){this.ba(a,null,b,"CMOS_ADDR",O.Cf,this.we);return this.we};k.Do=function(a,b,c){this.ba(a,b,c,"CMOS_ADDR",O.Cf);this.we=b;this.Vg=b&128?0:128};k.jn=function(a,b){var c=this.we&63,d=13>=c?Sh(this,c):this.pa[c];this.ba(a,null,b,"CMOS_DATA["+r(c)+"]",O.Cf,d);return d};
+k.Eo=function(a,b,c){var d=this.we&63;this.ba(a,b,c,"CMOS_DATA["+r(d)+"]",O.Cf);a=this.pa;13>=d&&10>d&&(c=!1,this.pa[11]&4||(b=10*(b>>4)+(b&15),c=!0),4==d||5==d)&&(c&&12=b?b=12==b?0:b:(b-=116,b=24==b?12:b)));a[d]=b};k.An=function(a,b){this.ba(a,null,b,"MFG_DATA",O.uc,this.Mf);return this.Mf};k.So=function(a,b,c){this.ba(a,b,c,"MFG_DATA",O.uc);this.Mf=b};k.Uo=function(a,b,c){this.ba(a,b,c,"NMI",O.uc);this.Vg=b};
+k.Qn=function(a){var b=this.S.G>>8;this.X&&E(this.X,O.wm)&&(Ec(this.X,26,a),Fc(this.S,a,function(a,d){return function(e){d=F(a.S)-d;var f,g=a.S.J&255,h=a.S.J>>8,m=a.S.J&255,n=a.S.J>>8;if(2==b||3==b)f=" CH(hour)="+u(h)+" CL(min)="+r(g)+" DH(sec)="+r(n);else if(4==b||5==b)f=" CX(year)="+u(a.S.I)+" DH(month)="+r(n)+" DL(day)="+r(m);Gc(a.X,26,e,d,f)}}(this,F(this.S))));return!0};function Ch(a,b){if(void 0===a)return b;for(var c=0,d=1,e=0;ec||2E4>8&255,this.yb[c++]=f[b]>>16&255,this.yb[c++]=f[b]>>24&255;else this.yb=d;this.ai=d.symbols;if(!this.yb.length){w("Empty ROM: "+a);return}if(1==this.yb.length){w(this.yb[0]);return}}catch(g){this.Ga("ROM data error: "+
-g.message);return}else for(a=b.replace(/\n/gm," ").replace(/ +$/,"").split(" "),this.yb=Array(a.length),d=0;dthis.Pg?21:23,c=a.pa[b]|a.pa[b+1]<<8,c=c+(this.Od>>10);a.pa[b]=c&255;a.pa[b+1]=c>>8;ai(a)}}else w("No RAM allocated")};
-Ba(function(){for(var a=B(window.document,"pcjs","ram"),b=0;b>8&255,this.yb[c++]=f[b]>>16&255,this.yb[c++]=f[b]>>24&255;else this.yb=d;this.ci=d.symbols;if(!this.yb.length){w("Empty ROM: "+a);return}if(1==this.yb.length){w(this.yb[0]);return}}catch(g){this.Ga("ROM data error: "+
+g.message);return}else for(a=b.replace(/\n/gm," ").replace(/ +$/,"").split(" "),this.yb=Array(a.length),d=0;dthis.Pg?21:23,c=a.pa[b]|a.pa[b+1]<<8,c=c+(this.Od>>10);a.pa[b]=c&255;a.pa[b+1]=c>>8;ai(a)}}else w("No RAM allocated")};
+Ba(function(){for(var a=B(window.document,"pcjs","ram"),b=0;ba.zc.length){if(!(!d&&!a.$h[c]||d&&a.$h[c])){a.$h[c]=d;a.Qa("scan code "+r(b)+" buffered");a.zc.push(b);1==a.zc.length&&a.ka&&zi(a.ka,1);for(var e in Yi)if(Yi[e]==c){(c=a.sa["key-"+e])&&void 0!==d&&(c.style.color=d?"#ffffff":"#000000",c.style.backgroundColor=d?"#000000":"#ffffff");break}}}else 20==a.zc.length&&a.zc.push(255),a.Qa("scan code buffer overflow")}function cj(a,b){var c=b?a.Wn:a.Vn;a.S&&a.S.ld&&(c/=a.S.ld);return c}
+d,b=function(a,b,c){return function(){bj(a,c)}}(this,c,Yi[c]),c=function(a,b,c){return function(){bj(a,c)}}(this,c,Yi[c]|128),"ontouchstart"in window?(d.ontouchstart=b,d.ontouchend=c):(d.onmousedown=b,d.onmouseup=d.onmouseout=c),!0}return!1};k.pc=function(a,b,c,d){this.na=b;this.S=c;this.X=d;this.Da=a;this.ka=C(a,"ChipSet")};k.Ta=function(){this.Bk=(this.Rm=va("iOS"))||va("Android");this.Qa("mobile keyboard support: "+(this.Bk?"true":"false"));return x.prototype.Ta.call(this)};
+function Li(a){a.Qa("keyboard reset",!0);a.zc=[170];a.ka&&zi(a.ka,1,4)}function Hi(a,b,c){var d=!1;a.zi!==c&&(a.zi=a.Fi=c);a.lh!==b&&(a.lh=b)&&!a.Fi&&Mi(a);a.lh&&a.Fi&&(Li(a),a.Fi=!1,d=!0);return d}function Fi(a,b){var c=0;a.zc.length&&(c=a.zc[0],a.Qa("scan code "+r(c)+" delivered"),b&&Mi(a));return c}function Mi(a,b){0a.zc.length){if(!(!d&&!a.bi[c]||d&&a.bi[c])){a.bi[c]=d;a.Qa("scan code "+r(b)+" buffered");a.zc.push(b);1==a.zc.length&&a.ka&&zi(a.ka,1);for(var e in Yi)if(Yi[e]==c){(c=a.sa["key-"+e])&&void 0!==d&&(c.style.color=d?"#ffffff":"#000000",c.style.backgroundColor=d?"#000000":"#ffffff");break}}}else 20==a.zc.length&&a.zc.push(255),a.Qa("scan code buffer overflow")}function cj(a,b){var c=b?a.Zn:a.Yn;a.S&&a.S.ld&&(c/=a.S.ld);return c}
function dj(a,b){!a.Me||void 0!==b&&b==a.Me||(clearTimeout(a.qd[a.Me]),ej(a,a.Me,!1))}
-function $i(a,b,c){var d,e=!c,f=b.keyCode;c&&(a.Vl=f);240==f+224?(a.Ea&=-2,c&&(a.Ea|=1),f+=224,e=!1):241==f+224?(a.Ea&=-5,c&&(a.Ea|=4),f+=224,e=!1):242==f+224?(a.Ea&=-9,c&&(a.Ea|=8),f+=224,e=!1):244==f+224?(a.Ea&=-17,c&&(a.Ea|=16),f+=224,d=aj(a,f)):91==f?(a.Ea&=-33,c&&(a.Ea|=32),e=!1,d=!0):9==f||27==f||8==f?(8==f&&4==(a.Ea&12)&&(f=254),d=c?!aj(a,f):!1):void 0!==P[f+224]?f+=224:b.altKey||b.ctrlKey?65<=f&&90>=f&&(f+=32):d=!0;e&&(a.Ea&=-33,a.yk||f!=a.Vl||dj(a));void 0===d&&(d=!ej(a,f,c));return d}
+function $i(a,b,c){var d,e=!c,f=b.keyCode;c&&(a.Yl=f);240==f+224?(a.Ea&=-2,c&&(a.Ea|=1),f+=224,e=!1):241==f+224?(a.Ea&=-5,c&&(a.Ea|=4),f+=224,e=!1):242==f+224?(a.Ea&=-9,c&&(a.Ea|=8),f+=224,e=!1):244==f+224?(a.Ea&=-17,c&&(a.Ea|=16),f+=224,d=aj(a,f)):91==f?(a.Ea&=-33,c&&(a.Ea|=32),e=!1,d=!0):9==f||27==f||8==f?(8==f&&4==(a.Ea&12)&&(f=254),d=c?!aj(a,f):!1):void 0!==P[f+224]?f+=224:b.altKey||b.ctrlKey?65<=f&&90>=f&&(f+=32):d=!0;e&&(a.Ea&=-33,a.Bk||f!=a.Yl||dj(a));void 0===d&&(d=!ej(a,f,c));return d}
function aj(a,b,c){var d=!1;dj(a,b);ej(a,b,!0)&&(c?ej(a,b,!1):(c=!1,a.qd[b]&&(clearTimeout(a.qd[b]),c=!0),c=cj(a,c),a.qd[a.Me=b]=setTimeout(function(a){return function(){ej(a,b,!1)}}(a),c)),d=!0);return d}
-function ej(a,b,c){var d=!1;c||(a.qd[b]=null,a.Me==b&&(a.Me=0));var e=P[b];void 0===e&&1<=b&&26>=b&&(e=P[b+64]&255|61696);if(void 0!==e){14==e&&12==(a.Ea&12)&&(e=83);b=[];for(b.push(e&255|(c?0:128));e>>=8;){var d=0,f=e&255;240==f?a.Ea&17||(d=42):224==f?a.Ea&18||(d=54):241==f?a.Ea&4||(d=29):242==f&&(a.Ea&8||(d=56));d&&(c?b.unshift(d):b.push(d|128))}for(c=0;c=b&&(e=P[b+64]&255|61696);if(void 0!==e){14==e&&12==(a.Ea&12)&&(e=83);b=[];for(b.push(e&255|(c?0:128));e>>=8;){var d=0,f=e&255;240==f?a.Ea&17||(d=42):224==f?a.Ea&18||(d=54):241==f?a.Ea&4||(d=29):242==f&&(a.Ea&8||(d=56));d&&(c?b.unshift(d):b.push(d|128))}for(c=0;cc.length)c=[!1,0,null,null,0,Array(qj)];this.X=a.X;this.type=e[0];this.port=e[1];this.he=b;this.cb=e[2];this.tc=e[3];this.Vc=d||e[4];65536<=this.Vc&&720896<=this.cb&&(this.tc=Math.min(this.Vc>>2,32768));this.kc=c[0];this.Bc=c[1];this.$e=c[2];this.vf=c[3];this.mc=c[4]&255;this.rh=c[4]>>8&255;this.bc=c[5];this.Ni=qj;this.Qg=rj;if(5==b){this.Ni=sj;this.Qg=tj;b=c[6];void 0===b&&(b=[!1,0,Array(20),0,3==f?0:1,0,0,Array(5),
-0,0,0,Array(9),0,this.Vc,Array(this.Vc>>2),771,0,4294967295,0,4294967295,0,4294967295,0]);this.hd=b[0];this.Bd=b[1];this.Rd=b[2];this.ci=uj;this.Rh=b[3];this.bg=b[4];this.qh=b[5];this.Dd=b[6];this.Ff=b[7];this.ei=vj;this.Hi=b[8];this.Ii=b[9];this.Cd=b[10];this.se=b[11];this.di=wj;this.vb=b[12];d=this.Vc>>2;if((this.ed=b[14])&&this.ed.lengthc.length)c=[!1,0,null,null,0,Array(qj)];this.X=a.X;this.type=e[0];this.port=e[1];this.he=b;this.cb=e[2];this.tc=e[3];this.Vc=d||e[4];65536<=this.Vc&&720896<=this.cb&&(this.tc=Math.min(this.Vc>>2,32768));this.mc=c[0];this.Bc=c[1];this.$e=c[2];this.vf=c[3];this.oc=c[4]&255;this.rh=c[4]>>8&255;this.cc=c[5];this.Pi=qj;this.Qg=rj;if(5==b){this.Pi=sj;this.Qg=tj;b=c[6];void 0===b&&(b=[!1,0,Array(20),0,3==f?0:1,0,0,Array(5),
+0,0,0,Array(9),0,this.Vc,Array(this.Vc>>2),771,0,4294967295,0,4294967295,0,4294967295,0]);this.hd=b[0];this.Bd=b[1];this.Rd=b[2];this.ei=uj;this.Th=b[3];this.bg=b[4];this.qh=b[5];this.Dd=b[6];this.Ff=b[7];this.gi=vj;this.Ji=b[8];this.Ki=b[9];this.Cd=b[10];this.se=b[11];this.fi=wj;this.vb=b[12];d=this.Vc>>2;if((this.ed=b[14])&&this.ed.length>8&255)}
-var U=[,,function(a){a+=this.offset;return(this.ia.vb=this.ra[a])>>this.ia.Gj&255},function(a){a+=this.offset;var b=a&-2;return(a&1?this.ra[b]>>8:this.ra[b])&255}];U[16]=function(a){a+=this.offset;a=this.ra[a];for(var b=this.ia.Pi&this.ia.Qi,c=0,d=128;d;)(a&b)==b&&(c|=d),b>>>=1,d>>=1;return c};U[512]=function(a,b){var c=a+this.offset,d;d=this.ra[c]&~this.ia.gb|(b|b<<8|b<<16|b<<24)&this.ia.gb;d=d&this.ia.ob|this.ia.vb&~this.ia.ob;this.ra[c]!=d&&(this.ra[c]=d,this.mb=!0)};
-U[1024]=function(a,b){var c=a+this.offset;b=b>>this.ia.md|b<<8-this.ia.md&255;var d;d=(b|b<<8|b<<16|b<<24)&this.ia.le|this.ia.Je;d=d&this.ia.gb|this.ra[c]&~this.ia.gb;d=d&this.ia.ob|this.ia.vb&~this.ia.ob;this.ra[c]!=d&&(this.ra[c]=d,this.mb=!0)};
-U[1536]=function(a,b){var c=a+this.offset;b=b>>this.ia.md|b<<8-this.ia.md&255;var d;d=(b|b<<8|b<<16|b<<24)&this.ia.le|this.ia.Je;d&=this.ia.vb;d=d&this.ia.gb|this.ra[c]&~this.ia.gb;d=d&this.ia.ob|this.ia.vb&~this.ia.ob;this.ra[c]!=d&&(this.ra[c]=d,this.mb=!0)};
-U[2560]=function(a,b){var c=a+this.offset;b=b>>this.ia.md|b<<8-this.ia.md&255;var d;d=(b|b<<8|b<<16|b<<24)&this.ia.le|this.ia.Je;d|=this.ia.vb;d=d&this.ia.gb|this.ra[c]&~this.ia.gb;d=d&this.ia.ob|this.ia.vb&~this.ia.ob;this.ra[c]!=d&&(this.ra[c]=d,this.mb=!0)};
-U[3584]=function(a,b){var c=a+this.offset;b=b>>this.ia.md|b<<8-this.ia.md&255;var d;d=(b|b<<8|b<<16|b<<24)&this.ia.le|this.ia.Je;d^=this.ia.vb;d=d&this.ia.gb|this.ra[c]&~this.ia.gb;d=d&this.ia.ob|this.ia.vb&~this.ia.ob;this.ra[c]!=d&&(this.ra[c]=d,this.mb=!0)};U[768]=function(a,b){a+=this.offset;var c,d=a&-2;c=this.ia.gb&(d==a?16711935:4278255360);c=(b|b<<8|b<<16|b<<24)&c|this.ra[d]&~c;c=c&this.ia.ob|this.ia.vb&~this.ia.ob;this.ra[d]!=c&&(this.ra[d]=c,this.mb=!0)};
-U[4096]=function(a){a+=this.offset;var b=this.ra[a]&~this.ia.gb|this.ia.vb&this.ia.gb;this.ra[a]!=b&&(this.ra[a]=b,this.mb=!0)};U[8192]=function(a,b){var c=a+this.offset,d=nj[b&15],d=d&this.ia.gb|this.ra[c]&~this.ia.gb,d=d&this.ia.ob|this.ia.vb&~this.ia.ob;this.ra[c]!=d&&(this.ra[c]=d,this.mb=!0)};U[24576]=function(a,b){var c=a+this.offset,d=nj[b&15],d=d&this.ia.vb,d=d&this.ia.gb|this.ra[c]&~this.ia.gb,d=d&this.ia.ob|this.ia.vb&~this.ia.ob;this.ra[c]!=d&&(this.ra[c]=d,this.mb=!0)};
-U[40960]=function(a,b){var c=a+this.offset,d=nj[b&15],d=d|this.ia.vb,d=d&this.ia.gb|this.ra[c]&~this.ia.gb,d=d&this.ia.ob|this.ia.vb&~this.ia.ob;this.ra[c]!=d&&(this.ra[c]=d,this.mb=!0)};U[57344]=function(a,b){var c=a+this.offset,d=nj[b&15],d=d^this.ia.vb,d=d&this.ia.gb|this.ra[c]&~this.ia.gb,d=d&this.ia.ob|this.ia.vb&~this.ia.ob;this.ra[c]!=d&&(this.ra[c]=d,this.mb=!0)};
-function zj(a){var b=[];if(void 0!==a.he){b[0]=a.kc;b[1]=a.Bc;b[2]=a.$e;b[3]=a.vf;b[4]=a.mc|a.rh<<8;b[5]=a.bc;if(5==a.he){var c=[];c[0]=a.hd;c[1]=a.Bd;c[2]=a.Rd;c[3]=a.Rh;c[4]=a.bg;c[5]=a.qh;c[6]=a.Dd;c[7]=a.Ff;c[8]=a.Hi;c[9]=a.Ii;c[10]=a.Cd;c[11]=a.se;c[12]=a.vb;c[13]=a.Vc;var d;a:if(d=a.ed){var e=0,f=[];if(void 0!==d[0])for(var g=0;2>g;g++)for(var h=g;h>1;f[e++]=m;h=n}if(f.lengtha&&(a=0);for(var c="",d=0;8>d;d++){for(var n=p(b.cb+a)+":",q=0;8>q&&a>this.ia.Jj&255},function(a){a+=this.offset;var b=a&-2;return(a&1?this.ra[b]>>8:this.ra[b])&255}];U[16]=function(a){a+=this.offset;a=this.ra[a];for(var b=this.ia.Ri&this.ia.Si,c=0,d=128;d;)(a&b)==b&&(c|=d),b>>>=1,d>>=1;return c};U[512]=function(a,b){var c=a+this.offset,d;d=this.ra[c]&~this.ia.gb|(b|b<<8|b<<16|b<<24)&this.ia.gb;d=d&this.ia.nb|this.ia.vb&~this.ia.nb;this.ra[c]!=d&&(this.ra[c]=d,this.lb=!0)};
+U[1024]=function(a,b){var c=a+this.offset;b=b>>this.ia.md|b<<8-this.ia.md&255;var d;d=(b|b<<8|b<<16|b<<24)&this.ia.le|this.ia.Je;d=d&this.ia.gb|this.ra[c]&~this.ia.gb;d=d&this.ia.nb|this.ia.vb&~this.ia.nb;this.ra[c]!=d&&(this.ra[c]=d,this.lb=!0)};
+U[1536]=function(a,b){var c=a+this.offset;b=b>>this.ia.md|b<<8-this.ia.md&255;var d;d=(b|b<<8|b<<16|b<<24)&this.ia.le|this.ia.Je;d&=this.ia.vb;d=d&this.ia.gb|this.ra[c]&~this.ia.gb;d=d&this.ia.nb|this.ia.vb&~this.ia.nb;this.ra[c]!=d&&(this.ra[c]=d,this.lb=!0)};
+U[2560]=function(a,b){var c=a+this.offset;b=b>>this.ia.md|b<<8-this.ia.md&255;var d;d=(b|b<<8|b<<16|b<<24)&this.ia.le|this.ia.Je;d|=this.ia.vb;d=d&this.ia.gb|this.ra[c]&~this.ia.gb;d=d&this.ia.nb|this.ia.vb&~this.ia.nb;this.ra[c]!=d&&(this.ra[c]=d,this.lb=!0)};
+U[3584]=function(a,b){var c=a+this.offset;b=b>>this.ia.md|b<<8-this.ia.md&255;var d;d=(b|b<<8|b<<16|b<<24)&this.ia.le|this.ia.Je;d^=this.ia.vb;d=d&this.ia.gb|this.ra[c]&~this.ia.gb;d=d&this.ia.nb|this.ia.vb&~this.ia.nb;this.ra[c]!=d&&(this.ra[c]=d,this.lb=!0)};U[768]=function(a,b){a+=this.offset;var c,d=a&-2;c=this.ia.gb&(d==a?16711935:4278255360);c=(b|b<<8|b<<16|b<<24)&c|this.ra[d]&~c;c=c&this.ia.nb|this.ia.vb&~this.ia.nb;this.ra[d]!=c&&(this.ra[d]=c,this.lb=!0)};
+U[4096]=function(a){a+=this.offset;var b=this.ra[a]&~this.ia.gb|this.ia.vb&this.ia.gb;this.ra[a]!=b&&(this.ra[a]=b,this.lb=!0)};U[8192]=function(a,b){var c=a+this.offset,d=nj[b&15],d=d&this.ia.gb|this.ra[c]&~this.ia.gb,d=d&this.ia.nb|this.ia.vb&~this.ia.nb;this.ra[c]!=d&&(this.ra[c]=d,this.lb=!0)};U[24576]=function(a,b){var c=a+this.offset,d=nj[b&15],d=d&this.ia.vb,d=d&this.ia.gb|this.ra[c]&~this.ia.gb,d=d&this.ia.nb|this.ia.vb&~this.ia.nb;this.ra[c]!=d&&(this.ra[c]=d,this.lb=!0)};
+U[40960]=function(a,b){var c=a+this.offset,d=nj[b&15],d=d|this.ia.vb,d=d&this.ia.gb|this.ra[c]&~this.ia.gb,d=d&this.ia.nb|this.ia.vb&~this.ia.nb;this.ra[c]!=d&&(this.ra[c]=d,this.lb=!0)};U[57344]=function(a,b){var c=a+this.offset,d=nj[b&15],d=d^this.ia.vb,d=d&this.ia.gb|this.ra[c]&~this.ia.gb,d=d&this.ia.nb|this.ia.vb&~this.ia.nb;this.ra[c]!=d&&(this.ra[c]=d,this.lb=!0)};
+function zj(a){var b=[];if(void 0!==a.he){b[0]=a.mc;b[1]=a.Bc;b[2]=a.$e;b[3]=a.vf;b[4]=a.oc|a.rh<<8;b[5]=a.cc;if(5==a.he){var c=[];c[0]=a.hd;c[1]=a.Bd;c[2]=a.Rd;c[3]=a.Th;c[4]=a.bg;c[5]=a.qh;c[6]=a.Dd;c[7]=a.Ff;c[8]=a.Ji;c[9]=a.Ki;c[10]=a.Cd;c[11]=a.se;c[12]=a.vb;c[13]=a.Vc;var d;a:if(d=a.ed){var e=0,f=[];if(void 0!==d[0])for(var g=0;2>g;g++)for(var h=g;h>1;f[e++]=m;h=n}if(f.lengtha&&(a=0);for(var c="",d=0;8>d;d++){for(var n=p(b.cb+a)+":",q=0;8>q&&a>1&255,d=d>>8&-129,d>>4==(d&15)&&(d^=15)):(c=d&255,d=(d&256?7:112)|8&d>>8),eb(this.na,b,c|d<<8);zb(this,!0)}};function Hj(a){a.la.bg&1?(a.Uc=a.ki,a.zb=a.la):(a.Uc=a.la,a.zb=a.bh)}k.save=function(){var a=new H(this);a.set(0,zj(this.ki));a.set(1,zj(this.bh));a.set(2,[this.je,this.nd,this.Jd]);a.set(3,zj(this.la));return a.data()};
-k.restore=function(a){var b=a[2];this.je=b[0];this.nd=b[1];this.Jd=b[2];this.Ca=null;this.Uc=this.ki=new oj(this,1,a[0]);this.zb=this.bh=new oj(this,3,a[1]);this.la=new oj(this,5,a[3],this.Vc);this.la.kc&&Hj(this);Ij(this);if(!Kj(this))return!1;Lj(this);return!0};
-k.ho=function(a,b,c){if(c)this.Ga("Unable to load font ROM image (error "+c+")");else{try{var d=eval("("+b+")");if(!d.length){w("Empty font ROM image: "+a);return}if(1==d.length){w(d[0]);return}if(8192==d.length)Ri(this,d,[0,6144]);else{this.Ga("Unrecognized font data length ("+d.length+")");return}}catch(e){this.Ga("Font ROM data error: "+e.message);return}this.Ta()}};
-function Mj(a,b){if(1==b)return a.td[0]=S[0],a.td[1]=S[7],a.td;if(2==b){var c=a.Ca.$e;if(a.Ca===a.la){var d=a.la.Rd[0],c=d&7;d&16&&(c|=8);18!=a.la.Rd[1]&&(c|=32)}a.td[0]=S[c&15];c=c&32?lj:kj;for(d=0;dvb||!ka?vb:8,Yd=Ti.createImageData(n.ic,n.jc),Ha=0;256>Ha;Ha++){for(gb=
-0;gb=vb-2,rl=Qc[gb>(8<=Ob&&176<=Ha&&223>=Ha?7:Ob)?s:Xd;Pj(Yd,Ui,Vi,Wi);A&&Pj(Yd,Ui+1,Vi,Wi)}Ti.putImageData(Yd,(Ha&15)*n.ic,(Ha>>4)*n.jc)}n.Ve[v]="#"+r(s[0])+r(s[1])+r(s[2]);n.fk[v]=s;n.Xh[v]=Rc;n=!0}}a.Td[b]=t;return n}function Qj(a){0a.Be&&(a.Be=0):a.Be=-1}
-function Lj(a){if(a.Sb){for(var b=10;15>=b;b++)if(null==a.Ca.bc[b])return;var c=a.Ca.bc[10],b=c&31,d=a.Ca.bc[11]&31,e=a.Ca.bc[9]&31,f=!1;a.Ca===a.la&&(f=!0,7!=e||4!=b||d||(d=7));if(c&32||b>d&&!f||b>e)Rj(a);else{c=a.Ca.bc[15]+((a.Ca.bc[14]&63)<<8);a.Lc!=c&&(Rj(a),a.Lc=c);d=d-b+1;if(a.km!=b||a.uk!=d)a.km=b,a.uk=d;a.ee=e+1;Qj(a)}}}
-function Rj(a){if(0<=a.Lc){if(void 0!==a.cc){var b=a.cc[a.Lc];if(b&131072){var b=b&-131073,c=a.Lc%a.Bb,d=Math.floor(a.Lc/a.Bb);a.Sb&&a.Td[a.Sb]&&(a.af&&Sj(a,c,d,b,a.af),Sj(a,c,d,b));a.cc[a.Lc]=b}}a.Lc=-1}}
-function Tj(a){var b;a=a.Ca;var c=a.se[5];if(null!=c){b=2;var d=512,e=a.se[3]&31;switch(c&3){case 0:if(e){d=1024;switch(e&24){case 8:d=1536;break;case 16:d=2560;break;case 24:d=3584}a.md=e&7}break;case 1:d=4096;break;case 2:switch(e&24){default:d=8192;break;case 8:d=24576;break;case 16:d=40960;break;case 24:d=57344}}c&8&&(b=16);c&16&&(b|=1,d|=256);b|=d}return b}k.Pe=function(a){var b=this.Ca;null!=a&&b&&a!=b.yh&&(b.Oh(a),this.na.Oh(b.cb,b.tc,b.Jf))};
-function Kj(a,b){var c,d=a.Jd,e=a.Ca;if(e)if(1==e.he)d=fj;else if(5==e.he){var d=null,f=e.Vc>>2,g=32768f&&(d=c?13:14):c&&(d-=2));c=Tj(a)}}else e.Bc&8&&(e.Bc&2?(d=e.Bc&16?6:5,e.Bc&4||(d-=1)):(d=e.Bc&1?3:1,e.Bc&4&&(d-=
+k.reset=function(){var a=!0,b=0;this.ka&&(b=Yh(this.ka));var c=!1;if(this.Fa)switch(this.Fa){case "ega":var c=!0,d=hj[this.Sg];d&&(b=d[0]);b||(b=4);break;case "mda":b=3;break;default:b=2}this.je!==b&&(this.je=b,a=!0);this.Ca=null;this.Uc=this.mi=new oj(this,1);this.zb=this.bh=new oj(this,3);c?(this.la=new oj(this,5,null,this.Vc),Hj(this)):this.la=new oj;Ij(this);this.Jd=null;this.nd=3==b?fj:3;this.Be=this.Lc=-1;this.Ae=0;Jj(this,this.nd);if(this.Ca.cb&&a){a=this.Ca.cb+this.ni;for(b=this.Ca.cb;b>1&255,d=d>>8&-129,d>>4==(d&15)&&(d^=15)):(c=d&255,d=(d&256?7:112)|8&d>>8),eb(this.na,b,c|d<<8);zb(this,!0)}};function Hj(a){a.la.bg&1?(a.Uc=a.mi,a.zb=a.la):(a.Uc=a.la,a.zb=a.bh)}k.save=function(){var a=new H(this);a.set(0,zj(this.mi));a.set(1,zj(this.bh));a.set(2,[this.je,this.nd,this.Jd]);a.set(3,zj(this.la));return a.data()};
+k.restore=function(a){var b=a[2];this.je=b[0];this.nd=b[1];this.Jd=b[2];this.Ca=null;this.Uc=this.mi=new oj(this,1,a[0]);this.zb=this.bh=new oj(this,3,a[1]);this.la=new oj(this,5,a[3],this.Vc);this.la.mc&&Hj(this);Ij(this);if(!Kj(this))return!1;Lj(this);return!0};
+k.ko=function(a,b,c){if(c)this.Ga("Unable to load font ROM image (error "+c+")");else{try{var d=eval("("+b+")");if(!d.length){w("Empty font ROM image: "+a);return}if(1==d.length){w(d[0]);return}if(8192==d.length)Ri(this,d,[0,6144]);else{this.Ga("Unrecognized font data length ("+d.length+")");return}}catch(e){this.Ga("Font ROM data error: "+e.message);return}this.Ta()}};
+function Mj(a,b){if(1==b)return a.td[0]=S[0],a.td[1]=S[7],a.td;if(2==b){var c=a.Ca.$e;if(a.Ca===a.la){var d=a.la.Rd[0],c=d&7;d&16&&(c|=8);18!=a.la.Rd[1]&&(c|=32)}a.td[0]=S[c&15];c=c&32?lj:kj;for(d=0;dvb||!ka?vb:8,Yd=Ti.createImageData(n.kc,n.lc),Ha=0;256>Ha;Ha++){for(gb=
+0;gb=vb-2,rl=Qc[gb>(8<=Ob&&176<=Ha&&223>=Ha?7:Ob)?s:Xd;Pj(Yd,Ui,Vi,Wi);A&&Pj(Yd,Ui+1,Vi,Wi)}Ti.putImageData(Yd,(Ha&15)*n.kc,(Ha>>4)*n.lc)}n.Ve[v]="#"+r(s[0])+r(s[1])+r(s[2]);n.ik[v]=s;n.Zh[v]=Rc;n=!0}}a.Td[b]=t;return n}function Qj(a){0a.Be&&(a.Be=0):a.Be=-1}
+function Lj(a){if(a.Sb){for(var b=10;15>=b;b++)if(null==a.Ca.cc[b])return;var c=a.Ca.cc[10],b=c&31,d=a.Ca.cc[11]&31,e=a.Ca.cc[9]&31,f=!1;a.Ca===a.la&&(f=!0,7!=e||4!=b||d||(d=7));if(c&32||b>d&&!f||b>e)Rj(a);else{c=a.Ca.cc[15]+((a.Ca.cc[14]&63)<<8);a.Lc!=c&&(Rj(a),a.Lc=c);d=d-b+1;if(a.nm!=b||a.xk!=d)a.nm=b,a.xk=d;a.ee=e+1;Qj(a)}}}
+function Rj(a){if(0<=a.Lc){if(void 0!==a.dc){var b=a.dc[a.Lc];if(b&131072){var b=b&-131073,c=a.Lc%a.Bb,d=Math.floor(a.Lc/a.Bb);a.Sb&&a.Td[a.Sb]&&(a.af&&Sj(a,c,d,b,a.af),Sj(a,c,d,b));a.dc[a.Lc]=b}}a.Lc=-1}}
+function Tj(a){var b;a=a.Ca;var c=a.se[5];if(null!=c){b=2;var d=512,e=a.se[3]&31;switch(c&3){case 0:if(e){d=1024;switch(e&24){case 8:d=1536;break;case 16:d=2560;break;case 24:d=3584}a.md=e&7}break;case 1:d=4096;break;case 2:switch(e&24){default:d=8192;break;case 8:d=24576;break;case 16:d=40960;break;case 24:d=57344}}c&8&&(b=16);c&16&&(b|=1,d|=256);b|=d}return b}k.Pe=function(a){var b=this.Ca;null!=a&&b&&a!=b.yh&&(b.Qh(a),this.na.Qh(b.cb,b.tc,b.Jf))};
+function Kj(a,b){var c,d=a.Jd,e=a.Ca;if(e)if(1==e.he)d=fj;else if(5==e.he){var d=null,f=e.Vc>>2,g=32768f&&(d=c?13:14):c&&(d-=2));c=Tj(a)}}else e.Bc&8&&(e.Bc&2?(d=e.Bc&16?6:5,e.Bc&4||(d-=1)):(d=e.Bc&1?3:1,e.Bc&4&&(d-=
1)));else a.Jd=null,null==d&&(d=a.nd);if(!Jj(a,d,b))return!1;a.Pe(c);return!0}
-function Jj(a,b,c){if(null!=b&&(b!=a.Jd||c)){a.ym=0;a.Jd=b;b=a.Ca||(b==fj?a.Uc:a.zb);if(b!=a.Ca||b.cb!=a.cb||b.tc!=a.tc){Rj(a);if(a.cb){if(!ab(a.na,a.cb,a.tc))return!1;a.Ca&&(a.Ca.kc=!1)}a.Ca=b;b.kc=!0;a.cb=b.cb;a.tc=b.tc;if(!Za(a.na,b.cb,b.tc,!1,b===a.la?b:null))return!1}a.Sb=0;a.Bb=a.Bh;a.qc=a.Ti;a.Oi=R[fj][2];b=0;var d=R[a.Jd];d&&(a.Bb=d[0],a.qc=d[1],a.Oi=d[2],b=d[3]||0,a.Sb=d[4],4==a.je&&a.Ca===a.la&&3==a.Sb&&(7==a.la.bc[9]?a.qc=43:a.Sb=5));a.Mk=a.Bb*a.qc;a.Ah=a.Mk/a.Oi;a.li=(a.Ah<<1)+b;a.rk=
-b?a.li+b>>1:0;13<=a.Jd&&(a.Ah<<=1);a.Td.length&&(a.yd=Math.floor(a.xd/a.Bb),a.zd=Math.floor(a.fe/a.qc),a.Sb?(b=a.Td[a.Sb],d=a.Td[a.Sb<<1],a.Fm&&80==a.Bb?d&&a.yd>=3*d.ic>>2&&(a.Sb<<=1,b=d):(d&&a.yd>=d.ic&&(a.Sb<<=1,b=d),b&&(a.yd=b.ic,a.zd=b.jc)),a.Wf=a.Xf=0,b&&(a.Wf=a.Bb*b.ic,a.Xf=a.qc*b.jc)):(a.yd=a.zd=1,a.Wf=a.Bb,a.Xf=a.qc),a.uh=a.Xc.createImageData(a.Wf,a.Xf),a.Ze=window.document.createElement("canvas"),a.Ze.width=a.Wf,a.Ze.height=a.Xf,a.af=a.Ze.getContext("2d"),a.Yj=a.Zj=0,a.ni=a.xd,a.oi=a.fe,
-b=a.xd-a.Bb*a.yd,d=a.fe-a.qc*a.zd,0>1,a.ni-=b),0>1,a.oi-=d),b||d)&&(a.Xc.fillStyle=a.Lb.style.backgroundColor,a.Xc.fillRect(0,0,a.xd,a.fe));!1!==c?zb(a,!0):Uj(a,!0)}return!0}function Pj(a,b,c,d){b=(b+c*a.width)*d.length;a.data[b+0]=d[0];a.data[b+1]=d[1];a.data[b+2]=d[2];a.data[b+3]=d[3]}function Uj(a,b){var c;if(b){if(c=a.Ah,void 0===a.cc||a.cc.length!=c)a.cc=Array(c)}else{if(void 0===a.cc)return;c=a.cc.length}for(var d=0;d>8;d=g&15;var h=a.Td[a.Sb];h.Ef&&(d=h.Ef[d]);var m=g>>4&15;h.Ef&&(m=h.Ef[m]);e?(b*=h.ic,c*=h.jc,e.fillStyle=h.Ve[m],e.fillRect(b,c,h.ic,h.jc)):(b=b*a.yd+a.Yj,c=c*a.zd+a.Zj,a.Xc.fillStyle=h.Ve[m],a.Xc.fillRect(b,c,a.yd,a.zd));g&256&&(m=(f&15)*h.ic,f=(f>>4)*h.jc,e?e.drawImage(h.Xh[d],m,f,h.ic,h.jc,b,c,h.ic,h.jc):a.Xc.drawImage(h.Xh[d],m,f,h.ic,h.jc,b,c,a.yd,a.zd));g&512&&(f=a.km,g=a.uk,e?(a.ee&&a.ee!==h.jc&&(f=Math.floor(f*h.jc/a.ee),g=Math.floor(g*h.jc/a.ee)),
-e.fillStyle=h.Ve[d],e.fillRect(b,c+f,h.ic,g)):(a.ee&&a.ee!==a.zd&&(f=Math.floor(f*a.zd/a.ee),g=Math.floor(g*a.zd/a.ee)),a.Xc.fillStyle=h.Ve[d],a.Xc.fillRect(b,c+f,a.yd,g)))}
-function zb(a,b){if(a.Nb){var c=!1;a.Ca&&(a.Ca===a.la?a.la.Bd&32&&(c=!0):a.Ca.Bc&8&&(c=!0));if(c||b){if(b)Uj(a,!0);else if(void 0===a.cc)return;var d=!1;!(b||++a.ym&15)&&0<=a.Be&&(a.Be++,d=!0);var e=0,f=a.Mk,c=a.Ca.cb,g=c+a.Ca.tc,h=(a.Ca.bc[12]<<8)+a.Ca.bc[13];a.Sb&&(h<<=1);var c=c+h,m=a.li;c+m>g&&(m=g-c,0>m&&(m=0));g=c+m;if(h=!b){for(var h=a.na,n=!0,q=c>>h.rb;0a.Lc)return;e=a.Lc;f=e+1}}if(a.Sb){if(a.Td[a.Sb]){d=
-0;h=a.Ae=0;m=1048575;a.Ca.Bc&32&&(h=32768,m&=~h,a.Be&2||(m&=-65537));for(c+=e<<1;c>8|
-(t&255)<<8;s=h;var vb=16;q>=m))>>(vb-=m);Pj(a.uh,q++,v,n[Xd])}q>D&&(D=q);v=la&&(la=v+1)}e+=2;g++;if(q>=a.Bb){q=0;v+=2;if(v>a.qc)break;v==a.qc&&(v=1,e=c+a.rk)}}Aka;ka++)la=D&2155905152,
-0>la&&(la=-la),la=T[la]||0,Pj(a.uh,h++,m,g[la]),D<<=1;h>q&&(q=h);m=A&&(A=m+1)}e++;if(h>=a.Bb&&(h=0,++m>a.qc))break}n>2),c=this.la.Rh&-17|(this.Sg&1<f&&(f=0);f%b.Ri>b.Zn&&(d|=1);f%=b.Pk;f>b.bo&&(d|=8);b.Xi=e-f;b===a.la?(d|=b.vf&48^48,b.hd=!1):d=(b.vf^=9)|240;b.vf=d;a.ba(b.port+6,null,c,b===a.la?"STATUS1":"STATUS",d);return d}k.Qa=function(a,b){this.X&&(b||E(this.X,this.X.Hg))&&this.X.message(a)};k.ba=function(a,b,c,d,e){this.X&&this.X.ba(this,a,b,c,d,this.X.Hg,e)};
-var Bj={948:Q.prototype.un,949:Q.prototype.tn,952:Q.prototype.vn,954:Q.prototype.wn,980:Q.prototype.bn,981:Q.prototype.an,984:Q.prototype.cn,985:Q.prototype.$m,986:Q.prototype.dn},Cj={948:Q.prototype.No,949:Q.prototype.Mo,952:Q.prototype.Oo,980:Q.prototype.yo,981:Q.prototype.xo,984:Q.prototype.zo,985:Q.prototype.wo},Dj={960:Q.prototype.Ik,961:Q.prototype.Ik,962:Q.prototype.Gn,964:Q.prototype.Fn,965:Q.prototype.En,970:Q.prototype.nn,972:Q.prototype.mn,974:Q.prototype.ln,975:Q.prototype.kn},Ej={954:Q.prototype.Tl,
-960:Q.prototype.Sl,961:Q.prototype.Sl,962:Q.prototype.Qo,964:Q.prototype.Xo,965:Q.prototype.Wo,970:Q.prototype.Io,972:Q.prototype.Ho,974:Q.prototype.Go,975:Q.prototype.Fo,986:Q.prototype.Tl};
+function Jj(a,b,c){if(null!=b&&(b!=a.Jd||c)){a.Bm=0;a.Jd=b;b=a.Ca||(b==fj?a.Uc:a.zb);if(b!=a.Ca||b.cb!=a.cb||b.tc!=a.tc){Rj(a);if(a.cb){if(!ab(a.na,a.cb,a.tc))return!1;a.Ca&&(a.Ca.mc=!1)}a.Ca=b;b.mc=!0;a.cb=b.cb;a.tc=b.tc;if(!Za(a.na,b.cb,b.tc,!1,b===a.la?b:null))return!1}a.Sb=0;a.Bb=a.Bh;a.rc=a.Vi;a.Qi=R[fj][2];b=0;var d=R[a.Jd];d&&(a.Bb=d[0],a.rc=d[1],a.Qi=d[2],b=d[3]||0,a.Sb=d[4],4==a.je&&a.Ca===a.la&&3==a.Sb&&(7==a.la.cc[9]?a.rc=43:a.Sb=5));a.Pk=a.Bb*a.rc;a.Ah=a.Pk/a.Qi;a.ni=(a.Ah<<1)+b;a.uk=
+b?a.ni+b>>1:0;13<=a.Jd&&(a.Ah<<=1);a.Td.length&&(a.yd=Math.floor(a.xd/a.Bb),a.zd=Math.floor(a.fe/a.rc),a.Sb?(b=a.Td[a.Sb],d=a.Td[a.Sb<<1],a.Im&&80==a.Bb?d&&a.yd>=3*d.kc>>2&&(a.Sb<<=1,b=d):(d&&a.yd>=d.kc&&(a.Sb<<=1,b=d),b&&(a.yd=b.kc,a.zd=b.lc)),a.Wf=a.Xf=0,b&&(a.Wf=a.Bb*b.kc,a.Xf=a.rc*b.lc)):(a.yd=a.zd=1,a.Wf=a.Bb,a.Xf=a.rc),a.uh=a.Xc.createImageData(a.Wf,a.Xf),a.Ze=window.document.createElement("canvas"),a.Ze.width=a.Wf,a.Ze.height=a.Xf,a.af=a.Ze.getContext("2d"),a.ak=a.bk=0,a.pi=a.xd,a.qi=a.fe,
+b=a.xd-a.Bb*a.yd,d=a.fe-a.rc*a.zd,0>1,a.pi-=b),0>1,a.qi-=d),b||d)&&(a.Xc.fillStyle=a.Lb.style.backgroundColor,a.Xc.fillRect(0,0,a.xd,a.fe));!1!==c?zb(a,!0):Uj(a,!0)}return!0}function Pj(a,b,c,d){b=(b+c*a.width)*d.length;a.data[b+0]=d[0];a.data[b+1]=d[1];a.data[b+2]=d[2];a.data[b+3]=d[3]}function Uj(a,b){var c;if(b){if(c=a.Ah,void 0===a.dc||a.dc.length!=c)a.dc=Array(c)}else{if(void 0===a.dc)return;c=a.dc.length}for(var d=0;d>8;d=g&15;var h=a.Td[a.Sb];h.Ef&&(d=h.Ef[d]);var m=g>>4&15;h.Ef&&(m=h.Ef[m]);e?(b*=h.kc,c*=h.lc,e.fillStyle=h.Ve[m],e.fillRect(b,c,h.kc,h.lc)):(b=b*a.yd+a.ak,c=c*a.zd+a.bk,a.Xc.fillStyle=h.Ve[m],a.Xc.fillRect(b,c,a.yd,a.zd));g&256&&(m=(f&15)*h.kc,f=(f>>4)*h.lc,e?e.drawImage(h.Zh[d],m,f,h.kc,h.lc,b,c,h.kc,h.lc):a.Xc.drawImage(h.Zh[d],m,f,h.kc,h.lc,b,c,a.yd,a.zd));g&512&&(f=a.nm,g=a.xk,e?(a.ee&&a.ee!==h.lc&&(f=Math.floor(f*h.lc/a.ee),g=Math.floor(g*h.lc/a.ee)),
+e.fillStyle=h.Ve[d],e.fillRect(b,c+f,h.kc,g)):(a.ee&&a.ee!==a.zd&&(f=Math.floor(f*a.zd/a.ee),g=Math.floor(g*a.zd/a.ee)),a.Xc.fillStyle=h.Ve[d],a.Xc.fillRect(b,c+f,a.yd,g)))}
+function zb(a,b){if(a.Nb){var c=!1;a.Ca&&(a.Ca===a.la?a.la.Bd&32&&(c=!0):a.Ca.Bc&8&&(c=!0));if(c||b){if(b)Uj(a,!0);else if(void 0===a.dc)return;var d=!1;!(b||++a.Bm&15)&&0<=a.Be&&(a.Be++,d=!0);var e=0,f=a.Pk,c=a.Ca.cb,g=c+a.Ca.tc,h=(a.Ca.cc[12]<<8)+a.Ca.cc[13];a.Sb&&(h<<=1);var c=c+h,m=a.ni;c+m>g&&(m=g-c,0>m&&(m=0));g=c+m;if(h=!b){for(var h=a.na,n=!0,q=c>>h.rb;0a.Lc)return;e=a.Lc;f=e+1}}if(a.Sb){if(a.Td[a.Sb]){d=
+0;h=a.Ae=0;m=1048575;a.Ca.Bc&32&&(h=32768,m&=~h,a.Be&2||(m&=-65537));for(c+=e<<1;c>8|
+(t&255)<<8;s=h;var vb=16;q>=m))>>(vb-=m);Pj(a.uh,q++,v,n[Xd])}q>D&&(D=q);v=la&&(la=v+1)}e+=2;g++;if(q>=a.Bb){q=0;v+=2;if(v>a.rc)break;v==a.rc&&(v=1,e=c+a.uk)}}Aka;ka++)la=D&2155905152,
+0>la&&(la=-la),la=T[la]||0,Pj(a.uh,h++,m,g[la]),D<<=1;h>q&&(q=h);m=A&&(A=m+1)}e++;if(h>=a.Bb&&(h=0,++m>a.rc))break}n>2),c=this.la.Th&-17|(this.Sg&1<f&&(f=0);f%b.Ti>b.bo&&(d|=1);f%=b.Sk;f>b.fo&&(d|=8);b.$i=e-f;b===a.la?(d|=b.vf&48^48,b.hd=!1):d=(b.vf^=9)|240;b.vf=d;a.ba(b.port+6,null,c,b===a.la?"STATUS1":"STATUS",d);return d}k.Qa=function(a,b){this.X&&(b||E(this.X,this.X.Hg))&&this.X.message(a)};k.ba=function(a,b,c,d,e){this.X&&this.X.ba(this,a,b,c,d,this.X.Hg,e)};
+var Bj={948:Q.prototype.xn,949:Q.prototype.wn,952:Q.prototype.yn,954:Q.prototype.zn,980:Q.prototype.en,981:Q.prototype.dn,984:Q.prototype.fn,985:Q.prototype.cn,986:Q.prototype.gn},Cj={948:Q.prototype.Qo,949:Q.prototype.Po,952:Q.prototype.Ro,980:Q.prototype.Bo,981:Q.prototype.Ao,984:Q.prototype.Co,985:Q.prototype.zo},Dj={960:Q.prototype.Lk,961:Q.prototype.Lk,962:Q.prototype.Jn,964:Q.prototype.In,965:Q.prototype.Hn,970:Q.prototype.qn,972:Q.prototype.pn,974:Q.prototype.on,975:Q.prototype.nn},Ej={954:Q.prototype.Wl,
+960:Q.prototype.Vl,961:Q.prototype.Vl,962:Q.prototype.To,964:Q.prototype.$o,965:Q.prototype.Zo,970:Q.prototype.Lo,972:Q.prototype.Ko,974:Q.prototype.Jo,975:Q.prototype.Io,986:Q.prototype.Wl};
Ba(function(){for(var a=B(window.document,"pcjs","video"),b=0;b Missing <canvas> support; try a new web browser.";break}e.setAttribute("class","pcjs-canvas");e.setAttribute("width",d.screenWidth);e.setAttribute("height",d.screenHeight);e.setAttribute("contenteditable","true");e.setAttribute("autocapitalize","off");e.setAttribute("autocorrect","off");e.style.backgroundColor=d.screenColor;
e.style.height=c.style.height="auto";0<=(window?window.navigator.userAgent:"").indexOf("MSIE")&&(e.style.height=(c.clientWidth*d.screenHeight/d.screenWidth|0)+"px",c.onresize=function(a,b,c,d){return function(){b.style.height=(a.clientWidth*d/c|0)+"px"}}(c,e,d.screenWidth,d.screenHeight));c.appendChild(e);var f=e.getContext("2d"),d=new Q(d,e,f);Oa(d,c)}});
-function V(a){this.Fk=a.adapter;switch(this.Fk){case 1:this.Nj=1016;this.kg=4;break;case 2:this.Nj=760;this.kg=3;break;default:w("Unrecognized serial adapter #"+this.Fk);return}this.ce=null;x.call(this,"SerialPort",a,V);var b=a.binding,c;a=ak;b&&(void 0===c&&(c="Panel"),(c=Na(c,this.id))&&(b=c.sa[b])&&this.xb(null,null,a,b))}y(x,V);var ak="buffer";k=V.prototype;k.ik=function(a,b){return a==this.sh?(this.Jk=b,this):null};
-k.xb=function(a,b,c,d){var e=this;switch(c){case ak:return this.sa[c]=this.ce=d,d.onkeydown=function(a){a=a||window.event;var b=a.charCode||a.keyCode;8===b&&(a.preventDefault&&a.preventDefault(),bk(e,[b]))},d.onkeypress=function(a){a=a||window.event;bk(e,[a.which||a.keyCode])},!0}return!1};k.nc=function(a,b,c,d){this.na=b;this.S=c;this.X=d;this.ka=C(a,"ChipSet");d&&Ph(d,V);ib(b,this,ck,this.Nj);mb(b,this,dk,this.Nj);this.Ta()};
-k.$b=function(a,b){if(!b)if(!a||!this.restore)this.reset();else if(!this.restore(a))return!1;return!0};k.Wb=function(a){return a&&this.save?this.save():!0};k.reset=function(){this.ie()};k.save=function(){var a=new H(this),b=0,c=[];c[b++]=this.ii;c[b++]=this.mk;c[b++]=this.Re;c[b++]=this.Tg;c[b++]=this.Zd;c[b++]=this.Tc;c[b++]=this.fd;c[b++]=this.Gc;c[b++]=this.kk;c[b]=this.Hf;a.set(0,c);return a.data()};k.restore=function(a){return this.ie(a[0])};
-k.ie=function(a){var b=0;void 0===a&&(a=[0,0,384,0,1,0,0,96,48,[]]);this.ii=a[b++];this.mk=a[b++];this.Re=a[b++];this.Tg=a[b++];this.Zd=a[b++];this.Tc=a[b++];this.fd=a[b++];this.Gc=a[b++];this.kk=a[b++];this.Hf=a[b];return!0};function bk(a,b){a.Hf=a.Hf.concat(b);ek(a)}function ek(a){0>8:this.Tg;this.ba(a,null,b,this.Tc&128?"DLM":"IER",c);return c};k.pn=function(a,b){var c=this.Zd;this.ba(a,null,b,"IIR",c);return c};k.qn=function(a,b){var c=this.Tc;this.ba(a,null,b,"LCR",c);return c};k.sn=function(a,b){var c=this.fd;this.ba(a,null,b,"MCR",c);return c};
-k.rn=function(a,b){var c=this.Gc;this.ba(a,null,b,"LSR",c);return c};k.yn=function(a,b){var c=this.kk;this.ba(a,null,b,"MSR",c);return c};k.Yo=function(a,b,c){this.ba(a,b,c,this.Tc&128?"DLL":"THR");this.Tc&128?this.Re=this.Re&-256|b:(this.mk=b,this.Gc&=-97,this.ce?(13!=b&&(8==b?this.ce.value=this.ce.value.slice(0,-1):(this.ce.value+=String.fromCharCode(b),this.ce.scrollTop=this.ce.scrollHeight)),a=!0):a=!1,a&&(this.Gc|=96))};
-k.Jo=function(a,b,c){this.ba(a,b,c,this.Tc&128?"DLM":"IER");this.Tc&128?this.Re=this.Re&255|b<<8:this.Tg=b};k.Ko=function(a,b,c){this.ba(a,b,c,"LCR");this.Tc=b};
-k.Lo=function(a,b,c){var d=this.fd;this.ba(a,b,c,"MCR");this.fd=b;this.Jk&&(d^b)&3&&(a=this.Jk,b=this.fd,(c=3==(b&3))?a.kc||(d=!1,a.fd&2||(a.reset(),a.Qa("serial mouse reset"),d=!0),a.fd&1||(a.Qa("serial mouse ID requested"),d=!0),d&&(bk(a.Sf,[77]),a.Qa("serial mouse ID sent")),fk(a,a.Lb),a.kc=c):a.kc&&(a.Qa("serial mouse inactive"),gk(a.Lb),a.kc=c),a.fd=b)};k.Qa=function(a){this.X&&E(this.X,this.X.ck)&&this.X.message(a)};k.ba=function(a,b,c,d,e){this.X&&this.X.ba(this,a,b,c,d,this.X.ck,e)};
-var ck={0:V.prototype.Dn,1:V.prototype.on,2:V.prototype.pn,3:V.prototype.qn,4:V.prototype.sn,5:V.prototype.rn,6:V.prototype.yn},dk={0:V.prototype.Yo,1:V.prototype.Jo,3:V.prototype.Ko,4:V.prototype.Lo};Ba(function(){for(var a=B(window.document,"pcjs","serial"),b=0;ba.Cg||0>a.Dg)a.Cg=b.clientX,a.Dg=b.clientY;a.yf=b.clientX-a.Cg;a.zf=b.clientY-a.Dg;(a.yf||a.zf)&&ik(a,null,b.clientX,b.clientY);a.Cg=b.clientX;a.Dg=b.clientY}},!1),b.addEventListener("mousedown",function(b){jk(a,b.button,!0)},!1),b.addEventListener("mouseup",function(b){jk(a,b.button,!1)},!1),a.wi=!0),b.style.cursor="none")}function gk(a){a&&(a.style.cursor="auto")}
-function jk(a,b,c){if(a.kc&&a.S&&a.S.Ob)switch(b){case 0:a.ih!=c&&(a.ih=c,ik(a,"mouse button1 "+(c?"dn":"up")));break;case 2:a.jh!=c&&(a.jh=c,ik(a,"mouse button2 "+(c?"dn":"up")))}}function ik(a,b,c,d){var e=64|(a.ih?32:0)|(a.jh?16:0)|(a.zf&192)>>4|(a.yf&192)>>6,f=a.yf&63,g=a.zf&63;a.Qa((b?b+": ":"")+(void 0!==d?"mouse ("+c+","+d+"): ":"")+"serial packet ["+r(e)+","+r(f)+","+r(g)+"]");bk(a.Sf,[e,f,g]);a.yf=a.zf=0}k.Qa=function(a){this.X&&E(this.X,this.X.sm)&&this.X.message(a)};
-Ba(function(){for(var a=B(window.document,"pcjs","mouse"),b=0;bb.indexOf("/api/v1/dump")&&(a=fa(b),"json"==a?d=encodeURI(b):"demandrw"==this.mode||"demandro"==this.mode?(a="action=open&volume="+b+("&mode="+this.mode),a+="&chs="+this.oc+":"+this.fc+":"+this.rc+":"+this.Mb,a+="&machine="+this.ia.gf(),a+="&user="+this.ia.ge(),d=sa()+"/api/v1/disk?"+a,this.Bi=!0):(c="path",d="&mbhd=10",!b.indexOf("http:")||!b.indexOf("ftp:")||0<="dsk ima img 360 720 12 144".split(" ").indexOf(a)?(c="disk",d="&mbhd=0"):
--1!==b.indexOf("/",b.length-1)&&(c="dir"),d=sa()+"/api/v1/dump?"+c+"="+encodeURIComponent(b)+(this.ef?"":d)+"&format=json"));ra(d,!0,null,this,this.co,b)};
-k.co=function(a,b,c,d){var e=null;this.ff=!1;var f=0>c&&this.Da&&!this.Da.Nb;if(this.Bi)c?this.Ga('Unable to connect to disk "'+d+'" (error '+c+": "+b+")",f):(this.Ad=!0,e=this);else if(c)this.Ga('Unable to load disk "'+this.Kd+'" (error '+c+")",f);else try{if(0g&&0b.indexOf("0x")&&'["'!=
+function V(a){this.Ik=a.adapter;switch(this.Ik){case 1:this.Qj=1016;this.kg=4;break;case 2:this.Qj=760;this.kg=3;break;default:w("Unrecognized serial adapter #"+this.Ik);return}this.ce=null;x.call(this,"SerialPort",a,V);var b=a.binding,c;a=ak;b&&(void 0===c&&(c="Panel"),(c=Na(c,this.id))&&(b=c.sa[b])&&this.xb(null,null,a,b))}y(x,V);var ak="buffer";k=V.prototype;k.lk=function(a,b){return a==this.sh?(this.Mk=b,this):null};
+k.xb=function(a,b,c,d){var e=this;switch(c){case ak:return this.sa[c]=this.ce=d,d.onkeydown=function(a){a=a||window.event;var b=a.charCode||a.keyCode;8===b&&(a.preventDefault&&a.preventDefault(),bk(e,[b]))},d.onkeypress=function(a){a=a||window.event;bk(e,[a.which||a.keyCode])},!0}return!1};k.pc=function(a,b,c,d){this.na=b;this.S=c;this.X=d;this.ka=C(a,"ChipSet");d&&Ph(d,V);ib(b,this,ck,this.Qj);mb(b,this,dk,this.Qj);this.Ta()};
+k.ac=function(a,b){if(!b)if(!a||!this.restore)this.reset();else if(!this.restore(a))return!1;return!0};k.Wb=function(a){return a&&this.save?this.save():!0};k.reset=function(){this.ie()};k.save=function(){var a=new H(this),b=0,c=[];c[b++]=this.ki;c[b++]=this.pk;c[b++]=this.Re;c[b++]=this.Tg;c[b++]=this.Zd;c[b++]=this.Tc;c[b++]=this.fd;c[b++]=this.Gc;c[b++]=this.nk;c[b]=this.Hf;a.set(0,c);return a.data()};k.restore=function(a){return this.ie(a[0])};
+k.ie=function(a){var b=0;void 0===a&&(a=[0,0,384,0,1,0,0,96,48,[]]);this.ki=a[b++];this.pk=a[b++];this.Re=a[b++];this.Tg=a[b++];this.Zd=a[b++];this.Tc=a[b++];this.fd=a[b++];this.Gc=a[b++];this.nk=a[b++];this.Hf=a[b];return!0};function bk(a,b){a.Hf=a.Hf.concat(b);ek(a)}function ek(a){0>8:this.Tg;this.ba(a,null,b,this.Tc&128?"DLM":"IER",c);return c};k.sn=function(a,b){var c=this.Zd;this.ba(a,null,b,"IIR",c);return c};k.tn=function(a,b){var c=this.Tc;this.ba(a,null,b,"LCR",c);return c};k.vn=function(a,b){var c=this.fd;this.ba(a,null,b,"MCR",c);return c};
+k.un=function(a,b){var c=this.Gc;this.ba(a,null,b,"LSR",c);return c};k.Bn=function(a,b){var c=this.nk;this.ba(a,null,b,"MSR",c);return c};k.ap=function(a,b,c){this.ba(a,b,c,this.Tc&128?"DLL":"THR");this.Tc&128?this.Re=this.Re&-256|b:(this.pk=b,this.Gc&=-97,this.ce?(13!=b&&(8==b?this.ce.value=this.ce.value.slice(0,-1):(this.ce.value+=String.fromCharCode(b),this.ce.scrollTop=this.ce.scrollHeight)),a=!0):a=!1,a&&(this.Gc|=96))};
+k.Mo=function(a,b,c){this.ba(a,b,c,this.Tc&128?"DLM":"IER");this.Tc&128?this.Re=this.Re&255|b<<8:this.Tg=b};k.No=function(a,b,c){this.ba(a,b,c,"LCR");this.Tc=b};
+k.Oo=function(a,b,c){var d=this.fd;this.ba(a,b,c,"MCR");this.fd=b;this.Mk&&(d^b)&3&&(a=this.Mk,b=this.fd,(c=3==(b&3))?a.mc||(d=!1,a.fd&2||(a.reset(),a.Qa("serial mouse reset"),d=!0),a.fd&1||(a.Qa("serial mouse ID requested"),d=!0),d&&(bk(a.Sf,[77]),a.Qa("serial mouse ID sent")),fk(a,a.Lb),a.mc=c):a.mc&&(a.Qa("serial mouse inactive"),gk(a.Lb),a.mc=c),a.fd=b)};k.Qa=function(a){this.X&&E(this.X,this.X.fk)&&this.X.message(a)};k.ba=function(a,b,c,d,e){this.X&&this.X.ba(this,a,b,c,d,this.X.fk,e)};
+var ck={0:V.prototype.Gn,1:V.prototype.rn,2:V.prototype.sn,3:V.prototype.tn,4:V.prototype.vn,5:V.prototype.un,6:V.prototype.Bn},dk={0:V.prototype.ap,1:V.prototype.Mo,3:V.prototype.No,4:V.prototype.Oo};Ba(function(){for(var a=B(window.document,"pcjs","serial"),b=0;ba.Cg||0>a.Dg)a.Cg=b.clientX,a.Dg=b.clientY;a.yf=b.clientX-a.Cg;a.zf=b.clientY-a.Dg;(a.yf||a.zf)&&ik(a,null,b.clientX,b.clientY);a.Cg=b.clientX;a.Dg=b.clientY}},!1),b.addEventListener("mousedown",function(b){jk(a,b.button,!0)},!1),b.addEventListener("mouseup",function(b){jk(a,b.button,!1)},!1),a.yi=!0),b.style.cursor="none")}function gk(a){a&&(a.style.cursor="auto")}
+function jk(a,b,c){if(a.mc&&a.S&&a.S.Ob)switch(b){case 0:a.ih!=c&&(a.ih=c,ik(a,"mouse button1 "+(c?"dn":"up")));break;case 2:a.jh!=c&&(a.jh=c,ik(a,"mouse button2 "+(c?"dn":"up")))}}function ik(a,b,c,d){var e=64|(a.ih?32:0)|(a.jh?16:0)|(a.zf&192)>>4|(a.yf&192)>>6,f=a.yf&63,g=a.zf&63;a.Qa((b?b+": ":"")+(void 0!==d?"mouse ("+c+","+d+"): ":"")+"serial packet ["+r(e)+","+r(f)+","+r(g)+"]");bk(a.Sf,[e,f,g]);a.yf=a.zf=0}k.Qa=function(a){this.X&&E(this.X,this.X.vm)&&this.X.message(a)};
+Ba(function(){for(var a=B(window.document,"pcjs","mouse"),b=0;bb.indexOf("/api/v1/dump")&&(a=fa(b),"json"==a?d=encodeURI(b):"demandrw"==this.mode||"demandro"==this.mode?(a="action=open&volume="+b+("&mode="+this.mode),a+="&chs="+this.gc+":"+this.$b+":"+this.jc+":"+this.Mb,a+="&machine="+this.ia.gf(),a+="&user="+this.ia.ge(),d=sa()+"/api/v1/disk?"+a,this.Di=!0):(c="path",d="&mbhd=10",!b.indexOf("http:")||!b.indexOf("ftp:")||0<="dsk ima img 360 720 12 144".split(" ").indexOf(a)?(c="disk",d="&mbhd=0"):
+-1!==b.indexOf("/",b.length-1)&&(c="dir"),d=sa()+"/api/v1/dump?"+c+"="+encodeURIComponent(b)+(this.ef?"":d)+"&format=json"));ra(d,!0,null,this,this.ho,b)};
+k.ho=function(a,b,c,d){var e=null;this.ff=!1;var f=0>c&&this.Da&&!this.Da.Nb;if(this.Di)c?this.Ga('Unable to connect to disk "'+d+'" (error '+c+": "+b+")",f):(this.Ad=!0,e=this);else if(c)this.Ga('Unable to load disk "'+this.Kd+'" (error '+c+")",f);else try{if(0g&&0b.indexOf("0x")&&'["'!=
b.substr(0,2)?JSON.parse(b.replace(/([a-z]+):/gm,'"$1":').replace(/\/\/[^\n]*/gm,"")):eval("("+b+")");if(h.length)if(1==h.length)w(h[0]);else{for(b=a=0;b>2,q=m.pattern;void 0===q&&(q=m.pattern=0);var t=m.data;if(void 0===t){var s=m.bytes;if(void 0!==s&&s.length){for(var f=n<<2,v=s.length;vb&&(b=0);2E3b&&(b=0);2E3>2,e=Array(d),f=0;f>2,e=a.data;a=a.pattern;for(var f=0;f>8&255;c[d++]=g>>16&255;c[d++]=g>>24&255}return c}function tk(a,b){var c=-1;if(b>2,c=(d>((b&3)<<3)&255;return c}
k.write=function(a,b,c){if(this.ff)return!1;if(b>2;b=(b&3)<<3;for(var g=d.length;g<=f;g++)d[g]=e;a.Hc?f=a.Zc+a.Hc&&(a.Hc+=f-(a.Zc+a.Hc)+1):(a.Zc=f,a.Hc=1);d[f]=d[f]&~(255<=this.ib.length||m>=this.ib[h].length||n>=this.ib[h][m].length){c="sector "+h+":"+m+":"+n+" out of range ("+b+" changes applied)";b=-1;break}if(this.ff){c="unable to modify write-protected disk";b=-1;break}e=
-g[f++];f=g[f++];g=e+f.length;h=this.ib[h][m][n];for(m=h.data.length;mb&&this.Ga("unable to restore disk '"+this.Kd+": "+c);return b};k.Qa=function(a){this.X&&E(this.X,this.X.om)&&this.X.message(a)};
-function uk(a){x.call(this,"FDC",a,uk);this.dmaRead=this.qi;this.dmaWrite=this.ri;this.dmaFormat=this.Am;this.Le=null;if(a.autoMount&&(this.Le=a.autoMount,"string"==typeof this.Le))try{this.Le=eval("("+a.autoMount+")")}catch(b){w("FDC auto-mount error: "+b.message+" ("+a.autoMount+")"),this.Le=null}this.wc=[]}y(x,uk);l={};aa={};
-var vk={3:{wd:3,be:0,name:aa.Jp},4:{wd:2,be:1,name:aa.Hp},5:{wd:9,be:7,name:aa.Sp},6:{wd:9,be:7,name:aa.Cp},7:{wd:2,be:0,name:aa.Ep},8:{wd:1,be:2,name:aa.Ip},10:{wd:2,be:7,name:aa.Dp},13:{wd:6,be:7,name:aa.xp},15:{wd:3,be:0,name:aa.Gp}};k=uk.prototype;
+k.save=function(){var a=0,b=[];b[a++]=[this.tf,this.gh];if(!this.Ad&&!this.ff)for(var c=this.pb,d=0;d=this.pb.length||m>=this.pb[h].length||n>=this.pb[h][m].length){c="sector "+h+":"+m+":"+n+" out of range ("+b+" changes applied)";b=-1;break}if(this.ff){c="unable to modify write-protected disk";b=-1;break}e=
+g[f++];f=g[f++];g=e+f.length;h=this.pb[h][m][n];for(m=h.data.length;mb&&this.Ga("unable to restore disk '"+this.Kd+": "+c);return b};k.Qa=function(a){this.X&&E(this.X,this.X.rm)&&this.X.message(a)};
+function uk(a){x.call(this,"FDC",a,uk);this.dmaRead=this.si;this.dmaWrite=this.ti;this.dmaFormat=this.Dm;this.Le=null;if(a.autoMount&&(this.Le=a.autoMount,"string"==typeof this.Le))try{this.Le=eval("("+a.autoMount+")")}catch(b){w("FDC auto-mount error: "+b.message+" ("+a.autoMount+")"),this.Le=null}this.wc=[]}y(x,uk);l={};aa={};
+var vk={3:{wd:3,be:0,name:aa.Mp},4:{wd:2,be:1,name:aa.Kp},5:{wd:9,be:7,name:aa.Vp},6:{wd:9,be:7,name:aa.Fp},7:{wd:2,be:0,name:aa.Hp},8:{wd:1,be:2,name:aa.Lp},10:{wd:2,be:7,name:aa.Gp},13:{wd:6,be:7,name:aa.Ap},15:{wd:3,be:0,name:aa.Jp}};k=uk.prototype;
k.xb=function(a,b,c,d){switch(c){case "listDisks":return this.sa[c]=d,a=window.document.createElement("option"),a.value="?",a.innerHTML="User-defined URL...",d.appendChild(a),d.onchange=function(a,b){return function(){var c=a.sa.descDisk;if(c){var d=b.options[b.selectedIndex];if(d){var m={};if(d=d.getAttribute("data-value"))try{m=eval("({"+d+"})")}catch(n){w("FDC option error: "+(n.message||n))}d=m.desc;void 0===d&&(d="");m=m.href;void 0!==m&&(d=''+d+"");c.innerHTML=
d}}}}(this,d),!0;case "descDisk":case "listDrives":return this.sa[c]=d,d.onchange=function(a,b){return function(){var c=parseInt(b.value,10);isNaN(c)||wk(a,c)}}(this,d),!0;case "loadDrive":return this.sa[c]=d,d.onclick=function(a){return function(){var b,c=a.sa.listDisks,d=a.sa.listDrives;if(c&&d&&!isNaN(b=parseInt(d.value,10))&&0<=b&&ba.va.restore(f)&&(e=!1);e&&a.va&&void 0!==a.Va&&(a.Ra=a.va.seek(a.lb,a.Ha,a.Na));return e};k.Uj=function(){for(var a=0,b=[],c=0;ca.oc&&(this.Ga('Diskette "'+c+'" too large for drive '+String.fromCharCode(65+a.fb)),b=null);b&&(a.va=b,a.bm=c,a.Oe=d,Dk(this,c,d,b),this.oe|=128,this.Ga('Mounted diskette "'+c+'" in drive '+String.fromCharCode(65+a.fb),a.Fe));a.Fe&&(a.Fe=!1,--this.ze||this.Ta());wk(this,a.fb)};
-function wk(a,b){if(0<=b&&b=this.Xa&&(this.ya&=-81,this.pb=this.Xa=0);return c};
-k.Do=function(a,b,c){this.ba(a,b,c,"DATA["+this.Xa+"]");this.Xa=vk[a].wd){b=!1;this.pb=0;var d;a=this.Oa()&31;switch(a){case 3:this.Oa(l.Kp);this.Oa(l.zp);this.Kb();break;case 4:c=this.Oa(l.Af);this.fb=c&3;d=this.za[this.fb];this.Kb();this.hb((d.Ya&4278190080)>>>24,l.Op);break;case 5:case 6:c=this.Oa(l.Af);this.fb=c&3;d=this.za[this.fb];d.Ha=c>>2&1;d.lb=this.Oa(l.Sh);this.Oa(l.Th);d.Na=this.Oa(l.Wh);b=this.Oa(l.Ig);
-d.Wa=128<>2&1;d.Na=1;b=0;d.Ya=0;d.va&&
-(d.Ra=d.va.seek(d.lb,d.Ha,d.Na))?b=d.Ra.length:d.Ya=1088;Ek(this,d);Fk(this,d);Gk(this,d);this.hb(d.lb,l.Sh);this.hb(d.Ha,l.Th);this.hb(d.Na,l.Wh);this.hb(b,l.Ig);b=!0;break;case 13:c=this.Oa(l.Af);this.fb=c&3;d=this.za[this.fb];d.Ha=c>>2&1;b=this.Oa(l.Ig);d.Wa=128<>2&1,a=this.Oa(l.Ap),d.lb+=a-d.Yd,0>d.lb&&(d.lb=0),d.lb>=d.oc&&(d.lb=d.oc-1),d.Yd=a,d.Ya=32,0==d.lb&&(d.Ya|=268435456),this.Kb(),b=!0}0>>8,l.Mp)}function Gk(a,b){a.hb((b.Ya&16711680)>>>16,l.Np)}k.qi=function(a,b,c){void 0===b||0>b?this.sc(a,c):c(-1,!1)};k.ri=function(a,b){return void 0!==b&&0<=b?this.Dc(a,b):-1};k.Am=function(a,b){return void 0!==b&&0<=b?this.Wj(a,b):-1};k.si=function(a){a.Ya=72;a.va&&(a.Ra=null,a.Ya=0,this.ka&&(si(this.ka,2,this,"dmaRead",a),mi(this.ka,2)))};
-k.ti=function(a){a.Ya=72;a.va&&(a.va.ff?a.Ya=576:(a.Ra=null,a.Ya=0,this.ka&&(si(this.ka,2,this,"dmaWrite",a),mi(this.ka,2))))};k.vk=function(a){a.Ya=72;a.va&&(a.Ra=null,a.Ya=0,this.ka&&(a.Ce=0,a.yc=Array(4),a.Lf=!0,a.Rf=0,si(this.ka,2,this,"dmaFormat",a),mi(this.ka,2),a.Lf=!1))};k.sc=function(a,b){var c=-1;if(!a.Ya&&a.va){do{if(a.Ra&&0<=(c=tk(a.Ra,a.Va++)))break;a.Ra=a.va.seek(a.lb,a.Ha,a.Na);if(!a.Ra){a.Ya=1088;break}a.Va=0;this.If(a)}while(1)}b(c,!1)};
-k.Dc=function(a,b){if(a.Ya||!a.va)return-1;do{if(a.Ra&&a.va.write(a.Ra,a.Va++,b))break;a.Ra=a.va.seek(a.lb,a.Ha,a.Na);if(!a.Ra){a.Ya=8256;b=-1;break}a.Va=0;this.If(a)}while(1);return b};k.If=function(a){a.Na++;a.Na>=a.rc+1&&(a.Na=1,a.Ha++,a.Ha>=a.fc&&(a.Ha=0,a.lb++))};k.Wj=function(a,b){if(a.Ya)return-1;a.yc[a.Ce++]=b;if(a.Ce==a.yc.length){a.lb=a.yc[0];a.Ha=a.yc[1];a.Na=a.yc[2];a.Wa=128<this.Dc(a,a.jk))return-1;a.Rf++}a.Rf>=a.$d&&(b=-1);return b};
-k.Mi=function(a){var b=this.S.J&255;this.X&&E(this.X,this.X.Eg)&&128>b&&(Ec(this.X,19,a),Fc(this.S,a,function(a,b){return function(e){Gc(a.X,19,e,F(a.S)-b)}}(this,F(this.S))));return!0};k.Qa=function(a){this.X&&E(this.X,this.X.Eg)&&this.X.message(a)};k.ba=function(a,b,c,d,e){this.X&&this.X.ba(this,a,b,c,d,this.X.Eg,e)};var zk={1012:uk.prototype.jn,1013:uk.prototype.gn,1015:uk.prototype.hn},Ak={1010:uk.prototype.Eo,1013:uk.prototype.Do,1015:uk.prototype.Co};
-Ba(function(){for(var a=B(window.document,"pcjs","fdc"),b=0;b=e&&(this.qf|=(f.type&3)<<(1-e<<1))}return d};
-k.Sj=function(){var a=0,b=[];this.Ee?(b[a++]=this.ne,b[a++]=this.am,b[a++]=this.Lh,b[a++]=this.Mh,b[a++]=this.Kh,b[a++]=this.Jh,b[a++]=this.rf,b[a++]=this.ya,b[a++]=this.Pj):(b[a++]=this.qf,b[a++]=this.ya,b[a++]=this.ac,b[a++]=this.pb,b[a++]=this.Xa,b[a++]=this.$l,b[a++]=this.Zl,b[a++]=this.Yl,b[a++]=this.hf);b[a]=this.Uj();return b};
-k.Ki=function(a,b,c,d,e){var f=0,g=!0;void 0===d&&(d=[0,0,!1,Array(8)]);b.fb=a;b.errorCode=d[f++];b.gm=d[f++];b.ef=d[f++];b.We=d[f++];b.Xe=d[f++];b.Ha=d[f++];b.fc=d[f++];b.Qd=d[f++];b.Na=d[f++];b.$d=d[f++];b.Wa=d[f++];b.Yg=this.Ee?0:1;b.name=c.name;void 0===b.name&&(b.name="Hard Drive");b.path=c.path;b.mode=c.mode||(b.path?"preload":"local");"demandro"!=b.mode&&"demandrw"!=b.mode||this.ge()||(b.mode="local");b.type=c.type;if(void 0===b.type||void 0===Hk[this.ag][b.type])b.type=this.Mm;c=Hk[this.ag][b.type];
-b.rc=c[2]||17;b.Mb=c[3]||512;if(e&&this.ka&&(e=this.ka,c=b.type,e.pa)){var h=e.pa[18],h=a?h&240|c:h&15|c<<4;e.pa&&(e.pa[18]=h,ai(e))}void 0===b.va&&(b.va=null,this.Ga("Type "+b.type+' "'+b.name+'" is fixed disk '+a,!0));Mk(this,b);b.Va=d[f++];b.Ra=null;b.va&&(a=d[f],void 0!==a&&0>b.va.restore(a)&&(g=!1),g&&void 0!==b.Va&&(b.Ra=b.va.seek(b.Qd,b.Ha,b.Na+b.Yg)));return g};k.Uj=function(){for(var a=0,b=[],c=0;c=this.Xa&&(this.pb=this.Xa=0,this.ya&=-15);return c};
-k.$o=function(a,b,c){this.ba(a,b,c,"DATA["+this.Xa+"]");this.Xa=a&&(this.ya|=2,this.ya&=-2,Nk(this))};k.Kn=function(a,b){var c=this.ya;this.ba(a,null,b,"STATUS",c);this.pb=this.Pa.Mb){var e=this;this.sc(this.Pa,function(a){0<=a?e.ka&&zi(e.ka,14):(e.ya=1,e.ne=16)},!1)}else this.ya=80;d||this.ba(a,null,b,"DATA",c);return c};
-k.ro=function(a,b,c){this.Pa&&0!=this.Pa.Va||this.ba(a,b,c,"DATA");this.Pa&&this.Pa.Wa>=this.Pa.Mb&&(0>this.Dc(this.Pa,b)?(this.ya=1,this.ne=16):this.Pa.Va==this.Pa.Mb&&(this.Pa.Wa-=this.Pa.Mb,this.ka&&zi(this.ka,14),this.Pa.Wa>=this.Pa.Mb||(this.ya=80)))};k.Wm=function(a,b){var c=this.ne;this.ba(a,null,b,"ERROR",c);return c};k.vo=function(a,b,c){this.ba(a,b,c,"WPREC");this.am=b};k.Xm=function(a,b){var c=this.Lh;this.ba(a,null,b,"SECCNT",c);return c};
-k.to=function(a,b,c){this.ba(a,b,c,"SECCNT");this.Lh=b};k.Ym=function(a,b){var c=this.Mh;this.ba(a,null,b,"SECNUM",c);return c};k.uo=function(a,b,c){this.ba(a,b,c,"SECNUM");this.Mh=b};k.Tm=function(a,b){var c=this.Kh;this.ba(a,null,b,"CYLLO",c);return c};k.qo=function(a,b,c){this.ba(a,b,c,"CYLLO");this.Kh=b};k.Sm=function(a,b){var c=this.Jh;this.ba(a,null,b,"CYLHI",c);return c};k.po=function(a,b,c){this.ba(a,b,c,"CYLHI");this.Jh=b};k.Vm=function(a,b){var c=this.rf;this.ba(a,null,b,"DRVHD",c);return c};
-k.so=function(a,b,c){this.ba(a,b,c,"DRVHD");this.rf=b;this.ya=this.za[this.rf&16?1:0]?this.ya|64:this.ya&-65};k.Zm=function(a,b){var c=this.ya;this.ba(a,null,b,"STATUS",c);return c};k.oo=function(a,b,c){this.ba(a,b,c,"COMMAND");this.Pj=b;this.ka&&Ai(this.ka,14);Ok(this)};
-function Ok(a){var b=!1,c=a.Pj,d=a.rf&16?1:0,e=a.rf&15,f=a.Kh|(a.Jh&3)<<8,g=a.Mh,h=a.Lh;a.Pa=null;a.ne=0;a.ya=80;(d=a.za[d])?(d.Qd=f,d.Ha=e,d.Na=g,d.Wa=h*d.Mb,c=144<=c?c:c&240,d.Ra=null,d.errorCode=0,a.Pa=d):c=-1;switch(c&240){case 32:a.sc(d,function(b){0<=b&&a.ka?(zi(a.ka,14),a.ya=136):(a.ya=1,a.ne=16)},!1);break;case 48:a.ka?(zi(a.ka,14),a.ya=136):(a.ya=1,a.ne=4);break;case 16:b=!0;break;case 64:b=!0;break;case 144:a.ne=1;b=!0;break;case 145:d.fc=e+1,d.rc=h,b=!0}b&&a.ka&&zi(a.ka,14)}
-function Nk(a){a.pb=0;var b=a.Oa(),c=a.Oa(),d=c&32,e=d>>5,f=c&31,g=a.Oa(),h=a.Oa(),m=g<<2&768|h,n=g&63,q=a.Oa(),t=a.Oa(),s=a.za[e];s&&(s.Qd=m,s.Ha=f,s.Na=n,s.Wa=q*s.Mb);switch(b){case 3:a.Kb(s?s.errorCode:4);a.hb(c);a.hb(g);a.hb(h);a.hb(0|d);b=-1;break;case 12:for(c=0;0<=(b=a.Oa());)s&&cb?this.sc(a,c):c(-1,!1)};
-k.ri=function(a,b){return void 0!==b&&0<=b?this.Dc(a,b):-1};k.Bm=function(a,b){var c;void 0!==b&&0<=b?(c=b,a.Vaa.va.restore(f)&&(e=!1);e&&a.va&&void 0!==a.Va&&(a.Ra=a.va.seek(a.kb,a.Ha,a.Na));return e};k.Xj=function(){for(var a=0,b=[],c=0;ca.gc||e[1]>a.$b||e[2]>a.jc)&&(this.Ga('Diskette "'+c+'" too large for drive '+String.fromCharCode(65+a.fb)),b=null);b&&(a.va=b,a.em=c,a.Oe=d,Dk(this,c,d,b),this.oe|=128,this.Ga('Mounted diskette "'+c+'" in drive '+String.fromCharCode(65+a.fb),a.Fe),a.Wi=e[0],a.Ch=e[1],a.Dh=e[2]);a.Fe&&(a.Fe=!1,--this.ze||this.Ta());wk(this,a.fb)};
+function wk(a,b){if(0<=b&&b=this.Xa&&(this.ya&=-81,this.ob=this.Xa=0);return c};
+k.Go=function(a,b,c){this.ba(a,b,c,"DATA["+this.Xa+"]");this.Xa=vk[a].wd){b=!1;this.ob=0;var d;a=this.Oa()&31;switch(a){case 3:this.Oa(l.Np);this.Oa(l.Cp);this.Kb();break;case 4:c=this.Oa(l.Af);this.fb=c&3;d=this.za[this.fb];this.Kb();this.hb((d.Ya&4278190080)>>>24,l.Rp);break;case 5:case 6:c=this.Oa(l.Af);this.fb=c&3;d=this.za[this.fb];d.Ha=c>>2&1;d.kb=this.Oa(l.Uh);this.Oa(l.Vh);d.Na=this.Oa(l.Yh);b=this.Oa(l.Ig);
+d.Wa=128<>2&1;d.Na=1;b=0;d.Ya=0;d.va&&
+(d.Ra=d.va.seek(d.kb,d.Ha,d.Na))?b=d.Ra.length:d.Ya=1088;Ek(this,d);Fk(this,d);Gk(this,d);this.hb(d.kb,l.Uh);this.hb(d.Ha,l.Vh);this.hb(d.Na,l.Yh);this.hb(b,l.Ig);b=!0;break;case 13:c=this.Oa(l.Af);this.fb=c&3;d=this.za[this.fb];d.Ha=c>>2&1;b=this.Oa(l.Ig);d.Wa=128<>2&1,a=this.Oa(l.Dp),d.kb+=a-d.Yd,0>d.kb&&(d.kb=0),d.kb>=d.gc&&(d.kb=d.gc-1),d.Yd=a,d.Ya=32,0==d.kb&&(d.Ya|=268435456),this.Kb(),b=!0}0>>8,l.Pp)}function Gk(a,b){a.hb((b.Ya&16711680)>>>16,l.Qp)}k.si=function(a,b,c){void 0===b||0>b?this.sc(a,c):c(-1,!1)};k.ti=function(a,b){return void 0!==b&&0<=b?this.Dc(a,b):-1};k.Dm=function(a,b){return void 0!==b&&0<=b?this.Zj(a,b):-1};k.ui=function(a){a.Ya=72;a.va&&(a.Ra=null,a.Ya=0,this.ka&&(si(this.ka,2,this,"dmaRead",a),mi(this.ka,2)))};
+k.vi=function(a){a.Ya=72;a.va&&(a.va.ff?a.Ya=576:(a.Ra=null,a.Ya=0,this.ka&&(si(this.ka,2,this,"dmaWrite",a),mi(this.ka,2))))};k.yk=function(a){a.Ya=72;a.va&&(a.Ra=null,a.Ya=0,this.ka&&(a.Ce=0,a.yc=Array(4),a.Lf=!0,a.Rf=0,si(this.ka,2,this,"dmaFormat",a),mi(this.ka,2),a.Lf=!1))};k.sc=function(a,b){var c=-1;if(!a.Ya&&a.va){do{if(a.Ra&&0<=(c=tk(a.Ra,a.Va++)))break;a.Ra=a.va.seek(a.kb,a.Ha,a.Na);if(!a.Ra){a.Ya=1088;break}a.Va=0;this.If(a)}while(1)}b(c,!1)};
+k.Dc=function(a,b){if(a.Ya||!a.va)return-1;do{if(a.Ra&&a.va.write(a.Ra,a.Va++,b))break;a.Ra=a.va.seek(a.kb,a.Ha,a.Na);if(!a.Ra){a.Ya=8256;b=-1;break}a.Va=0;this.If(a)}while(1);return b};k.If=function(a){a.Na++;a.Na>=a.Dh+1&&(a.Na=1,a.Ha++,a.Ha>=a.Ch&&(a.Ha=0,a.kb++))};k.Zj=function(a,b){if(a.Ya)return-1;a.yc[a.Ce++]=b;if(a.Ce==a.yc.length){a.kb=a.yc[0];a.Ha=a.yc[1];a.Na=a.yc[2];a.Wa=128<this.Dc(a,a.mk))return-1;a.Rf++}a.Rf>=a.$d&&(b=-1);return b};
+k.Oi=function(a){var b=this.S.J&255;this.X&&E(this.X,this.X.Eg)&&128>b&&(Ec(this.X,19,a),Fc(this.S,a,function(a,b){return function(e){Gc(a.X,19,e,F(a.S)-b)}}(this,F(this.S))));return!0};k.Qa=function(a){this.X&&E(this.X,this.X.Eg)&&this.X.message(a)};k.ba=function(a,b,c,d,e){this.X&&this.X.ba(this,a,b,c,d,this.X.Eg,e)};var zk={1012:uk.prototype.mn,1013:uk.prototype.kn,1015:uk.prototype.ln},Ak={1010:uk.prototype.Ho,1013:uk.prototype.Go,1015:uk.prototype.Fo};
+Ba(function(){for(var a=B(window.document,"pcjs","fdc"),b=0;b=e&&(this.qf|=(f.type&3)<<(1-e<<1))}return d};
+k.Vj=function(){var a=0,b=[];this.Ee?(b[a++]=this.ne,b[a++]=this.dm,b[a++]=this.Nh,b[a++]=this.Oh,b[a++]=this.Mh,b[a++]=this.Lh,b[a++]=this.rf,b[a++]=this.ya,b[a++]=this.Sj):(b[a++]=this.qf,b[a++]=this.ya,b[a++]=this.bc,b[a++]=this.ob,b[a++]=this.Xa,b[a++]=this.cm,b[a++]=this.bm,b[a++]=this.am,b[a++]=this.hf);b[a]=this.Xj();return b};
+k.Mi=function(a,b,c,d,e){var f=0,g=!0;void 0===d&&(d=[0,0,!1,Array(8)]);b.fb=a;b.errorCode=d[f++];b.jm=d[f++];b.ef=d[f++];b.We=d[f++];b.Xe=d[f++];b.Ha=d[f++];b.$b=d[f++];b.Qd=d[f++];b.Na=d[f++];b.$d=d[f++];b.Wa=d[f++];b.Yg=this.Ee?0:1;b.name=c.name;void 0===b.name&&(b.name="Hard Drive");b.path=c.path;b.mode=c.mode||(b.path?"preload":"local");"demandro"!=b.mode&&"demandrw"!=b.mode||this.ge()||(b.mode="local");b.type=c.type;if(void 0===b.type||void 0===Hk[this.ag][b.type])b.type=this.Pm;c=Hk[this.ag][b.type];
+b.jc=c[2]||17;b.Mb=c[3]||512;if(e&&this.ka&&(e=this.ka,c=b.type,e.pa)){var h=e.pa[18],h=a?h&240|c:h&15|c<<4;e.pa&&(e.pa[18]=h,ai(e))}void 0===b.va&&(b.va=null,this.Ga("Type "+b.type+' "'+b.name+'" is fixed disk '+a,!0));Mk(this,b);b.Va=d[f++];b.Ra=null;b.va&&(a=d[f],void 0!==a&&0>b.va.restore(a)&&(g=!1),g&&void 0!==b.Va&&(b.Ra=b.va.seek(b.Qd,b.Ha,b.Na+b.Yg)));return g};k.Xj=function(){for(var a=0,b=[],c=0;c=this.Xa&&(this.ob=this.Xa=0,this.ya&=-15);return c};
+k.cp=function(a,b,c){this.ba(a,b,c,"DATA["+this.Xa+"]");this.Xa=a&&(this.ya|=2,this.ya&=-2,Nk(this))};k.Nn=function(a,b){var c=this.ya;this.ba(a,null,b,"STATUS",c);this.ob=this.Pa.Mb){var e=this;this.sc(this.Pa,function(a){0<=a?e.ka&&zi(e.ka,14):(e.ya=1,e.ne=16)},!1)}else this.ya=80;d||this.ba(a,null,b,"DATA",c);return c};
+k.uo=function(a,b,c){this.Pa&&0!=this.Pa.Va||this.ba(a,b,c,"DATA");this.Pa&&this.Pa.Wa>=this.Pa.Mb&&(0>this.Dc(this.Pa,b)?(this.ya=1,this.ne=16):this.Pa.Va==this.Pa.Mb&&(this.Pa.Wa-=this.Pa.Mb,this.ka&&zi(this.ka,14),this.Pa.Wa>=this.Pa.Mb||(this.ya=80)))};k.Zm=function(a,b){var c=this.ne;this.ba(a,null,b,"ERROR",c);return c};k.yo=function(a,b,c){this.ba(a,b,c,"WPREC");this.dm=b};k.$m=function(a,b){var c=this.Nh;this.ba(a,null,b,"SECCNT",c);return c};
+k.wo=function(a,b,c){this.ba(a,b,c,"SECCNT");this.Nh=b};k.an=function(a,b){var c=this.Oh;this.ba(a,null,b,"SECNUM",c);return c};k.xo=function(a,b,c){this.ba(a,b,c,"SECNUM");this.Oh=b};k.Wm=function(a,b){var c=this.Mh;this.ba(a,null,b,"CYLLO",c);return c};k.to=function(a,b,c){this.ba(a,b,c,"CYLLO");this.Mh=b};k.Vm=function(a,b){var c=this.Lh;this.ba(a,null,b,"CYLHI",c);return c};k.so=function(a,b,c){this.ba(a,b,c,"CYLHI");this.Lh=b};k.Ym=function(a,b){var c=this.rf;this.ba(a,null,b,"DRVHD",c);return c};
+k.vo=function(a,b,c){this.ba(a,b,c,"DRVHD");this.rf=b;this.ya=this.za[this.rf&16?1:0]?this.ya|64:this.ya&-65};k.bn=function(a,b){var c=this.ya;this.ba(a,null,b,"STATUS",c);return c};k.ro=function(a,b,c){this.ba(a,b,c,"COMMAND");this.Sj=b;this.ka&&Ai(this.ka,14);Ok(this)};
+function Ok(a){var b=!1,c=a.Sj,d=a.rf&16?1:0,e=a.rf&15,f=a.Mh|(a.Lh&3)<<8,g=a.Oh,h=a.Nh;a.Pa=null;a.ne=0;a.ya=80;(d=a.za[d])?(d.Qd=f,d.Ha=e,d.Na=g,d.Wa=h*d.Mb,c=144<=c?c:c&240,d.Ra=null,d.errorCode=0,a.Pa=d):c=-1;switch(c&240){case 32:a.sc(d,function(b){0<=b&&a.ka?(zi(a.ka,14),a.ya=136):(a.ya=1,a.ne=16)},!1);break;case 48:a.ka?(zi(a.ka,14),a.ya=136):(a.ya=1,a.ne=4);break;case 16:b=!0;break;case 64:b=!0;break;case 144:a.ne=1;b=!0;break;case 145:d.$b=e+1,d.jc=h,b=!0}b&&a.ka&&zi(a.ka,14)}
+function Nk(a){a.ob=0;var b=a.Oa(),c=a.Oa(),d=c&32,e=d>>5,f=c&31,g=a.Oa(),h=a.Oa(),m=g<<2&768|h,n=g&63,q=a.Oa(),t=a.Oa(),s=a.za[e];s&&(s.Qd=m,s.Ha=f,s.Na=n,s.Wa=q*s.Mb);switch(b){case 3:a.Kb(s?s.errorCode:4);a.hb(c);a.hb(g);a.hb(h);a.hb(0|d);b=-1;break;case 12:for(c=0;0<=(b=a.Oa());)s&&cb?this.sc(a,c):c(-1,!1)};
+k.ti=function(a,b){return void 0!==b&&0<=b?this.Dc(a,b):-1};k.Em=function(a,b){var c;void 0!==b&&0<=b?(c=b,a.Va=a.rc+b&&(a.Na=b,a.Ha++,a.Ha>=a.fc&&(a.Ha=0,a.Qd++))};
-k.Wj=function(a,b){if(a.errorCode)return-1;a.yc[a.Ce++]=b;if(a.Ce==a.yc.length){a.Qd=a.yc[0];a.Ha=a.yc[1];a.Na=a.yc[2];a.Wa=128<this.Dc(a,a.jk))return-1;a.Rf++}a.Rf>=a.$d&&(b=-1);return b};k.Mn=function(a){var b=this.S.J&255;!(this.S.G>>8)&&128>8)||(a=!this.ka)||(a=!(this.ka.tb[0].vd&64));return a?!0:!1};k.Qa=function(a){this.X&&E(this.X,this.X.Vh)&&this.X.message(a)};k.ba=function(a,b,c,d,e){this.X&&this.X.ba(this,a,b,c,d,this.X.Vh,e)};
-var Jk={800:W.prototype.Jn,801:W.prototype.Kn,802:W.prototype.In},Ik={496:W.prototype.Um,497:W.prototype.Wm,498:W.prototype.Xm,499:W.prototype.Ym,500:W.prototype.Tm,501:W.prototype.Sm,502:W.prototype.Vm,503:W.prototype.Zm},Lk={800:W.prototype.$o,801:W.prototype.cp,802:W.prototype.bp,803:W.prototype.ap,807:W.prototype.Kj,811:W.prototype.Kj,815:W.prototype.Kj},Kk={496:W.prototype.ro,497:W.prototype.vo,498:W.prototype.to,499:W.prototype.uo,500:W.prototype.qo,501:W.prototype.po,502:W.prototype.so,503:W.prototype.oo};
-Ba(function(){for(var a=B(window.document,"pcjs","hdc"),b=0;b=a.jc+b&&(a.Na=b,a.Ha++,a.Ha>=a.$b&&(a.Ha=0,a.Qd++))};
+k.Zj=function(a,b){if(a.errorCode)return-1;a.yc[a.Ce++]=b;if(a.Ce==a.yc.length){a.Qd=a.yc[0];a.Ha=a.yc[1];a.Na=a.yc[2];a.Wa=128<this.Dc(a,a.mk))return-1;a.Rf++}a.Rf>=a.$d&&(b=-1);return b};k.Pn=function(a){var b=this.S.J&255;!(this.S.G>>8)&&128>8)||(a=!this.ka)||(a=!(this.ka.tb[0].vd&64));return a?!0:!1};k.Qa=function(a){this.X&&E(this.X,this.X.Xh)&&this.X.message(a)};k.ba=function(a,b,c,d,e){this.X&&this.X.ba(this,a,b,c,d,this.X.Xh,e)};
+var Jk={800:W.prototype.Mn,801:W.prototype.Nn,802:W.prototype.Ln},Ik={496:W.prototype.Xm,497:W.prototype.Zm,498:W.prototype.$m,499:W.prototype.an,500:W.prototype.Wm,501:W.prototype.Vm,502:W.prototype.Ym,503:W.prototype.bn},Lk={800:W.prototype.cp,801:W.prototype.fp,802:W.prototype.ep,803:W.prototype.dp,807:W.prototype.Nj,811:W.prototype.Nj,815:W.prototype.Nj},Kk={496:W.prototype.uo,497:W.prototype.yo,498:W.prototype.wo,499:W.prototype.xo,500:W.prototype.to,501:W.prototype.so,502:W.prototype.vo,503:W.prototype.ro};
+Ba(function(){for(var a=B(window.document,"pcjs","hdc"),b=0;bb&&16!=b&&21!=b&&22!=b&&26!=b&&28!=b){var d=a.S.G>>8,e=$k[b];if(e=e&&e[d]||""){var f=a.S;a.jb[X[0]]=r(f.G&255);a.jb[X[1]]=r(f.I&255);a.jb[X[2]]=r(f.J&255);a.jb[X[3]]=r(f.B&255);a.jb[X[4]]=r(f.G>>8);a.jb[X[5]]=r(f.I>>8);a.jb[X[6]]=r(f.J>>8);a.jb[X[7]]=r(f.B>>8);a.jb[X[8]]=u(f.G);a.jb[X[9]]=u(f.I);a.jb[X[10]]=u(f.J);a.jb[X[11]]=u(f.B);a.jb[X[12]]=u(f.Y);a.jb[X[13]]=u(f.H);a.jb[X[14]]=u(f.F);a.jb[X[15]]=u(f.D);a.jb[X[16]]=u(f.Za.oa);a.jb[X[17]]=u(f.ua.oa);a.jb[X[18]]=u(f.wb.oa);
-a.jb[X[19]]=u(f.Eb.oa);a.jb[X[20]]=u(f.qa);e=" "+ia(a.jb,e)}a.message("INT 0x"+r(b)+": AH="+r(d)+" at "+da(c-a.S.ua.Ua,a.S.ua.oa)+e)}}function Gc(a,b,c,d,e){32>b&&16!=b&&21!=b&&22!=b&&26!=b&&28!=b&&a.message("INT 0x"+r(b)+"("+c+"): C="+(Uc(a.S)?1:0)+(e||"")+" (cycles="+d+")")}
-k.ba=function(a,b,c,d,e,f,g){f||(f=0);f|=Y.bk.La;if(null==d||(this.dc&f)==f)f=null,null!=d&&(f=this.S.ua.oa,d-=this.S.ua.Ua),this.message(a.sh+"."+(null!=c?"outPort":"inPort")+"(0x"+u(b)+","+(e?e:"unknown")+(null!=c?",0x"+r(c):"")+")"+(null!=g?": 0x"+r(g):"")+(null!=d?" at "+da(d,f):""))};k.message=function(a){this.ca(a);this.S&&(this.dc&Y.qm.La&&this.S.Ab(),a=this.S,a.of=0,a.Oc-=a.A,a.A=0,a.eh())};k.Pn=function(a){E(this,this.pm)&&Ec(this,33,a);return!0};k.Ln=function(){this.ca("Type ? for list of debugger commands")};
+!0}return!1};k.Md=function(){this.Tf&&this.Tf.focus()};function Ph(a,b,c,d){d&&(a.di=[]);d=0;c=al(a,c);for(var e in Y)b[e]=Y[e].La,0<=c.indexOf(Y[e].Ma)&&(d|=Y[e].La,a.ca(Y[e].Ma+" messages enabled"));void 0===a.ec&&(a.ec=0);a.ec|=d}function Qh(a,b,c){for(var d in Y)if(b==Y[d].La){a.di[d]=c;break}}function E(a,b){return(a.ec&b)===b}
+function Ec(a,b,c){if(32>b&&16!=b&&21!=b&&22!=b&&26!=b&&28!=b){var d=a.S.G>>8,e=$k[b];if(e=e&&e[d]||""){var f=a.S;a.ib[X[0]]=r(f.G&255);a.ib[X[1]]=r(f.I&255);a.ib[X[2]]=r(f.J&255);a.ib[X[3]]=r(f.B&255);a.ib[X[4]]=r(f.G>>8);a.ib[X[5]]=r(f.I>>8);a.ib[X[6]]=r(f.J>>8);a.ib[X[7]]=r(f.B>>8);a.ib[X[8]]=u(f.G);a.ib[X[9]]=u(f.I);a.ib[X[10]]=u(f.J);a.ib[X[11]]=u(f.B);a.ib[X[12]]=u(f.Y);a.ib[X[13]]=u(f.H);a.ib[X[14]]=u(f.F);a.ib[X[15]]=u(f.D);a.ib[X[16]]=u(f.Za.oa);a.ib[X[17]]=u(f.ua.oa);a.ib[X[18]]=u(f.wb.oa);
+a.ib[X[19]]=u(f.Eb.oa);a.ib[X[20]]=u(f.qa);e=" "+ia(a.ib,e)}a.message("INT 0x"+r(b)+": AH="+r(d)+" at "+da(c-a.S.ua.Ua,a.S.ua.oa)+e)}}function Gc(a,b,c,d,e){32>b&&16!=b&&21!=b&&22!=b&&26!=b&&28!=b&&a.message("INT 0x"+r(b)+"("+c+"): C="+(Uc(a.S)?1:0)+(e||"")+" (cycles="+d+")")}
+k.ba=function(a,b,c,d,e,f,g){f||(f=0);f|=Y.ek.La;if(null==d||(this.ec&f)==f)f=null,null!=d&&(f=this.S.ua.oa,d-=this.S.ua.Ua),this.message(a.sh+"."+(null!=c?"outPort":"inPort")+"(0x"+u(b)+","+(e?e:"unknown")+(null!=c?",0x"+r(c):"")+")"+(null!=g?": 0x"+r(g):"")+(null!=d?" at "+da(d,f):""))};k.message=function(a){this.ca(a);this.S&&(this.ec&Y.tm.La&&this.S.Ab(),a=this.S,a.of=0,a.Oc-=a.A,a.A=0,a.eh())};k.Sn=function(a){E(this,this.sm)&&Ec(this,33,a);return!0};k.On=function(){this.ca("Type ? for list of debugger commands")};
function Sk(a){var b;if(jd(a)){if(!a.Ud||!a.Ud.length){a.Ud=Array(1E4);for(b=0;b>c.rb],!1)}a.Sd=["read"];if(void 0!==a.Qc)for(b=1;b>c.rb],!0);a.Qc=["write"]}k.Vd=function(a,b,c){if(!kl(this,a,b)){b[2]=il(this,b);b[3]=c;a.push(b);if(a!=this.vc){var d=this.na,e=il(this,b);d.Aa[e>>d.rb].Vd(e&d.eb,a==this.Qc)}c||this.ca("breakpoint enabled: "+$(b)+" ("+a[0]+")");Sk(this);return!0}return!1};
function kl(a,b,c,d){var e=!1;c=il(a,c);for(var f=1;f>d.rb],b==a.Qc));g[3]||a.ca("breakpoint cleared: "+$(g)+" ("+b[0]+")");Sk(a);break}a.ca("breakpoint exists: "+$(g)+" ("+b[0]+")");break}}return e}function ll(a,b){for(var c=1;c=b&&f>g.rb].Vd(f&g.eb,d==a.Qc)}}}function fl(a,b){if(void 0!==b)gl(a,b,a.vc,!0),a.lc=0;else for(var c=1;c=b&&f>g.rb].Vd(f&g.eb,d==a.Qc)}}}function fl(a,b){if(void 0!==b)gl(a,b,a.vc,!0),a.nc=0;else for(var c=1;c=Uk.length&&(m=a.ub(b,1),g=Zk[h-Uk.length][m>>3&7]);var n=2,h="";if(164<=f&&167>=f||170<=f&&175>=f)n=0;for(f=1;f<=n;f++){var q="",t=g[f];if(void 0!==t){var s=t&15;if(0!=s&&15!=s){var v=t&240;if(128<=v)if(0>m&&(m=a.ub(b,1)),160<=v)q=m>>3&7,176==(t&240)?q+=16:3<=(t&15)&&(q+=8),q=X[q];else{if(128<=v){var q=a,A=t,s=b,D="",v=m>>6,D=m&7;3>v?(A=void 0,v||6!=D?(D=Vk[D],1==v?(A=q.ub(s,
1),A&128?(A=A<<24>>24,D+="-"+r(-A)):D+="+"+r(A)):2==v&&(A=q.Ia(s,2),D+="+"+u(A))):(A=q.Ia(s,2),D=u(A)),D="["+D+"]"):D=X[D+(1==(A&15)?0:8)];q=D}}else if(16==v)q="1";else if(0==v){q=a;v=t;s=b;A=" ";switch(v&15){case 1:v&12288&&(A=r(q.ub(s,1)));break;case 2:A=u(q.ub(s,1)<<24>>24);break;case 3:case 4:A=u(q.Ia(s,2));break;case 6:v=q.Ia(s,2);q=q.Ia(s,2);A=$([v,q,void 0]);break;default:A="imm("+u(v)+")"}q=A}else 32==v?q="["+u(a.Ia(b,2))+"]":48==v?(1==s?(q=a.ub(b,1),q=q<<24>>24):q=a.Ia(b,2),q=b[0]+q&65535,
q=nl(a,[q,b[1],void 0])[0]||u(q)):96==v?q=X[(t&3840)>>8]:112==v?q=X[((t&3840)>>8)+16]:64==v?q="DS:[SI]":80==v&&(q="ES:[DI]");q.length||(q="type("+u(t)+")");0>>4),d[0]=g,d[1]=h,void 0!==m.p&&(d[2]=m.p));break}}if(d&&d.length)return d;d=b.indexOf(":");0>d?null!=e?(c=ul(a,b),d=null):d=ul(a,b):(e=ul(a,b.substring(0,d)),c=ul(a,b.substring(d+1)),d=
+function tl(a,b,c){var d=2==c?a.hk:a.Ec;c=d[0];var e=d[1],d=d[2];if(void 0!==b){"%"==b.charAt(0)&&(b=b.substr(1),e=null);var f=b,d=null;if(f.match(/^[a-z_][a-z0-9_]*$/i))for(var d=[],g=f.toUpperCase(),h=0;h>>4),d[0]=g,d[1]=h,void 0!==m.p&&(d[2]=m.p));break}}if(d&&d.length)return d;d=b.indexOf(":");0>d?null!=e?(c=ul(a,b),d=null):d=ul(a,b):(e=ul(a,b.substring(0,d)),c=ul(a,b.substring(d+1)),d=
null)}return[c,e,d]}
function ul(a,b,c){var d;if(void 0!==b)switch(b=b.toUpperCase(),b){case "AX":d=a.S.G;break;case "BX":d=a.S.B;break;case "CX":d=a.S.I;break;case "DX":d=a.S.J;break;case "SI":d=a.S.F;break;case "DI":d=a.S.D;break;case "BP":d=a.S.H;break;case "SP":d=a.S.Y;break;case "CS":d=a.S.ua.oa;break;case "DS":d=a.S.Eb.oa;break;case "ES":d=a.S.Za.oa;break;case "SS":d=a.S.wb.oa;break;case "IP":d=a.S.qa;break;default:d=ca(b),void 0===d&&a.ca("invalid "+(c?c:"value")+": "+b)}else a.ca("missing "+(c?c:"value"));return d}
function Pi(a,b,c,d){function e(a,b){return a[0]>b[0]?1:a[0]=g&&eb[0]?1:a[0]c?(a.ca("out of data at address "+$(b)),q=!0):(a.bd(b,c,1),n++)})})(a,c);a.ca(n+" bytes read at "+e)}else a.ca("sector "+e+" request out of range");else a.ca("drive "+d+" not loaded");else a.ca("invalid drive: "+d)}else a.ca("disk controller not present")}}}
+f=ul(a,b[4],"# of sectors");void 0===f&&(f=1)}var h=a.Lm;2<=d&&a.Hk&&(d-=2,h=a.Hk);if(h){var m=h.wk(d);if(m)if(m.va)if(g)a.ca(sk(m.va));else if(h.hm(m,e,f)){for(var n=0,q=!1,e=$(c);!q&&0c?(a.ca("out of data at address "+$(b)),q=!0):(a.bd(b,c,1),n++)})})(a,c);a.ca(n+" bytes read at "+e)}else a.ca("sector "+e+" request out of range");else a.ca("drive "+d+" not loaded");else a.ca("invalid drive: "+d)}else a.ca("disk controller not present")}}}
function dl(a,b,c){if(b&&"?"==b[1])a.ca("\nregister commands:"),a.ca("\tr\t\tdisplay all registers"),a.ca("\tr [target=#]\tmodify target register"),a.ca("supported targets:"),a.ca("\tall registers and flags V,D,I,S,Z,A,P,C");else{var d=!0,e;if(null!=b&&1c||"z">>4),(d=h[f].l)&&(f=d),a.ca(da(n,m)+" "+f)));else{for(n in Y)if(g==Y[n].Ma){(f=a.bi[n])?f(m):a.ca("no dump registered for "+g);break a}f=tl(a,g,2);if(null!=f[0])if("ds"==h)if(c=hl(a,f[0]),null!=c.oa){f="selector="+u(f[0])+" limit="+u(c.Nc)+" base="+p(c.Ua);if(c.ab){f+=
+a.ca("\tbr [a]\tset read breakpoint at addr [a]"),a.ca("\tbw [a]\tset write breakpoint at addr [a]"),a.ca("\tbc [a]\tclear breakpoint at addr [a]"),a.ca("\tbl\tlist all breakpoints");break;case "c":a.Uf&&(a.Uf.value="");break;case "d":a:{var h=c[0],g=c[1],m=c[2],n;if("?"==g){f="symbols";for(n in Y)a.di[n]&&(f.length&&(f+=","),f+=Y[n].Ma);f+=",state";a.ca("\ndump commands:");a.ca("\tdb [a] [#] dump bytes at address a");a.ca("\tdw [a] [#] dump words at address a");a.ca("\tds [s] dump descriptor for selector s");
+f.length&&a.ca("dumps are also available for: "+f)}else if("state"==g)a.ca(zl(a.Da,!0));else if("symbols"==g)for(c=0;c>>4),(d=h[f].l)&&(f=d),a.ca(da(n,m)+" "+f)));else{for(n in Y)if(g==Y[n].Ma){(f=a.di[n])?f(m):a.ca("no dump registered for "+g);break a}f=tl(a,g,2);if(null!=f[0])if("ds"==h)if(c=hl(a,f[0]),null!=c.oa){f="selector="+u(f[0])+" limit="+u(c.Nc)+" base="+p(c.Ua);if(c.ab){f+=
" access="+u(c.ab);if(c.ab&4096)c.ab&2048?(f=f+"code:"+(c.ab&512?"readable,":"execonly,"),f+=c.ab&1024?"conforming,":"nonconforming,"):(f+="data:",f+=c.ab&512?"writeable,":"readonly,",f+=c.ab&1024?"expand down,":"expand up,"),f+=c.ab&256?"accessed":"not accessed";else switch(f+="type:",c.ab&7936){case 256:f+="tss";break;case 512:f+="ldt";break;case 768:f+="tss(busy)";break;case 1024:f+="call";break;case 1280:f+="task";break;case 1536:f+="int";break;case 1792:f+="trap";break;default:f+="unknown"}f+=
-",dpl"+(c.ab>>13&24576);f+=c.ab&32768?",present":",not present"}a.ca(f)}else a.ca("invalid selector: "+u(f[0]));else{c=0;void 0!==m&&("l"==m.charAt(0)&&(m=m.substr(1)),c=parseInt(m,10));n="";c||(c=8);for(m=0;mt;t++){var s=a.ub(f,1);"dw"==h?t&1&&(d+=u(q|s<<8)+(7==t?" - ":" ")):d+=r(s)+(7==t?"-":" ");e+=32<=s&&128>s?String.fromCharCode(s):".";q=s}n&&(n+="\n");n+=g+" "+d+" "+e}n&&a.ca(n);a.ek=f}}}break;case "e":f=c[1];if(void 0===f)a.ca("missing address");else if(f=
-tl(a,f,2),null!=f[0])for(g=2;gh.length&&(a.ca("note: only "+h.length+" available"),n=h.length),g-=
-n,0>g&&(null!=h[h.length-1][1]?g+=h.length:(n=g+n,g=0)),void 0!==m&&a.ca(n+" instructions earlier:");c&&g!=a.jf;){m=h[g];if(null==m[1])break;m=[m[0],m[1],m[2]];a.ca(ml(a,m,"history",-n));++g==h.length&&(g=0);a.Rl=--n;c--}10==c&&(a.ca("no "+f+"history available"),a.Rl=void 0)}break;case "i":(f=c[1])&&"?"!=f?(f=ul(a,f),void 0!==f&&(c=jb(a.na,f),a.ca(u(f)+": "+r(c)))):(a.ca("\ninput commands:"),a.ca("\ti [p]\tread port [p]"),a.ca("warning: port accesses can affect hardware state"));break;case "l":xl(a,
-c);break;case "m":a:{f=null;h=c[1];"?"==h&&(h=void 0);if(void 0!==h){n=0;if("all"==h)n=4294967295,h=null;else if("on"==h)f=!0,h=null;else if("off"==h)f=!1,h=null;else{for(g in Y)if(h==Y[g].Ma){n=Y[g].La;f=!!(a.dc&n);break}if(!n){a.ca("unknown message category: "+h);break a}}n&&("on"==c[2]?(a.dc|=n,f=!0):"off"==c[2]&&(a.dc&=~n,f=!1))}c=0;n="";for(g in Y)if(!h||h==Y[g].Ma)if(m=!!(a.dc&Y[g].La),null===f||f==m)n&&(n+=","),++c%10||(n+="\n\t"),n+=Y[g].Ma;void 0===h&&a.ca("\nmessage commands:\n\tm [category] [on|off]\tturn categories on/off");
-a.ca((null!==f?f?"messages on: ":"messages off: ":"message categories:\n\t")+(n||"none"))}break;case "o":f=c[1];c=c[2];f&&"?"!=f?(f=ul(a,f,"port #"),c=ul(a,c),void 0!==f&&void 0!==c&&nb(a.na,f,c)):(a.ca("\noutput commands:"),a.ca("\to [p] [d]\twrite data [d] to port [p]"),a.ca("warning: port accesses can affect hardware state"));break;case "p":case "pr":f="pr"==c[0]?1:0;c=1+f;if(a.lc)a.ca("step in progress");else{h=!1;n=[a.S.qa,a.S.ua.oa,void 0];do switch(g=!1,a.ub(n)){case 38:case 46:case 54:case 62:case 240:jl(n,
-1);g=!0;break;case 204:case 206:a.lc=c;jl(n,1);break;case 205:case 224:case 225:case 226:a.lc=c;jl(n,2);break;case 232:a.lc=c;jl(n,3);break;case 154:a.lc=c;jl(n,5);break;case 255:a.lc=0<=ml(a,n).indexOf("CALL")?c:0;break;case 243:case 242:jl(n,1);h=g=!0;break;case 164:case 165:case 166:case 167:case 170:case 171:case 172:case 173:case 174:case 175:h&&(a.lc=c,jl(n,1))}while(g);a.lc?(a.Vd(a.vc,n,!0),a.Ne()||(a.S.Md(),a.lc=0)):yl(a,f?"tr":"t")}break;case "r":dl(a,c);break;case "t":case "tr":yl(a,c[0],
+",dpl"+(c.ab>>13&24576);f+=c.ab&32768?",present":",not present"}a.ca(f)}else a.ca("invalid selector: "+u(f[0]));else{c=0;void 0!==m&&("l"==m.charAt(0)&&(m=m.substr(1)),c=parseInt(m,10));n="";c||(c=8);for(m=0;mt;t++){var s=a.ub(f,1);"dw"==h?t&1&&(d+=u(q|s<<8)+(7==t?" - ":" ")):d+=r(s)+(7==t?"-":" ");e+=32<=s&&128>s?String.fromCharCode(s):".";q=s}n&&(n+="\n");n+=g+" "+d+" "+e}n&&a.ca(n);a.hk=f}}}break;case "e":f=c[1];if(void 0===f)a.ca("missing address");else if(f=
+tl(a,f,2),null!=f[0])for(g=2;gh.length&&(a.ca("note: only "+h.length+" available"),n=h.length),g-=
+n,0>g&&(null!=h[h.length-1][1]?g+=h.length:(n=g+n,g=0)),void 0!==m&&a.ca(n+" instructions earlier:");c&&g!=a.jf;){m=h[g];if(null==m[1])break;m=[m[0],m[1],m[2]];a.ca(ml(a,m,"history",-n));++g==h.length&&(g=0);a.Ul=--n;c--}10==c&&(a.ca("no "+f+"history available"),a.Ul=void 0)}break;case "i":(f=c[1])&&"?"!=f?(f=ul(a,f),void 0!==f&&(c=jb(a.na,f),a.ca(u(f)+": "+r(c)))):(a.ca("\ninput commands:"),a.ca("\ti [p]\tread port [p]"),a.ca("warning: port accesses can affect hardware state"));break;case "l":xl(a,
+c);break;case "m":a:{f=null;h=c[1];"?"==h&&(h=void 0);if(void 0!==h){n=0;if("all"==h)n=4294967295,h=null;else if("on"==h)f=!0,h=null;else if("off"==h)f=!1,h=null;else{for(g in Y)if(h==Y[g].Ma){n=Y[g].La;f=!!(a.ec&n);break}if(!n){a.ca("unknown message category: "+h);break a}}n&&("on"==c[2]?(a.ec|=n,f=!0):"off"==c[2]&&(a.ec&=~n,f=!1))}c=0;n="";for(g in Y)if(!h||h==Y[g].Ma)if(m=!!(a.ec&Y[g].La),null===f||f==m)n&&(n+=","),++c%10||(n+="\n\t"),n+=Y[g].Ma;void 0===h&&a.ca("\nmessage commands:\n\tm [category] [on|off]\tturn categories on/off");
+a.ca((null!==f?f?"messages on: ":"messages off: ":"message categories:\n\t")+(n||"none"))}break;case "o":f=c[1];c=c[2];f&&"?"!=f?(f=ul(a,f,"port #"),c=ul(a,c),void 0!==f&&void 0!==c&&nb(a.na,f,c)):(a.ca("\noutput commands:"),a.ca("\to [p] [d]\twrite data [d] to port [p]"),a.ca("warning: port accesses can affect hardware state"));break;case "p":case "pr":f="pr"==c[0]?1:0;c=1+f;if(a.nc)a.ca("step in progress");else{h=!1;n=[a.S.qa,a.S.ua.oa,void 0];do switch(g=!1,a.ub(n)){case 38:case 46:case 54:case 62:case 240:jl(n,
+1);g=!0;break;case 204:case 206:a.nc=c;jl(n,1);break;case 205:case 224:case 225:case 226:a.nc=c;jl(n,2);break;case 232:a.nc=c;jl(n,3);break;case 154:a.nc=c;jl(n,5);break;case 255:a.nc=0<=ml(a,n).indexOf("CALL")?c:0;break;case 243:case 242:jl(n,1);h=g=!0;break;case 164:case 165:case 166:case 167:case 170:case 171:case 172:case 173:case 174:case 175:h&&(a.nc=c,jl(n,1))}while(g);a.nc?(a.Vd(a.vc,n,!0),a.Ne()||(a.S.Md(),a.nc=0)):yl(a,f?"tr":"t")}break;case "r":dl(a,c);break;case "t":case "tr":yl(a,c[0],
c[1]);break;case "u":el(a,c[1],c[2],8);break;case "x":a:if(void 0===c[1]||"?"==c[1])a.ca("\nexecution options:"),a.ca("\tcs int #\tset checksum cycle interval to #"),a.ca("\tcs start #\tset checksum cycle start count to #"),a.ca("\tcs stop #\tset checksum cycle stop count to #"),a.ca("\tsp #\t\tset speed multiplier to #");else switch(c[1]){case "cs":void 0!==c[3]&&(m=parseInt(c[3],10));switch(c[2]){case "int":a.S.lf=m;break;case "start":a.S.fg=m;break;case "stop":a.S.nf=m;break;default:a.ca("unknown cs option");
break a}void 0!==m&&Bb(a.S);a.ca("checksums "+(a.S.cf?"enabled":"disabled"));break;case "sp":void 0!==c[2]&&Hb(a.S,parseInt(c[2],10));a.ca("target speed: "+(a.S.Ge.toFixed(2)+"Mhz")+" ("+a.S.Gd+"x)");break;default:a.ca("unknown option: "+c[1])}break;case "?":f="commands:";for(h in Tk)f+="\n"+h+" ".substr(0,7-h.length)+Tk[h];jd(a)||(f+="\nnote: frequency/history disabled if no exec breakpoints");a.ca(f);break;default:a.ca("unknown command: "+b)}}}
-Ba(function(){for(var a=B(window.document,"pcjs","debugger"),b=0;bFl){if(d.load(this.yg)){this.uf=new H(this,"1.15.5","failsafe");this.uf.load()&&(Jl(this,d),a=2);this.uf.set("timestamp",pa());Dl(this.uf);var e=this.Cc&&!this.ph;if(1==a||ta("Click OK to restore previous PCjs machine state.")){if(c=d.parse()){var f=d.get("code"),g=d.get("data");f&&("ok"==f?d.load(g):("error"==f&&"no machine state"!=g?(this.Ga("Error: "+g),"unable to verify user"==
-g&&(ua(""),this.Pc=null)):this.ca(f+": "+g),Bl(d),d.load()?(c=d.parse(),e=!0):c=!1))}e&&Il(this,c?d:null)}else 2==a&&d.clear()}else Il(this);delete this.yg;delete this.Qh}e=La(this.id);for(f=0;fa[1];a=a[2];this.Nb=!0;this.xk||(this.ca("PCjs v1.15.5\nCopyright \u00a9 2012-2014 Jeff Parsons \nLicense: GPL version 3 or later "),this.xk=!0);this.S&&Kl(this,this.S,b,c,a);this.zk&&(Jl(this,b),b.clear());!c&&this.uf&&(this.uf.clear(),delete this.uf)};
+k.Ih=function(a){void 0===a&&(a=this.yg?1:this.Cc);var b=!1,c=!1;this.Ck=!1;var d=this.Sh||new H(this,"1.15.5");if(-1==a)b=!0;else if(a>Fl){if(d.load(this.yg)){this.uf=new H(this,"1.15.5","failsafe");this.uf.load()&&(Jl(this,d),a=2);this.uf.set("timestamp",pa());Dl(this.uf);var e=this.Cc&&!this.ph;if(1==a||ta("Click OK to restore previous PCjs machine state.")){if(c=d.parse()){var f=d.get("code"),g=d.get("data");f&&("ok"==f?d.load(g):("error"==f&&"no machine state"!=g?(this.Ga("Error: "+g),"unable to verify user"==
+g&&(ua(""),this.Pc=null)):this.ca(f+": "+g),Bl(d),d.load()?(c=d.parse(),e=!0):c=!1))}e&&Il(this,c?d:null)}else 2==a&&d.clear()}else Il(this);delete this.yg;delete this.Sh}e=La(this.id);for(f=0;fa[1];a=a[2];this.Nb=!0;this.Ak||(this.ca("PCjs v1.15.5\nCopyright \u00a9 2012-2014 Jeff Parsons \nLicense: GPL version 3 or later "),this.Ak=!0);this.S&&Kl(this,this.S,b,c,a);this.Ck&&(Jl(this,b),b.clear());!c&&this.uf&&(this.uf.clear(),delete this.uf)};
function Jl(a,b){if(ta("There may be a problem with PCjs.\nClick OK to send your PCjs machine state to http://www.pcjs.org.")){var c=a.ge(),d=b.toString(),e={app:"PCjs",ver:"1.15.5"};e.url=a.url;e.user=c;e.type="bug";e.data=d;ra("http://www.pcjs.org/api/v1/report",!0,e)}}
function zl(a,b,c){var d,e="none",f=new H(a,"1.15.5"),g=new H(a,"1.15.5","validate"),h=pa();g.set("timestamp",h);f.set("timestamp",h);f.set("version","1.15.5");f.set("url",window?window.location.href:null);f.set("browser",window?window.navigator.userAgent:"");a.S&&a.S.Wb&&(c&&a.S.Ab(),d=a.S.Wb(b,c),"object"===typeof d&&f.set(a.S.id,d),c&&(a.S.Nb=!1,!1===d&&(e=null)));for(var h=La(a.id),m=0;m/g;f=g.exec(a);){var h=f[2],m=ra(h),n=m[1];if(m[0]||!n)throw c="unable to resolve XML reference: "+f[0]+" ("+m[0]+")",Error(c);if(m=f[3]){var q=n.match(new RegExp("<"+f[1]+"[^>]*>"));if(q){for(var h=q[0],t,s=/( [a-z]+=)(['"])(.*?)\2/g;t=s.exec(m);)h=0>h.indexOf(t[1])?h.replace(">",t[0]+">"):h.replace(new RegExp(t[1]+"(['\"])(.*?)\\1"),t[0]);q[0]!=h&&(n=n.replace(q[0],h))}else throw c="missing <"+f[1]+"> in "+h,
Error(c);}n=n.replace(/<\?xml[^>]*>[\r\n]*/,"");a=a.replace(f[0],n);g.lastIndex=0}c&&(b&&0>b.indexOf("/")&&(b=window.location.pathname+b),a=a.replace(/(]*\sid=)(['"]).*?\2/,"$1$2"+c+"$2"+(d?" state=$2"+d+"$2":"")+(b?" url=$2"+b+"$2":"")));if(0===a.indexOf("<"))window.ActiveXObject||"ActiveXObject"in window?(e||(a=a.replace(/\s*/g,"")),f=new window.ActiveXObject("Microsoft.XMLDOM"),f.async=!1,f.loadXML(a)):f=(new window.DOMParser).parseFromString(a,"text/xml");else throw Error("unrecognized XML: "+
(255"']/g,function(a){return fa[a]})}function h
function t(a,b,c,d,e,f){b=!!b;var l=0,k=null,m=da(a),n=window.XMLHttpRequest?new window.XMLHttpRequest:new window.ActiveXObject("Microsoft.XMLHTTP");b&&(n.onreadystatechange=function(){4===n.readyState&&(n.onreadystatechange=void 0,k=n.responseText,200!=n.status&&(l=n.status||-1),d&&e&&e.call(d,m,k,l,f))});if(c){var q="",s;for(s in c)c.hasOwnProperty(s)&&(q&&(q+="&"),q+=s+"="+encodeURIComponent(c[s]));q=q.replace(/%20/g,"+");n.open("POST",a,b);n.setRequestHeader("Content-type","application/x-www-form-urlencoded");
n.send(q)}else n.open("GET",a,b),n.send();a=[];b||(k=n.responseText,200!=n.status&&(l=n.status||-1),d&&e&&e.call(d,m,k,l,f),a=[l,k]);return a}function ka(){return"http://"+(window?window.location.host:"www.pcjs.org")}function u(a){window?window.alert(a):console.log(a)}function la(a){var b=!1;window&&(b=window.confirm(a));return b}function ma(a){if(window)try{window.localStorage.setItem("user",a)}catch(b){}}
function na(a){if(window){var b=window?window.navigator.userAgent:"";return"iOS"==a&&b.match(/(iPod|iPhone|iPad)/)&&b.match(/AppleWebKit/)||"MSIE"==a&&b.match(/(MSIE|Trident)/)||0<=b.indexOf(a)?!0:!1}return!1}var oa={init:[],show:[],exit:[]},pa=!0;function qa(a,b){if(window){var c=window[a];window[a]="function"!==typeof c?b:function(){c&&c();b()}}}function v(a){oa.init.push(a)}function ra(a){if(pa)for(var b=0;b=this.hf?12:14;this.nc=1<>2;this.eb=this.nc-1;this.Zf=(this.Oe+this.nc)/this.nc|0;this.Pd=this.Zf-1;this.Mf=[];this.Nf=[];this.Hh();this.Pa()}z(w,Ha);Ha.prototype.Hh=function(){this.ya=Array(this.Zf);for(var a=0;a>a.Ib;0>this.Ib;0>a.Ib;0>a.Ib].Ki(b&a.eb)}function Oa(a,b){var c=b&a.eb,d=(b&a.wb)>>a.Ib;return c!=a.eb?a.ya[d].Bn(c):a.ya[d++].Ki(c)|a.ya[d&a.Pd].Ki(0)<<8}
-function Pa(a,b,c){a.ya[(b&a.wb)>>a.Ib].Si(b&a.eb,c&255)}function Qa(a,b,c){var d=b&a.eb;b=(b&a.wb)>>a.Ib;d!=a.eb?a.ya[b].Ln(d,c&65535):(a.ya[b++].Si(d,c&255),a.ya[b&a.Pd].Si(0,c>>8&255))}function Sa(a){for(var b=0,c=[],d=0;d=this.hf?12:14;this.nc=1<>2;this.eb=this.nc-1;this.Zf=(this.Oe+this.nc)/this.nc|0;this.Pd=this.Zf-1;this.Mf=[];this.Nf=[];this.Jh();this.Pa()}z(w,Ha);Ha.prototype.Jh=function(){this.ya=Array(this.Zf);for(var a=0;a>a.Ib;0>this.Ib;0>a.Ib;0>a.Ib].Ni(b&a.eb)}function Oa(a,b){var c=b&a.eb,d=(b&a.xb)>>a.Ib;return c!=a.eb?a.ya[d].En(c):a.ya[d++].Ni(c)|a.ya[d&a.Pd].Ni(0)<<8}
+function Pa(a,b,c){a.ya[(b&a.xb)>>a.Ib].Vi(b&a.eb,c&255)}function Qa(a,b,c){var d=b&a.eb;b=(b&a.xb)>>a.Ib;d!=a.eb?a.ya[b].On(d,c&65535):(a.ya[b++].Vi(d,c&255),a.ya[b&a.Pd].Vi(0,c>>8&255))}function Sa(a){for(var b=0,c=[],d=0;d>2);for(d=0;d>2]>>>((a&3)<<3)&255},Cn:function(a){var b=a>>2;a=(a&3)<<3;var c=this.la[b]>>>a;return 24>a?c&65535:c&255|(this.la[b+1]&255)<<8},Jn:function(a,b){var c=a>>2,d=(a&3)<<3;this.la[c]=this.la[c]&~(255<>2,d=(a&3)<<3;24>d?this.la[c]=this.la[c]&~(65535<>8);this.Xa=!0},save:function(){return this.ea?
-null:this.la},restore:function(a){return this.ea?null===a:this.cl==a.length<<2?(this.la=a,this.Xa=!0):!1},fe:function(a,b){a||(a=[]);void 0===b&&(b=!0);var c=a;this.vc=c[0]?c[0]:this.Eg;this.An=c[1]?c[1]:this.Eg;b&&(this.Ki=c[0]?c[0]:this.Eg,this.Bn=c[1]?c[1]:this.Eg);c=a;this.xc=c[2]&&!this.nj?c[2]:this.Pg;this.Kn=c[3]&&!this.nj?c[3]:this.Pg;b&&(this.Si=c[2]?c[2]:this.Pg,this.Ln=c[3]?c[3]:this.Pg)}};var Xa=[Ia.prototype.zn,Ia.prototype.Cn,Ia.prototype.Jn,Ia.prototype.Mn];
-function Ya(a,b){w.call(this,"CPU",a,Ya);var c=a.multiplier||1;this.cd=a.cycles||b;this.yd=c;this.rg=Math.round(this.cd/1E4)/100;this.we=this.rg*this.yd;this.rc=this.zb=!1;this.ph=a.autoStart;c=ua.autostart;void 0!==c&&(this.ph="true"==c?!0:"false"==c?!1:null);this.gg=!1;this.wg=this.ye=0;this.xg=a.csStart;this.kf=a.csInterval;this.lf=a.csStop;var d=this;this.Dm=function(){Za(d)};this.Pa()}z(w,Ya);g=Ya.prototype;
-g.ic=function(a,b,c,d){this.ma=b;this.Na=d;this.Fa=a;var e=D(a,"Video");e&&(this.df=function(){$a(e)},this.Ee=function(){e.Ee()});this.ga=D(a,"ChipSet");this.Pa()};g.reset=function(){};g.save=function(){return null};g.restore=function(){return!1};g.Sb=function(a,b){if(!b){if(a&&this.restore){ab(this);if(!this.restore(a))return!1;bb(this)}else this.reset();this.Tb("No debugger detected")}this.zb=!0;!cb(this)&&this.Na&&this.Na.to();this.df();this.cf();return!0};
-g.Jb=function(a){this.zb=!1;return a&&this.save?this.save():!0};function cb(a){return!0===a.ph||null===a.ph&&void 0===a.oa.run?(Za(a),!0):!1}g.Ee=function(){};g.sj=function(){return 0};function bb(a){void 0===a.xg&&(a.xg=0);void 0===a.kf&&(a.kf=-1);void 0===a.lf&&(a.lf=-1);a.gg=0<=a.xg&&0c&&(c=60);2>c&&(c=2);var d=1;b&&1a.rg&&(c=Math.round(c/a.yd));return c}function ab(a){a.Kc=0;a.ug=1;a.be=a.Bd=a.Lc=a.A=0;bb(a);fb(a,1)}
-function fb(a,b,c){void 0!==b&&(0.8>a.Kc/a.we&&(b=1),a.yd=b,b=a.rg*a.yd,a.we!=b&&(a.we=b,b=a.we.toFixed(2)+"Mhz",a.oa.setSpeed&&(a.oa.setSpeed.innerHTML=b),a.Tb("target speed: "+b)),c&&a.Ee());hb(a,a.Bd);a.Bd=0;a.xe=ha();a.Zd=0;ib(a)}
-function Za(a,b){if(Ca(a,!0)){a.rc||(fb(a),a.Fa&&a.Fa.start(a.xe,jb(a)),a.rc=!0,a.ga&&kb(a.ga),a.oa.run&&(a.oa.run.innerHTML="Halt"),b&&a.Ee());a.Di>=a.cd&&ib(a,!0);a.pf=0;a.tg=ha();if(a.Zd){var c=a.tg-a.Zd;c>a.yj&&(a.xe+=c,a.xe>a.tg&&(a.xe=a.tg))}try{do{a.Tk(a.gg?1:Math.round(a.wm/a.ug));var d=a.Lc-a.A;a.Bd+=d;a.pf+=d;hb(a,0,!0);var c=a,e=d;if(c.gg){var f=!1;c.wg=c.wg+c.sj()|0;c.ye-=e;0>=c.ye&&(c.ye+=c.kf,f=!0);0<=c.lf&&c.lf<=jb(c)&&(c.kf=c.lf=-1,bb(c),db(c),f=!0);f&&c.Tb(jb(c)+" cycles: checksum="+
-p(c.wg))}a.nf-=d;0>=a.nf&&(a.nf+=a.Cj,a.df());a.mf-=d;0>=a.mf&&(a.mf+=a.Bj,a.cf());a.of-=d;if(0>=a.of){a.of+=a.Oh;break}}while(a.rc)}catch(l){db(a);a.df();a.cf();a.Fa&&a.Fa.stop(ha(),jb(a));Ca(a,!1);Ea(a,l.message);return}d=setTimeout;c=a.Dm;a.Zd=ha();e=a.yj;a.pf&&(e=Math.round(e*a.pf/a.Oh));e-=a.Zd-a.tg;if(f=a.Zd-a.xe)a.Kc=Math.round(a.Bd/(10*f))/100,864E5<=f&&(a.be=0,a.ga&&lb(a.ga,!0),fb(a));if(0>e||a.Kc>2);for(d=0;d>2]>>>((a&3)<<3)&255},Fn:function(a){var b=a>>2;a=(a&3)<<3;var c=this.la[b]>>>a;return 24>a?c&65535:c&255|(this.la[b+1]&255)<<8},Mn:function(a,b){var c=a>>2,d=(a&3)<<3;this.la[c]=this.la[c]&~(255<>2,d=(a&3)<<3;24>d?this.la[c]=this.la[c]&~(65535<>8);this.Xa=!0},save:function(){return this.ea?
+null:this.la},restore:function(a){return this.ea?null===a:this.fl==a.length<<2?(this.la=a,this.Xa=!0):!1},fe:function(a,b){a||(a=[]);void 0===b&&(b=!0);var c=a;this.vc=c[0]?c[0]:this.Gg;this.Dn=c[1]?c[1]:this.Gg;b&&(this.Ni=c[0]?c[0]:this.Gg,this.En=c[1]?c[1]:this.Gg);c=a;this.xc=c[2]&&!this.qj?c[2]:this.Rg;this.Nn=c[3]&&!this.qj?c[3]:this.Rg;b&&(this.Vi=c[2]?c[2]:this.Rg,this.On=c[3]?c[3]:this.Rg)}};var Xa=[Ia.prototype.Cn,Ia.prototype.Fn,Ia.prototype.Mn,Ia.prototype.Pn];
+function Ya(a,b){w.call(this,"CPU",a,Ya);var c=a.multiplier||1;this.cd=a.cycles||b;this.yd=c;this.rg=Math.round(this.cd/1E4)/100;this.we=this.rg*this.yd;this.rc=this.Ab=!1;this.rh=a.autoStart;c=ua.autostart;void 0!==c&&(this.rh="true"==c?!0:"false"==c?!1:null);this.gg=!1;this.wg=this.ye=0;this.xg=a.csStart;this.kf=a.csInterval;this.lf=a.csStop;var d=this;this.Gm=function(){Za(d)};this.Pa()}z(w,Ya);g=Ya.prototype;
+g.ic=function(a,b,c,d){this.ma=b;this.Na=d;this.Fa=a;var e=D(a,"Video");e&&(this.df=function(){$a(e)},this.Ee=function(){e.Ee()});this.ga=D(a,"ChipSet");this.Pa()};g.reset=function(){};g.save=function(){return null};g.restore=function(){return!1};g.Ub=function(a,b){if(!b){if(a&&this.restore){ab(this);if(!this.restore(a))return!1;bb(this)}else this.reset();this.Vb("No debugger detected")}this.Ab=!0;!cb(this)&&this.Na&&this.Na.wo();this.df();this.cf();return!0};
+g.Kb=function(a){this.Ab=!1;return a&&this.save?this.save():!0};function cb(a){return!0===a.rh||null===a.rh&&void 0===a.oa.run?(Za(a),!0):!1}g.Ee=function(){};g.vj=function(){return 0};function bb(a){void 0===a.xg&&(a.xg=0);void 0===a.kf&&(a.kf=-1);void 0===a.lf&&(a.lf=-1);a.gg=0<=a.xg&&0c&&(c=60);2>c&&(c=2);var d=1;b&&1