From 2ff339f190f4fa60322e27bc50313da38c29dee3 Mon Sep 17 00:00:00 2001 From: Jeff Parsons Date: Sun, 30 Nov 2014 12:56:59 -0800 Subject: [PATCH] Cleaned up debugger message handling --- Gruntfile.js | 4 +- modules/c1pjs/lib/.jshintrc | 4 +- modules/c1pjs/lib/debugger.js | 40 ++--- modules/c1pjs/lib/disk.js | 4 +- modules/c1pjs/lib/rom.js | 2 +- modules/c1pjs/lib/serial.js | 4 +- modules/c1pjs/lib/video.js | 6 +- modules/pcjs/lib/.jshintrc | 7 + modules/pcjs/lib/bus.js | 6 +- modules/pcjs/lib/chipset.js | 296 +++++++++++++++----------------- modules/pcjs/lib/computer.js | 89 +++++----- modules/pcjs/lib/cpu.js | 6 +- modules/pcjs/lib/debugger.js | 98 ++++------- modules/pcjs/lib/disk.js | 89 ++++++---- modules/pcjs/lib/fdc.js | 85 ++------- modules/pcjs/lib/hdc.js | 124 ++++++------- modules/pcjs/lib/keyboard.js | 65 ++++--- modules/pcjs/lib/mem.js | 2 +- modules/pcjs/lib/mouse.js | 29 +--- modules/pcjs/lib/nodebugger.js | 4 +- modules/pcjs/lib/serial.js | 36 +--- modules/pcjs/lib/state.js | 59 +++++-- modules/pcjs/lib/video.js | 152 ++++++++-------- modules/pcjs/lib/x86cpu.js | 35 +--- modules/pcjs/lib/x86help.js | 35 ++-- modules/pcjs/lib/x86op0f.js | 3 + modules/pcjs/lib/x86opxx.js | 4 +- modules/pcjs/lib/x86seg.js | 26 ++- modules/shared/lib/component.js | 65 ++++++- modules/shared/lib/embed.js | 2 +- modules/shared/lib/weblib.js | 6 +- 31 files changed, 646 insertions(+), 741 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 4b9860fbc..7ae302340 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -171,7 +171,7 @@ module.exports = function(grunt) { banner: '"use strict";\n\n', process: function(src, filepath) { return "// " + filepath + "\n\n" + - src.replace(/(^|\n)[ \t]*(['"])use strict\2;?\s*/g, '$1').replace(/[ \t]*if\s*\(typeof\s+(module|APP_PCJS)\s*!==\s*(['"])undefined\2\)\s*(\{[^}]*}|[^\n]*)(\n|$)/gm, ''); + src.replace(/(^|\n)[ \t]*(['"])use strict\2;?\s*/g, '$1').replace(/[ \t]*if\s*\(typeof\s+(module|APP_PCJS)\s*!==\s*(['"])undefined\2\)\s*(\{[^}]*}|[^\n]*)(\n|$)/gm, '').replace(/[ \t]*[A-Za-z_][A-Za-z0-9_\.]*\.assert\(.*\);[^\n]*(\n|$)/g, ''); } } }, @@ -182,7 +182,7 @@ module.exports = function(grunt) { banner: '"use strict";\n\n', process: function(src, filepath) { return "// " + filepath + "\n\n" + - src.replace(/(^|\n)[ \t]*(['"])use strict\2;?\s*/g, '$1').replace(/[ \t]*if\s*\(typeof\s+(module|APP_PCJS)\s*!==\s*(['"])undefined\2\)\s*(\{[^}]*}|[^\n]*)(\n|$)/gm, ''); + src.replace(/(^|\n)[ \t]*(['"])use strict\2;?\s*/g, '$1').replace(/[ \t]*if\s*\(typeof\s+(module|APP_PCJS)\s*!==\s*(['"])undefined\2\)\s*(\{[^}]*}|[^\n]*)(\n|$)/gm, '').replace(/[ \t]*[A-Za-z_][A-Za-z0-9_\.]*\.assert\(.*\);[^\n]*(\n|$)/g, ''); } } } diff --git a/modules/c1pjs/lib/.jshintrc b/modules/c1pjs/lib/.jshintrc index 7f232ec83..92dd589e8 100644 --- a/modules/c1pjs/lib/.jshintrc +++ b/modules/c1pjs/lib/.jshintrc @@ -32,8 +32,10 @@ "global": true, "module": true, "require": true, + "FileReader": false, "setTimeout": false, "clearTimeout": false, - "Image": false + "Image": false, + "DumpAPI": false } } diff --git a/modules/c1pjs/lib/debugger.js b/modules/c1pjs/lib/debugger.js index 347dff4be..ad6672689 100644 --- a/modules/c1pjs/lib/debugger.js +++ b/modules/c1pjs/lib/debugger.js @@ -49,6 +49,7 @@ function C1PDebugger(parmsDbg) Component.call(this, "C1PDebugger", parmsDbg); + this.dbg = this; /* * This keeps track of instruction activity, but only when tracing or when * Debugger checks have been enabled (eg, one or more breakpoints have been set). @@ -122,7 +123,7 @@ function C1PDebugger(parmsDbg) this.MESSAGE_SERIAL = 0x80; this.MESSAGE_NONE = 0x00; // this.MESSAGE_ALL = 0xff; - this.bMessages = this.MESSAGE_NONE; + this.bitsMessage = this.MESSAGE_NONE; this.aMessageCategories = { 'port': this.MESSAGE_PORT, 'kbd': this.MESSAGE_KBD, @@ -694,7 +695,7 @@ if (DEBUGGER) { ]; for (iMode=0; iMode < this.aOpModes.length; iMode++) { sMode = this.aOpModes[iMode]; - sRegEx += "(" + sMode.replace(/\[/g, "\\[").replace(/\]/g, "\\]").replace(/nnnn/g, "[0-9A-F][0-9A-F][0-9A-F][0-9A-F]?").replace(/nn/g, "[0-9A-F][0-9A-F]?").replace(/\+/g, "\\+") + "|)"; + sRegEx += "(" + sMode.replace(/\[/g, "\\[").replace(/]/g, "\\]").replace(/nnnn/g, "[0-9A-F][0-9A-F][0-9A-F][0-9A-F]?").replace(/nn/g, "[0-9A-F][0-9A-F]?").replace(/\+/g, "\\+") + "|)"; } this.regexOpModes = new RegExp(sRegEx); } @@ -732,31 +733,18 @@ if (DEBUGGER) { } }; - /** - * @this {C1PDebugger} - * @param {number} bMessage is one or more Debugger MESSAGE_* category flag(s) - * @return {boolean} true if message category is enabled, false if not - * - * NOTE: If the caller specifies MULTIPLE category flags, then ALL the corresponding flags - * in the Debugger's bMessages variable must be enabled as well, else the result will be false - */ - C1PDebugger.prototype.messageEnabled = function(bMessage) - { - return ((this.bMessages & bMessage) === bMessage); - }; - /** * @this {C1PDebugger} * @param {Component} component * @param {number} addr * @param {number|undefined} addrFrom - * @param {boolean} bMessage is a Debugger MESSAGE_* category flag + * @param {boolean} bitsMessage is a Debugger MESSAGE_* category flag * @param {boolean|undefined} [fWrite] is true if this was a write, false (or undefined) if read * @param {string|undefined} [name] of the port, if any */ - C1PDebugger.prototype.messagePort = function(component, addr, addrFrom, bMessage, fWrite, name) + C1PDebugger.prototype.messageIO = function(component, addr, addrFrom, bitsMessage, fWrite, name) { - if ((this.bMessages & bMessage) == bMessage) { + if ((this.bitsMessage & bitsMessage) == bitsMessage) { var b = this.cpu.getByte(addr); this.message(component.id + "." + (fWrite? "setByte":"getByte") + "(" + str.toHexWord(addr) + ")" + (addrFrom !== undefined? (" @" + str.toHexWord(addrFrom)) : "") + ": " + (name? (name + "=") : "") + str.toHexByte(b)); } @@ -1947,25 +1935,25 @@ if (DEBUGGER) { this.println("modern syntax enabled"); break; case "msg": - var bMessage = 0; + var bitsMessage = 0; if (asArgs[2] !== undefined) { if (asArgs[2] == "all") - bMessage = 0xff; + bitsMessage = 0xff; else if (this.aMessageCategories[asArgs[2]] !== undefined) - bMessage = this.aMessageCategories[asArgs[2]]; - if (bMessage) { + bitsMessage = this.aMessageCategories[asArgs[2]]; + if (bitsMessage) { if (asArgs[3] == "on") { - this.bMessages |= bMessage; + this.bitsMessage |= bitsMessage; } else if (asArgs[3] == "off") { - this.bMessages &= ~bMessage; + this.bitsMessage &= ~bitsMessage; } } } for (var sCategory in this.aMessageCategories) { if (asArgs[2] !== undefined && (asArgs[2] != "all" && asArgs[2] != sCategory)) continue; - bMessage = this.aMessageCategories[sCategory]; - this.println(sCategory + " messages: " + ((this.bMessages & bMessage)? "on" : "off")); + bitsMessage = this.aMessageCategories[sCategory]; + this.println(sCategory + " messages: " + ((this.bitsMessage & bitsMessage)? "on" : "off")); } break; default: diff --git a/modules/c1pjs/lib/disk.js b/modules/c1pjs/lib/disk.js index 2d4b3ede7..6a388d42c 100644 --- a/modules/c1pjs/lib/disk.js +++ b/modules/c1pjs/lib/disk.js @@ -970,7 +970,7 @@ C1PDiskController.prototype.getByte = function(addr, addrFrom) if (addrFrom !== undefined) { var port = addr - this.addrController; var reg = this.getReg(port, false); - if (DEBUGGER && this.dbg) this.dbg.messagePort(this, addr, addrFrom, this.dbg.MESSAGE_DISK, false, reg.sName); + if (DEBUGGER && this.dbg) this.dbg.messageIO(this, addr, addrFrom, this.dbg.MESSAGE_DISK, false, reg.sName); reg.read(); } }; @@ -991,7 +991,7 @@ C1PDiskController.prototype.setByte = function(addr, addrFrom) var port = addr - this.addrController; var reg = this.getReg(port, true); if (DEBUGGER && this.dbg && this.dbg.messageEnabled(this.dbg.MESSAGE_DISK | this.dbg.MESSAGE_PORT)) { - this.dbg.messagePort(this, addr, addrFrom, this.dbg.MESSAGE_DISK, true, reg.sName); + this.dbg.messageIO(this, addr, addrFrom, this.dbg.MESSAGE_DISK, true, reg.sName); if (reg.aBitIDs) { var bTest = 0x80; var bChanged = reg.bits ^ b; diff --git a/modules/c1pjs/lib/rom.js b/modules/c1pjs/lib/rom.js index e50e3e4d9..4255afe64 100644 --- a/modules/c1pjs/lib/rom.js +++ b/modules/c1pjs/lib/rom.js @@ -127,7 +127,7 @@ C1PROM.prototype.setByte = function(addr, addrFrom) * we need to allow the Debugger to modify ROM contents). */ if (addrFrom !== undefined) { - if (DEBUGGER && this.dbg) this.dbg.messagePort(this, addr, addrFrom, this.dbg.MESSAGE_PORT, true); + if (DEBUGGER && this.dbg) this.dbg.messageIO(this, addr, addrFrom, this.dbg.MESSAGE_PORT, true); var offset = (addr - this.offROM); Component.assert(offset >= 0 && offset < this.cbROM); if (!this.abImage) diff --git a/modules/c1pjs/lib/serial.js b/modules/c1pjs/lib/serial.js index 7965aa819..e5a9cfabd 100644 --- a/modules/c1pjs/lib/serial.js +++ b/modules/c1pjs/lib/serial.js @@ -141,7 +141,7 @@ C1PSerialPort.prototype.setBinding = function(sHTMLType, sBinding, control) var fieldset = control.children[0]; var files = fieldset.children[0].files; var submit = fieldset.children[1]; - submit.disabled = (files.length == 0); + submit.disabled = !files.length; }); control.onsubmit = function(event) { @@ -321,7 +321,7 @@ C1PSerialPort.prototype.setByte = function(addr, addrFrom) * the Debugger performed this write (need a special Debugger I/O command if/when you really want to do that). */ if (addrFrom !== undefined) { - if (DEBUGGER && this.dbg) this.dbg.messagePort(this, addr, addrFrom, this.dbg.MESSAGE_SERIAL, true); + if (DEBUGGER && this.dbg) this.dbg.messageIO(this, addr, addrFrom, this.dbg.MESSAGE_SERIAL, true); /* * WARNING: I don't yet care what state the CPU puts the port into. When it's time to support serial output, * obviously that will become an issue. diff --git a/modules/c1pjs/lib/video.js b/modules/c1pjs/lib/video.js index 0b9784e19..bf29d2725 100644 --- a/modules/c1pjs/lib/video.js +++ b/modules/c1pjs/lib/video.js @@ -364,7 +364,7 @@ C1PVideo.prototype.getByte = function(addr, addrFrom) { var b = this.cpu.getByte(addr); if (addrFrom !== undefined) { - if (DEBUGGER && this.dbg) this.dbg.messagePort(this, addr, addrFrom, this.dbg.MESSAGE_VIDEO); + if (DEBUGGER && this.dbg) this.dbg.messageIO(this, addr, addrFrom, this.dbg.MESSAGE_VIDEO); } /* * The only documented READ bit in addrVideoPort is bit 7, which is supposed to alternate between @@ -388,7 +388,7 @@ C1PVideo.prototype.getByte = function(addr, addrFrom) C1PVideo.prototype.setByte = function(addr, addrFrom) { if (addrFrom !== undefined) { - if (DEBUGGER && this.dbg) this.dbg.messagePort(this, addr, addrFrom, this.dbg.MESSAGE_VIDEO); + if (DEBUGGER && this.dbg) this.dbg.messageIO(this, addr, addrFrom, this.dbg.MESSAGE_VIDEO); } }; @@ -404,7 +404,7 @@ C1PVideo.prototype.tripGuard = function(addr, addrFrom) * the Debugger performed this read (need a special Debugger I/O command if/when you really want to do that). */ if (addrFrom !== undefined) { - if (DEBUGGER && this.dbg) this.dbg.messagePort(this, addr, addrFrom, this.dbg.MESSAGE_VIDEO, true); + if (DEBUGGER && this.dbg) this.dbg.messageIO(this, addr, addrFrom, this.dbg.MESSAGE_VIDEO, true); /* * The CPU has just written to the guard address we established just beyond the video buffer's 1K boundary, * implying that the system thinks we have a 2K buffer instead. So we bump our model to 540, bump the diff --git a/modules/pcjs/lib/.jshintrc b/modules/pcjs/lib/.jshintrc index 8d6a42516..3c344cec6 100644 --- a/modules/pcjs/lib/.jshintrc +++ b/modules/pcjs/lib/.jshintrc @@ -10,6 +10,7 @@ "APPNAME": false, "APPVERSION": false, "SITEHOST": false, + "COMPILED": true, "DEBUG": true, "MAXDEBUG": false, "PCJSCLASS": true, @@ -18,6 +19,7 @@ "EAFUNCS": true, "FATARRAYS": true, "TYPEDARRAYS": true, + "SAMPLER": true, "Component": true, "State": true, "Bus": true, @@ -47,9 +49,14 @@ "str": true, "usr": true, "web": true, + "document": true, "global": true, "module": true, "require": true, + "ArrayBuffer": false, + "DataView": false, + "FileReader": false, + "Uint8Array": false, "setTimeout": false, "clearTimeout": false, "webkitAudioContext": false, diff --git a/modules/pcjs/lib/bus.js b/modules/pcjs/lib/bus.js index b31710a71..185673da5 100644 --- a/modules/pcjs/lib/bus.js +++ b/modules/pcjs/lib/bus.js @@ -290,7 +290,7 @@ Bus.prototype.getA20 = function() */ Bus.prototype.setA20 = function(fEnable) { - if (DEBUG) this.assert(fEnable !== undefined); + this.assert(fEnable !== undefined); if (fEnable !== undefined) { if (this.nBusWidth > 20) { var addrMask = (this.addrMask & ~0x100000) | (fEnable? 0x100000 : 0); @@ -643,7 +643,7 @@ Bus.prototype.checkPortInputNotify = function(port, addrFrom) } else { if (DEBUGGER && this.dbg) { - this.dbg.messagePort(this, port, null, addrFrom); + this.dbg.messageIO(this, port, null, addrFrom); if (this.fPortInputBreakAll) this.dbg.checkPortInput(port, bIn); } } @@ -759,7 +759,7 @@ Bus.prototype.checkPortOutputNotify = function(port, bOut, addrFrom) } else { if (DEBUGGER && this.dbg) { - this.dbg.messagePort(this, port, bOut, addrFrom); + this.dbg.messageIO(this, port, bOut, addrFrom); if (this.fPortOutputBreakAll) this.dbg.checkPortOutput(port, bOut); } } diff --git a/modules/pcjs/lib/chipset.js b/modules/pcjs/lib/chipset.js index 9a89da935..5f32ff705 100644 --- a/modules/pcjs/lib/chipset.js +++ b/modules/pcjs/lib/chipset.js @@ -77,7 +77,7 @@ if (typeof module !== 'undefined') { * be programmed to return it (which we support), but its purpose remains unclear to me (see PPI_B.ENABLE_SW2). * * For example, sw1="01110011" indicates that all SW1 DIP switches are ON, except for SW1[1], SW1[5] and SW1[6], - * which are OFF. Internally, the order of these bits must reversed (to 11001110) and then inverted (to 00110001) + * which are OFF. Internally, the order of these bits must reversed (to 11001110) and then inverted (to 00110001) * to yield the value that the 8255A PPI returns. Reading the final value right-to-left, 00110001 indicates an * IPL floppy drive, 1X of RAM (where X is 16Kb on a MODEL_5150 and 64Kb on a MODEL_5160), MDA, and 1 floppy drive. * @@ -88,7 +88,7 @@ if (typeof module !== 'undefined') { * a valid stack causes the system to crash after the next IRET. The BIOS should have either halted or modified * the actual memory size to match the results of the memory test. * - * This component provides support for many of the following components (except where a separate component is noted). + * This module provides support for many of the following components (except where a separate component is noted). * This list is taken from p.1-8 ("System Unit") of the IBM 5160 (PC XT) Technical Reference Manual (as revised * April 1983), only because I didn't see a similar listing in the original 5150 TechRef. * @@ -147,7 +147,7 @@ if (typeof module !== 'undefined') { */ function ChipSet(parmsChipSet) { - Component.call(this, "ChipSet", parmsChipSet, ChipSet); + Component.call(this, "ChipSet", parmsChipSet, ChipSet, Debugger.MESSAGE.CHIPSET); this.model = parmsChipSet['model']; this.model = (this.model? parseInt(this.model, 10) : ChipSet.MODEL_5150); @@ -187,15 +187,18 @@ function ChipSet(parmsChipSet) } /* - * 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. + * 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 - * supported on the motherboard) is the "size" parameter of the RAM component. NOTE: If you use the "size" parameter, - * you will not be able to dynamically alter the memory configuration; the RAM component will ignore any changes to SW1. + * 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 supported on the motherboard) is the "size" parameter of the RAM component. + * + * NOTE: If you use the "size" parameter, you will not be able to dynamically alter the memory configuration; + * the RAM component will ignore any changes to SW1. */ this.sw2Init = this.parseSwitches(parmsChipSet['sw2'] || "11110000", 0); @@ -214,7 +217,7 @@ function ChipSet(parmsChipSet) /* * 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. + * sound generation, using the API to make the same noises as the IBM PC speaker seems straightforward. * * To start, we create an audio context, unless the 'sound' parameter has been explicitly set to false. * @@ -426,8 +429,8 @@ ChipSet.DMA_HDC = 0x03; // DMA channel assigned to the Hard Drive Contro * * 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? + * TODO: Determine why the original ROM BIOS chose buffered/slave over buffered/master. + * Did it simply not matter in pre-AT systems with only one PIC, or am I misreading something? * * TODO: Consider support for level-triggered PIC interrupts, even though the original IBM PCs * (up through MODEL_5170) used only edge-triggered interrupts. @@ -643,6 +646,7 @@ ChipSet.PPI_SW = { * * 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 @@ -655,7 +659,7 @@ ChipSet.PPI_SW = { * 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: + * 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") @@ -863,9 +867,9 @@ ChipSet.CMOS = { * 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, - * perhaps treating them as scratch registers. + * We'll refer to it as a "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, presumably treating them as scratch registers. */ ChipSet.MFG = { // this.bMFGData PORT: 0x80 @@ -1130,11 +1134,11 @@ ChipSet.prototype.reset = function(fHard) * * 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 + * 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 updateRTCTime() won't * require any conversions. * - * We take the same approach with the CMOS_STATUSB.HOUR24 setting: internally, we always operate in 24-hour mode, + * 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 @@ -1206,7 +1210,7 @@ ChipSet.prototype.initRTCTime = function(sDate) */ ChipSet.prototype.getRTCByte = function(iRTC) { - if (DEBUG) this.assert(iRTC >= 0 && iRTC <= ChipSet.CMOS.ADDR.STATUSD); + this.assert(iRTC >= 0 && iRTC <= ChipSet.CMOS.ADDR.STATUSD); var b = this.abCMOSData[iRTC]; @@ -1258,7 +1262,7 @@ ChipSet.prototype.getRTCByte = function(iRTC) */ ChipSet.prototype.setRTCByte = function(iRTC, b) { - if (DEBUG) this.assert(iRTC >= 0 && iRTC <= ChipSet.CMOS.ADDR.STATUSD); + this.assert(iRTC >= 0 && iRTC <= ChipSet.CMOS.ADDR.STATUSD); if (iRTC < ChipSet.CMOS.ADDR.STATUSA) { var fBCD = false; @@ -1276,8 +1280,8 @@ ChipSet.prototype.setRTCByte = function(iRTC, b) * 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. */ - if (b > 12) { - if (DEBUG) this.assert(b >= 0x51 && b <= 0x5c); + if (b > 23) { + this.assert(b >= 0x51 && b <= 0x5c); b += 0x30; } } @@ -1328,17 +1332,17 @@ ChipSet.prototype.getRTCCycleLimit = function(nCycles) if (nCyclesUpdate > 0) { if (nCycles > nCyclesUpdate) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.RTC)) { - this.messageDebugger("getRTCCycleLimit(" + nCycles + "): reduced to " + nCyclesUpdate + " cycles", Debugger.MESSAGE.RTC); + this.messageDebugger("getRTCCycleLimit(" + nCycles + "): reduced to " + nCyclesUpdate + " cycles"); } nCycles = nCyclesUpdate; } else { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.RTC)) { - this.messageDebugger("getRTCCycleLimit(" + nCycles + "): already less than " + nCyclesUpdate + " cycles", Debugger.MESSAGE.RTC); + this.messageDebugger("getRTCCycleLimit(" + nCycles + "): already less than " + nCyclesUpdate + " cycles"); } } } else { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.RTC)) { - this.messageDebugger("RTC next update has passed by " + nCyclesUpdate + " cycles", Debugger.MESSAGE.RTC); + this.messageDebugger("RTC next update has passed by " + nCyclesUpdate + " cycles"); } } } @@ -1434,7 +1438,7 @@ ChipSet.prototype.updateRTCTime = function() * Step 3: Update the RTC date/time and deal with Update Interrupts */ var nCyclesDelta = nCyclesUpdate - this.nRTCCyclesLastUpdate; - if (DEBUG) this.assert(nCyclesDelta >= 0); + this.assert(nCyclesDelta >= 0); var nSecondsDelta = Math.floor(nCyclesDelta / nCyclesPerSecond); /* @@ -1444,7 +1448,7 @@ ChipSet.prototype.updateRTCTime = function() * (nCyclesDelta % nCyclesPerSecond) back into nRTCCyclesLastUpdate, so that we will eventually * see a one-second delta. */ - if (DEBUG) this.assert(nSecondsDelta <= 1); + this.assert(nSecondsDelta <= 1); /* * Make sure that CMOS.STATUSB.SET isn't set; if it is, then the once-per-second RTC updates must be @@ -1512,8 +1516,8 @@ ChipSet.prototype.initCMOSData = function() } /* - * We propagate all compatible "legacy" SW1 bits to the CMOS_EQUIP byte using the old SW masks, but any further - * access to CMOS_ADDR.EQUIP should use the new CMOS_EQUIP flags (eg, CMOS_EQUIP.COPROC, CMOS_EQUIP.MONITOR.CGA80, etc). + * We propagate all compatible "legacy" SW1 bits to the CMOS.EQUIP byte using the old SW masks, but any further + * access to CMOS.ADDR.EQUIP should use the new CMOS_EQUIP flags (eg, CMOS.EQUIP.COPROC, CMOS.EQUIP.MONITOR.CGA80, etc). */ this.abCMOSData[ChipSet.CMOS.ADDR.EQUIP] = this.sw1 & (ChipSet.PPI_SW.MONITOR.MASK | ChipSet.PPI_SW.COPROC | ChipSet.PPI_SW.FDRIVE.IPL | ChipSet.PPI_SW.FDRIVE.MASK); this.abCMOSData[ChipSet.CMOS.ADDR.FDRIVE] = (this.getSWFloppyDriveType(0) << 4) | this.getSWFloppyDriveType(1); @@ -1538,7 +1542,7 @@ ChipSet.prototype.initCMOSData = function() ChipSet.prototype.setCMOSByte = function(iCMOS, b) { if (this.abCMOSData) { - if (DEBUG) this.assert(iCMOS >= ChipSet.CMOS.ADDR.FDRIVE && iCMOS < ChipSet.CMOS.ADDR.CHKSUM_HI); + this.assert(iCMOS >= ChipSet.CMOS.ADDR.FDRIVE && iCMOS < ChipSet.CMOS.ADDR.CHKSUM_HI); this.abCMOSData[iCMOS] = b; this.updateCMOSChecksum(); return true; @@ -1590,7 +1594,7 @@ ChipSet.prototype.setCMOSDriveType = function(iDrive, bType) { if (this.abCMOSData) { var b = this.abCMOSData[ChipSet.CMOS.ADDR.HDRIVE]; - if (DEBUG) this.assert(bType > 0 && bType < 0xf); + this.assert(bType > 0 && bType < 0xf); if (iDrive) { b = (b & ChipSet.CMOS.HDRIVE.D0_MASK) | bType; } else { @@ -1690,7 +1694,7 @@ ChipSet.prototype.restore = function(data) a = data[5]; if (a) { - if (DEBUG) this.assert(this.model >= ChipSet.MODEL_5170); + this.assert(this.model >= ChipSet.MODEL_5170); this.b8042Status = a[0]; this.b8042InBuff = a[1]; this.b8042CmdData = a[2]; @@ -1701,7 +1705,7 @@ ChipSet.prototype.restore = function(data) a = data[6]; if (a) { - if (DEBUG) this.assert(this.model >= ChipSet.MODEL_5170); + this.assert(this.model >= ChipSet.MODEL_5170); this.bMFGData = a[0]; this.abDMAPageSpare = a[1]; this.bCMOSAddr = a[2]; @@ -1734,7 +1738,7 @@ ChipSet.prototype.initDMAController = function(iDMAC, aState) { var controller = this.aDMACs[iDMAC]; if (!controller) { - if (DEBUG) this.assert(!aState); + this.assert(!aState); controller = { aChannels: new Array(4) }; @@ -1765,7 +1769,7 @@ ChipSet.prototype.initDMAChannel = function(controller, iChannel, aState) { var channel = controller.aChannels[iChannel]; if (!channel) { - if (DEBUG) this.assert(!aState); + this.assert(!aState); channel = { addrInit: [0,0], countInit: [0,0], @@ -2041,7 +2045,7 @@ ChipSet.prototype.getSWFloppyDriveType = function(iDrive) return ChipSet.CMOS.FDRIVE.FD1440; } } - if (DEBUG) this.assert(false); // we should never get here (else something is out of out sync) + this.assert(false); // we should never get here (else something is out of out sync) } return ChipSet.CMOS.FDRIVE.NONE; }; @@ -2062,7 +2066,7 @@ ChipSet.prototype.getSWFloppyDriveSize = function(iDrive) if (iDrive < this.aFloppyDrives.length) { return this.aFloppyDrives[iDrive]; } - if (DEBUG) this.assert(false); // we should never get here (else something is out of out sync) + this.assert(false); // we should never get here (else something is out of out sync) } return 0; }; @@ -2285,7 +2289,7 @@ ChipSet.prototype.inDMAChannelAddr = function(iDMAC, iChannel, port, addrFrom) var channel = controller.aChannels[iChannel]; var b = channel.addrCurrent[controller.bIndex]; if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".ADDR[" + controller.bIndex + "]", Debugger.MESSAGE.DMA, b); + this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".ADDR[" + controller.bIndex + "]", 0, b); } controller.bIndex ^= 0x1; /* @@ -2322,7 +2326,7 @@ ChipSet.prototype.outDMAChannelAddr = function outDMAChannelAddr(iDMAC, iChannel { var controller = this.aDMACs[iDMAC]; if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".ADDR[" + controller.bIndex + "]", Debugger.MESSAGE.DMA); + this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".ADDR[" + controller.bIndex + "]"); } var channel = controller.aChannels[iChannel]; channel.addrCurrent[controller.bIndex] = channel.addrInit[controller.bIndex] = bOut; @@ -2345,7 +2349,7 @@ ChipSet.prototype.inDMAChannelCount = function(iDMAC, iChannel, port, addrFrom) var channel = controller.aChannels[iChannel]; var b = channel.countCurrent[controller.bIndex]; if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".COUNT[" + controller.bIndex + "]", Debugger.MESSAGE.DMA, b); + this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".COUNT[" + controller.bIndex + "]", 0, b); } controller.bIndex ^= 0x1; /* @@ -2386,7 +2390,7 @@ ChipSet.prototype.outDMAChannelCount = function(iDMAC, iChannel, port, bOut, add { var controller = this.aDMACs[iDMAC]; if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".COUNT[" + controller.bIndex + "]", Debugger.MESSAGE.DMA); + this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".COUNT[" + controller.bIndex + "]"); } var channel = controller.aChannels[iChannel]; channel.countCurrent[controller.bIndex] = channel.countInit[controller.bIndex] = bOut; @@ -2429,7 +2433,7 @@ ChipSet.prototype.inDMAStatus = function(iDMAC, port, addrFrom) var b = controller.bStatus | ChipSet.DMA_STATUS.CH0_TC; controller.bStatus &= ~ChipSet.DMA_STATUS.ALL_TC; if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".STATUS", Debugger.MESSAGE.DMA, b); + this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".STATUS", 0, b); } return b; }; @@ -2446,7 +2450,7 @@ ChipSet.prototype.inDMAStatus = function(iDMAC, port, addrFrom) ChipSet.prototype.outDMACmd = function(iDMAC, port, bOut, addrFrom) { if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".CMD", Debugger.MESSAGE.DMA); + this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".CMD"); } this.aDMACs[iDMAC].bCmd = bOut; }; @@ -2474,7 +2478,7 @@ ChipSet.prototype.outDMAReq = function(iDMAC, port, bOut, addrFrom) { var controller = this.aDMACs[iDMAC]; if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".REQ", Debugger.MESSAGE.DMA); + this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".REQ"); } /* * Bits 0-1 contain the channel number @@ -2501,7 +2505,7 @@ ChipSet.prototype.outDMAMask = function(iDMAC, port, bOut, addrFrom) { var controller = this.aDMACs[iDMAC]; if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".MASK", Debugger.MESSAGE.DMA); + this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".MASK"); } var iChannel = bOut & ChipSet.DMA_MASK.CHANNEL; var channel = controller.aChannels[iChannel]; @@ -2521,7 +2525,7 @@ ChipSet.prototype.outDMAMask = function(iDMAC, port, bOut, addrFrom) ChipSet.prototype.outDMAMode = function(iDMAC, port, bOut, addrFrom) { if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".MODE", Debugger.MESSAGE.DMA); + this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".MODE"); } var iChannel = bOut & ChipSet.DMA_MODE.CHANNEL; this.aDMACs[iDMAC].aChannels[iChannel].mode = bOut; @@ -2542,7 +2546,7 @@ ChipSet.prototype.outDMAMode = function(iDMAC, port, bOut, addrFrom) ChipSet.prototype.outDMAResetFF = function(iDMAC, port, bOut, addrFrom) { if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".RESET_FF", Debugger.MESSAGE.DMA); + this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".RESET_FF"); } this.aDMACs[iDMAC].bIndex = 0; }; @@ -2559,7 +2563,7 @@ ChipSet.prototype.outDMAResetFF = function(iDMAC, port, bOut, addrFrom) ChipSet.prototype.outDMAMasterClear = function(iDMAC, port, bOut, addrFrom) { if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".MASTER_CLEAR", Debugger.MESSAGE.DMA); + this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".MASTER_CLEAR"); } /* * The value written to this port doesn't matter; any write triggers a "master clear" operation @@ -2586,7 +2590,7 @@ ChipSet.prototype.inDMAPageReg = function(iDMAC, iChannel, port, addrFrom) { var bIn = this.aDMACs[iDMAC].aChannels[iChannel].bPage; if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".PAGE", Debugger.MESSAGE.DMA, bIn); + this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".PAGE", 0, bIn); } return bIn; }; @@ -2604,7 +2608,7 @@ ChipSet.prototype.inDMAPageReg = function(iDMAC, iChannel, port, addrFrom) ChipSet.prototype.outDMAPageReg = function(iDMAC, iChannel, port, bOut, addrFrom) { if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".PAGE", Debugger.MESSAGE.DMA); + this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".PAGE"); } this.aDMACs[iDMAC].aChannels[iChannel].bPage = bOut; }; @@ -2622,7 +2626,7 @@ ChipSet.prototype.inDMAPageSpare = function(iSpare, port, addrFrom) { var bIn = this.abDMAPageSpare[iSpare]; if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, null, addrFrom, "DMA.SPARE" + iSpare + ".PAGE", Debugger.MESSAGE.DMA, bIn); + this.messagePort(port, null, addrFrom, "DMA.SPARE" + iSpare + ".PAGE", 0, bIn); } return bIn; }; @@ -2639,7 +2643,7 @@ ChipSet.prototype.inDMAPageSpare = function(iSpare, port, addrFrom) ChipSet.prototype.outDMAPageSpare = function(iSpare, port, bOut, addrFrom) { if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { - this.messagePort(port, bOut, addrFrom, "DMA.SPARE" + iSpare + ".PAGE", Debugger.MESSAGE.DMA); + this.messagePort(port, bOut, addrFrom, "DMA.SPARE" + iSpare + ".PAGE"); } this.abDMAPageSpare[iSpare] = bOut; }; @@ -2709,7 +2713,7 @@ ChipSet.prototype.requestDMA = function(iDMAChannel, done) if (!channel.component || !channel.fnTransfer || !channel.obj) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.OTHER)) { - this.messageDebugger("requestDMA(" + iDMAChannel + "): not connected to a component", Debugger.MESSAGE.DMA | Debugger.MESSAGE.OTHER); + this.messageDebugger("requestDMA(" + iDMAChannel + "): not connected to a component"); } if (done) done(true); return; @@ -2726,7 +2730,7 @@ ChipSet.prototype.requestDMA = function(iDMAChannel, done) if (channel.masked) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.OTHER)) { - this.messageDebugger("requestDMA(" + iDMAChannel + "): channel masked, request queued", Debugger.MESSAGE.DMA | Debugger.MESSAGE.OTHER); + this.messageDebugger("requestDMA(" + iDMAChannel + "): channel masked, request queued"); } return; } @@ -2778,8 +2782,8 @@ ChipSet.prototype.advanceDMA = function(channel, fInit) var addr = (channel.bPage << 16) | (channel.addrCurrent[1] << 8) | channel.addrCurrent[0]; if (DEBUG && DEBUGGER && channel.sAddrDebug === null) { channel.sAddrDebug = str.toHex(addr >> 4, 4) + ":" + str.toHex(addr & 0xf, 4); - if (this.messageEnabled(Debugger.MESSAGE.DMA | (iDMAChannel == ChipSet.DMA_FDC? Debugger.MESSAGE.FDC : (iDMAChannel == ChipSet.DMA_HDC? Debugger.MESSAGE.HDC : 0))) && channel.xfer != ChipSet.DMA_MODE.XFER_WRITE) { - this.dbg.message("advanceDMA(" + iDMAChannel + ") transferring " + channel.cbDebug + " bytes from " + channel.sAddrDebug); + if (this.messageEnabled(this.messageBitsDMA(iDMAChannel)) && channel.xfer != ChipSet.DMA_MODE.XFER_WRITE) { + this.messageDebugger("advanceDMA(" + iDMAChannel + ") transferring " + channel.cbDebug + " bytes from " + channel.sAddrDebug); this.dbg.doDump("db", channel.sAddrDebug, "l" + Math.floor((channel.cbDebug + 15) / 16)); } } @@ -2790,7 +2794,7 @@ ChipSet.prototype.advanceDMA = function(channel, fInit) if (b < 0) { if (!channel.fWarning) { if (DEBUG && obj.messageEnabled(Debugger.MESSAGE.DMA)) { - obj.messageDebugger("advanceDMA(" + iDMAChannel + ") ran out of data, assuming 0xff", Debugger.MESSAGE.DMA); + obj.messageDebugger("advanceDMA(" + iDMAChannel + ") ran out of data, assuming 0xff"); } channel.fWarning = true; } @@ -2839,7 +2843,7 @@ ChipSet.prototype.advanceDMA = function(channel, fInit) } else { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.WARN)) { - this.messageDebugger("advanceDMA(" + iDMAChannel + ") unsupported xfer mode: " + str.toHexWord(channel.xfer), Debugger.MESSAGE.DMA | Debugger.MESSAGE.WARN); + this.messageDebugger("advanceDMA(" + iDMAChannel + ") unsupported xfer mode: " + str.toHexWord(channel.xfer)); } channel.fError = true; } @@ -2892,8 +2896,8 @@ ChipSet.prototype.updateDMA = function(channel) channel.component = channel.obj = null; } - if (DEBUG && this.messageEnabled(Debugger.MESSAGE.DMA | (iDMAChannel == ChipSet.DMA_FDC? Debugger.MESSAGE.FDC : (iDMAChannel == ChipSet.DMA_HDC? Debugger.MESSAGE.HDC : 0))) && channel.xfer == ChipSet.DMA_MODE.XFER_WRITE && channel.sAddrDebug) { - this.dbg.message("updateDMA(" + iDMAChannel + ") transferred " + channel.cbDebug + " bytes to " + channel.sAddrDebug); + if (DEBUG && this.messageEnabled(this.messageBitsDMA(iDMAChannel)) && channel.xfer == ChipSet.DMA_MODE.XFER_WRITE && channel.sAddrDebug) { + this.messageDebugger("updateDMA(" + iDMAChannel + ") transferred " + channel.cbDebug + " bytes to " + channel.sAddrDebug); this.dbg.doDump("db", channel.sAddrDebug, "l" + Math.floor((channel.cbDebug + 15) / 16)); } @@ -2935,7 +2939,7 @@ ChipSet.prototype.inPICLo = function(iPIC, addrFrom) } } if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT)) { - this.messagePort(pic.port, null, addrFrom, "PIC" + iPIC, Debugger.MESSAGE.PIC, b); + this.messagePort(pic.port, null, addrFrom, "PIC" + iPIC, 0, b); } return b; }; @@ -2952,7 +2956,7 @@ ChipSet.prototype.outPICLo = function(iPIC, bOut, addrFrom) { var pic = this.aPICs[iPIC]; if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT)) { - this.messagePort(pic.port, bOut, addrFrom, "PIC" + iPIC, Debugger.MESSAGE.PIC); + this.messagePort(pic.port, bOut, addrFrom, "PIC" + iPIC); } if (bOut & ChipSet.PIC_LO.ICW1) { /* @@ -3035,23 +3039,23 @@ ChipSet.prototype.outPICLo = function(iPIC, bOut, addrFrom) } var nIRQ = (nIRL == null? undefined : pic.nIRQBase + nIRL); if (pic.bISR & bIREnd) { - if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PIC, nIRQ)) { - this.messageDebugger("outPIC" + iPIC + "(" + str.toHexByte(pic.port) + "): IRQ " + nIRQ + " going out of service", Debugger.MESSAGE.PIC, nIRQ); + if (DEBUG && this.messageEnabled(this.messageBitsIRQ(nIRQ))) { + this.messageDebugger("outPIC" + iPIC + "(" + str.toHexByte(pic.port) + "): IRQ " + nIRQ + " going out of service"); } pic.bISR &= ~bIREnd; this.checkIRR(iPIC); } else { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.WARN)) { - this.messageDebugger("outPIC" + iPIC + "(" + str.toHexByte(pic.port) + "): unexpected EOI command, IRQ " + nIRQ + " not in service", Debugger.MESSAGE.PIC | Debugger.MESSAGE.WARN); - if (this.dbg && !SAMPLER && MAXDEBUG) this.dbg.stopCPU(); + this.messageDebugger("outPIC" + iPIC + "(" + str.toHexByte(pic.port) + "): unexpected EOI command, IRQ " + nIRQ + " not in service"); + if (!SAMPLER && MAXDEBUG) this.dbg.stopCPU(); } } /* * TODO: Support EOI commands with automatic rotation (eg, ChipSet.PIC_LO.OCW2_EOI_ROT and ChipSet.PIC_LO.OCW2_EOI_ROTSPEC) */ if (DEBUG && (bOCW2 & ChipSet.PIC_LO.OCW2_SET_ROTAUTO) && this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.WARN)) { - this.messageDebugger("outPIC" + iPIC + "(" + str.toHexByte(pic.port) + "): unsupported OCW2 rotate command: " + str.toHexByte(bOut), Debugger.MESSAGE.PIC | Debugger.MESSAGE.WARN); - if (this.dbg) this.dbg.stopCPU(); + this.messageDebugger("outPIC" + iPIC + "(" + str.toHexByte(pic.port) + "): unsupported OCW2 rotate command: " + str.toHexByte(bOut)); + this.dbg.stopCPU(); } } else if (bOCW2 == ChipSet.PIC_LO.OCW2_SET_PRI) { @@ -3065,8 +3069,8 @@ ChipSet.prototype.outPICLo = function(iPIC, bOut, addrFrom) * TODO: Remaining commands to support: ChipSet.PIC_LO.OCW2_SET_ROTAUTO and ChipSet.PIC_LO.OCW2_CLR_ROTAUTO */ if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.WARN)) { - this.messageDebugger("outPIC" + iPIC + "(" + str.toHexByte(pic.port) + "): unsupported OCW2 automatic EOI command: " + str.toHexByte(bOut), Debugger.MESSAGE.PIC | Debugger.MESSAGE.WARN); - if (this.dbg) this.dbg.stopCPU(); + this.messageDebugger("outPIC" + iPIC + "(" + str.toHexByte(pic.port) + "): unsupported OCW2 automatic EOI command: " + str.toHexByte(bOut)); + this.dbg.stopCPU(); } } } else { @@ -3078,7 +3082,7 @@ ChipSet.prototype.outPICLo = function(iPIC, bOut, addrFrom) */ if (bOut & (ChipSet.PIC_LO.OCW3_POLL_CMD | ChipSet.PIC_LO.OCW3_SMM_CMD)) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.WARN)) { - this.messageDebugger("outPIC" + iPIC + "(" + str.toHexByte(pic.port) + "): unsupported OCW3 command: " + str.toHexByte(bOut), Debugger.MESSAGE.PIC | Debugger.MESSAGE.WARN); + this.messageDebugger("outPIC" + iPIC + "(" + str.toHexByte(pic.port) + "): unsupported OCW3 command: " + str.toHexByte(bOut)); } } pic.bOCW3 = bOut; @@ -3098,7 +3102,7 @@ ChipSet.prototype.inPICHi = function(iPIC, addrFrom) var pic = this.aPICs[iPIC]; var b = pic.bIMR; if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT)) { - this.messagePort(pic.port+1, null, addrFrom, "PIC" + iPIC, Debugger.MESSAGE.PIC, b); + this.messagePort(pic.port+1, null, addrFrom, "PIC" + iPIC, 0, b); } return b; }; @@ -3115,7 +3119,7 @@ ChipSet.prototype.outPICHi = function(iPIC, bOut, addrFrom) { var pic = this.aPICs[iPIC]; if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT)) { - this.messagePort(pic.port+1, bOut, addrFrom, "PIC" + iPIC, Debugger.MESSAGE.PIC); + this.messagePort(pic.port+1, bOut, addrFrom, "PIC" + iPIC); } if (pic.nICW < pic.aICW.length) { pic.aICW[pic.nICW++] = bOut; @@ -3174,8 +3178,8 @@ ChipSet.prototype.setIRR = function(nIRQ, nDelay) var nIRL = nIRQ & 0x7; var pic = this.aPICs[iPIC]; pic.bIRR |= 1 << nIRL; - if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PIC, nIRQ)) { - this.messageDebugger("setIRR(" + nIRQ + ")", Debugger.MESSAGE.PIC, nIRQ); + if (DEBUG && this.messageEnabled(this.messageBitsIRQ(nIRQ))) { + this.messageDebugger("setIRR(" + nIRQ + ")"); } pic.nDelay = nDelay || 0; /* @@ -3199,8 +3203,8 @@ ChipSet.prototype.clearIRR = function(nIRQ) var bIRR = (1 << nIRL); if (pic.bIRR & bIRR) { pic.bIRR &= ~bIRR; - if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PIC, nIRQ)) { - this.messageDebugger("clearIRR(" + nIRQ + ")", Debugger.MESSAGE.PIC, nIRQ); + if (DEBUG && this.messageEnabled(this.messageBitsIRQ(nIRQ))) { + this.messageDebugger("clearIRR(" + nIRQ + ")"); } /* * When all slave IRRs go low, I'm assuming that the master's slave IRR line should go low as well @@ -3297,8 +3301,8 @@ ChipSet.prototype.getIRRVector = function(iPIC) } var nIRQ = pic.nIRQBase + nIRL; - if (DEBUG && this.messageEnabled(0, nIRQ)) { - this.messageDebugger("getIRRVector(): IRQ " + nIRQ + " interrupting @" + str.toHexAddr(this.cpu.regIP, this.cpu.segCS.sel) + " stack=" + str.toHexAddr(this.cpu.regSP, this.cpu.segSS.sel), 0, nIRQ); + if (DEBUG && this.messageEnabled(this.messageBitsIRQ(nIRQ))) { + this.messageDebugger("getIRRVector(): IRQ " + nIRQ + " interrupting @" + str.toHexAddr(this.cpu.regIP, this.cpu.segCS.sel) + " stack=" + str.toHexAddr(this.cpu.regSP, this.cpu.segSS.sel)); } if (MAXDEBUG && DEBUGGER) { this.acInterrupts[nIRQ]++; @@ -3334,7 +3338,7 @@ ChipSet.prototype.inTimer = function(iTimer, addrFrom) this.updateTimer(iTimer); b = timer.countCurrent[timer.countIndex++]; if (this.messageEnabled(Debugger.MESSAGE.TIMER | Debugger.MESSAGE.PORT)) { - this.messagePort(ChipSet.TIMER0.PORT + iTimer, null, addrFrom, "TIMER" + iTimer, Debugger.MESSAGE.TIMER, b); + this.messagePort(ChipSet.TIMER0.PORT + iTimer, null, addrFrom, "TIMER" + iTimer, 0, b); } return b; }; @@ -3359,7 +3363,7 @@ ChipSet.prototype.inTimer = function(iTimer, addrFrom) ChipSet.prototype.outTimer = function(iTimer, bOut, addrFrom) { if (this.messageEnabled(Debugger.MESSAGE.TIMER | Debugger.MESSAGE.PORT)) { - this.messagePort(ChipSet.TIMER0.PORT + iTimer, bOut, addrFrom, "TIMER" + iTimer, Debugger.MESSAGE.TIMER); + this.messagePort(ChipSet.TIMER0.PORT + iTimer, bOut, addrFrom, "TIMER" + iTimer); } var timer = this.aTimers[iTimer]; if (timer.countIndex == timer.countBytes) this.resetTimerIndex(iTimer); @@ -3486,7 +3490,7 @@ ChipSet.prototype.outTimerCtrl = function(port, bOut, addrFrom) timer.countStart[1] = timer.countInit[1]; timer.nCyclesStart = this.cpu.getCycles(this.fScaleTimers); if (DEBUG && this.messageEnabled(Debugger.MESSAGE.TIMER)) { - this.messageDebugger("TIMER0 count reset @" + timer.nCyclesStart + " cycles", Debugger.MESSAGE.TIMER); + this.messageDebugger("TIMER0 count reset @" + timer.nCyclesStart + " cycles"); } } } @@ -3540,11 +3544,11 @@ ChipSet.prototype.getTimerCycleLimit = function(iTimer, nCycles) if (timer.fCounting) { var nCyclesUpdate = this.cpu.getCycles(this.fScaleTimers); var ticksElapsed = ((nCyclesUpdate - timer.nCyclesStart) / this.nTicksDivisor) | 0; - if (DEBUG) this.assert(ticksElapsed >= 0); + this.assert(ticksElapsed >= 0); var countStart = this.getTimerStart(iTimer); var count = countStart - ticksElapsed; if (timer.mode == ChipSet.TIMER_CTRL.MODE3) count -= ticksElapsed; - if (DEBUG) this.assert(count > 0); + this.assert(count > 0); var nCyclesRemain = (count * this.nTicksDivisor) | 0; if (timer.mode == ChipSet.TIMER_CTRL.MODE3) nCyclesRemain >>= 1; if (nCycles > nCyclesRemain) nCycles = nCyclesRemain; @@ -3689,7 +3693,7 @@ ChipSet.prototype.updateTimer = function(iTimer, fCycleReset) if (ticksElapsed < 0) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.TIMER)) { - this.messageDebugger("updateTimer(" + iTimer + "): negative tick count (" + ticksElapsed + ")", Debugger.MESSAGE.TIMER); + this.messageDebugger("updateTimer(" + iTimer + "): negative tick count (" + ticksElapsed + ")"); } timer.nCyclesStart = nCycles; ticksElapsed = 0; @@ -3709,7 +3713,7 @@ ChipSet.prototype.updateTimer = function(iTimer, fCycleReset) if (timer.mode == ChipSet.TIMER_CTRL.MODE0) { if (count <= 0) count = 0; if (DEBUG && this.messageEnabled(Debugger.MESSAGE.TIMER)) { - this.messageDebugger("updateTimer(" + iTimer + "): MODE0 timer count=" + count, Debugger.MESSAGE.TIMER); + this.messageDebugger("updateTimer(" + iTimer + "): MODE0 timer count=" + count); } if (!count) { timer.fOUT = true; @@ -3744,7 +3748,7 @@ ChipSet.prototype.updateTimer = function(iTimer, fCycleReset) count = countInit + count; if (count <= 0) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.TIMER)) { - this.messageDebugger("updateTimer(" + iTimer + "): underflow=" + count, Debugger.MESSAGE.TIMER); + this.messageDebugger("updateTimer(" + iTimer + "): underflow=" + count); } count = countInit; } @@ -3776,7 +3780,7 @@ ChipSet.prototype.updateTimer = function(iTimer, fCycleReset) count = countInit + count; if (count <= 0) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.TIMER)) { - this.messageDebugger("updateTimer(" + iTimer + "): underflow=" + count, Debugger.MESSAGE.TIMER); + this.messageDebugger("updateTimer(" + iTimer + "): underflow=" + count); } count = countInit; } @@ -4232,7 +4236,7 @@ ChipSet.prototype.in8042Status = function(port, addrFrom) ChipSet.prototype.out8042InBuffCmd = function(port, bOut, addrFrom) { this.messagePort(port, bOut, addrFrom, "8042_INBUFF.CMD", Debugger.MESSAGE.C8042); - if (DEBUG) this.assert(!(this.b8042Status & ChipSet.KBC.STATUS.INBUFF_FULL)); + this.assert(!(this.b8042Status & ChipSet.KBC.STATUS.INBUFF_FULL)); this.b8042InBuff = bOut; this.b8042Status |= ChipSet.KBC.STATUS.CMD_FLAG; @@ -4298,8 +4302,8 @@ ChipSet.prototype.out8042InBuffCmd = function(port, bOut, addrFrom) default: if (DEBUG && this.messageEnabled(Debugger.MESSAGE.C8042)) { - this.messageDebugger("unrecognized 8042 command: " + str.toHexByte(this.b8042InBuff), Debugger.MESSAGE.C8042); - if (this.dbg) this.dbg.stopCPU(); + this.messageDebugger("unrecognized 8042 command: " + str.toHexByte(this.b8042InBuff)); + this.dbg.stopCPU(); } break; } @@ -4315,7 +4319,7 @@ ChipSet.prototype.set8042CmdData = function(b) { var bClockWasEnabled = !(this.b8042CmdData & ChipSet.KBC.DATA.CMD.NO_CLOCK); this.b8042CmdData = b; - if (DEBUG) this.assert(ChipSet.KBC.DATA.CMD.SYS_FLAG === ChipSet.KBC.STATUS.SYS_FLAG); + this.assert(ChipSet.KBC.DATA.CMD.SYS_FLAG === ChipSet.KBC.STATUS.SYS_FLAG); this.b8042Status = (this.b8042Status & ~ChipSet.KBC.STATUS.SYS_FLAG) | (b & ChipSet.KBC.DATA.CMD.SYS_FLAG); if (this.kbd) { /* @@ -4374,9 +4378,9 @@ ChipSet.prototype.set8042OutPort = function(b) * KBC.CMD.PULSE_OUTPORT command, so if a RESET is detected via this command, we should try to * determine if that's what the caller intended. */ - if (DEBUG) { + if (DEBUG && this.messageEnabled(Debugger.MESSAGE.C8042)) { this.messageDebugger("unexpected 8042 output port reset: " + str.toHexByte(b)); - if (this.dbg) this.dbg.stopCPU(); + this.dbg.stopCPU(); } this.cpu.resetRegs(); } @@ -4489,7 +4493,7 @@ ChipSet.prototype.notifyKbdData = function(fAvail) */ ChipSet.prototype.inCMOSAddr = function(port, addrFrom) { - this.messagePort(port, null, addrFrom, "CMOS_ADDR", Debugger.MESSAGE.CMOS, this.bCMOSAddr); + this.messagePort(port, null, addrFrom, "CMOS.ADDR", Debugger.MESSAGE.CMOS, this.bCMOSAddr); return this.bCMOSAddr; }; @@ -4503,7 +4507,7 @@ ChipSet.prototype.inCMOSAddr = function(port, addrFrom) */ ChipSet.prototype.outCMOSAddr = function(port, bOut, addrFrom) { - this.messagePort(port, bOut, addrFrom, "CMOS_ADDR", Debugger.MESSAGE.CMOS); + this.messagePort(port, bOut, addrFrom, "CMOS.ADDR", Debugger.MESSAGE.CMOS); this.bCMOSAddr = bOut; this.bNMI = (bOut & ChipSet.CMOS.ADDR.NMI_DISABLE)? ChipSet.NMI.DISABLE : ChipSet.NMI.ENABLE; }; @@ -4521,7 +4525,7 @@ ChipSet.prototype.inCMOSData = function(port, addrFrom) var bAddr = this.bCMOSAddr & ChipSet.CMOS.ADDR.MASK; var bIn = (bAddr <= ChipSet.CMOS.ADDR.STATUSD? this.getRTCByte(bAddr) : this.abCMOSData[bAddr]); if (this.messageEnabled(Debugger.MESSAGE.CMOS | Debugger.MESSAGE.PORT)) { - this.messagePort(port, null, addrFrom, "CMOS_DATA[" + str.toHexByte(bAddr) + "]", Debugger.MESSAGE.CMOS, bIn); + this.messagePort(port, null, addrFrom, "CMOS.DATA[" + str.toHexByte(bAddr) + "]", 0, bIn); } if (addrFrom != null) { if (bAddr == ChipSet.CMOS.ADDR.STATUSC) { @@ -4556,7 +4560,7 @@ ChipSet.prototype.outCMOSData = function(port, bOut, addrFrom) { var bAddr = this.bCMOSAddr & ChipSet.CMOS.ADDR.MASK; if (this.messageEnabled(Debugger.MESSAGE.CMOS | Debugger.MESSAGE.PORT)) { - this.messagePort(port, bOut, addrFrom, "CMOS_DATA[" + str.toHexByte(bAddr) + "]", Debugger.MESSAGE.CMOS); + this.messagePort(port, bOut, addrFrom, "CMOS.DATA[" + str.toHexByte(bAddr) + "]"); } var bDelta = bOut ^ this.abCMOSData[bAddr]; this.abCMOSData[bAddr] = (bAddr <= ChipSet.CMOS.ADDR.STATUSD? this.setRTCByte(bAddr, bOut) : bOut); @@ -4708,7 +4712,7 @@ ChipSet.prototype.setSpeaker = function(fOn) if (this.sourceAudio) { this.sourceAudio['frequency']['value'] = freq; if (this.messageEnabled(Debugger.MESSAGE.SPEAKER)) { - this.messageDebugger("speaker set to " + freq + "hz", Debugger.MESSAGE.SPEAKER); + this.messageDebugger("speaker set to " + freq + "hz"); } } else { this.sourceAudio = this.contextAudio['createOscillator'](); @@ -4716,7 +4720,7 @@ ChipSet.prototype.setSpeaker = function(fOn) this.sourceAudio['connect'](this.contextAudio['destination']); this.sourceAudio['frequency']['value'] = freq; if (this.messageEnabled(Debugger.MESSAGE.SPEAKER)) { - this.messageDebugger("speaker on at " + freq + "hz", Debugger.MESSAGE.SPEAKER); + this.messageDebugger("speaker on at " + freq + "hz"); } this.sourceAudio['noteOn'](0); // aka start() } @@ -4726,7 +4730,7 @@ ChipSet.prototype.setSpeaker = function(fOn) this.sourceAudio['disconnect'](); // QUESTION: is this automatic following a stop(), since this particular source cannot be started again? delete this.sourceAudio; // QUESTION: ditto? if (this.messageEnabled(Debugger.MESSAGE.SPEAKER)) { - this.messageDebugger("speaker off at " + freq + "hz", Debugger.MESSAGE.SPEAKER); + this.messageDebugger("speaker off at " + freq + "hz"); } } } @@ -4736,69 +4740,41 @@ ChipSet.prototype.setSpeaker = function(fOn) }; /** - * messageEnabled(bitsMessage, nIRQ) + * messageBitsDMA(iChannel) + * + * @this {ChipSet} + * @param {number} [iChannel] if the message is associated with a particular IRQ # + * @return {number} + */ +ChipSet.prototype.messageBitsDMA = function(iChannel) +{ + var bitsMessage = Debugger.MESSAGE.DMA; + if (iChannel == ChipSet.DMA_FDC) { + bitsMessage |= Debugger.MESSAGE.FDC; + } else if (iChannel == ChipSet.DMA_HDC) { + bitsMessage |= Debugger.MESSAGE.HDC; + } + return bitsMessage; +}; + +/** + * messageBitsIRQ(nIRQ) * * @this {ChipSet} - * @param {number} [bitsMessage] is one or more Debugger MESSAGE_* category flag(s) * @param {number|undefined} [nIRQ] if the message is associated with a particular IRQ # - * @return {boolean} + * @return {number} */ -ChipSet.prototype.messageEnabled = function(bitsMessage, nIRQ) +ChipSet.prototype.messageBitsIRQ = function(nIRQ) { - if (DEBUGGER && this.dbg) { - if (bitsMessage == null) { - bitsMessage = Debugger.MESSAGE.CHIPSET; - } - if (nIRQ !== undefined) { - bitsMessage |= (nIRQ == ChipSet.IRQ.TIMER0? Debugger.MESSAGE.TIMER : (nIRQ == ChipSet.IRQ.KBD? Debugger.MESSAGE.KBD : (nIRQ == ChipSet.IRQ.FDC? Debugger.MESSAGE.FDC : 0))) | Debugger.MESSAGE.PIC; - } - return this.dbg.messageEnabled(bitsMessage); - } - return false; -}; - -/** - * 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) - * @param {number} [nIRQ] if the message is associated with a particular IRQ # - * - * This is a combination of the Debugger's messageEnabled() and message() functions, for convenience. - * - * NOTE: If the caller specifies multiple MESSAGE category flags, then ALL the corresponding message - * categories in the Debugger must be enabled as well, else the message will not be displayed. - */ -ChipSet.prototype.messageDebugger = function(sMessage, bitsMessage, nIRQ) -{ - if (DEBUGGER && this.dbg) { - if (this.messageEnabled(bitsMessage, nIRQ)) this.dbg.message(sMessage); - } -}; - -/** - * messagePort(port, bOut, addrFrom, name, bitsMessage, bIn) - * - * @this {ChipSet} - * @param {number} port - * @param {number|null} bOut if an output operation - * @param {number|null} [addrFrom] - * @param {string|null} [name] of the port, if any - * @param {number|null} [bitsMessage] is one or more a Debugger MESSAGE_* category flag(s) - * @param {number} [bIn] is the input value, if known, on an input operation - * - * This is an internal version of the Debugger's messagePort() function, for convenience. - * - * NOTE: If the caller specifies multiple MESSAGE category flags, then ALL the corresponding message - * categories in the Debugger must be enabled as well, else the message will not be displayed. - */ -ChipSet.prototype.messagePort = function(port, bOut, addrFrom, name, bitsMessage, bIn) -{ - if (DEBUGGER && this.dbg) { - if (bitsMessage == null) bitsMessage = Debugger.MESSAGE.CHIPSET; - this.dbg.messagePort(this, port, bOut, addrFrom, name, bitsMessage, bIn); + var bitsMessage = Debugger.MESSAGE.PIC; + if (nIRQ == ChipSet.IRQ.TIMER0) { + bitsMessage |= Debugger.MESSAGE.TIMER; + } else if (nIRQ == ChipSet.IRQ.KBD) { + bitsMessage |= Debugger.MESSAGE.KBD; + } else if (nIRQ == ChipSet.IRQ.FDC) { + bitsMessage |= Debugger.MESSAGE.FDC; } + return bitsMessage; }; /* diff --git a/modules/pcjs/lib/computer.js b/modules/pcjs/lib/computer.js index 1b2bc818e..657ca51ed 100644 --- a/modules/pcjs/lib/computer.js +++ b/modules/pcjs/lib/computer.js @@ -122,7 +122,7 @@ if (typeof module !== 'undefined') { */ function Computer(parmsComputer, parmsMachine, fSuspended) { - Component.call(this, "Computer", parmsComputer, Computer); + Component.call(this, "Computer", parmsComputer, Computer, Debugger.MESSAGE.COMPUTER); this.bitField.fPowered = false; this.nBusWidth = parmsComputer['buswidth']; @@ -174,7 +174,7 @@ function Computer(parmsComputer, parmsMachine, fSuspended) { } } - if (DEBUG) this.messageDebugger("PREFETCH: " + PREFETCH + ", TYPEDARRAYS: " + TYPEDARRAYS); + if (DEBUG && this.messageEnabled()) this.messageDebugger("PREFETCH: " + PREFETCH + ", TYPEDARRAYS: " + TYPEDARRAYS); /* * Iterate through all the components again and call their initBus() handler, if any @@ -319,7 +319,9 @@ 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.messageEnabled()) { + this.messageDebugger("loaded state file " + sStateFile.replace(this.sUserID || "xxx", "xxx")); + } } else { this.sResumePath = null; this.fServerState = false; @@ -360,7 +362,7 @@ Computer.prototype.wait = function(fn, parms) return; } } - if (DEBUG) this.messageDebugger("Computer.wait(ready)"); + if (DEBUG && this.messageEnabled()) this.messageDebugger("Computer.wait(ready)"); fn.call(this, parms); }; @@ -385,7 +387,9 @@ Computer.prototype.validateState = function(stateComputer) fValid = false; if (!stateComputer) stateValidate.clear(); } else { - if (DEBUG) this.messageDebugger("Last state: " + sTimestampComputer + " (validate: " + sTimestampValidate + ")"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("Last state: " + sTimestampComputer + " (validate: " + sTimestampValidate + ")"); + } } } return fValid; @@ -405,7 +409,9 @@ Computer.prototype.powerOn = function(resume) resume = this.resume || (this.sStateData? Computer.RESUME_AUTO : Computer.RESUME_NONE); } - if (DEBUG) this.messageDebugger("Computer.powerOn(" + (resume == Computer.RESUME_REPOWER ? "repower" : (resume ? "resume" : "")) + ")"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("Computer.powerOn(" + (resume == Computer.RESUME_REPOWER ? "repower" : (resume ? "resume" : "")) + ")"); + } var fRepower = false; var fRestore = false; @@ -642,7 +648,9 @@ Computer.prototype.donePowerOn = function(aParms) var fRepower = (aParms[1] < 0); var fRestore = aParms[2]; - if (DEBUG && this.bitField.fPowered) this.messageDebugger("Computer.donePowerOn(): redundant"); + if (DEBUG && this.bitField.fPowered && this.messageEnabled()) { + this.messageDebugger("Computer.donePowerOn(): redundant"); + } this.bitField.fPowered = true; @@ -726,7 +734,9 @@ Computer.prototype.powerOff = function(fSave, fShutdown) var data; var sState = "none"; - if (DEBUG) this.messageDebugger("Computer.powerOff(" + (fSave ? "save" : "nosave") + (fShutdown ? ",shutdown" : "") + ")"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("Computer.powerOff(" + (fSave ? "save" : "nosave") + (fShutdown ? ",shutdown" : "") + ")"); + } var stateComputer = new State(this, Computer.sAppVer); var stateValidate = new State(this, Computer.sAppVer, Computer.STATE_VALIDATE); @@ -832,14 +842,14 @@ Computer.prototype.powerOff = function(fSave, fShutdown) Computer.prototype.reset = function() { if (this.bus && this.bus.reset) { - this.messageDebugger("Resetting " + this.bus.type, true); + this.messageDebugger("Resetting " + this.bus.type); this.bus.reset(); } var aComponents = Component.getComponents(this.id); for (var iComponent = 0; iComponent < aComponents.length; iComponent++) { var component = aComponents[iComponent]; if (component !== this && component !== this.bus && component.reset) { - this.messageDebugger("Resetting " + component.type, true); + this.messageDebugger("Resetting " + component.type); component.reset(); } } @@ -978,7 +988,8 @@ Computer.prototype.queryUserID = function(fPrompt) Computer.prototype.verifyUserID = function(sUserID) { this.sUserID = null; - if (DEBUG) this.messageDebugger("verifyUserID(" + sUserID + ")"); + var fMessages = DEBUG && this.messageEnabled(); + if (fMessages) this.messageDebugger("verifyUserID(" + sUserID + ")"); var sRequest = web.getHost() + UserAPI.ENDPOINT + '?' + UserAPI.QUERY.REQ + '=' + UserAPI.REQ.VERIFY + '&' + UserAPI.QUERY.USER + '=' + sUserID; var response = web.loadResource(sRequest); var nErrorCode = response[0]; @@ -988,16 +999,16 @@ Computer.prototype.verifyUserID = function(sUserID) response = eval("(" + sResponse + ")"); if (response.code && response.code == UserAPI.CODE.OK) { web.setLocalStorageItem(Computer.STATE_USERID, response.data); - if (DEBUG) this.messageDebugger(Computer.STATE_USERID + " updated: " + response.data); + if (fMessages) this.messageDebugger(Computer.STATE_USERID + " updated: " + response.data); this.sUserID = response.data; } else { - if (DEBUG) this.messageDebugger(response.code + ": " + response.data); + if (fMessages) this.messageDebugger(response.code + ": " + response.data); } } catch (e) { Component.error(e.message + " (" + sResponse + ")"); } } else { - if (DEBUG) this.messageDebugger("invalid response (error " + nErrorCode + ")"); + if (fMessages) this.messageDebugger("invalid response (error " + nErrorCode + ")"); } return this.sUserID; }; @@ -1012,10 +1023,14 @@ Computer.prototype.getServerStatePath = function() { var sStatePath = null; if (this.sUserID) { - if (DEBUG) this.messageDebugger(Computer.STATE_USERID + " for load: " + this.sUserID); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger(Computer.STATE_USERID + " for load: " + this.sUserID); + } sStatePath = web.getHost() + UserAPI.ENDPOINT + '?' + UserAPI.QUERY.REQ + '=' + UserAPI.REQ.LOAD + '&' + UserAPI.QUERY.USER + '=' + this.sUserID + '&' + UserAPI.QUERY.STATE + '=' + State.key(this, Computer.sAppVer); } else { - if (DEBUG) this.messageDebugger(Computer.STATE_USERID + " unavailable"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger(Computer.STATE_USERID + " unavailable"); + } } return sStatePath; }; @@ -1035,7 +1050,9 @@ Computer.prototype.saveServerState = function(sUserID, sState) * tend to blow off alerts() and the like when closing down. */ if (sState) { - if (DEBUG) this.messageDebugger("size of server state: " + sState.length + " bytes"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("size of server state: " + sState.length + " bytes"); + } var response = this.storeServerState(sUserID, sState, true); if (response && response[UserAPI.RES.CODE] == UserAPI.CODE.OK) { this.notice("Machine state saved to server"); @@ -1050,7 +1067,9 @@ Computer.prototype.saveServerState = function(sUserID, sState) this.resetUserID(); } } else { - if (DEBUG) this.messageDebugger("no state to store"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("no state to store"); + } } }; @@ -1065,7 +1084,9 @@ Computer.prototype.saveServerState = function(sUserID, sState) */ Computer.prototype.storeServerState = function(sUserID, sState, fSync) { - if (DEBUG) this.messageDebugger(Computer.STATE_USERID + " for store: " + sUserID); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger(Computer.STATE_USERID + " for store: " + sUserID); + } /* * TODO: Determine whether or not any browsers cancel our request if we're called during a browser "shutdown" event, * and whether or not it matters if we do an async request (currently, we're not, to try to ensure the request goes through). @@ -1089,7 +1110,7 @@ Computer.prototype.storeServerState = function(sUserID, sState, fSync) } sResponse = '{"' + UserAPI.RES.CODE + '":' + response[0] + ',"' + UserAPI.RES.DATA + '":"' + sResponse + '"}'; } - if (DEBUG) this.messageDebugger(sResponse); + if (DEBUG && this.messageEnabled()) this.messageDebugger(sResponse); return JSON.parse(sResponse); } return null; @@ -1165,22 +1186,6 @@ Computer.prototype.getComponentByType = function(sType, componentPrev) return null; }; -/** - * messageDebugger(sMessage, fForce) - * - * This is a combination of the Debugger's messageEnabled(MESSAGE_COMPUTER) and message() functions, for convenience. - * - * @this {Computer} - * @param {string} sMessage is any caller-defined message string - * @param {boolean} [fForce] is true to force display of the message - */ -Computer.prototype.messageDebugger = function(sMessage, fForce) -{ - if (DEBUGGER && this.dbg) { - if (fForce || this.dbg.messageEnabled(Debugger.MESSAGE.COMPUTER)) this.dbg.message(sMessage); - } -}; - /** * Computer.init() * @@ -1213,7 +1218,9 @@ Computer.init = function() */ var computer = new Computer(parmsComputer, parmsMachine, true); - if (DEBUG) computer.messageDebugger("onInit(" + computer.bitField.fPowered + ")"); + if (DEBUG && computer.messageEnabled()) { + computer.messageDebugger("onInit(" + computer.bitField.fPowered + ")"); + } /* * For now, all we support are "reset" and "save" buttons. We may eventually add a "power" @@ -1243,7 +1250,9 @@ Computer.show = function() var computer = Component.getComponentByType("Computer", parmsComputer['id']); if (computer) { - if (DEBUG) computer.messageDebugger("onShow(" + computer.fInitialized + "," + computer.bitField.fPowered + ")"); + if (DEBUG && computer.messageEnabled()) { + computer.messageDebugger("onShow(" + computer.fInitialized + "," + computer.bitField.fPowered + ")"); + } if (computer.fInitialized && !computer.bitField.fPowered) { /** @@ -1290,7 +1299,9 @@ Computer.exit = function() var computer = Component.getComponentByType("Computer", parmsComputer['id']); if (computer) { - if (DEBUG) computer.messageDebugger("onExit(" + computer.bitField.fPowered + ")"); + if (DEBUG && computer.messageEnabled()) { + computer.messageDebugger("onExit(" + computer.bitField.fPowered + ")"); + } if (computer.bitField.fPowered) { /** diff --git a/modules/pcjs/lib/cpu.js b/modules/pcjs/lib/cpu.js index 5641494be..d2b259e84 100644 --- a/modules/pcjs/lib/cpu.js +++ b/modules/pcjs/lib/cpu.js @@ -75,7 +75,7 @@ if (typeof module !== 'undefined') { */ function CPU(parmsCPU, nCyclesDefault) { - Component.call(this, "CPU", parmsCPU, CPU); + Component.call(this, "CPU", parmsCPU, CPU, Debugger.MESSAGE.CPU); var nCycles = parmsCPU['cycles'] || nCyclesDefault; @@ -865,7 +865,7 @@ CPU.prototype.calcStartTime = function() * in case, I make absolutely sure it cannot happen, since doing so could result in negative * speed calculations. */ - if (DEBUG) this.assert(this.aCounts.msStartRun <= this.aCounts.msStartThisRun); + this.assert(this.aCounts.msStartRun <= this.aCounts.msStartThisRun); if (this.aCounts.msStartRun > this.aCounts.msStartThisRun) { this.aCounts.msStartRun = this.aCounts.msStartThisRun; } @@ -936,7 +936,7 @@ CPU.prototype.calcRemainingTime = function() */ this.aCounts.nCyclesRecalc += this.aCounts.nCyclesThisRun; - if (DEBUG && this.dbg && this.dbg.messageEnabled(Debugger.MESSAGE.LOG) && msRemainsThisRun) { + if (DEBUG && this.messageEnabled(Debugger.MESSAGE.LOG) && msRemainsThisRun) { this.log("calcRemainingTime: " + msRemainsThisRun + "ms to sleep after " + this.aCounts.msEndThisRun + "ms"); } diff --git a/modules/pcjs/lib/debugger.js b/modules/pcjs/lib/debugger.js index 34b3574db..9526b5111 100644 --- a/modules/pcjs/lib/debugger.js +++ b/modules/pcjs/lib/debugger.js @@ -1558,14 +1558,15 @@ if (DEBUGGER) { */ Debugger.prototype.initMessages = function(sEnable) { - this.afnDumpers = []; - this.bitsMessageEnabled = Debugger.MESSAGE.WARN; + this.dbg = this; + this.bitsMessage = this.bitsWarning = Debugger.MESSAGE.WARN; this.sMessagePrev = null; + this.afnDumpers = []; var aEnable = this.parseCommand(sEnable); if (aEnable.length) { for (var m in Debugger.MESSAGES) { if (aEnable.indexOf(m) >= 0) { - this.bitsMessageEnabled |= Debugger.MESSAGES[m]; + this.bitsMessage |= Debugger.MESSAGES[m]; this.println(m + " messages enabled"); } } @@ -1591,24 +1592,6 @@ if (DEBUGGER) { return false; }; - /** - * messageEnabled(bitsMessage) - * - * NOTE: If the caller specifies multiple MESSAGE category flags, then ALL the corresponding flags - * in the Debugger's bitsMessageEnabled variable must be enabled as well, else the result will be false. - * - * One wrinkle is MESSAGE.WARN: if that category is enabled, then ANY value with that bit will return true. - * - * @this {Debugger} - * @param {number} bitsMessage is one or more Debugger MESSAGE_* category flag(s) - * @return {boolean} true if message category is enabled, false if not - */ - Debugger.prototype.messageEnabled = function(bitsMessage) - { - var bitsEnabled = this.bitsMessageEnabled & bitsMessage; - return (bitsEnabled === bitsMessage || !!(bitsEnabled & Debugger.MESSAGE.WARN)); - }; - /** * messageRegs() * @@ -1652,8 +1635,8 @@ if (DEBUGGER) { { var nCategory = Debugger.INT_MESSAGE[nInt]; var fMessage = nCategory && this.messageEnabled(nCategory); + var AH = this.cpu.regAX >> 8; if (fMessage) { - var AH = this.cpu.regAX >> 8; var DL = this.cpu.regDX & 0xff; if (nInt == Debugger.INT.DOS && AH == 0x0b || nCategory == Debugger.MESSAGE.FDC && DL >= 0x80 || nCategory == Debugger.MESSAGE.HDC && DL < 0x80) { @@ -1693,31 +1676,7 @@ if (DEBUGGER) { }; /** - * messageMem(component, addr, fWrite, addrFrom, name, bitsMessage) - * - * NOTE: Not currently used - * - * @this {Debugger} - * @param {Component} component - * @param {number} addr - * @param {boolean} fWrite is true if this was a write, false if read - * @param {number|null} [addrFrom] - * @param {string|null} [name] of the memory address, if any - * @param {number} [bitsMessage] is one or more Debugger MESSAGE_* category flag(s) - * - Debugger.prototype.messageMem = function(component, addr, fWrite, addrFrom, name, bitsMessage) - { - if (!bitsMessage) bitsMessage = 0; - bitsMessage |= Debugger.MESSAGES_MEM; - if (addrFrom == null || (this.bitsMessageEnabled & bitsMessage) == bitsMessage) { - var b = this.bus.getByteDirect(addr); - this.message(component.idComponent + "." + (fWrite? "setByte" : "getByte") + "(0x" + str.toHexAddr(addr) + ")" + (addrFrom != null? (" at " + str.toHexAddr(addrFrom)) : "") + ": " + (name? (name + "=") : "") + str.toHexByte(b)); - } - }; - */ - - /** - * messagePort(component, port, bOut, addrFrom, name, bitsMessage, bIn) + * messageIO(component, port, bOut, addrFrom, name, bIn, bitsMessage) * * @this {Debugger} * @param {Component} component @@ -1725,14 +1684,14 @@ if (DEBUGGER) { * @param {number|null} bOut if an output operation * @param {number|null} [addrFrom] * @param {string|null} [name] of the port, if any - * @param {number|null} [bitsMessage] is one or more Debugger MESSAGE_* category flag(s) * @param {number} [bIn] is the input value, if known, on an input operation + * @param {number} [bitsMessage] is one or more Debugger MESSAGE_* category flag(s) */ - Debugger.prototype.messagePort = function(component, port, bOut, addrFrom, name, bitsMessage, bIn) + Debugger.prototype.messageIO = function(component, port, bOut, addrFrom, name, bIn, bitsMessage) { if (!bitsMessage) bitsMessage = 0; bitsMessage |= Debugger.MESSAGE.PORT; - if (addrFrom == null || (this.bitsMessageEnabled & bitsMessage) == bitsMessage) { + if (addrFrom == null || (this.bitsMessage & bitsMessage) == bitsMessage) { var segFrom = null; if (addrFrom != null) { segFrom = this.cpu.segCS.sel; @@ -1743,13 +1702,18 @@ if (DEBUGGER) { }; /** - * message(sMessage) + * message(sMessage, fAddress) * * @this {Debugger} * @param {string} sMessage is any caller-defined message string + * @param {boolean} [fAddress] is true to display the current CS:IP */ - Debugger.prototype.message = function(sMessage) + Debugger.prototype.message = function(sMessage, fAddress) { + if (fAddress) { + sMessage += " @" + str.toHexAddr(this.cpu.regIP, this.cpu.segCS.sel); + } + if (this.sMessagePrev && sMessage == this.sMessagePrev) return; if (!SAMPLER) this.println(sMessage); // + " (" + this.cpu.getCycles() + " cycles)" @@ -1757,7 +1721,7 @@ if (DEBUGGER) { this.sMessagePrev = sMessage; if (this.cpu) { - if (this.bitsMessageEnabled & Debugger.MESSAGE.HALT) { + if (this.bitsMessage & Debugger.MESSAGE.HALT) { this.cpu.stopCPU(); } /* @@ -2073,7 +2037,7 @@ if (DEBUGGER) { var state = new State(this); state.set(0, this.aAddrNextCode); state.set(1, this.aAddrAssemble); - state.set(2, [this.aPrevCmds, this.fAssemble, this.bitsMessageEnabled]); + state.set(2, [this.aPrevCmds, this.fAssemble, this.bitsMessage]); return state.data(); }; @@ -2095,16 +2059,16 @@ if (DEBUGGER) { this.aPrevCmds = data[i][0]; if (typeof this.aPrevCmds == "string") this.aPrevCmds = [this.aPrevCmds]; this.fAssemble = data[i][1]; - if (!this.bitsMessageEnabled) { + if (!this.bitsMessage) { /* - * It's actually kinda annoying that a restored (or predefined) state will trump my initial state, + * It's actually kind of annoying that a restored (or predefined) state will trump my initial state, * at least in situations where I've changed the initial state, if I want to diagnose something. * Perhaps I should save/restore both the initial and current bitsMessageEnabled, and if the initial * values don't agree, then leave the current value alone. * * But, it's much easier to just leave bitsMessageEnabled alone whenever it already contains set bits. */ - this.bitsMessageEnabled = data[i][2]; + this.bitsMessage = data[i][2]; } } return true; @@ -2213,12 +2177,8 @@ if (DEBUGGER) { */ Debugger.prototype.checkInstruction = function(addr, fSkipBP) { - /* - * Assert that general-purpose register contents remain within their respective ranges; - * this isn't intended to be complete, just a spot-check. - */ - if (DEBUG) { - this.assert(!(this.cpu.regAX & ~0xffff) && !(this.cpu.regBX & ~0xffff) && !(this.cpu.regCX & ~0xffff) && !(this.cpu.regDX & ~0xffff), "register out of bounds"); + if (!fSkipBP && this.cpu.segCS.cpl == 3 && !(this.cpu.regPS & X86.PS.IF)) { + return true; } if (!fSkipBP && this.checkBreakpoint(addr, this.aBreakExec)) { @@ -2410,7 +2370,7 @@ if (DEBUGGER) { var addr = this.getAddr(aAddr, false, 0); if (addr >= 0) { b = this.bus.getByteDirect(addr); - if (DEBUG) this.assert((b == (b & 0xff)), "invalid byte (" + b + ") at address: " + this.hexAddr(aAddr)); + this.assert((b == (b & 0xff)), "invalid byte (" + b + ") at address: " + this.hexAddr(aAddr)); if (inc !== undefined) this.incAddr(aAddr, inc); } return b; @@ -2430,7 +2390,7 @@ if (DEBUGGER) { var addr = this.getAddr(aAddr, false, 1); if (addr >= 0) { w = this.bus.getWordDirect(addr); - if (DEBUG) this.assert((w == (w & 0xffff)), "invalid word (" + w + ") at address: " + this.hexAddr(aAddr)); + this.assert((w == (w & 0xffff)), "invalid word (" + w + ") at address: " + this.hexAddr(aAddr)); if (inc !== undefined) this.incAddr(aAddr, inc); } return w; @@ -4181,7 +4141,7 @@ if (DEBUGGER) { for (m in Debugger.MESSAGES) { if (sCategory == m) { bitsMessage = Debugger.MESSAGES[m]; - fCriteria = !!(this.bitsMessageEnabled & bitsMessage); + fCriteria = !!(this.bitsMessage & bitsMessage); break; } } @@ -4192,11 +4152,11 @@ if (DEBUGGER) { } if (bitsMessage) { if (asArgs[2] == "on") { - this.bitsMessageEnabled |= bitsMessage; + this.bitsMessage |= bitsMessage; fCriteria = true; } else if (asArgs[2] == "off") { - this.bitsMessageEnabled &= ~bitsMessage; + this.bitsMessage &= ~bitsMessage; fCriteria = false; } } @@ -4210,7 +4170,7 @@ if (DEBUGGER) { for (m in Debugger.MESSAGES) { if (!sCategory || sCategory == m) { var bitMessage = Debugger.MESSAGES[m]; - var fEnabled = !!(this.bitsMessageEnabled & bitMessage); + var fEnabled = !!(this.bitsMessage & bitMessage); if (fCriteria !== null && fCriteria != fEnabled) continue; if (sCategories) sCategories += ","; if (!(++n % 10)) sCategories += "\n\t"; // jshint ignore:line diff --git a/modules/pcjs/lib/disk.js b/modules/pcjs/lib/disk.js index e9468ff6c..938d6f6dd 100644 --- a/modules/pcjs/lib/disk.js +++ b/modules/pcjs/lib/disk.js @@ -231,7 +231,7 @@ if (typeof module !== 'undefined') { */ function Disk(controller, drive, mode) { - Component.call(this, "Disk", {'id': controller.idMachine + ".disk" + Disk.nDisks++}, Disk); + Component.call(this, "Disk", {'id': controller.idMachine + ".disk" + Disk.nDisks++}, Disk, Debugger.MESSAGE.DISK); /* * Route all non-Debugger messages (eg, notice() and println() calls) through @@ -444,7 +444,9 @@ Disk.prototype.create = function(mode, nCylinders, nHeads, nSectors, cbSector) * it wouldn't hurt to let create() do its thing, too, but it's a waste of time. */ if (this.mode != DiskAPI.MODE.PRELOAD) { - if (DEBUG) this.messageDebugger("blank disk for \"" + this.sDiskName + "\": " + this.nCylinders + " cylinders, " + this.nHeads + " head(s)"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("blank disk for \"" + this.sDiskName + "\": " + this.nCylinders + " cylinders, " + this.nHeads + " head(s)"); + } var aCylinders = new Array(this.nCylinders); for (var iCylinder = 0; iCylinder < aCylinders.length; iCylinder++) { var aHeads = new Array(this.nHeads); @@ -656,7 +658,9 @@ Disk.prototype.doneLoad = function(sDiskFile, sDiskData, nErrorCode, sDiskPath) if (this.fOnDemand) { if (!nErrorCode) { - if (DEBUG) this.messageDebugger('Disk.doneLoad("' + sDiskFile + '","' + sDiskPath + '")'); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger('Disk.doneLoad("' + sDiskFile + '","' + sDiskPath + '")'); + } this.fRemote = true; disk = this; } else { @@ -673,7 +677,9 @@ Disk.prototype.doneLoad = function(sDiskFile, sDiskData, nErrorCode, sDiskPath) */ this.controller.notice("Unable to load disk \"" + this.sDiskName + "\" (error " + nErrorCode + ")", fPrintOnly); } else { - if (DEBUG) this.messageDebugger('Disk.doneLoad("' + sDiskFile + '","' + sDiskPath + '")'); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger('Disk.doneLoad("' + sDiskFile + '","' + sDiskPath + '")'); + } try { /* * The following code was a hack to turn on write-protection for a disk image if there was @@ -764,13 +770,13 @@ Disk.prototype.doneLoad = function(sDiskFile, sDiskData, nErrorCode, sDiskPath) * conversion to a forward-compatible 'data' array. */ else { - if (MAXDEBUG && DEBUGGER && this.dbg && this.dbg.messageEnabled(Debugger.MESSAGE.DISK)) { + if (MAXDEBUG && this.messageEnabled()) { var sCylinders = aDiskData.length + " track" + (aDiskData.length > 1 ? "s" : ""); var nHeads = aDiskData[0].length; var sHeads = nHeads + " head" + (nHeads > 1 ? "s" : ""); var nSectorsPerTrack = aDiskData[0][0].length; var sSectorsPerTrack = nSectorsPerTrack + " sector" + (nSectorsPerTrack > 1 ? "s" : "") + "/track"; - this.dbg.message(sCylinders + ", " + sHeads + ", " + sSectorsPerTrack); + this.messageDebugger(sCylinders + ", " + sHeads + ", " + sSectorsPerTrack); } /* * Before the image is usable, we must "normalize" all the sectors. In the past, this meant @@ -811,7 +817,7 @@ Disk.prototype.doneLoad = function(sDiskFile, sDiskData, nErrorCode, sDiskPath) * pattern, if any, into a dword pattern. */ adw = []; - if (DEBUG) this.assert((dwPattern & 0xff) == dwPattern); + this.assert((dwPattern & 0xff) == dwPattern); dwPattern = sector['pattern'] = (dwPattern | (dwPattern << 8) | (dwPattern << 16) | (dwPattern << 24)); sector['data'] = adw; } else { @@ -913,7 +919,9 @@ Disk.prototype.onLoadParseSectors = function(sURLName, sURLData, nErrorCode, sec var nSectors = sectorInfo[3]; fAsync = sectorInfo[4]; - if (DEBUG) this.messageDebugger("Disk.onLoadParseSectors(" + iCylinder + ":" + iHead + ":" + iSector + ":" + nSectors + ")"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("Disk.onLoadParseSectors(" + iCylinder + ":" + iHead + ":" + iSector + ":" + nSectors + ")"); + } var abData = JSON.parse(sURLData); var offData = 0; @@ -929,7 +937,9 @@ Disk.prototype.onLoadParseSectors = function(sURLName, sURLData, nErrorCode, sec */ var sector = this.seek(iCylinder, iHead, iSector, true); if (!sector) { - if (DEBUG) this.messageDebugger("Disk.onLoadParseSectors(): seek(" + iCylinder + "," + iHead + "," + iSector + ") failed"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("Disk.onLoadParseSectors(): seek(" + iCylinder + "," + iHead + "," + iSector + ") failed"); + } break; } this.fill(sector, abData, offData); @@ -979,7 +989,9 @@ 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 (DEBUG && this.messageEnabled()) { + this.messageDebugger("Disk.readRemoteSectors(" + iCylinder + ":" + iHead + ":" + iSector + ":" + nSectors + "," + cbSector + ")"); + } if (this.fRemote) { var sParms = DiskAPI.QUERY.ACTION + '=' + DiskAPI.ACTION.READ; @@ -1017,7 +1029,9 @@ 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 (DEBUG && this.messageEnabled()) { + this.messageDebugger("Disk.writeRemoteSectors(" + iCylinder + ":" + iHead + ":" + iSector + ":" + nSectors + ")"); + } if (this.fRemote) { var data = {}; @@ -1084,7 +1098,9 @@ Disk.prototype.queueDirtySector = function(sector, fAsync) this.aDirtySectors.push(sector); this.aDirtyTimestamps.push(usr.getTime()); - if (DEBUG) this.messageDebugger("Disk.queueDirtySector(" + sector.iCylinder + ":" + sector.iHead + ":" + sector['sector'] + "): " + this.aDirtySectors.length + " dirty"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("Disk.queueDirtySector(" + sector.iCylinder + ":" + sector.iHead + ":" + sector['sector'] + "): " + this.aDirtySectors.length + " dirty"); + } return fAsync && this.updateWriteTimer(); }; @@ -1152,15 +1168,17 @@ Disk.prototype.findDirtySectors = function(fAsync) var sectorNext = this.aDiskData[iCylinder][iHead][i]; if (!sectorNext.fDirty) break; var j = this.aDirtySectors.indexOf(sectorNext); - if (DEBUG) this.assert(j >= 0, "dirty sector (" + iCylinder + ":" + iHead + ":" + sectorNext['sector'] + ") missing from aDirtySectors"); - if (DEBUG) this.messageDebugger("Disk.findDirtySectors(" + iCylinder + ":" + iHead + ":" + sectorNext['sector'] + ")"); + this.assert(j >= 0, "dirty sector (" + iCylinder + ":" + iHead + ":" + sectorNext['sector'] + ") missing from aDirtySectors"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("Disk.findDirtySectors(" + iCylinder + ":" + iHead + ":" + sectorNext['sector'] + ")"); + } this.aDirtySectors.splice(j, 1); this.aDirtyTimestamps.splice(j, 1); abSectors = abSectors.concat(this.toBytes(sectorNext)); sectorNext.fDirty = false; nSectors++; } - if (DEBUG) this.assert(!!abSectors.length, "no data for dirty sector (" + iCylinder + ":" + iHead + ":" + sector['sector'] + ")"); + this.assert(!!abSectors.length, "no data for dirty sector (" + iCylinder + ":" + iHead + ":" + sector['sector'] + ")"); var response = this.writeRemoteSectors(iCylinder, iHead, iSector, nSectors, abSectors, fAsync); return fAsync || response; } @@ -1188,7 +1206,9 @@ Disk.prototype.onWriteCleanSectors = function(sURLName, sURLData, nErrorCode, se for (var i = iSector - 1; nSectors-- > 0 && i >= 0 && i < this.aDiskData[iCylinder][iHead].length; i++) { var sector = this.aDiskData[iCylinder][iHead][i]; - if (DEBUG) this.messageDebugger("Disk.onWriteCleanSectors(" + iCylinder + ":" + iHead + ":" + sector['sector'] + ")"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("Disk.onWriteCleanSectors(" + iCylinder + ":" + iHead + ":" + sector['sector'] + ")"); + } if (!nErrorCode) { if (!sector.fDirty) { @@ -1318,7 +1338,9 @@ Disk.prototype.seek = function(iCylinder, iHead, iSector, fWrite, done) }); return null; } else { - if (DEBUG) this.messageDebugger('Disk.seek("' + this.sDiskName + '"): uninitialized sector ' + iCylinder + ':' + iHead + ':' + iSector); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger('Disk.seek("' + this.sDiskName + '"): uninitialized sector ' + iCylinder + ':' + iHead + ':' + iSector); + } } } break; @@ -1395,7 +1417,9 @@ 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 (DEBUG && !ibSector && !fCompare && this.messageEnabled()) { + this.messageDebugger("Disk.read(" + this.controller.id + ":" + this.drive.iDrive + "," + sector.iCylinder + ":" + sector.iHead + ":" + sector['sector'] + ")"); + } if (ibSector < sector['length']) { var adw = sector['data']; @@ -1420,7 +1444,9 @@ 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 (DEBUG && !ibSector && this.messageEnabled()) { + this.messageDebugger("Disk.write(" + this.controller.id + ":" + this.drive.iDrive + "," + sector.iCylinder + ":" + sector.iHead + ":" + sector['sector'] + ")"); + } if (ibSector < sector['length']) { if (b != this.read(sector, ibSector, true)) { @@ -1490,7 +1516,9 @@ Disk.prototype.save = function() } } } - if (DEBUG) this.messageDebugger('Disk.save("' + this.sDiskName + '"): saved ' + (deltas.length - 1) + ' change(s)'); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger('Disk.save("' + this.sDiskName + '"): saved ' + (deltas.length - 1) + ' change(s)'); + } return deltas; }; @@ -1618,26 +1646,11 @@ Disk.prototype.restore = function(deltas) if (nChanges < 0) { this.controller.notice("unable to restore disk '" + this.sDiskName + ": " + sReason); } else { - if (DEBUG) this.messageDebugger('Disk.restore("' + this.sDiskName + '"): restored ' + nChanges + ' change(s)'); - } - return nChanges; -}; - -/** - * 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 - */ -Disk.prototype.messageDebugger = function(sMessage) -{ - if (DEBUGGER && this.dbg) { - if (this.dbg.messageEnabled(Debugger.MESSAGE.DISK)) { - this.dbg.message(sMessage); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger('Disk.restore("' + this.sDiskName + '"): restored ' + nChanges + ' change(s)'); } } + return nChanges; }; if (typeof APP_PCJS !== 'undefined') APP_PCJS.Disk = Disk; diff --git a/modules/pcjs/lib/fdc.js b/modules/pcjs/lib/fdc.js index 38a5e6dd7..69048bb90 100644 --- a/modules/pcjs/lib/fdc.js +++ b/modules/pcjs/lib/fdc.js @@ -137,7 +137,7 @@ function FDC(parmsFDC) { * TODO: Indicate the type of diskette image being loaded (this might help folks understand what's going * on when they try to load a diskette image that's larger than what the selected operating system supports). */ - Component.call(this, "FDC", parmsFDC, FDC); + Component.call(this, "FDC", parmsFDC, FDC, Debugger.MESSAGE.FDC); this['dmaRead'] = this.dmaRead; this['dmaWrite'] = this.dmaWrite; @@ -211,7 +211,7 @@ if (DEBUG) { ST1: "ST1", // Status Register 1 ST2: "ST2", // Status Register 2 ST3: "ST3" // Status Register 3 - } + }; } else { FDC.TERMS = {}; } @@ -390,7 +390,7 @@ if (DEBUG) { READ_ID: "READ ID", FORMAT: "FORMAT", SEEK: "SEEK" - } + }; } else { FDC.CMDS = {}; } @@ -483,7 +483,7 @@ FDC.prototype.setBinding = function(sHTMLType, sBinding, control) var fieldset = control.children[0]; var files = fieldset.children[0].files; var submit = fieldset.children[1]; - submit.disabled = (files.length == 0); + submit.disabled = !files.length; }); control.onsubmit = function(event) { @@ -740,6 +740,7 @@ FDC.prototype.initController = function(data) /* falls through */ case 320: case 360: + /* falls through */ default: // drives that don't have a recognized capacity default to 360 drive.nCylinders = 40; drive.nSectors = 9; // drives capable of writing 8 sectors/track can also write 9 sectors/track @@ -1525,7 +1526,7 @@ FDC.prototype.unloadAllDrives = function(fDiscard) FDC.prototype.addDiskHistory = function(sDisketteName, sDiskettePath, disk) { var i; - if (DEBUG) this.assert(!!sDiskettePath); + this.assert(!!sDiskettePath); for (i = 0; i < this.aDiskHistory.length; i++) { if (this.aDiskHistory[i][1] == sDiskettePath) { var nChanges = disk.restore(this.aDiskHistory[i][2]); @@ -1719,7 +1720,7 @@ FDC.prototype.outFDCData = function(port, bOut, addrFrom) } if (DEBUG && this.messageEnabled()) { this.messageDebugger("unsupported FDC command: " + str.toHexByte(bCmd)); - if (DEBUGGER) this.cpu.stopCPU(); + this.dbg.stopCPU(); } }; @@ -1814,7 +1815,7 @@ FDC.prototype.doCmd = function() * Controller docs say that H should always match HD, so I assert that, but what if someone * made a mistake and didn't program them identically -- what would happen? Which should we honor? */ - if (DEBUG) this.assert(h == bHead); + this.assert(h == bHead); r = drive.bSector = this.popCmd(FDC.TERMS.R); // R n = this.popCmd(FDC.TERMS.N); // N drive.nBytes = 128 << n; // 0 => 128, 1 => 256, 2 => 512, 3 => 1024 @@ -1938,7 +1939,7 @@ FDC.prototype.doCmd = function() * update() function that all FDC commands can use. This code is merely sufficient to get us * through the "DSKETTE_SETUP" gauntlet in the MODEL_5170 BIOS. */ - if (drive.bCylinder == 0) { + if (!drive.bCylinder) { drive.resCode |= FDC.REG_DATA.RES.TRACK0; } this.beginResult(); // like FDC.REG_DATA.CMD.RECALIBRATE, no results are provided @@ -1948,7 +1949,7 @@ FDC.prototype.doCmd = function() default: if (DEBUG && this.messageEnabled()) { this.messageDebugger("FDC operation unsupported (command=0x: " + str.toHexByte(bCmd) + ")"); - if (DEBUGGER) this.cpu.stopCPU(); + this.dbg.stopCPU(); } break; } @@ -2023,12 +2024,12 @@ FDC.prototype.pushResults = function(drive, bCmd, bHead, c, h, r, n) */ FDC.prototype.popCmd = function(name) { - if (DEBUG) this.assert((!this.regDataIndex || name !== undefined) && this.regDataIndex < this.regDataTotal); + this.assert((!this.regDataIndex || name !== undefined) && this.regDataIndex < this.regDataTotal); var bCmd = this.regDataArray[this.regDataIndex]; if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PORT)) { var bCmdMasked = bCmd & FDC.REG_DATA.CMD.MASK; if (!name && !this.regDataIndex && FDC.aCmdInfo[bCmdMasked]) name = FDC.aCmdInfo[bCmdMasked].name; - this.messageDebugger("FDC.CMD[" + (name || this.regDataIndex) + "]: 0x" + str.toHexByte(bCmd), Debugger.MESSAGE.PORT); + this.messageDebugger("FDC.CMD[" + (name || this.regDataIndex) + "]: 0x" + str.toHexByte(bCmd)); } this.regDataIndex++; return bCmd; @@ -2080,7 +2081,7 @@ FDC.prototype.beginResult = function() FDC.prototype.pushResult = function(bResult, name) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PORT)) { - this.messageDebugger("FDC.RES[" + (name || this.regDataTotal) + "]: 0x" + str.toHexByte(bResult), Debugger.MESSAGE.PORT); + this.messageDebugger("FDC.RES[" + (name || this.regDataTotal) + "]: 0x" + str.toHexByte(bResult)); } this.regDataArray[this.regDataTotal++] = bResult; }; @@ -2396,7 +2397,7 @@ FDC.prototype.writeByte = function(drive, b) */ FDC.prototype.advanceSector = function(drive) { - if (DEBUG) this.assert(drive.bCylinder < drive.nDiskCylinders); + this.assert(drive.bCylinder < drive.nDiskCylinders); drive.bSector++; var bSectorStart = 1; if (drive.bSector >= drive.nDiskSectors + bSectorStart) { @@ -2441,64 +2442,6 @@ FDC.prototype.writeFormat = function(drive, b) return b; }; -/** - * messageEnabled(bitsMessage) - * - * @this {FDC} - * @param {number} [bitsMessage] is one or more Debugger MESSAGE_* category flag(s) - * @return {boolean} - */ -FDC.prototype.messageEnabled = function(bitsMessage) -{ - if (DEBUGGER && this.dbg) { - if (bitsMessage == null) { - bitsMessage = Debugger.MESSAGE.FDC; - } else { - bitsMessage |= Debugger.MESSAGE.FDC; - } - return this.dbg.messageEnabled(bitsMessage); - } - return false; -}; - -/** - * messageDebugger(sMessage, bitsMessage) - * - * This is a combination of the Debugger's messageEnabled(MESSAGE_FDC) and message() functions, for convenience. - * - * @this {FDC} - * @param {string} sMessage is any caller-defined message string - * @param {number} [bitsMessage] is one or more Debugger MESSAGE_* category flag(s) - */ -FDC.prototype.messageDebugger = function(sMessage, bitsMessage) -{ - if (DEBUGGER && this.dbg) { - if (bitsMessage == null) { - bitsMessage = Debugger.MESSAGE.FDC; - } else { - bitsMessage |= Debugger.MESSAGE.FDC; - } - if (this.dbg.messageEnabled(bitsMessage)) this.dbg.message(sMessage); - } -}; - -/** - * messagePort(port, bOut, addrFrom, name, bIn) - * - * This is an internal version of the Debugger's messagePort() function, for convenience. - * - * @this {FDC} - * @param {number} port - * @param {number|null} bOut if an output operation - * @param {number|null} [addrFrom] - * @param {string|null} [name] of the port, if any - * @param {number} [bIn] is the input value, if known, on an input operation - */ -FDC.prototype.messagePort = function(port, bOut, addrFrom, name, bIn) -{ - if (DEBUGGER && this.dbg) this.dbg.messagePort(this, port, bOut, addrFrom, name, Debugger.MESSAGE.FDC, bIn); -}; - /* * Port input notification table * diff --git a/modules/pcjs/lib/hdc.js b/modules/pcjs/lib/hdc.js index 428392268..3a1fcf641 100644 --- a/modules/pcjs/lib/hdc.js +++ b/modules/pcjs/lib/hdc.js @@ -78,7 +78,7 @@ if (typeof module !== 'undefined') { */ function HDC(parmsHDC) { - Component.call(this, "HDC", parmsHDC, HDC); + Component.call(this, "HDC", parmsHDC, HDC, Debugger.MESSAGE.HDC); this['dmaRead'] = this.dmaRead; this['dmaWrite'] = this.dmaWrite; @@ -747,7 +747,9 @@ HDC.prototype.initController = function(data, fHard) this.regConfig |= (drive.type & 0x3) << ((1 - iDrive) << 1); } } - if (DEBUG) this.messageDebugger("HDC initialized for " + this.aDrives.length + " drive(s)"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("HDC initialized for " + this.aDrives.length + " drive(s)"); + } return fSuccess; }; @@ -1147,7 +1149,7 @@ HDC.prototype.loadDisk = function(iDrive, sDiskName, sDiskPath, fAutoMount) if (fAutoMount) { drive.fAutoMount = true; this.cAutoMount++; - this.messageDebugger("loading " + sDiskName); + if (this.messageEnabled()) this.messageDebugger("loading " + sDiskName); } var disk = drive.disk || new Disk(this, drive, drive.mode); disk.load(sDiskName, sDiskPath, null, this.doneLoadDisk); @@ -1399,7 +1401,7 @@ HDC.prototype.inATCData = function(port, addrFrom) * well, then the caller will get 0xff. */ bIn = this.readByte(this.drive); - if (DEBUG) this.assert(bIn >= 0); + this.assert(bIn >= 0); /* * Now that we've supplied a full sector of data, see if the caller's expecting additional sectors; @@ -1420,7 +1422,7 @@ HDC.prototype.inATCData = function(port, addrFrom) /* * I shouldn't have to set BUSY (or DATA_REQ) again, because it should still be set, no? */ - if (DEBUG) hdc.assert(!!(hdc.regStatus & HDC.ATC.STATUS.BUSY)); + hdc.assert(!!(hdc.regStatus & HDC.ATC.STATUS.BUSY)); } else { /* * TODO: It would be nice to be a bit more specific about the error (if any) that just occurred. @@ -1432,7 +1434,7 @@ HDC.prototype.inATCData = function(port, addrFrom) } }, false); } else { - if (DEBUG) this.assert(this.drive.nBytes == 0); + this.assert(!this.drive.nBytes); this.regStatus = HDC.ATC.STATUS.READY | HDC.ATC.STATUS.SEEK_OK; } } @@ -1454,7 +1456,7 @@ HDC.prototype.outATCData = function(port, bOut, addrFrom) /* * messagePort() calls, if enabled, can be overwhelming for this port, so limit them to the first byte. */ - if (!this.drive || this.drive.ibSector == 0) this.messagePort(port, bOut, addrFrom, "DATA"); + if (!this.drive || !this.drive.ibSector) this.messagePort(port, bOut, addrFrom, "DATA"); if (this.drive) { if (this.drive.nBytes >= this.drive.cbSector) { @@ -1465,7 +1467,9 @@ HDC.prototype.outATCData = function(port, bOut, addrFrom) */ this.regStatus = HDC.ATC.STATUS.ERROR; this.regError = HDC.ATC.ERROR.NO_CHS; - if (DEBUG) this.messageDebugger("HDC.outATCData(" + str.toHexByte(bOut) + "): write failed"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("HDC.outATCData(" + str.toHexByte(bOut) + "): write failed"); + } } else if (this.drive.ibSector == this.drive.cbSector) { this.drive.nBytes -= this.drive.cbSector; @@ -1475,9 +1479,9 @@ HDC.prototype.outATCData = function(port, bOut, addrFrom) /* * I shouldn't have to set BUSY (or DATA_REQ) again, because it should still be set, no? */ - if (DEBUG) this.assert(!!(this.regStatus & HDC.ATC.STATUS.BUSY)); + this.assert(!!(this.regStatus & HDC.ATC.STATUS.BUSY)); } else { - if (DEBUG) this.assert(this.drive.nBytes == 0); + this.assert(!this.drive.nBytes); this.regStatus = HDC.ATC.STATUS.READY | HDC.ATC.STATUS.SEEK_OK; } } @@ -1485,13 +1489,17 @@ HDC.prototype.outATCData = function(port, bOut, addrFrom) /* * TODO: What to do about unexpected writes? The number of bytes has exceeded what the command specified. */ - if (DEBUG) this.messageDebugger("HDC.outATCData(" + str.toHexByte(bOut) + "): write exceeds count (" + this.drive.nBytes + ")"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("HDC.outATCData(" + str.toHexByte(bOut) + "): write exceeds count (" + this.drive.nBytes + ")"); + } } } else { /* * TODO: What to do about unexpected writes? The number of bytes has exceeded what the command specified. */ - if (DEBUG) this.messageDebugger("HDC.outATCData(" + str.toHexByte(bOut) + "): write without command"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("HDC.outATCData(" + str.toHexByte(bOut) + "): write without command"); + } } }; @@ -1791,7 +1799,9 @@ HDC.prototype.doATCommand = function() this.drive = drive; } - if (DEBUG) this.messageDebugger("HDC.doATCommand(" + str.toHexByte(bCmd) + "): " + HDC.aATCCommands[bCmd], Debugger.MESSAGE.PORT | Debugger.MESSAGE.HDC); + if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PORT | Debugger.MESSAGE.HDC)) { + this.messageDebugger("HDC.doATCommand(" + str.toHexByte(bCmd) + "): " + HDC.aATCCommands[bCmd]); + } switch (bCmd & HDC.ATC.COMMAND.MASK) { @@ -1868,16 +1878,18 @@ HDC.prototype.doATCommand = function() * The importance of SECCNT (nSectors) and DRVHD (nHeads) is controlling how multi-sector operations * advance to the next sector; see advanceSector(). */ - if (DEBUG) this.assert(drive.nHeads == nHead + 1); - if (DEBUG) this.assert(drive.nSectors == nSectors); + this.assert(drive.nHeads == nHead + 1); + this.assert(drive.nSectors == nSectors); drive.nHeads = nHead + 1; drive.nSectors = nSectors; fInterrupt = true; break; default: - if (DEBUG) this.messageDebugger("HDC.doATCommand(" + str.toHexByte(this.regCommand) + "): " + (bCmd < 0? ("invalid drive (" + iDrive + ")") : "unsupported operation")); - if (DEBUG && DEBUGGER && this.dbg && this.dbg.messageEnabled(Debugger.MESSAGE.HDC) && bCmd >= 0) this.cpu.stopCPU(); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("HDC.doATCommand(" + str.toHexByte(this.regCommand) + "): " + (bCmd < 0? ("invalid drive (" + iDrive + ")") : "unsupported operation")); + if (bCmd >= 0) this.dbg.stopCPU(); + } break; } @@ -2009,7 +2021,9 @@ HDC.prototype.doXTCommand = function() case HDC.XTC.DATA.CMD.RECALIBRATE: // 0x01 drive.bControl = bControl; - if (DEBUG) this.messageDebugger("HDC.doXTCommand(): drive " + iDrive + " control byte: 0x" + str.toHexByte(bControl)); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("HDC.doXTCommand(): drive " + iDrive + " control byte: 0x" + str.toHexByte(bControl)); + } this.beginResult(HDC.XTC.DATA.STATUS_OK | bDrive); break; @@ -2044,9 +2058,11 @@ HDC.prototype.doXTCommand = function() break; default: - if (DEBUG) this.messageDebugger("HDC.doXTCommand(" + str.toHexByte(bCmdOrig) + "): " + (bCmd < 0? ("invalid drive (" + iDrive + ")") : "unsupported operation")); this.beginResult(HDC.XTC.DATA.STATUS_ERROR | bDrive); - if (DEBUG && DEBUGGER && this.dbg && this.dbg.messageEnabled(Debugger.MESSAGE.HDC) && bCmd >= 0) this.cpu.stopCPU(); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("HDC.doXTCommand(" + str.toHexByte(bCmdOrig) + "): " + (bCmd < 0? ("invalid drive (" + iDrive + ")") : "unsupported operation")); + if (bCmd >= 0) this.dbg.stopCPU(); + } break; } } @@ -2064,7 +2080,9 @@ HDC.prototype.popCmd = function() var bCmdIndex = this.regDataIndex; if (bCmdIndex < this.regDataTotal) { bCmd = this.regDataArray[this.regDataIndex++]; - if (DEBUG) this.messageDebugger("HDC.CMD[" + bCmdIndex + "]: 0x" + str.toHexByte(bCmd) + (!bCmdIndex && HDC.aXTCCommands[bCmd]? (" (" + HDC.aXTCCommands[bCmd] + ")") : ""), (bCmdIndex > 0? Debugger.MESSAGE.PORT : 0) | Debugger.MESSAGE.HDC); + if (DEBUG && this.messageEnabled((bCmdIndex > 0? Debugger.MESSAGE.PORT : 0) | Debugger.MESSAGE.HDC)) { + this.messageDebugger("HDC.CMD[" + bCmdIndex + "]: 0x" + str.toHexByte(bCmd) + (!bCmdIndex && HDC.aXTCCommands[bCmd]? (" (" + HDC.aXTCCommands[bCmd] + ")") : "")); + } } return bCmd; }; @@ -2080,7 +2098,9 @@ HDC.prototype.beginResult = function(bResult) this.regDataIndex = this.regDataTotal = 0; if (bResult !== undefined) { - if (DEBUG) this.messageDebugger("HDC.beginResult(0x" + str.toHexByte(bResult) + ")"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("HDC.beginResult(0x" + str.toHexByte(bResult) + ")"); + } this.pushResult(bResult); } /* @@ -2100,7 +2120,9 @@ HDC.prototype.beginResult = function(bResult) */ HDC.prototype.pushResult = function(bResult) { - if (DEBUG) this.messageDebugger("HDC.RES[" + this.regDataTotal + "]: 0x" + str.toHexByte(bResult), (this.regDataTotal > 0? Debugger.MESSAGE.PORT : 0) | Debugger.MESSAGE.HDC); + if (DEBUG && this.messageEnabled((this.regDataTotal > 0? Debugger.MESSAGE.PORT : 0) | Debugger.MESSAGE.HDC)) { + this.messageDebugger("HDC.RES[" + this.regDataTotal + "]: 0x" + str.toHexByte(bResult)); + } this.regDataArray[this.regDataTotal++] = bResult; }; @@ -2193,9 +2215,9 @@ HDC.prototype.doRead = function(drive, done) { drive.errorCode = HDC.XTC.DATA.ERR.NOT_READY; - if (DEBUG) this.messageDebugger("HDC.doRead(" + drive.wCylinder + ":" + drive.bHead + ":" + drive.bSector + ")"); - - // if (DEBUG) this.messageDebugger("HDC.doRead(head=" + str.toHexByte(drive.bHead) + ",cyl=" + str.toHexWord(drive.wCylinder) + ",sec=" + str.toHexByte(drive.bSector) + ")"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("HDC.doRead(" + drive.wCylinder + ":" + drive.bHead + ":" + drive.bSector + ")"); + } if (drive.disk) { drive.sector = null; @@ -2237,9 +2259,9 @@ HDC.prototype.doWrite = function(drive, done) { drive.errorCode = HDC.XTC.DATA.ERR.NOT_READY; - if (DEBUG) this.messageDebugger("HDC.doWrite(" + drive.wCylinder + ":" + drive.bHead + ":" + drive.bSector + ")"); - - // if (DEBUG) this.messageDebugger("HDC.doWrite(head=" + str.toHexByte(drive.bHead) + ",cyl=" + str.toHexWord(drive.wCylinder) + ",sec=" + str.toHexByte(drive.bSector) + ")"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("HDC.doWrite(" + drive.wCylinder + ":" + drive.bHead + ":" + drive.bSector + ")"); + } if (drive.disk) { drive.sector = null; @@ -2340,8 +2362,6 @@ HDC.prototype.doFormat = function(drive, done) { drive.errorCode = HDC.XTC.DATA.ERR.NOT_READY; - // if (DEBUG) this.messageDebugger("HDC.doFormat()"); - if (drive.disk) { drive.sector = null; if (this.chipset) { @@ -2525,7 +2545,7 @@ HDC.prototype.writeByte = function(drive, b) */ HDC.prototype.advanceSector = function(drive) { - if (DEBUG) this.assert(drive.wCylinder < drive.nCylinders); + this.assert(drive.wCylinder < drive.nCylinders); drive.bSector++; var bSectorStart = (1 - drive.bSectorBias); if (drive.bSector >= drive.nSectors + bSectorStart) { @@ -2585,9 +2605,9 @@ HDC.prototype.writeFormat = function(drive, b) drive.nBytes = 128 << drive.abFormat[3];// N (0 => 128, 1 => 256, 2 => 512, 3 => 1024) drive.cbFormat = 0; - if (DEBUG) this.messageDebugger("HDC.writeFormat(" + drive.wCylinder + ":" + drive.bHead + ":" + drive.bSector + ":" + drive.nBytes + ")"); - - // if (DEBUG) this.messageDebugger("HDC.writeFormat(head=" + str.toHexByte(drive.bHead) + ",cyl=" + str.toHexWord(drive.wCylinder) + ",sec=" + str.toHexByte(drive.bSector) + ",len=" + str.toHexWord(drive.nBytes) + ")"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("HDC.writeFormat(" + drive.wCylinder + ":" + drive.bHead + ":" + drive.bSector + ":" + drive.nBytes + ")"); + } for (var i = 0; i < drive.nBytes; i++) { if (this.writeByte(drive, drive.bFiller) < 0) { @@ -2677,40 +2697,6 @@ HDC.prototype.intBIOSDiskette = function(addr) return true; }; -/** - * messageDebugger(sMessage, bitsMessage) - * - * This is a combination of the Debugger's messageEnabled(MESSAGE_HDC) and message() functions, for convenience. - * - * @this {HDC} - * @param {string} sMessage is any caller-defined message string - * @param {number} [bitsMessage] is one or more Debugger MESSAGE_* category flag(s) - */ -HDC.prototype.messageDebugger = function(sMessage, bitsMessage) -{ - if (DEBUGGER && this.dbg) { - if (bitsMessage == null) bitsMessage = Debugger.MESSAGE.HDC; - if (this.dbg.messageEnabled(bitsMessage)) this.dbg.message(sMessage); - } -}; - -/** - * messagePort(port, bOut, addrFrom, name, bIn) - * - * This is an internal version of the Debugger's messagePort() function, for convenience. - * - * @this {HDC} - * @param {number} port - * @param {number|null} bOut if an output operation - * @param {number|null} [addrFrom] - * @param {string|null} [name] of the port, if any - * @param {number} [bIn] is the input value, if known, on an input operation - */ -HDC.prototype.messagePort = function(port, bOut, addrFrom, name, bIn) -{ - if (DEBUGGER && this.dbg) this.dbg.messagePort(this, port, bOut, addrFrom, name, Debugger.MESSAGE.HDC, bIn); -}; - /* * Port input notification tables */ diff --git a/modules/pcjs/lib/keyboard.js b/modules/pcjs/lib/keyboard.js index 3eb118a6a..1e9259e25 100644 --- a/modules/pcjs/lib/keyboard.js +++ b/modules/pcjs/lib/keyboard.js @@ -60,9 +60,9 @@ if (typeof module !== 'undefined') { * @extends Component * @param {Object} parmsKbd */ -function Keyboard(parmsKbd) { - - Component.call(this, "Keyboard", parmsKbd, Keyboard); +function Keyboard(parmsKbd) +{ + Component.call(this, "Keyboard", parmsKbd, Keyboard, Debugger.MESSAGE.KBD); this.nDefaultModel = parmsKbd['model']; this.fEscapeDisabled = false; @@ -842,7 +842,7 @@ Keyboard.prototype.setBinding = function(sHTMLType, sBinding, control) this.bindings[id] = control; control.onclick = function(kbd, sKey, keyCode) { return function onClickKeyboard(event) { - if (DEBUG) kbd.messageDebugger(sKey + " clicked", Debugger.MESSAGE.KEYS); + if (DEBUG && kbd.messageEnabled()) kbd.messageDebugger(sKey + " clicked", Debugger.MESSAGE.KEYS); if (kbd.cpu) kbd.cpu.setFocus(); kbd.checkShiftState(keyCode); return !kbd.keySimulatePress(keyCode); @@ -989,7 +989,9 @@ Keyboard.prototype.setEnable = function(fData, fClock) { var fReset = false; if (this.fClock !== fClock) { - if (DEBUG) this.messageDebugger("keyboard clock line changing to " + fClock, Debugger.MESSAGE.PORT); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("keyboard clock line changing to " + fClock, Debugger.MESSAGE.PORT); + } /* * Toggling the clock line low and then high signals a "reset", which we acknowledge once the * data line is high as well. @@ -997,7 +999,9 @@ Keyboard.prototype.setEnable = function(fData, fClock) this.fClock = this.fResetOnEnable = fClock; } if (this.fData !== fData) { - if (DEBUG) this.messageDebugger("keyboard data line changing to " + fData, Debugger.MESSAGE.PORT); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("keyboard data line changing to " + fData, Debugger.MESSAGE.PORT); + } this.fData = fData; /* * TODO: Review this code; it was added during the early days of MODEL_5150 testing and may not be @@ -1054,7 +1058,7 @@ Keyboard.prototype.readScanCode = function(fShift) var b = 0; if (this.abScanBuffer.length) { b = this.abScanBuffer[0]; - this.messageDebugger("scan code 0x" + str.toHexByte(b) + " delivered"); + if (this.messageEnabled()) this.messageDebugger("scan code 0x" + str.toHexByte(b) + " delivered"); if (fShift) this.shiftScanCode(); } return b; @@ -1274,11 +1278,11 @@ Keyboard.prototype.addScanCode = function(bScan, fRepeat) if (this.abScanBuffer) { if (this.abScanBuffer.length < Keyboard.LIMIT.MAX_SCANCODES) { if (!fDown && !this.aScanCodesActive[bKey] || fDown && this.aScanCodesActive[bKey] && !fRepeat) { - if (MAXDEBUG) this.messageDebugger("scan code 0x" + str.toHexByte(bScan) + " redundant"); + if (MAXDEBUG && this.messageEnabled()) this.messageDebugger("scan code 0x" + str.toHexByte(bScan) + " redundant"); return; } this.aScanCodesActive[bKey] = fDown; - this.messageDebugger("scan code 0x" + str.toHexByte(bScan) + " buffered"); + if (this.messageEnabled()) this.messageDebugger("scan code 0x" + str.toHexByte(bScan) + " buffered"); this.abScanBuffer.push(bScan); if (this.abScanBuffer.length == 1) { if (this.chipset) this.chipset.notifyKbdData(true); @@ -1333,7 +1337,7 @@ Keyboard.prototype.autoClear = function(notKeyCode) { if (this.prevCharDown && (notKeyCode === undefined || notKeyCode != this.prevCharDown)) { if (DEBUG) { - this.messageDebugger("autoClear(" + this.prevCharDown + ")"); + if (this.messageEnabled()) this.messageDebugger("autoClear(" + this.prevCharDown + ")"); this.assert(this.aKeyTimers[this.prevCharDown]); } clearTimeout(this.aKeyTimers[this.prevCharDown]); @@ -1632,7 +1636,9 @@ Keyboard.prototype.keyUpDown = function(event, fDown) fPass = !this.keySimulateUpOrDown(keyCodeSim, fDown, Keyboard.SIMCODE.KEYUPDOWN); } - if (DEBUG) this.messageDebugger(/*(fDown?"\n":"") +*/ "key" + (fDown? "Down" : "Up") + "(" + keyCode + "): " + (fPass? "pass" : "consume"), Debugger.MESSAGE.KEYS); + if (DEBUG && this.messageEnabled(Debugger.MESSAGE.KEYS)) { + this.messageDebugger(/*(fDown?"\n":"") +*/ "key" + (fDown? "Down" : "Up") + "(" + keyCode + "): " + (fPass? "pass" : "consume")); + } return fPass; }; @@ -1680,7 +1686,9 @@ Keyboard.prototype.keyPress = function(event) } } - if (DEBUG) this.messageDebugger("keyPress(" + keyCode + "): " + (fPass? "pass" : "consume"), Debugger.MESSAGE.KEYS); + if (DEBUG && this.messageEnabled(Debugger.MESSAGE.KEYS)) { + this.messageDebugger("keyPress(" + keyCode + "): " + (fPass? "pass" : "consume")); + } return fPass; }; @@ -1734,11 +1742,15 @@ Keyboard.prototype.keySimulatePress = function(keyCode, fCheckShift, fQuickRelea kbd.keySimulateUpOrDown(keyCode, false, Keyboard.SIMCODE.KEYTIMEOUT); }; }(this), msDelay); - if (DEBUG) this.messageDebugger("keySimulatePress(" + keyCode + "): setTimeout()"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("keySimulatePress(" + keyCode + "): setTimeout()"); + } } fSimulated = true; } - if (DEBUG) this.messageDebugger("keySimulatePress(" + keyCode + "): " + (fSimulated? "true" : "false"), Debugger.MESSAGE.KEYS); + if (DEBUG && this.messageEnabled(Debugger.MESSAGE.KEYS)) { + this.messageDebugger("keySimulatePress(" + keyCode + "): " + (fSimulated? "true" : "false")); + } return fSimulated; }; @@ -1823,29 +1835,10 @@ Keyboard.prototype.keySimulateUpOrDown = function(keyCode, fDown, simCode) fSimulated = true; } - if (DEBUG && DEBUGGER) this.messageDebugger("keySimulateUpOrDown(" + keyCode + "," + (fDown? "down" : "up") + "," + Keyboard.aSimCodeDescs[simCode] + "): " + (fSimulated? "true" : "false"), Debugger.MESSAGE.KEYS); - return fSimulated; -}; - -/** - * messageDebugger(sMessage, bitsMessage) - * - * 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 {number} [bitsMessage] is one or more Debugger MESSAGE_* category flag(s) - */ -Keyboard.prototype.messageDebugger = function(sMessage, bitsMessage) -{ - if (DEBUGGER && this.dbg) { - if (bitsMessage == null) { - bitsMessage = Debugger.MESSAGE.KBD; - } else { - bitsMessage |= Debugger.MESSAGE.KBD; - } - if (this.dbg.messageEnabled(bitsMessage)) this.dbg.message(sMessage); + if (DEBUG && this.messageEnabled(Debugger.MESSAGE.KEYS)) { + this.messageDebugger("keySimulateUpOrDown(" + keyCode + "," + (fDown? "down" : "up") + "," + Keyboard.aSimCodeDescs[simCode] + "): " + (fSimulated? "true" : "false")); } + return fSimulated; }; /** diff --git a/modules/pcjs/lib/mem.js b/modules/pcjs/lib/mem.js index 081ebfba9..ea6228256 100644 --- a/modules/pcjs/lib/mem.js +++ b/modules/pcjs/lib/mem.js @@ -179,7 +179,7 @@ Memory.prototype = { */ writeNone: function(off, v) { if (DEBUGGER && this.dbg.messageEnabled(Debugger.MESSAGE.MEM) && !off) { - this.dbg.message("attempt to write 0x" + str.toHexWord(v) + " to invalid block %" + str.toHex(this.addr) + " from " + str.toHexAddr(this.cpu.regIP, this.cpu.segCS.sel)); + this.dbg.message("attempt to write 0x" + str.toHexWord(v) + " to invalid block %" + str.toHex(this.addr), true); } }, /** diff --git a/modules/pcjs/lib/mouse.js b/modules/pcjs/lib/mouse.js index 9cefdc081..ecba9975b 100644 --- a/modules/pcjs/lib/mouse.js +++ b/modules/pcjs/lib/mouse.js @@ -71,7 +71,7 @@ if (typeof module !== 'undefined') { */ function Mouse(parmsMouse) { - Component.call(this, "Mouse", parmsMouse, Mouse); + Component.call(this, "Mouse", parmsMouse, Mouse, Debugger.MESSAGE.MOUSE); this.idAdapter = parmsMouse['serial']; if (this.idAdapter) { @@ -543,7 +543,9 @@ Mouse.prototype.sendPacket = function(sDiag, xDiag, yDiag) var b1 = 0x40 | (this.fButton1? 0x20 : 0) | (this.fButton2? 0x10 : 0) | ((this.yDelta & 0xC0) >> 4) | ((this.xDelta & 0xC0) >> 6); var b2 = this.xDelta & 0x3F; var b3 = this.yDelta & 0x3F; - this.messageDebugger((sDiag? (sDiag + ": ") : "") + (yDiag !== undefined? ("mouse (" + xDiag + "," + yDiag + "): ") : "") + "serial packet [" + str.toHexByte(b1) + "," + str.toHexByte(b2) + "," + str.toHexByte(b3) + "]", Debugger.MESSAGE.SERIAL); + if (this.messageEnabled(Debugger.MESSAGE.SERIAL)) { + this.messageDebugger((sDiag? (sDiag + ": ") : "") + (yDiag !== undefined? ("mouse (" + xDiag + "," + yDiag + "): ") : "") + "serial packet [" + str.toHexByte(b1) + "," + str.toHexByte(b2) + "," + str.toHexByte(b3) + "]", 0, true); + } this.componentAdapter.sendRBR([b1, b2, b3]); this.xDelta = this.yDelta = 0; }; @@ -630,29 +632,6 @@ Mouse.prototype.notifyMCR = function(bMCR) this.bMCR = 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 - * @param {number} [bitsMessage] is one or more Debugger MESSAGE_* category flag(s) - */ -Mouse.prototype.messageDebugger = function(sMessage, bitsMessage) -{ - if (DEBUGGER && this.dbg) { - if (bitsMessage == null) { - bitsMessage = Debugger.MESSAGE.MOUSE; - } else { - bitsMessage |= Debugger.MESSAGE.MOUSE; - } - if (this.dbg.messageEnabled(bitsMessage)) { - this.dbg.message(sMessage + " @" + str.toHexAddr(this.cpu.regIP, this.cpu.segCS.sel)); - } - } -}; - /** * Mouse.init() * diff --git a/modules/pcjs/lib/nodebugger.js b/modules/pcjs/lib/nodebugger.js index f878ab598..59749eed8 100644 --- a/modules/pcjs/lib/nodebugger.js +++ b/modules/pcjs/lib/nodebugger.js @@ -40,8 +40,8 @@ * debugger.js from the compilation process altogether. * * However, when we're in "development mode" and running uncompiled code in debugger-less configurations, - * I would still like to skip loading debugger.js altogether. To do that, we must arrange for an additional file, - * nodebugger.js, to be loaded as early as possible, which must explicitly UPDATE the value of DEBUGGER to *false*. + * I would still like to skip loading debugger.js altogether. To do that, we must arrange for this additional file, + * nodebugger.js, to be loaded as early as possible, which explicitly UPDATES the value of DEBUGGER to false. */ DEBUGGER = false; diff --git a/modules/pcjs/lib/serial.js b/modules/pcjs/lib/serial.js index f08287096..5a2a342fc 100644 --- a/modules/pcjs/lib/serial.js +++ b/modules/pcjs/lib/serial.js @@ -87,7 +87,7 @@ function SerialPort(parmsSerial) { */ this.controlIOBuffer = null; - Component.call(this, "SerialPort", parmsSerial, SerialPort); + Component.call(this, "SerialPort", parmsSerial, SerialPort, Debugger.MESSAGE.SERIAL); Component.bindExternalControl(this, parmsSerial['binding'], SerialPort.sIOBuffer); } @@ -715,40 +715,6 @@ SerialPort.prototype.echoByte = function(b) { return false; }; -/** - * 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 - */ -SerialPort.prototype.messageDebugger = function(sMessage) { - if (DEBUGGER && this.dbg) { - if (this.dbg.messageEnabled(Debugger.MESSAGE.SERIAL)) { - this.dbg.message(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 - * @param {number|null} [addrFrom] - * @param {string|null} [name] of the port, if any - * @param {number} [bIn] is the input value, if known, on an input operation - */ -SerialPort.prototype.messagePort = function(port, bOut, addrFrom, name, bIn) { - if (DEBUGGER && this.dbg) { - this.dbg.messagePort(this, port, bOut, addrFrom, name, Debugger.MESSAGE.SERIAL, bIn); - } -}; - /* * Port input notification table */ diff --git a/modules/pcjs/lib/state.js b/modules/pcjs/lib/state.js index 09ca096a2..3ddf2d28c 100644 --- a/modules/pcjs/lib/state.js +++ b/modules/pcjs/lib/state.js @@ -50,7 +50,8 @@ if (typeof module !== 'undefined') { * * WARNING: Since State objects are low-level objects that have no UI requirements, * they do not inherit from the Component class, so you should only use class methods - * of Component, such as Component.assert(), or Debugger methods if the Debugger is available. + * of Component, such as Component.assert(), or Debugger methods if the Debugger + * is available. * * @constructor * @param {Component} component @@ -136,12 +137,14 @@ State.decompress = function(aComp, nLength) { /** * State.compressEvenOdd(aSrc) * - * This is a very simple variation on compress() that compresses all the EVEN elements of aSrc first, followed by all the ODD - * elements. This tends to work better on EGA video memory, because when odd/even addressing is enabled (eg, for text - * modes), the DWORD values tend to alternate, which is the worst case for compress(), but the best case for compressEvenOdd(). + * This is a very simple variation on compress() that compresses all the EVEN elements of aSrc first, + * followed by all the ODD elements. This tends to work better on EGA video memory, because when odd/even + * addressing is enabled (eg, for text modes), the DWORD values tend to alternate, which is the worst case + * for compress(), but the best case for compressEvenOdd(). * - * One wrinkle we support: if the first element is uninitialized, then we assume the entire array is undefined, and return an - * empty compressed array. Conversely, decompressEvenOdd() will take an empty compressed array and return an uninitialized array. + * One wrinkle we support: if the first element is uninitialized, then we assume the entire array is undefined, + * and return an empty compressed array. Conversely, decompressEvenOdd() will take an empty compressed array + * and return an uninitialized array. * * @param {Array.|null} aSrc * @return {Array.|null} is either the original array (aSrc), or a smaller array of "count, value" pairs (aComp) @@ -170,9 +173,9 @@ State.compressEvenOdd = function(aSrc) { /** * State.decompressEvenOdd(aComp, nLength) * - * This is the counterpart to compressEvenOdd(). Note that because there's nothing in the compressed sequence that differentiates - * a compress() sequence from a compressEvenOdd() sequence, you simply have to be consistent -- if you used even/odd compression, then - * you must use even/odd decompression. + * This is the counterpart to compressEvenOdd(). Note that because there's nothing in the compressed sequence + * that differentiates a compress() sequence from a compressEvenOdd() sequence, you simply have to be consistent: + * if you used even/odd compression, then you must use even/odd decompression. * * @param {Array.} aComp * @param {number} nLength is expected length of decompressed data @@ -214,7 +217,7 @@ State.prototype = { try { this[this.id][id] = data; } catch(e) { - Component.log(e.message) + Component.log(e.message); } }, /** @@ -274,7 +277,9 @@ State.prototype = { if (s) { this[this.id] = s; this.fLoaded = true; - if (DEBUG) this.messageDebugger("localStorage(" + this.key + "): " + s.length + " bytes loaded"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("localStorage(" + this.key + "): " + s.length + " bytes loaded"); + } return true; } } @@ -311,7 +316,9 @@ State.prototype = { if (web.hasLocalStorage()) { var s = JSON.stringify(this[this.id]); if (web.setLocalStorageItem(this.key, s)) { - if (DEBUG) this.messageDebugger("localStorage(" + this.key + "): " + s.length + " bytes stored"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("localStorage(" + this.key + "): " + s.length + " bytes stored"); + } } else { /* * WARNING: Because browsers tend to disable all alerts() during an "unload" operation, @@ -369,24 +376,40 @@ State.prototype = { var sKey = aKeys[i]; if (sKey && (fAll || sKey.substr(0, this.key.length) == this.key)) { web.removeLocalStorageItem(sKey); - if (DEBUG) this.messageDebugger("localStorage(" + sKey + ") removed"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("localStorage(" + sKey + ") removed"); + } aKeys.splice(i, 1); i = 0; } } }, /** - * messageDebugger(sMessage) + * messageEnabled(bitsMessage) * - * This is a combination of the Debugger's messageEnabled(MESSAGE_STATE) and message() functions, for convenience. + * @this {State} + * @param {number} [bitsMessage] is one or more Debugger MESSAGE_* category flag(s) + * @return {boolean} + */ + messageEnabled: function(bitsMessage) { + if (DEBUGGER && this.dbg) { + if (bitsMessage == null) { + bitsMessage = Debugger.MESSAGE.STATE; + } else { + bitsMessage |= Debugger.MESSAGE.STATE; + } + return this.dbg.messageEnabled(bitsMessage); + } + return false; + }, + /** + * messageDebugger(sMessage) * * @this {State} * @param {string} sMessage is any caller-defined message string */ messageDebugger: function(sMessage) { - if (DEBUGGER && this.dbg) { - if (this.dbg.messageEnabled(Debugger.MESSAGE.STATE)) this.dbg.message(sMessage); - } + if (DEBUGGER && this.dbg) this.dbg.message(sMessage); } }; diff --git a/modules/pcjs/lib/video.js b/modules/pcjs/lib/video.js index 4a0056641..5a4fb7677 100644 --- a/modules/pcjs/lib/video.js +++ b/modules/pcjs/lib/video.js @@ -106,7 +106,7 @@ if (typeof module !== 'undefined') { */ function Video(parmsVideo, canvas, context, textarea) { - Component.call(this, "Video", parmsVideo, Video); + Component.call(this, "Video", parmsVideo, Video, Debugger.MESSAGE.VIDEO); /* * This records the model specified (eg, "mda", "cga", "ega" or "" if none specified); @@ -2189,7 +2189,9 @@ Video.prototype.captureTouch = function() */ Video.prototype.onFocusChange = function(fFocus) { - if (this.fHasFocus != fFocus && DEBUG) this.messageDebugger("onFocusChange(): focus is now " + fFocus); + if (this.fHasFocus != fFocus && DEBUG && this.messageEnabled()) { + this.messageDebugger("onFocusChange(): focus is now " + fFocus); + } this.fHasFocus = fFocus; }; @@ -2748,7 +2750,7 @@ Video.prototype.getCardColors = function(nBitsPerPixel) return Video.aCGAColors; } - if (DEBUG) this.assert(this.cardColor === this.cardEGA); + this.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++) { @@ -2867,7 +2869,10 @@ Video.prototype.buildFonts = function() Video.prototype.buildFont = function(nFont, offData, offSplit, cxChar, cyChar, abFontData, aRGBColors, aColorMap) { var fChanges = false; - if (DEBUG) this.messageDebugger("buildFont(" + nFont + "): building " + Video.cardSpecs[nFont][0] + " font"); + + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("buildFont(" + nFont + "): building " + Video.cardSpecs[nFont][0] + " font"); + } if (this.createFont(nFont, offData, offSplit, cxChar, cyChar, abFontData, aRGBColors, aColorMap)) fChanges = true; /* @@ -2877,7 +2882,9 @@ Video.prototype.buildFont = function(nFont, offData, offSplit, cxChar, cyChar, a */ if (this.fDoubleFont) { nFont <<= 1; - if (DEBUG) this.messageDebugger("buildFont(" + nFont + "): building " + Video.cardSpecs[nFont >> 1][0] + " double-size font"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("buildFont(" + nFont + "): building " + Video.cardSpecs[nFont >> 1][0] + " double-size font"); + } if (this.createFont(nFont, offData, offSplit, cxChar, cyChar, abFontData, aRGBColors, aColorMap)) fChanges = true; } return fChanges; @@ -2924,7 +2931,9 @@ Video.prototype.createFont = function(nFont, offData, offSplit, cxChar, cyChar, var rgbColor = aRGBColors[iColor]; var rgbColorOrig = font.aCSSColors[iColor]? font.aRGBColors[iColor] : []; if (rgbColor[0] !== rgbColorOrig[0] || rgbColor[1] !== rgbColorOrig[1] || rgbColor[2] !== rgbColorOrig[2]) { - if (DEBUG) this.messageDebugger("creating font color " + iColor + " for font " + nFont); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("creating font color " + iColor + " for font " + nFont); + } this.createFontColor(font, iColor, rgbColor, nDouble, offData, offSplit, cxChar, cyChar, abFontData); fChanges = true; } @@ -3154,7 +3163,9 @@ Video.prototype.checkCursor = function() */ var iCellCursor = (this.cardActive.aCRTCRegs[Card.CRTC.CURSOR_ADDR_LO] + ((this.cardActive.aCRTCRegs[Card.CRTC.CURSOR_ADDR_HI] & Card.CRTC.ADDR_HI_MASK) << 8)); if (this.iCellCursor != iCellCursor) { - if (DEBUG) this.messageDebugger("checkCursor(): cursor moved from " + this.iCellCursor + " to " + iCellCursor); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("checkCursor(): cursor moved from " + this.iCellCursor + " to " + iCellCursor); + } this.removeCursor(); this.iCellCursor = iCellCursor; } @@ -3207,7 +3218,9 @@ Video.prototype.removeCursor = function() */ this.updateChar(col, row, data); } - if (DEBUG) this.messageDebugger("removeCursor(): removed from " + row + "," + col); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("removeCursor(): removed from " + row + "," + col); + } this.aCellCache[this.iCellCursor] = data; } } @@ -3272,7 +3285,9 @@ Video.prototype.getAccess = function() } break; default: - if (DEBUG) this.messageDebugger("getAccess(): invalid GRC mode (" + str.toHexByte(regGRCMode) + ")"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("getAccess(): invalid GRC mode (" + str.toHexByte(regGRCMode) + ")"); + } break; } if (regGRCMode & Card.GRC.MODE.READ_MODE1) { @@ -3298,7 +3313,9 @@ 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) + ")"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("setAccess(0x" + str.toHexWord(nAccess) + ")"); + } card.setMemoryAccess(nAccess); @@ -3633,7 +3650,9 @@ Video.prototype.setMode = function(nMode, fForce) { if (nMode != null && (nMode != this.nMode || fForce)) { - if (DEBUG) this.messageDebugger("setMode(0x" + str.toHexWord(nMode) + (fForce? ",force" : "") + ")"); + if (DEBUG && this.messageEnabled()) { + 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; @@ -3657,7 +3676,9 @@ Video.prototype.setMode = function(nMode, fForce) if (this.addrBuffer) { - if (DEBUG) this.messageDebugger("setMode(" + nMode + "): removing 0x" + str.toHex(this.sizeBuffer) + " bytes from 0x" + str.toHex(this.addrBuffer)); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("setMode(" + nMode + "): removing 0x" + str.toHex(this.sizeBuffer) + " bytes from 0x" + str.toHex(this.addrBuffer)); + } if (!this.bus.removeMemory(this.addrBuffer, this.sizeBuffer)) { /* @@ -3674,7 +3695,9 @@ Video.prototype.setMode = function(nMode, fForce) this.addrBuffer = card.addrBuffer; this.sizeBuffer = card.sizeBuffer; - if (DEBUG) this.messageDebugger("setMode(" + nMode + "): adding 0x" + str.toHex(this.sizeBuffer) + " bytes to 0x" + str.toHex(this.addrBuffer)); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("setMode(" + nMode + "): adding 0x" + str.toHex(this.sizeBuffer) + " bytes to 0x" + str.toHex(this.addrBuffer)); + } var controller = (card === this.cardEGA? card : null); @@ -3824,7 +3847,7 @@ Video.prototype.updateChar = function(col, row, data, context) this.contextScreen.fillRect(xDst, yDst, this.cxScreenCell, this.cyScreenCell); } - if (MAXDEBUG && DEBUGGER && this.dbg && this.dbg.messageEnabled(Debugger.MESSAGE.VIDEO | Debugger.MESSAGE.LOG)) { + if (MAXDEBUG && this.messageEnabled(Debugger.MESSAGE.VIDEO | Debugger.MESSAGE.LOG)) { this.log("updateCharBgnd(" + col + "," + row + "," + bChar + "): filled " + xDst + "," + yDst); } @@ -3835,7 +3858,7 @@ Video.prototype.updateChar = function(col, row, data, context) var xSrcFgnd = (bChar & 0xf) * font.cxCell; var ySrcFgnd = (bChar >> 4) * font.cyCell; - if (MAXDEBUG && DEBUGGER && this.dbg && this.dbg.messageEnabled(Debugger.MESSAGE.VIDEO | Debugger.MESSAGE.LOG)) { + if (MAXDEBUG && this.messageEnabled(Debugger.MESSAGE.VIDEO | Debugger.MESSAGE.LOG)) { this.log("updateCharFgnd(" + col + "," + row + "," + bChar + "): draw from " + xSrcFgnd + "," + ySrcFgnd + " (" + font.cxCell + "," + font.cyCell + ") to " + xDst + "," + yDst); } @@ -4064,7 +4087,7 @@ Video.prototype.updateScreenText = function(addrScreen, addrScreenLimit, iCell, if (iCell == this.iCellCursor) { data |= ((this.cBlinks & 0x1)? (Video.ATTRS.DRAW_CURSOR << 8) : 0); } - if (DEBUG) this.assert(iCell < this.aCellCache.length); + this.assert(iCell < this.aCellCache.length); dataCache = this.aCellCache[iCell]; if (dataCache != data) { var col = iCell % this.nCols; @@ -4105,7 +4128,7 @@ Video.prototype.updateScreenGraphicsCGA = function(addrScreen, addrScreenLimit) var xDirty = this.nCols, xMaxDirty = 0, yDirty = this.nRows, yMaxDirty = 0; while (addr < addrScreenLimit) { data = this.bus.getWordDirect(addr); - if (DEBUG) this.assert(iCell < this.aCellCache.length); + this.assert(iCell < this.aCellCache.length); dataCache = this.aCellCache[iCell]; if (dataCache === data) { x += nPixelsPerCell; @@ -4183,9 +4206,9 @@ Video.prototype.updateScreenGraphicsEGA = function(addrScreen, addrScreenLimit) var xDirty = this.nCols, xMaxDirty = 0, yDirty = this.nRows, yMaxDirty = 0; while (addr < addrScreenLimit) { var idw = addr++ - this.addrBuffer; - if (DEBUG) this.assert(idw >= 0 && idw < adwMemory.length); + this.assert(idw >= 0 && idw < adwMemory.length); data = adwMemory[idw]; - if (DEBUG) this.assert(iCell < this.aCellCache.length); + this.assert(iCell < this.aCellCache.length); dataCache = this.aCellCache[iCell]; if (dataCache === data) { x += nPixelsPerCell; @@ -4211,7 +4234,7 @@ Video.prototype.updateScreenGraphicsEGA = function(addrScreen, addrScreenLimit) * Since assertions don't fix problems (only catch them, and only in DEBUG builds), I'm also ensuring * that bPixel will always default to 0 if an undefined value ever slips through again. */ - if (DEBUG) this.assert(Video.aEGADWToByte[dwPixel] !== undefined); + this.assert(Video.aEGADWToByte[dwPixel] !== undefined); var bPixel = Video.aEGADWToByte[dwPixel] || 0; this.setPixel(this.imageScreenBuffer, x++, y, aPixelColors[bPixel]); data <<= 1; @@ -4355,7 +4378,9 @@ Video.prototype.outFeat = function(port, bOut, addrFrom) Video.prototype.inATC = function(port, addrFrom) { var b = this.cardEGA.fATCData? this.cardEGA.aATCRegs[this.cardEGA.iATCReg & Card.ATC.INDX_MASK] : this.cardEGA.iATCReg; - this.messagePort(Card.ATC.PORT, null, addrFrom, "ATC." + (this.cardEGA.fATCData? this.cardEGA.asATCRegs[this.cardEGA.iATCReg & Card.ATC.INDX_MASK] : "INDX"), b); + if (this.messageEnabled()) { + this.messagePort(Card.ATC.PORT, null, addrFrom, "ATC." + (this.cardEGA.fATCData? this.cardEGA.asATCRegs[this.cardEGA.iATCReg & Card.ATC.INDX_MASK] : "INDX"), b); + } this.cardEGA.fATCData = !this.cardEGA.fATCData; return b; }; @@ -4377,9 +4402,13 @@ Video.prototype.outATC = function(port, bOut, addrFrom) this.cardEGA.fATCData = true; if ((bOut & Card.ATC.INDX_PAL_ENABLE) && !fPalEnabled) { if (!this.buildFonts()) { - if (DEBUG) this.messageDebugger("outATC(" + str.toHexByte(bOut) + "): no font changes required"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("outATC(" + str.toHexByte(bOut) + "): no font changes required"); + } } else { - if (DEBUG) this.messageDebugger("outATC(" + str.toHexByte(bOut) + "): redraw screen for font changes"); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("outATC(" + str.toHexByte(bOut) + "): redraw screen for font changes"); + } this.updateScreen(true); } } @@ -4387,7 +4416,9 @@ Video.prototype.outATC = function(port, bOut, addrFrom) var iReg = this.cardEGA.iATCReg & Card.ATC.INDX_MASK; if (iReg >= Card.ATC.PALETTE_REGS || !fPalEnabled) { if (Video.TRAPALL || this.cardEGA.aATCRegs[iReg] !== bOut) { - this.messagePort(port, bOut, addrFrom, "ATC." + this.cardEGA.asATCRegs[iReg]); + if (this.messageEnabled()) { + this.messagePort(port, bOut, addrFrom, "ATC." + this.cardEGA.asATCRegs[iReg]); + } this.cardEGA.aATCRegs[iReg] = bOut; } } @@ -4469,7 +4500,9 @@ Video.prototype.outSEQIndx = function(port, bOut, addrFrom) Video.prototype.inSEQData = function(port, addrFrom) { var b = this.cardEGA.aSEQRegs[this.cardEGA.iSEQReg]; - this.messagePort(Card.SEQ.DATA.PORT, null, addrFrom, "SEQ" + this.cardEGA.asSEQRegs[this.cardEGA.iSEQReg], b); + if (this.messageEnabled()) { + this.messagePort(Card.SEQ.DATA.PORT, null, addrFrom, "SEQ" + this.cardEGA.asSEQRegs[this.cardEGA.iSEQReg], b); + } return b; }; @@ -4484,7 +4517,9 @@ Video.prototype.inSEQData = function(port, addrFrom) Video.prototype.outSEQData = function(port, bOut, addrFrom) { if (Video.TRAPALL || this.cardEGA.aSEQRegs[this.cardEGA.iSEQReg] !== bOut) { - this.messagePort(Card.SEQ.DATA.PORT, bOut, addrFrom, "SEQ." + this.cardEGA.asSEQRegs[this.cardEGA.iSEQReg]); + if (this.messageEnabled()) { + this.messagePort(Card.SEQ.DATA.PORT, bOut, addrFrom, "SEQ." + this.cardEGA.asSEQRegs[this.cardEGA.iSEQReg]); + } this.cardEGA.aSEQRegs[this.cardEGA.iSEQReg] = bOut; } if (this.cardEGA.iSEQReg == Card.SEQ.MAPMASK.INDX) { @@ -4601,7 +4636,9 @@ Video.prototype.outGRCIndx = function(port, bOut, addrFrom) Video.prototype.inGRCData = function(port, addrFrom) { var b = this.cardEGA.aGRCRegs[this.cardEGA.iGRCReg]; - this.messagePort(Card.GRC.DATA.PORT, null, addrFrom, "GRC." + this.cardEGA.asGRCRegs[this.cardEGA.iGRCReg], b); + if (this.messageEnabled()) { + this.messagePort(Card.GRC.DATA.PORT, null, addrFrom, "GRC." + this.cardEGA.asGRCRegs[this.cardEGA.iGRCReg], b); + } return b; }; @@ -4616,7 +4653,9 @@ Video.prototype.inGRCData = function(port, addrFrom) Video.prototype.outGRCData = function(port, bOut, addrFrom) { if (Video.TRAPALL || this.cardEGA.aGRCRegs[this.cardEGA.iGRCReg] !== bOut) { - this.messagePort(Card.GRC.DATA.PORT, bOut, addrFrom, "GRC." + this.cardEGA.asGRCRegs[this.cardEGA.iGRCReg]); + if (this.messageEnabled()) { + this.messagePort(Card.GRC.DATA.PORT, bOut, addrFrom, "GRC." + this.cardEGA.asGRCRegs[this.cardEGA.iGRCReg]); + } this.cardEGA.aGRCRegs[this.cardEGA.iGRCReg] = bOut; } switch(this.cardEGA.iGRCReg) { @@ -4741,7 +4780,9 @@ Video.prototype.outCGAMode = function(port, bOut, addrFrom) Video.prototype.inCGAColor = function(port, addrFrom) { var b = this.cardColor.colorReg; - this.messagePort(this.cardColor.port + 5, null, addrFrom, this.cardColor.type + ".COLOR", b); + if (this.messageEnabled()) { + this.messagePort(this.cardColor.port + 5, null, addrFrom, this.cardColor.type + ".COLOR", b); + } return b; }; @@ -4755,7 +4796,9 @@ Video.prototype.inCGAColor = function(port, addrFrom) */ Video.prototype.outCGAColor = function(port, bOut, addrFrom) { - this.messagePort(this.cardColor.port + 5, bOut, addrFrom, this.cardColor.type + ".COLOR"); + if (this.messageEnabled()) { + this.messagePort(this.cardColor.port + 5, bOut, addrFrom, this.cardColor.type + ".COLOR"); + } if (this.cardColor.colorReg !== bOut) { this.cardColor.colorReg = bOut; /* @@ -4821,7 +4864,9 @@ Video.prototype.inCRTCData = function(card, addrFrom) { var b; if (card.iCRTCReg < card.nCRTCRegs) b = card.aCRTCRegs[card.iCRTCReg]; - this.messagePort(card.port + 1, null, addrFrom, "CRTC." + card.asCRTCRegs[card.iCRTCReg], b); + if (this.messageEnabled()) { + this.messagePort(card.port + 1, null, addrFrom, "CRTC." + card.asCRTCRegs[card.iCRTCReg], b); + } return b; }; @@ -4837,7 +4882,9 @@ Video.prototype.outCRTCData = function(card, bOut, addrFrom) { if (card.iCRTCReg < card.nCRTCRegs) { if (Video.TRAPALL || card.aCRTCRegs[card.iCRTCReg] !== bOut) { - this.messagePort(card.port + 1, bOut, addrFrom, "CRTC." + card.asCRTCRegs[card.iCRTCReg]); + if (this.messageEnabled()) { + this.messagePort(card.port + 1, bOut, addrFrom, "CRTC." + card.asCRTCRegs[card.iCRTCReg]); + } card.aCRTCRegs[card.iCRTCReg] = bOut; } /* @@ -4854,7 +4901,9 @@ Video.prototype.outCRTCData = function(card, bOut, addrFrom) } this.checkCursor(); } else { - if (DEBUG) this.messageDebugger("outCRTCData(): ignoring unexpected write to CRTC[" + str.toHexByte(card.iCRTCReg) + "]: " + str.toHexByte(bOut)); + if (DEBUG && this.messageEnabled()) { + this.messageDebugger("outCRTCData(): ignoring unexpected write to CRTC[" + str.toHexByte(card.iCRTCReg) + "]: " + str.toHexByte(bOut)); + } } }; @@ -4996,43 +5045,6 @@ 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 - */ -Video.prototype.messageDebugger = function(sMessage, fForce) -{ - if (DEBUGGER && this.dbg) { - if (fForce || this.dbg.messageEnabled(Debugger.MESSAGE.VIDEO)) { - this.dbg.message(sMessage); - } - } -}; - -/** - * 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 - * @param {number|null} [addrFrom] - * @param {string|null} [name] of the port, if any - * @param {number} [bIn] is the input value, if known, on an input operation - */ -Video.prototype.messagePort = function(port, bOut, addrFrom, name, bIn) -{ - if (DEBUGGER && this.dbg) { - this.dbg.messagePort(this, port, bOut, addrFrom, name, Debugger.MESSAGE.VIDEO, bIn); - } -}; - /* * Port input/output notification tables * diff --git a/modules/pcjs/lib/x86cpu.js b/modules/pcjs/lib/x86cpu.js index e09621b8b..5b87514f5 100644 --- a/modules/pcjs/lib/x86cpu.js +++ b/modules/pcjs/lib/x86cpu.js @@ -966,7 +966,7 @@ X86CPU.prototype.checkIntNotify = function(nInt) * checksEnabled() function, and therefore in fDebugCheck, so for maximum speed, we check fDebugCheck first. */ if (DEBUGGER && this.bitField.fDebugCheck) { - if (this.dbg.messageEnabled(Debugger.MESSAGE.INT) && this.dbg.messageInt(nInt, this.regEIP)) { + if (this.messageEnabled(Debugger.MESSAGE.INT) && this.dbg.messageInt(nInt, this.regEIP)) { this.addIntReturn(this.regEIP, function(cpu, nCycles) { return function onIntReturn(nLevel) { cpu.dbg.messageIntReturn(nInt, nLevel, cpu.getCycles() - nCycles); @@ -1210,7 +1210,7 @@ X86CPU.prototype.getSeg = function(sName) * HACK: We return a fake segment register object in which only the base physical address is valid, * because that's all the caller provided (ie, we must be restoring from an older state). */ - if (DEBUG) this.assert(typeof sName == "number"); + this.assert(typeof sName == "number"); return [0, sName, 0, 0, ""]; } }; @@ -1311,7 +1311,7 @@ X86CPU.prototype.setIP = function(off) */ X86CPU.prototype.setCSIP = function(off, sel, fCall) { - if (DEBUG) this.assert((off & 0xffff) == off); + this.assert((off & 0xffff) == off); this.segCS.fCall = fCall; /* * We break this operation into the following discrete steps (eg, set IP, load CS, and then update EIP) @@ -1668,7 +1668,7 @@ X86CPU.prototype.setPS = function(regPS) /* * Assert that all requested flag bits now agree with our simulated (PS_INDIRECT) bits */ - if (DEBUG) this.assert((regPS & X86.PS.INDIRECT) == (this.getPS() & X86.PS.INDIRECT)); + this.assert((regPS & X86.PS.INDIRECT) == (this.getPS() & X86.PS.INDIRECT)); if (this.regPS & X86.PS.TF) { this.intFlags |= X86.INTFLAG.TRAP; @@ -2233,7 +2233,7 @@ X86CPU.prototype.popWord = function() */ X86CPU.prototype.pushWord = function(w) { - if (DEBUG) this.assert((w & 0xffff) == w); + this.assert((w & 0xffff) == w); this.setSOWord(this.segSS, (this.regSP = (this.regSP - 2) & 0xffff), w); }; @@ -2308,7 +2308,7 @@ X86CPU.prototype.pushWord = function(w) */ X86CPU.prototype.checkINTR = function() { - if (DEBUG) this.assert(this.intFlags); + this.assert(this.intFlags); if (!(this.opFlags & X86.OPFLAG.NOINTR)) { if ((this.intFlags & X86.INTFLAG.INTR) && (this.regPS & X86.PS.IF)) { var nIDT = this.chipset.getIRRVector(); @@ -2495,7 +2495,7 @@ X86CPU.prototype.stepCPU = function(nMinCycles) * One exception I make here is when you've asked the Debugger to display PIC messages, the idea being that * if you're watching the PIC that closely, then you want to hardware interrupts to occur regardless. */ - if (!nMinCycles && this.dbg && !this.dbg.messageEnabled(Debugger.MESSAGE.PIC)) this.opFlags |= X86.OPFLAG.NOINTR; + if (!nMinCycles && !this.messageEnabled(Debugger.MESSAGE.PIC)) this.opFlags |= X86.OPFLAG.NOINTR; do { var opPrefixes = this.opFlags & X86.OPFLAG.PREFIXES; @@ -2553,7 +2553,7 @@ X86CPU.prototype.stepCPU = function(nMinCycles) if (++this.iSampleFreq >= this.nSampleFreq) { this.iSampleFreq = 0; if (this.iSampleSkip < this.nSampleSkip) { - this.iSampleSkip++ + this.iSampleSkip++; } else { if (this.iSampleNext == this.nSamples) { this.println("sample buffer full"); @@ -2621,25 +2621,6 @@ X86CPU.prototype.stepCPU = function(nMinCycles) return (this.bitField.fComplete? this.nBurstCycles - this.nStepCycles : (this.bitField.fComplete === undefined? 0 : -1)); }; -/** - * messageDebugger(sMessage, bitsMessage) - * - * This is a combination of the Debugger's messageEnabled(MESSAGE_CPU) and message() functions, for convenience. - * - * @this {X86CPU} - * @param {string} sMessage is any caller-defined message string - * @param {number} [bitsMessage] is one or more Debugger MESSAGE_* category flag(s) - */ -X86CPU.prototype.messageDebugger = function(sMessage, bitsMessage) -{ - if (DEBUGGER && this.dbg) { - if (bitsMessage == null) { - bitsMessage = Debugger.MESSAGE.CPU; - } - if (this.dbg.messageEnabled(bitsMessage)) this.dbg.message(sMessage); - } -}; - /** * X86CPU.init() * diff --git a/modules/pcjs/lib/x86help.js b/modules/pcjs/lib/x86help.js index 0ac68ab0c..224cf8fad 100644 --- a/modules/pcjs/lib/x86help.js +++ b/modules/pcjs/lib/x86help.js @@ -571,10 +571,10 @@ var X86Help = { * JavaScript exception), and since we don't want that instruction to perform any writes that might * be destructive, we should shut off all further reads/writes for the current instruction. * - * As long as we're not using EAFUNCS, this is easy for any EA-based memory accesses: simply set + * As long as we're not using EAFUNCS, that's easy for any EA-based memory accesses: simply set both * the NOREAD and NOWRITE flags. However, there may still be direct, non-EA-based memory accesses that - * could cause us grief. TODO: Implement the ultimate solution, which will involve setting a special - * flag and throwing an exception that the CPU must intercept and then quietly ignore. + * could cause us grief. TODO: Implement the ultimate solution, which will involve throwing a special + * JavaScript exception that cpu.js must intercept and quietly ignore. */ if (!EAFUNCS) { this.opFlags &= ~(X86.OPFLAG.NOREAD | X86.OPFLAG.NOWRITE); @@ -588,24 +588,20 @@ var X86Help = { * * TODO: Provide the Debugger with some UI to control its "interference" with fault dispatching, and to * continue the dispatch after it has interfered. At the moment, your only option is to single-step over - * the offending instruction to allow the fault to be dispatched. + * the offending instruction, which will allow the fault to be dispatched, and then continue execution. * * @this {X86CPU} * @param {number} nFault * @param {number} [nError] - * @param {boolean} [fHalt] will halt the CPU if true *and* a Debugger is loaded - * @return {boolean|undefined} true to block the fault, otherwise dispatch it + * @param {boolean} [fHalt] true if the CPU should always be halted, false if "it depends" + * @return {boolean|undefined} true to block the fault (often desirable when fHalt is true), otherwise dispatch it */ opHelpFaultMessage: function(nFault, nError, fHalt) { var bitsMessage = Debugger.MESSAGE.FAULT; var bOpcode = this.bus.getByteDirect(this.regEIP); - var fDebugger = false; - if (DEBUGGER && this.dbg) { - fDebugger = true; - if (nFault == X86.EXCEPTION.GP_FAULT) fHalt = true; - } + if (this.messageEnabled(bitsMessage)) fHalt = true; /* * OS/2 1.0 uses an INT3 (0xCC) opcode in conjunction with an invalid IDT to trigger a triple-fault @@ -633,15 +629,24 @@ var X86Help = { fHalt = false; } - if (fDebugger && this.dbg.messageEnabled(bitsMessage) || !fDebugger && fHalt) { + if (this.messageEnabled(bitsMessage) || fHalt) { var sMessage = (fHalt? '\n' : '') + "Fault " + str.toHexByte(nFault) + (nError != null? " (" + str.toHexWord(nError) + ")" : "") + " on opcode 0x" + str.toHexByte(bOpcode) + " at " + str.toHexAddr(this.regIP, this.segCS.sel) + " (%" + str.toHex(this.regEIP, 6) + ")"; - if (fDebugger) { - this.messageDebugger(sMessage, bitsMessage); + if (this.messageDebugger(sMessage)) { if (fHalt) { + /* + * By setting fHalt to fRunning (which is true while running but false while single-stepping), + * this allows a fault to be dispatched when you single-step over a faulting instruction; you can + * then continue single-stepping into the fault handler, or start running again. + */ fHalt = this.bitField.fRunning; this.dbg.stopCPU(); } - } else if (fHalt) { + } else { + /* + * If messageDebugger() returned false, then messageEnabled() must have returned false as well, which + * means that fHalt must be true. Which means we should shut the machine down. + */ + this.assert(fHalt); this.notice(sMessage); this.stopCPU(); } diff --git a/modules/pcjs/lib/x86op0f.js b/modules/pcjs/lib/x86op0f.js index 3d58c7e9a..95e24c7ad 100644 --- a/modules/pcjs/lib/x86op0f.js +++ b/modules/pcjs/lib/x86op0f.js @@ -126,6 +126,9 @@ var X86Op0F = { */ opLOADALL: function() { if (this.segCS.cpl) { + /* + * You're not allowed to use LOADALL at any privilege level other than zero + */ X86Help.opHelpFault.call(this, X86.EXCEPTION.GP_FAULT, 0, true); return; } diff --git a/modules/pcjs/lib/x86opxx.js b/modules/pcjs/lib/x86opxx.js index 74b29aebf..78ad90f3b 100644 --- a/modules/pcjs/lib/x86opxx.js +++ b/modules/pcjs/lib/x86opxx.js @@ -1980,7 +1980,7 @@ var X86OpXX = { * op=0x9B (wait) */ opWAIT: function() { - this.messageDebugger("WAIT not implemented"); + this.messageDebugger("WAIT not implemented", Debugger.MESSAGE.CPU); this.nStepCycles--; }, /** @@ -2026,7 +2026,7 @@ var X86OpXX = { if (ah & X86.PS.ZF) this.setZF(); else this.clearZF(); if (ah & X86.PS.SF) this.setSF(); else this.clearSF(); this.nStepCycles -= this.CYCLES.nOpCyclesLAHF; - if (DEBUG) this.assert((this.getPS() & X86.PS.SAHF) == (ah & X86.PS.SAHF)); + this.assert((this.getPS() & X86.PS.SAHF) == (ah & X86.PS.SAHF)); }, /** * @this {X86CPU} diff --git a/modules/pcjs/lib/x86seg.js b/modules/pcjs/lib/x86seg.js index f0fc8057a..788d3110c 100644 --- a/modules/pcjs/lib/x86seg.js +++ b/modules/pcjs/lib/x86seg.js @@ -193,9 +193,7 @@ X86Seg.loadProt = function loadProt(sel, fSuppress) X86Seg.loadRealIDT = function loadRealIDT(nIDT) { var cpu = this.cpu; - if (DEBUG) { - cpu.assert(nIDT >= 0 && nIDT < 256 && !cpu.addrIDT && cpu.addrIDTLimit == 0x03FF); - } + cpu.assert(nIDT >= 0 && nIDT < 256 && !cpu.addrIDT && cpu.addrIDTLimit == 0x03FF); /* * Intel documentation for INT/INTO under "REAL ADDRESS MODE EXCEPTIONS" says: * @@ -220,7 +218,7 @@ X86Seg.loadRealIDT = function loadRealIDT(nIDT) X86Seg.loadProtIDT = function loadProtIDT(nIDT) { var cpu = this.cpu; - if (DEBUG) cpu.assert(nIDT >= 0 && nIDT < 256); + cpu.assert(nIDT >= 0 && nIDT < 256); nIDT <<= 3; var addrDesc = cpu.addrIDT + nIDT; @@ -380,7 +378,7 @@ X86Seg.checkWriteProtDisallowed = function checkWriteProtDisallowed(off, cb, fSu X86Seg.switchTSS = function switchTSS(selNew, fNest) { var cpu = this.cpu; - if (DEBUG) cpu.assert(this === cpu.segCS); + cpu.assert(this === cpu.segCS); var addrOld = cpu.segTSS.base; var cplOld = this.cpl; @@ -424,7 +422,7 @@ X86Seg.switchTSS = function switchTSS(selNew, fNest) var offSS = X86.TSS.TASK_SS; var offSP = X86.TSS.TASK_SP; cpu.setPS(cpu.getWord(addrNew + X86.TSS.TASK_PS) | (fNest? X86.PS.NT : 0)); - if (DEBUG) cpu.assert(!fNest || !!(cpu.regPS & X86.PS.NT)); + cpu.assert(!fNest || !!(cpu.regPS & X86.PS.NT)); cpu.regAX = cpu.getWord(addrNew + X86.TSS.TASK_AX); cpu.regCX = cpu.getWord(addrNew + X86.TSS.TASK_CX); cpu.regDX = cpu.getWord(addrNew + X86.TSS.TASK_DX); @@ -581,14 +579,14 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress) if (rpl <= dpl) { cplPrev = this.cpl; if (this.load(selCode, true) == null) { - if (DEBUG) cpu.assert(false); + cpu.assert(false); base = null; break; } cpu.regIP = limit; if (this.cpl < cplPrev) { if (fCall !== true) { - if (DEBUG) cpu.assert(false); + cpu.assert(false); base = null; break; } @@ -612,7 +610,7 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress) } return this.base; } - if (DEBUG) cpu.assert(false); + cpu.assert(false); if (!fSuppress) X86Help.opHelpFault.call(cpu, X86.EXCEPTION.GP_FAULT, sel, true); base = null; break; @@ -628,7 +626,7 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress) if (dpl <= this.cpl) { cplPrev = this.cpl; if (this.load(selCode, true) == null) { - if (DEBUG) cpu.assert(false); + cpu.assert(false); base = null; break; } @@ -657,7 +655,7 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress) } return this.base; } - if (DEBUG) cpu.assert(false); + cpu.assert(false); if (!fSuppress) X86Help.opHelpFault.call(cpu, X86.EXCEPTION.GP_FAULT, sel | X86.ERRCODE.EXT, true); base = null; break; @@ -674,7 +672,7 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress) base = null; break; } - if (DEBUG) cpu.assert(!!selMasked); // a null CS selector should be caught by the final preceding check + cpu.assert(!!selMasked); // a null CS selector should be caught by the final preceding check } else if (this.id == X86Seg.ID.DATA) { if (selMasked) { @@ -726,8 +724,8 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress) * * 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 possibly LOADALL). + * required (eg, in resetRegs(), where the 80286 wants the real-mode CS selector to be 0xF000 but the + * CS base must be 0xFF0000). * * @this {X86Seg} * @param {number} addr diff --git a/modules/shared/lib/component.js b/modules/shared/lib/component.js index 64edc9ac1..c869979da 100644 --- a/modules/shared/lib/component.js +++ b/modules/shared/lib/component.js @@ -61,7 +61,7 @@ if (typeof module !== 'undefined') { } /** - * Component(type, parms, constructor) + * Component(type, parms, constructor, bitsMessage) * * A Component object requires: * @@ -79,8 +79,9 @@ if (typeof module !== 'undefined') { * @param {string} type * @param {Object} [parms] * @param {Object} [constructor] + * @param {number} [bitsMessage] */ -function Component(type, parms, constructor) +function Component(type, parms, constructor, bitsMessage) { this.type = type; @@ -125,6 +126,7 @@ function Component(type, parms, constructor) this.clearError(); this.bindings = {}; this.dbg = null; // by default, no connection to a Debugger + this.bitsMessage = bitsMessage || -1; Component.add(this); } @@ -729,7 +731,7 @@ Component.prototype = { * $('h') * ... * - * If you have no desire to stop on assertions, then yes, consider this a giant no-op. + * If you have no desire to stop on assertions, consider this a no-op. */ try { throw new Error(s); @@ -929,6 +931,63 @@ Component.prototype = { powerDown: function(fSave, fShutdown) { if (fShutdown) this.bitField.fPowered = false; return true; + }, + /** + * messageEnabled(bitsMessage, fOnly) + * + * @this {Component} + * @param {number} [bitsMessage] is one or more Debugger MESSAGE_* category flag(s) + * @return {boolean} true if all specified message enabled, false if not + */ + messageEnabled: function(bitsMessage) { + if (DEBUGGER && this.dbg) { + if (this === this.dbg) { + bitsMessage = bitsMessage || 0; + } else { + if (!bitsMessage) { + bitsMessage = this.bitsMessage; + } + } + var bitsEnabled = this.dbg.bitsMessage & bitsMessage; + return (bitsEnabled === bitsMessage || !!(bitsEnabled & this.dbg.bitsWarning)); + } + return false; + }, + /** + * messageDebugger(sMessage, bitsMessage, fAddress) + * + * @this {Component} + * @param {string} sMessage is any caller-defined message string + * @param {number} [bitsMessage] is one or more Debugger MESSAGE_* category flag(s) + * @param {boolean} [fAddress] is true to display the current address + * @return {boolean} true if Debugger available, false if not + */ + messageDebugger: function(sMessage, bitsMessage, fAddress) { + if (DEBUGGER && this.dbg) { + if (bitsMessage == null || this.messageEnabled(bitsMessage)) { + this.dbg.message(sMessage, fAddress); + } + return true; + } + return false; + }, + /** + * messagePort(port, bOut, addrFrom, name, bIn, bitsMessage) + * + * This is an internal version of the Debugger's messagePort() function, for convenience. + * + * @this {Component} + * @param {number} port + * @param {number|null} bOut if an output operation + * @param {number|null} [addrFrom] + * @param {string|null} [name] of the port, if any + * @param {number} [bIn] is the input value, if known, on an input operation + * @param {number} [bitsMessage] is one or more Debugger MESSAGE_* category flag(s) + */ + messagePort: function(port, bOut, addrFrom, name, bIn, bitsMessage) { + if (DEBUGGER && this.dbg) { + this.dbg.messageIO(this, port, bOut, addrFrom, name, bIn, bitsMessage || this.bitsMessage); + } } }; diff --git a/modules/shared/lib/embed.js b/modules/shared/lib/embed.js index 751ce4f6b..9134a6ac2 100644 --- a/modules/shared/lib/embed.js +++ b/modules/shared/lib/embed.js @@ -284,7 +284,7 @@ function embedMachine(sName, sVersion, idElement, sXMLFile, sXSLFile, sStateFile var doneMachine = function() { Component.assert(cMachines > 0); - if (--cMachines == 0) { + if (!--cMachines) { if (fAsync) web.enablePageEvents(true); } }; diff --git a/modules/shared/lib/weblib.js b/modules/shared/lib/weblib.js index ac36f3073..bd3a9a662 100644 --- a/modules/shared/lib/weblib.js +++ b/modules/shared/lib/weblib.js @@ -389,9 +389,9 @@ web.promptUser = function(sPrompt, sDefault) * * true if localStorage support exists, is enabled, and works; "falsey" otherwise * - * @type {boolean|undefined} + * @type {boolean|null} */ -web.fLocalStorage; +web.fLocalStorage = null; /** * hasLocalStorage @@ -401,7 +401,7 @@ web.fLocalStorage; * @return {boolean} */ web.hasLocalStorage = function() { - if (web.fLocalStorage === undefined) { + if (web.fLocalStorage == null) { var f; var sTest = 'PCjs.localStorage'; try {