From 5841d1d35ce075e266e06cb7255a3ae60d650cb3 Mon Sep 17 00:00:00 2001 From: Jeff Parsons Date: Sat, 8 Jun 2019 10:54:53 -0700 Subject: [PATCH] Added ability to edit ROMs of calculator devices --- _data/machines.json | 4 +- ...6-02-wordstar-for-the-ibm-pc-circa-1982.md | 2 +- devices/leds/life/README.md | 2 +- devices/leds/life/colors/README.md | 2 +- devices/leds/litebrite/README.md | 2 +- devices/leds/scroller/README.md | 2 +- devices/leds/symbols/README.md | 2 +- devices/ti42/machine/diags/README.md | 2 +- devices/ti55/machine/diags/README.md | 2 +- devices/ti57/machine/rev0/README.md | 2 +- devices/ti57/machine/rev1/README.md | 2 +- modules/devices/device.js | 2 +- modules/devices/input.js | 2 +- modules/devices/led.js | 2 +- modules/devices/ledctrl.js | 2 +- modules/devices/lib/stdio.js | 24 ++++--- modules/devices/machine.js | 2 +- modules/devices/rom.js | 62 +++++++++++++++++-- modules/devices/time.js | 2 +- modules/devices/tms1500.js | 36 ++++++++--- modules/shared/bin/bin2iso.js | 9 +-- 21 files changed, 117 insertions(+), 50 deletions(-) diff --git a/_data/machines.json b/_data/machines.json index c9c4e922c7..cd14383f65 100644 --- a/_data/machines.json +++ b/_data/machines.json @@ -74,7 +74,7 @@ "leds": { "name": "LEDs", "class": "leds", - "version": "1.20", + "version": "1.21", "defines": [ "COMPILED", "DEBUG", @@ -306,7 +306,7 @@ "ti57": { "name": "TI57", "class": "ti57", - "version": "1.20", + "version": "1.21", "defines": [ "COMPILED", "DEBUG", diff --git a/_posts/2019-06-02-wordstar-for-the-ibm-pc-circa-1982.md b/_posts/2019-06-02-wordstar-for-the-ibm-pc-circa-1982.md index 2d32f2ab00..d84f1bf10c 100644 --- a/_posts/2019-06-02-wordstar-for-the-ibm-pc-circa-1982.md +++ b/_posts/2019-06-02-wordstar-for-the-ibm-pc-circa-1982.md @@ -13,7 +13,7 @@ including: {% include gallery-begin.html %} {% include gallery-image.html src="https://demo-disks.pcjs.org/pcx86/apps/other/wordstar/3.20/WS320-ORIG.png" width="320" height="320" title="WordStar 3.20 Disk 1" link="/disks/pcx86/apps/other/wordstar/3.20/" %} {% include gallery-image.html src="https://demo-disks.pcjs.org/pcx86/apps/other/wordstar/3.20/MM320-ORIG.png" width="320" height="320" title="WordStar 3.20 Disk 2" link="/disks/pcx86/apps/other/wordstar/3.20/" %} -{% include gallery-image.html src="/disks/pcx86/apps/other/wordstar/3.20/WordStar32-Binder.png" width="320" height="460" title="WordStar 3.0 Training Guide" link="https://1drv.ms/u/s!ArcO_mFRe1Z9gqlTMVtF-s8OxtSNpA" %} +{% include gallery-image.html src="/disks/pcx86/apps/other/wordstar/3.20/WordStar32-Binder.png" width="320" height="460" title="WordStar Binder" link="https://1drv.ms/u/s!ArcO_mFRe1Z9gqlTMVtF-s8OxtSNpA" %} {% include gallery-image.html src="/disks/pcx86/apps/other/wordstar/3.20/WordStar30-Training-Guide.png" width="320" height="460" title="WordStar 3.0 Training Guide" link="https://1drv.ms/b/s!ArcO_mFRe1Z9gqlYINZ_GQ3Y6NVSUA?e=cUZyft" %} {% include gallery-image.html src="/disks/pcx86/apps/other/wordstar/3.20/WordStar32-General-Information.png" width="320" height="460" title="WordStar 3.2 General Information" link="https://1drv.ms/b/s!ArcO_mFRe1Z9gqkVkrQ_SzATTmls_Q?e=D3kVDU" %} {% include gallery-image.html src="/disks/pcx86/apps/other/wordstar/3.20/WordStar32-Reference-Manual.png" width="320" height="460" title="WordStar 3.2 Reference Manual" link="https://1drv.ms/b/s!ArcO_mFRe1Z9gqkWhsTCHW7gkQ2W7A?e=VLlYyf" %} diff --git a/devices/leds/life/README.md b/devices/leds/life/README.md index b4e41c291f..3db2e3cd40 100644 --- a/devices/leds/life/README.md +++ b/devices/leds/life/README.md @@ -51,6 +51,6 @@ There is also a ["Game of Life" Color Demo](colors/) that allows you to change L
- +
diff --git a/devices/leds/life/colors/README.md b/devices/leds/life/colors/README.md index f5c9ff0656..1751b633e9 100644 --- a/devices/leds/life/colors/README.md +++ b/devices/leds/life/colors/README.md @@ -54,6 +54,6 @@ Using [PCjs Devices](/modules/devices/), here's a simple demo of
- +
diff --git a/devices/leds/litebrite/README.md b/devices/leds/litebrite/README.md index 38dbb4cb4a..a64fa27f09 100644 --- a/devices/leds/litebrite/README.md +++ b/devices/leds/litebrite/README.md @@ -162,7 +162,7 @@ color codes (B, G, V, R, O, P, Y, and W).
- +
diff --git a/devices/leds/scroller/README.md b/devices/leds/scroller/README.md index 5a88385002..baf6509da0 100644 --- a/devices/leds/scroller/README.md +++ b/devices/leds/scroller/README.md @@ -37,7 +37,7 @@ You can enter new messages in the Diagnostics window using the `s` command (eg,
- +
diff --git a/devices/leds/symbols/README.md b/devices/leds/symbols/README.md index 4ac3afec04..b6cd9c6056 100644 --- a/devices/leds/symbols/README.md +++ b/devices/leds/symbols/README.md @@ -54,7 +54,7 @@ This page helps you build new LED symbols by displaying characters underneath th
- +
Symbol: diff --git a/devices/ti42/machine/diags/README.md b/devices/ti42/machine/diags/README.md index 06cf8349d9..6cff5b3156 100644 --- a/devices/ti42/machine/diags/README.md +++ b/devices/ti42/machine/diags/README.md @@ -75,7 +75,7 @@ The window also accepts a few debugging commands. Use '?' for help.

Diagnostics

- +
Stopped diff --git a/devices/ti55/machine/diags/README.md b/devices/ti55/machine/diags/README.md index ca7419bd10..5271051e2a 100644 --- a/devices/ti55/machine/diags/README.md +++ b/devices/ti55/machine/diags/README.md @@ -107,7 +107,7 @@ The window also accepts a few debugging commands. Use '?' for help.

Diagnostics

- +
Stopped diff --git a/devices/ti57/machine/rev0/README.md b/devices/ti57/machine/rev0/README.md index 4faad757d3..1e7d52c6ea 100644 --- a/devices/ti57/machine/rev0/README.md +++ b/devices/ti57/machine/rev0/README.md @@ -124,7 +124,7 @@ The window also accepts a few debugging commands. Use '?' for help.

Diagnostics

- +
Stopped diff --git a/devices/ti57/machine/rev1/README.md b/devices/ti57/machine/rev1/README.md index e1382d5b3a..ba3aadbfc9 100644 --- a/devices/ti57/machine/rev1/README.md +++ b/devices/ti57/machine/rev1/README.md @@ -107,7 +107,7 @@ The window also accepts a few debugging commands. Use '?' for help.

Diagnostics

- +
Stopped diff --git a/modules/devices/device.js b/modules/devices/device.js index f091136e2d..471113e408 100644 --- a/modules/devices/device.js +++ b/modules/devices/device.js @@ -46,7 +46,7 @@ var MACHINE = "Machine"; /** * @define {string} */ -var VERSION = ""; +var VERSION = "1.21"; /** * The following properties are the standard set of properties a Device's config object may contain. diff --git a/modules/devices/input.js b/modules/devices/input.js index fdaab97469..2e67bb6c3c 100644 --- a/modules/devices/input.js +++ b/modules/devices/input.js @@ -753,4 +753,4 @@ Input.KEYCODE = { // keyCode from keydown/keyup events Input.BUTTON_DELAY = 50; // minimum number of milliseconds to ensure between button presses and releases -Input.VERSION = +VERSION || 1.20; +Input.VERSION = +VERSION || 1.00; diff --git a/modules/devices/led.js b/modules/devices/led.js index a82c5c671f..bb3fe7c347 100644 --- a/modules/devices/led.js +++ b/modules/devices/led.js @@ -1293,4 +1293,4 @@ LED.SYMBOL_SEGMENTS = { '.': ['P'] }; -LED.VERSION = +VERSION || 1.20; +LED.VERSION = +VERSION || 1.00; diff --git a/modules/devices/ledctrl.js b/modules/devices/ledctrl.js index 4a40732863..40ac9c5ef7 100644 --- a/modules/devices/ledctrl.js +++ b/modules/devices/ledctrl.js @@ -1749,6 +1749,6 @@ Chip.FONTS = { } }; -Chip.VERSION = +VERSION || 1.20; +Chip.VERSION = +VERSION || 1.00; MACHINE = "LEDs"; diff --git a/modules/devices/lib/stdio.js b/modules/devices/lib/stdio.js index 74fc9cd5be..89677eccf0 100644 --- a/modules/devices/lib/stdio.js +++ b/modules/devices/lib/stdio.js @@ -279,14 +279,13 @@ class StdIO { } else { arg = args[args.length-1]; } - } else { - width = +width || 0; } + width = +width || 0; let precision = aParts[iPart+3]; precision = precision? +precision.substr(1) : -1; // let length = aParts[iPart+4]; // eg, 'h', 'l' or 'L' (all currently ignored) let hash = flags.indexOf('#') >= 0; - let ach = null, s, radix = 0, p, prefix = "" + let ach = null, s, radix = 0, prefix = "" switch(type) { case 'd': @@ -325,7 +324,7 @@ class StdIO { * the caller is providing an Object that should be rendered as JSON. If a width is included * (eg, "%2j"), it's used as an indentation value; otherwise, no whitespace is added. */ - buffer += JSON.stringify(arg, null, width || null); + buffer += JSON.stringify(arg, null, width || undefined); break; case 'c': @@ -381,22 +380,21 @@ class StdIO { */ arg = Number.parseInt(arg, arg.match(/(^0x|[a-f])/i)? 16 : 10); } - p = width? "" : prefix; + width -= prefix.length; do { let d = arg & (radix - 1); arg >>>= (radix == 16? 4 : 3); - if (flags.indexOf('0') >= 0 || s == "" || d || arg) { + if (flags.indexOf('0') >= 0 || !s || d || arg) { s = ach[d] + s; - } else if (width) { - if (!prefix) { - s = ' ' + s; - } else { - s = prefix.slice(-1) + s; - prefix = prefix.slice(0, -1); + } else { + if (prefix) { + s = prefix + s; + prefix = ""; } + if (width > 0) s = ' ' + s; } } while (--width > 0 || arg); - buffer += p + s; + buffer += prefix + s; break; case '%': diff --git a/modules/devices/machine.js b/modules/devices/machine.js index 20ac79504d..37d4f819e1 100644 --- a/modules/devices/machine.js +++ b/modules/devices/machine.js @@ -292,6 +292,6 @@ Machine.CLASSORDER = [ Machine.COPYRIGHT = "Copyright © 2012-2019 Jeff Parsons "; Machine.LICENSE = "License: GPL version 3 or later "; -Machine.VERSION = +VERSION || 1.20; +Machine.VERSION = +VERSION || 1.00; window[MACHINE] = Machine; diff --git a/modules/devices/rom.js b/modules/devices/rom.js index 36864166e7..280834a87e 100644 --- a/modules/devices/rom.js +++ b/modules/devices/rom.js @@ -196,16 +196,49 @@ class ROM extends Device { */ loadState(state) { + let length, success = true; let buffer = state.shift(); if (buffer && this.ledArray) { - this.assert(this.ledArray.buffer.length == buffer.length); - if (this.ledArray.buffer.length == buffer.length) { + length = buffer.length; + this.assert(this.ledArray.buffer.length == length); + if (this.ledArray.buffer.length == length) { this.ledArray.buffer = buffer; this.ledArray.drawBuffer(true); - return true; + } else { + this.printf("inconsistent saved LED state (%d), unable to load\n", length); + success = false; } } - return false; + /* + * Version 1.21 and up also saves the ROM contents, since our "mini-debugger" has been updated + * with an edit command ("e") to enable ROM patching. However, we prefer to detect improvements + * in saved state based on the length of the array, not the version number. + */ + if (state.length) { + let data = state.shift(); + let length = data && data.length || -1; + if (this.data.length == length) { + this.data = data; + } else { + this.printf("inconsistent saved ROM state (%d), unable to load\n", length); + success = false; + } + } + return success; + } + + /** + * reset() + * + * Called by the Chip (eg, TMS1500) onReset() handler. Originally, there was no need for this + * handler, until we added the min-debugger's ability to edit ROM locations via setData(). So this + * gives the user the ability to revert back to the original ROM if they want to undo any modifications. + * + * @this {ROM} + */ + reset() + { + this.data = this.config['values']; } /** @@ -218,6 +251,7 @@ class ROM extends Device { { if (this.ledArray) { state.push(this.ledArray.buffer); + state.push(this.data); } } @@ -231,6 +265,24 @@ class ROM extends Device { { this.chip = chip; } + + /** + * setData(addr, value) + * + * @this {ROM} + * @param {number} addr + * @param {number} value + * @return {number|undefined} (previous value, if available) + */ + setData(addr, value) + { + let prev; + if (addr >= 0 && addr < this.data.length) { + prev = this.data[addr]; + this.data[addr] = value; + } + return prev; + } } ROM.BINDING = { @@ -238,4 +290,4 @@ ROM.BINDING = { CELLDESC: "cellDesc" }; -ROM.VERSION = +VERSION || 1.20; +ROM.VERSION = +VERSION || 1.00; diff --git a/modules/devices/time.js b/modules/devices/time.js index 83c1b9d107..b3ea9a23a0 100644 --- a/modules/devices/time.js +++ b/modules/devices/time.js @@ -1107,4 +1107,4 @@ Time.BINDING = { Time.YIELDS_PER_SECOND = 120; Time.YIELDS_PER_UPDATE = 60; -Time.VERSION = +VERSION || 1.20; +Time.VERSION = +VERSION || 1.00; diff --git a/modules/devices/tms1500.js b/modules/devices/tms1500.js index 171500d7c2..79ae9d59ae 100644 --- a/modules/devices/tms1500.js +++ b/modules/devices/tms1500.js @@ -877,7 +877,7 @@ class Chip extends Device { sOp = "CALL"; v = opCode & 0x07FF; } - sOperands = this.sprintf("0x%04x", v); + sOperands = this.sprintf("%#06x", v); } else if (opCode >= 0) { let d, j, k, l, n; @@ -1032,7 +1032,7 @@ class Chip extends Device { break; } } - return this.sprintf(fCompact? "%03X %04X\n" : "0x%04x: 0x%04x %-8s%s\n", addr, opCode, sOp, sOperands); + return this.sprintf(fCompact? "%03X %04X\n" : "%#06x: %#06x %-8s%s\n", addr, opCode, sOp, sOperands); } /** @@ -1049,12 +1049,12 @@ class Chip extends Device { if (state) { let stateChip = state['stateChip'] || state[0]; if (!stateChip || !stateChip.length) { - this.println("Invalid saved state"); + this.println("invalid saved state"); return false; } let version = stateChip.shift(); if ((version|0) !== (Chip.VERSION|0)) { - this.printf("Saved state version mismatch: %3.2f\n", version); + this.printf("saved state version mismatch: %3.2f\n", version); return false; } try { @@ -1071,7 +1071,7 @@ class Chip extends Device { this.stack = stateChip.shift(); this.regKey = stateChip.shift(); } catch(err) { - this.println("Chip state error: " + err.message); + this.println("chip state error: " + err.message); return false; } let stateROM = state['stateROM'] || state[1]; @@ -1097,14 +1097,17 @@ class Chip extends Device { onCommand(aTokens, machine) { let sResult = ""; + let c, condition, count = 0, values = []; let s = aTokens[1]; let addr = Number.parseInt(aTokens[2], 16); if (isNaN(addr)) addr = -1; let nWords = Number.parseInt(aTokens[3], 10) || 8; - this.nStringFormat = Chip.SFORMAT.DEFAULT; + for (let i = 3; i < aTokens.length; i++) { + values.push(Number.parseInt(aTokens[i], 16)); + } - let c, condition; + this.nStringFormat = Chip.SFORMAT.DEFAULT; switch(s[0]) { case 'b': @@ -1125,6 +1128,17 @@ class Chip extends Device { } break; + case 'e': + for (let i = 0; i < values.length; i++) { + let prev = this.rom.setData(addr, values[i]); + if (prev == undefined) break; + sResult += this.sprintf("%#06x: %#06x changed to %#06x\n", addr, prev, values[i]); + count++; + addr++; + } + sResult += this.sprintf("%d locations updated\n", count); + break; + case 'g': if (this.time.start()) { this.addrStop = addr; @@ -1251,6 +1265,7 @@ class Chip extends Device { { this.println("reset"); this.regPC = 0; + this.rom.reset(); this.clearDisplays(); if (!this.time.isRunning()) { this.status(); @@ -1504,9 +1519,9 @@ class Chip extends Device { } s += "COND=" + (this.fCOND? 1 : 0); s += " BASE=" + this.base; - s += " R5=" + this.sprintf("0x%02x", this.regR5); + s += " R5=" + this.sprintf("%#04x", this.regR5); s += " RAB=" + this.regRAB + ' '; - this.stack.forEach((addr, i) => {s += this.sprintf("ST%d=0x%04x ", i, addr & 0xffff);}); + this.stack.forEach((addr, i) => {s += this.sprintf("ST%d=%#06x ", i, addr & 0xffff);}); if (this.rom) { s += '\n' + this.disassemble(this.rom.getData(this.regPC, true), this.regPC); } @@ -1756,6 +1771,7 @@ Chip.OP_INPUTS = ["A","B","C","D","1","?","R5L","R5"]; Chip.COMMANDS = [ "b[c]\t\tbreak on condition c", "bl\t\tlist break conditions", + "e [addr] ...\tedit ROM locations", "g [addr]\trun (to addr)", "h\t\thalt", "r[a]\t\tdump (all) registers", @@ -1763,6 +1779,6 @@ Chip.COMMANDS = [ "u [addr] [n]\tdisassemble (at addr)" ]; -Chip.VERSION = +VERSION || 1.20; +Chip.VERSION = +VERSION || 1.00; MACHINE = "TMS1500"; diff --git a/modules/shared/bin/bin2iso.js b/modules/shared/bin/bin2iso.js index 155d885cab..f8c1205c22 100644 --- a/modules/shared/bin/bin2iso.js +++ b/modules/shared/bin/bin2iso.js @@ -64,7 +64,7 @@ function dumpBytes(buffer, offset, length) } /** - * convertBinToISO(sInput, sOutput, fDebug, fOverwrite) + * convertBinToISO(sInput, sOutput, fDebug, fOverwrite, fVerbose) * * We assume that the ".bin" file is a CD-ROM dump consisting of 2352-byte sectors. Such a * dump can be produced by the macOS `dd` utility, using the physical CD-ROM device; eg: @@ -96,8 +96,9 @@ function dumpBytes(buffer, offset, length) * @param {string} sOutput * @param {boolean} [fDebug] * @param {boolean} [fOverwrite] + * @param {boolean} [fVerbose] */ -function convertBinToISO(sInput, sOutput, fDebug, fOverwrite) +function convertBinToISO(sInput, sOutput, fDebug, fOverwrite, fVerbose) { let bufferBin, streamISO; try { @@ -127,7 +128,7 @@ function convertBinToISO(sInput, sOutput, fDebug, fOverwrite) for (let iSector = 0; iSector < nSectors; iSector++) { let iBuffer = iSector * 2352; let bufferSector = Buffer.alloc(cbSector); - dumpBytes(bufferBin, iBuffer, 16); + if (fVerbose) dumpBytes(bufferBin, iBuffer, 16); iBuffer += 16; bufferBin.copy(bufferSector, 0, iBuffer, iBuffer + cbSector); streamISO.write(bufferSector); @@ -144,5 +145,5 @@ if (args.argc < 3) { printf("usage: node bin2iso [input file] [output file] [options]\n"); } else { let argv = args.argv; - convertBinToISO(argv[1], argv[2], argv['debug'], argv['overwrite']); + convertBinToISO(argv[1], argv[2], argv['debug'], argv['overwrite'], argv['verbose']); }