diff --git a/modules/pcx86/lib/fdc.js b/modules/pcx86/lib/fdc.js
index 88a200338..927eaf66a 100644
--- a/modules/pcx86/lib/fdc.js
+++ b/modules/pcx86/lib/fdc.js
@@ -517,7 +517,7 @@ FDC.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
};
return true;
- case "loadDrive":
+ case "loadDisk":
this.bindings[sBinding] = control;
control.onclick = function onClickLoadDrive(event) {
@@ -530,7 +530,7 @@ FDC.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
};
return true;
- case "saveDrive":
+ case "saveDisk":
/*
* Yes, technically, this feature does not require "Local disk support" (which is really a reference
* to FileReader support), but since fLocalDisks is also false for all mobile devices, and since there
@@ -575,7 +575,7 @@ FDC.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
};
return true;
- case "mountDrive":
+ case "mountDisk":
if (!this.fLocalDisks) {
if (DEBUG) this.log("Local disk support not available");
/*
diff --git a/modules/pcx86/lib/hdc.js b/modules/pcx86/lib/hdc.js
index 8740e8d19..12d15e299 100644
--- a/modules/pcx86/lib/hdc.js
+++ b/modules/pcx86/lib/hdc.js
@@ -568,7 +568,7 @@ HDC.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
var drive = hdc.aDrives && hdc.aDrives[iDrive];
if (drive && drive.disk) {
/*
- * Note the similarity (and hence factoring opportunity) between this code and the FDC's "saveDrive" binding.
+ * Note the similarity (and hence factoring opportunity) between this code and the FDC's "saveDisk" binding.
*/
var disk = drive.disk;
if (DEBUG) hdc.println("saving disk " + disk.sDiskPath + "...");
diff --git a/modules/pdp11/lib/cpu.js b/modules/pdp11/lib/cpu.js
index c611ba1a9..2954684b3 100644
--- a/modules/pdp11/lib/cpu.js
+++ b/modules/pdp11/lib/cpu.js
@@ -203,6 +203,13 @@ CPUPDP11.prototype.initBus = function(cmp, bus, cpu, dbg)
this.flags.autoStart = (sAutoStart == "true"? true : (sAutoStart == "false"? false : !!sAutoStart));
}
+ /*
+ * Start running automatically on power-up, assuming there's no Debugger and no "Run" button.
+ */
+ if ((!DEBUGGER || !this.dbg) && this.bindings["run"] === undefined) {
+ this.flags.autoStart = true;
+ }
+
this.setReady();
};
@@ -328,10 +335,10 @@ CPUPDP11.prototype.powerDown = function(fSave, fShutdown)
*/
CPUPDP11.prototype.autoStart = function()
{
- /*
- * Start running automatically on power-up, assuming there's no Debugger and no "Run" button
- */
- if (this.flags.autoStart || (!DEBUGGER || !this.dbg) && this.bindings["run"] === undefined) {
+ if (this.flags.running) {
+ return true;
+ }
+ if (this.flags.autoStart) {
/*
* We used to also set fUpdateFocus when calling startCPU(), on the assumption that in the "auto-starting"
* context, a machine without focus is like a day without sunshine, but in reality, focus should only be
diff --git a/modules/pdp11/lib/cpustate.js b/modules/pdp11/lib/cpustate.js
index 09808b041..719962c81 100644
--- a/modules/pdp11/lib/cpustate.js
+++ b/modules/pdp11/lib/cpustate.js
@@ -481,13 +481,13 @@ CPUStatePDP11.prototype.setMMR3 = function(newMMR3)
};
/**
- * setReset(addr, fReset)
+ * setReset(addr, fStart)
*
* @this {CPUStatePDP11}
* @param {number} addr
- * @param {boolean} [fReset] (true if called in the context of a complete reset, obviating the need to notify the Debugger)
+ * @param {boolean|undefined} fStart (true if a "startable" image was just loaded, false if not)
*/
-CPUStatePDP11.prototype.setReset = function(addr, fReset)
+CPUStatePDP11.prototype.setReset = function(addr, fStart)
{
this.addrReset = addr;
@@ -495,17 +495,25 @@ CPUStatePDP11.prototype.setReset = function(addr, fReset)
this.setPC(addr);
this.setPSW(0);
- if (!fReset && this.dbg) {
- /*
- * TODO: Review the decision to always stop the CPU if the Debugger is loaded. Note that
- * when stopCPU() stops a running CPU, the Debugger gets notified, so again, no need to notify it here.
- *
- * TODO: There are more serious problems to deal with if another component is slamming a new PC down
- * the CPU's throat (presumably while also dropping some new code into RAM) while the CPU was still running;
- * we should probably force a complete reset if the CPU is running, but for now, it's up to the user
- * to hit the reset button themselves.
- */
- if (!this.stopCPU()) this.dbg.updateStatus();
+ if (fStart) {
+ this.autoStart();
+ }
+ else {
+ if (this.dbg) {
+ /*
+ * TODO: Review the decision to always stop the CPU if the Debugger is loaded. Note that
+ * when stopCPU() stops a running CPU, the Debugger gets notified, so again, no need to notify it here.
+ *
+ * TODO: There are more serious problems to deal with if another component is slamming a new PC down
+ * the CPU's throat (presumably while also dropping some new code into RAM) while the CPU was still running;
+ * we should probably force a complete reset if the CPU is running, but for now, it's up to the user
+ * to hit the reset button themselves.
+ */
+ if (!this.stopCPU()) this.dbg.updateStatus();
+ }
+ else if (fStart === false) {
+ this.stopCPU();
+ }
}
};
diff --git a/modules/pdp11/lib/pc11.js b/modules/pdp11/lib/pc11.js
index 3596c25fe..1c09e380c 100644
--- a/modules/pdp11/lib/pc11.js
+++ b/modules/pdp11/lib/pc11.js
@@ -44,8 +44,8 @@ if (NODE) {
* The PC11 component has the following component-specific (parms) properties:
*
* autoMount: a JSON-encoded object containing 'name' and 'path' properties, describing a
- * tape resource to automatically attach at startup (only the "attach" operation is supported
- * for autoMount; if you want to "load" a tape image directly into RAM at startup, you must
+ * tape resource to automatically load at startup (only the "load" operation is supported
+ * for autoMount; if you want to "read" a tape image directly into RAM at startup, you must
* ask the RAM component to do that).
*
* baudReceive: the default number of bits/second that the device should receive data at;
@@ -67,11 +67,13 @@ function PC11(parms)
{
Component.call(this, "PC11", parms, PC11);
+ this.sDevice = "PTR"; // TODO: Make the device name configurable
+
/*
* We record any 'autoMount' object now, but we no longer parse it until initBus(), because the
* Computer's getMachineParm() service may have an override for us.
*/
- this.configMount = parms['autoMount'] || null;
+ this.configMount = this.parseConfig(parms['autoMount']);
this.cAutoMount = 0;
this.nBaudReceive = parms['baudReceive'] || PDP11.PC11.PRS.BAUD;
@@ -124,6 +126,30 @@ PC11.CSSCLASS = {
PROGRESS_BAR: PDP11.CSSCLASS + "-progress-bar"
};
+/**
+ * parseConfig(config)
+ *
+ * @this {PC11}
+ * @param {*} config
+ * @return {*}
+ */
+PC11.prototype.parseConfig = function(config)
+{
+ if (config && typeof config == "string") {
+ try {
+ /*
+ * The most likely source of any exception will be right here, where we're parsing
+ * this JSON-encoded data.
+ */
+ config = eval("(" + config + ")");
+ } catch (e) {
+ Component.error(this.type + " auto-mount error: " + e.message + " (" + config + ")");
+ config = null;
+ }
+ }
+ return config || {};
+};
+
/**
* setBinding(sType, sBinding, control, sValue)
*
@@ -170,18 +196,18 @@ PC11.prototype.setBinding = function(sType, sBinding, control, sValue)
return true;
/*
- * "loadTape" operation must do pretty much everything that the "attachTape" does, but whereas the attach
- * operation records the bytes in aTapeData, the load operation stuffs them directly into the machine's memory;
+ * "readTape" operation must do pretty much everything that the "loadTape" does, but whereas the load
+ * operation records the bytes in aTapeData, the read operation stuffs them directly into the machine's memory;
* the former sets nTapeTarget to TARGET.READER, while the latter sets it to TARGET.MEMORY.
*/
- case "loadTape":
+ case "readTape":
nTapeTarget = PC11.TARGET.MEMORY;
/* falls through */
- case "attachTape":
+ case "loadTape":
if (!nTapeTarget) nTapeTarget = PC11.TARGET.READER;
this.bindings[sBinding] = control;
- control.onclick = function onClickLoadTape(event) {
+ control.onclick = function onClickReadTape(event) {
var controlTapes = pc11.bindings["listTapes"];
if (controlTapes) {
var sTapeName = controlTapes.options[controlTapes.selectedIndex].text;
@@ -263,20 +289,15 @@ PC11.prototype.initBus = function(cmp, bus, cpu, dbg)
var pc11 = this;
- this.configMount = this.cmp.getMachineParm('autoMount') || this.configMount;
+ var configMount = this.parseConfig(this.cmp.getMachineParm('autoMount'));
- if (this.configMount) {
- if (typeof this.configMount == "string") {
- try {
- /*
- * The most likely source of any exception will be right here, where we're parsing
- * this JSON-encoded data.
- */
- this.configMount = eval("(" + this.configMount + ")");
- } catch (e) {
- Component.error("PC11 auto-mount error: " + e.message + " (" + this.configMount + ")");
- this.configMount = null;
- }
+ /*
+ * Add only devices from the machine-wide autoMount configuration that match devices managed by this component.
+ */
+ if (configMount) {
+ for (var sDevice in configMount) {
+ if (sDevice != this.sDevice) continue;
+ this.configMount[sDevice] = configMount[sDevice];
}
}
@@ -332,7 +353,7 @@ PC11.prototype.powerDown = function(fSave, fShutdown)
/**
* reset()
*
- * TODO: Consider making our reset() handler ALSO restore the original attached tape, in much the same
+ * TODO: Consider making our reset() handler ALSO restore the original loaded tape, in much the same
* way the RAM component now restores the original predefined memory or tape image after resetting the RAM.
*
* @this {PC11}
@@ -353,9 +374,10 @@ PC11.prototype.reset = function()
PC11.prototype.autoMount = function(fRemount)
{
if (!fRemount) this.cAutoMount = 0;
- if (this.configMount) {
- var sTapePath = this.configMount['path'] || "";
- var sTapeName = this.configMount['name'] || this.findTape(sTapePath);
+ var configMount = this.configMount[this.sDevice];
+ if (configMount) {
+ var sTapePath = configMount['path'] || "";
+ var sTapeName = configMount['name'] || this.findTape(sTapePath);
if (sTapePath && sTapeName) {
/*
* TODO: Provide a way to autoMount tapes into MEMORY as well as READER.
@@ -460,7 +482,7 @@ PC11.prototype.loadTape = function(sTapeName, sTapePath, nTapeTarget, fAutoMount
* Now that we're calling parseTape() again (so that the current tape can either be restarted on
* the reader or reloaded into RAM), we can also rely on it to display an appropriate status message, too.
*
- * this.status(this.nTapeTarget == PC11.TARGET.READER? "tape attached" : "tape loaded");
+ * this.status(this.nTapeTarget == PC11.TARGET.READER? "tape loaded" : "tape read");
*/
this.parseTape(this.sTapeName, this.sTapePath, this.nTapeTarget, this.aBytes, this.addrLoad, this.addrExec);
}
@@ -705,23 +727,28 @@ PC11.prototype.parseTape = function(sTapeName, sTapePath, nTapeTarget, aBytes, a
*
* For example, the "Absolute Loader" tape is NOT itself in the Absolute Loader format. You just have
* to know that in order to load that tape, you must first load the appropriate "Bootstrap Loader" (which
- * DOES include its own hard-coded load address), attach the "Absolute Loader" tape, and then run the
+ * DOES include its own hard-coded load address), load the "Absolute Loader" tape, and then run the
* "Bootstrap Loader".
*/
- if (!this.ram || !this.ram.loadImage(aBytes, addrLoad, addrExec)) {
- this.sTapeName = "";
- this.sTapePath = "";
- this.sTapeSource = PC11.SOURCE.NONE;
- this.nTapeTarget = PC11.TARGET.NONE;
- this.notice('No load address available for tape "' + sTapeName + '"');
+ if (!this.ram || !this.ram.loadImage(aBytes, addrLoad, addrExec, null, false)) {
+ /*
+ * This doesn't seem to serve any purpose, other than to be annoying, because perhaps you accidentally
+ * clicked "Read" instead of "Load"....
+ *
+ * this.sTapeName = "";
+ * this.sTapePath = "";
+ * this.sTapeSource = PC11.SOURCE.NONE;
+ * this.nTapeTarget = PC11.TARGET.NONE;
+ */
+ this.notice('No valid memory address for tape "' + sTapeName + '"');
return;
}
- this.status('Loaded tape "' + sTapeName + '"');
+ this.status('Read tape "' + sTapeName + '"');
return;
}
this.iTapeData = 0;
this.aTapeData = aBytes;
- this.status('Attached tape "' + sTapeName + '"');
+ this.status('Loaded tape "' + sTapeName + '"');
this.displayProgress(0);
};
diff --git a/modules/pdp11/lib/ram.js b/modules/pdp11/lib/ram.js
index 16a9d7b78..e9e937d02 100644
--- a/modules/pdp11/lib/ram.js
+++ b/modules/pdp11/lib/ram.js
@@ -260,7 +260,7 @@ RAMPDP11.prototype.reset = function()
};
/**
- * loadImage(aBytes, addrLoad, addrExec, addrInit, fReset)
+ * loadImage(aBytes, addrLoad, addrExec, addrInit, fStart)
*
* If the array contains a PAPER tape image in the "Absolute Format," load it as specified
* by the format; otherwise, load it as-is using the address(es) supplied.
@@ -270,11 +270,12 @@ RAMPDP11.prototype.reset = function()
* @param {number|null} [addrLoad]
* @param {number|null} [addrExec] (this CAN override any starting address INSIDE the image)
* @param {number|null} [addrInit]
- * @param {boolean} [fReset]
+ * @param {boolean} [fStart]
* @return {boolean} (true if loaded, false if not)
*/
-RAMPDP11.prototype.loadImage = function(aBytes, addrLoad, addrExec, addrInit, fReset)
+RAMPDP11.prototype.loadImage = function(aBytes, addrLoad, addrExec, addrInit, fStart)
{
+ var fStop = false;
var fLoaded = false;
/*
* Data on tapes in the "Absolute Format" is organized into blocks; each block begins with
@@ -343,7 +344,7 @@ RAMPDP11.prototype.loadImage = function(aBytes, addrLoad, addrExec, addrInit, fR
}
if (!cbData) {
if (addr & 0x1) {
- this.cpu.stopCPU();
+ fStop = true;
} else {
if (addrExec == null) addrExec = addr;
}
@@ -375,7 +376,13 @@ RAMPDP11.prototype.loadImage = function(aBytes, addrLoad, addrExec, addrInit, fR
* image, but we know that the directions for that diagnostic say to "Start and Restart at 200",
* so we have manually inserted an "exec":128 in the JSON containing the image.
*/
- if (addrExec != null) this.cpu.setReset(addrExec, fReset);
+ if (addrExec == null || fStop) {
+ this.cpu.stopCPU();
+ fStart = false;
+ }
+ if (addrExec != null) {
+ this.cpu.setReset(addrExec, fStart);
+ }
}
return fLoaded;
};
diff --git a/modules/pdp11/lib/rk11.js b/modules/pdp11/lib/rk11.js
index aac69cb3f..34daa709f 100644
--- a/modules/pdp11/lib/rk11.js
+++ b/modules/pdp11/lib/rk11.js
@@ -65,7 +65,7 @@ function RK11(parms)
* We record any 'autoMount' object now, but we no longer parse it until initBus(),
* because the Computer's getMachineParm() service may have an override for us.
*/
- this.configMount = parms['autoMount'] || {};
+ this.configMount = this.parseConfig(parms['autoMount']);
this.cAutoMount = 0;
/*
@@ -88,6 +88,30 @@ RK11.SOURCE = {
REMOTE: "??"
};
+/**
+ * parseConfig(config)
+ *
+ * @this {RK11}
+ * @param {*} config
+ * @return {*}
+ */
+RK11.prototype.parseConfig = function(config)
+{
+ if (config && typeof config == "string") {
+ try {
+ /*
+ * The most likely source of any exception will be right here, where we're parsing
+ * this JSON-encoded data.
+ */
+ config = eval("(" + config + ")");
+ } catch (e) {
+ Component.error(this.type + " auto-mount error: " + e.message + " (" + config + ")");
+ config = null;
+ }
+ }
+ return config || {};
+};
+
/**
* setBinding(sType, sBinding, control, sValue)
*
@@ -143,7 +167,7 @@ RK11.prototype.setBinding = function(sType, sBinding, control, sValue)
};
return true;
- case "loadDrive":
+ case "loadDisk":
this.bindings[sBinding] = control;
control.onclick = function onClickLoadDrive(event) {
@@ -156,7 +180,15 @@ RK11.prototype.setBinding = function(sType, sBinding, control, sValue)
};
return true;
- case "saveDrive":
+ case "bootDisk":
+ this.bindings[sBinding] = control;
+
+ control.onclick = function onClickBootDisk(event) {
+ rk11.bootSelectedDisk();
+ };
+ return true;
+
+ case "saveDisk":
/*
* Yes, technically, this feature does not require "Local disk support" (which is really a reference
* to FileReader support), but since fLocalDisks is also false for all mobile devices, and since there
@@ -201,7 +233,7 @@ RK11.prototype.setBinding = function(sType, sBinding, control, sValue)
};
return true;
- case "mountDrive":
+ case "mountDisk":
if (!this.fLocalDisks) {
if (DEBUG) this.log("Local disk support not available");
/*
@@ -263,21 +295,7 @@ RK11.prototype.initBus = function(cmp, bus, cpu, dbg)
this.cpu = cpu;
this.dbg = dbg;
- var configMount = this.cmp.getMachineParm('autoMount');
- if (configMount) {
- if (typeof configMount == "string") {
- try {
- /*
- * The most likely source of any exception will be right here, where we're parsing
- * this JSON-encoded data.
- */
- configMount = eval("(" + configMount + ")");
- } catch (e) {
- Component.error(this.type + " auto-mount error: " + e.message + " (" + configMount + ")");
- configMount = null;
- }
- }
- }
+ var configMount = this.parseConfig(this.cmp.getMachineParm('autoMount'));
/*
* Add only drives from the machine-wide autoMount configuration that match drives managed by this component.
@@ -527,6 +545,33 @@ RK11.prototype.loadSelectedDrive = function(sDiskName, sDiskPath, file)
this.loadDrive(iDrive, sDiskName, sDiskPath, false, file);
};
+/**
+ * bootSelectedDisk()
+ *
+ * @this {RK11}
+ */
+RK11.prototype.bootSelectedDisk = function()
+{
+ var drive;
+ var controlDrives = this.bindings["listDrives"];
+ var iDrive = controlDrives && str.parseInt(controlDrives.value, 10);
+
+ if (iDrive == null || iDrive < 0 || iDrive >= this.aDrives.length || !(drive = this.aDrives[iDrive])) {
+ this.notice("Unable to boot the selected drive");
+ return;
+ }
+ if (!drive.disk) {
+ this.notice("No disk loaded in the selected drive");
+ return;
+ }
+ var err = this.readData(drive, 0, 0, 0, drive.cbSector >> 1, 0);
+ if (err) {
+ this.notice("Unable to read the boot sector (" + err + ")");
+ return;
+ }
+ this.cpu.setReset(0, true);
+};
+
/**
* loadDrive(iDrive, sDiskName, sDiskPath, fAutoMount, file)
*
@@ -639,7 +684,7 @@ RK11.prototype.finishLoadDrive = function onLoadDrive(drive, disk, sDiskName, sD
* With the addition of notify(), users are now "alerted" whenever a disk has finished loading;
* notify() is selective about its output, using print() if a print window is open, alert() otherwise.
*/
- this.notice("Mounted disk \"" + sDiskName + "\" in drive " + this.getDriveName(drive.iDrive), drive.fAutoMount || fAutoMount);
+ this.notice("Loaded disk \"" + sDiskName + "\" in drive " + this.getDriveName(drive.iDrive), drive.fAutoMount || fAutoMount);
/*
* Since you usually want the Computer to have focus again after loading a new disk, let's try automatically
@@ -941,6 +986,7 @@ RK11.prototype.processCommand = function()
case PDP11.RK11.FUNC.WRITE:
if (!sFunc) sFunc = "WRITE";
+ if (!fnReadWrite) fnReadWrite = this.writeData;
iCylinder = (this.regRKDA & PDP11.RK11.RKDA.CA) >> PDP11.RK11.RKDA.SHIFT.CA;
iHead = (this.regRKDA & PDP11.RK11.RKDA.HS) >> PDP11.RK11.RKDA.SHIFT.HS;
@@ -950,8 +996,6 @@ RK11.prototype.processCommand = function()
if (this.messageEnabled()) this.printMessage(this.type + ": " + sFunc + "(" + iCylinder + ":" + iHead + ":" + iSector + ") @" + str.toOct(addr) + "-" + str.toOct(addr + ((nWords - 1) << 1)), true);
- if (!fnReadWrite) fnReadWrite = this.writeData;
-
if (iCylinder >= drive.nCylinders) {
this.regRKER |= PDP11.RK11.RKER.DRE | PDP11.RK11.RKER.NXC;
this.regRKCS |= PDP11.RK11.RKCS.HE | PDP11.RK11.RKCS.ERR;
@@ -1023,9 +1067,9 @@ RK11.prototype.endReadWrite = function(err, iCylinder, iHead, iSector, nWords, a
* @param {number} iSector
* @param {number} nWords
* @param {number} addr
- * @param {boolean} fCheck
- * @param {function(...)} done
- * @return {boolean} true if complete, false if queued
+ * @param {boolean} [fCheck]
+ * @param {function(...)} [done]
+ * @return {boolean|number} true if complete, false if queued (or if no done() is supplied, the error code, if any)
*/
RK11.prototype.readData = function(drive, iCylinder, iHead, iSector, nWords, addr, fCheck, done)
{
@@ -1084,7 +1128,7 @@ RK11.prototype.readData = function(drive, iCylinder, iHead, iSector, nWords, add
}
}
}
- return done(err, iCylinder, iHead, iSector, nWords, addr);
+ return done? done(err, iCylinder, iHead, iSector, nWords, addr) : err;
};
/**
@@ -1097,9 +1141,9 @@ RK11.prototype.readData = function(drive, iCylinder, iHead, iSector, nWords, add
* @param {number} iSector
* @param {number} nWords
* @param {number} addr
- * @param {boolean} fCheck
- * @param {function(...)} done
- * @return {boolean} true if complete, false if queued
+ * @param {boolean} [fCheck]
+ * @param {function(...)} [done]
+ * @return {boolean|number} true if complete, false if queued (or if no done() is supplied, the error code, if any)
*/
RK11.prototype.writeData = function(drive, iCylinder, iHead, iSector, nWords, addr, fCheck, done)
{
@@ -1157,7 +1201,7 @@ RK11.prototype.writeData = function(drive, iCylinder, iHead, iSector, nWords, ad
}
}
}
- return done(err, iCylinder, iHead, iSector, nWords, addr);
+ return done? done(err, iCylinder, iHead, iSector, nWords, addr) : err;
};
/**
diff --git a/modules/pdp11/lib/rl11.js b/modules/pdp11/lib/rl11.js
index f7c60a5d5..1a29c8259 100644
--- a/modules/pdp11/lib/rl11.js
+++ b/modules/pdp11/lib/rl11.js
@@ -67,7 +67,7 @@ function RL11(parms)
* We record any 'autoMount' object now, but we no longer parse it until initBus(),
* because the Computer's getMachineParm() service may have an override for us.
*/
- this.configMount = parms['autoMount'] || {};
+ this.configMount = this.parseConfig(parms['autoMount']);
this.cAutoMount = 0;
/*
@@ -90,6 +90,30 @@ RL11.SOURCE = {
REMOTE: "??"
};
+/**
+ * parseConfig(config)
+ *
+ * @this {RL11}
+ * @param {*} config
+ * @return {*}
+ */
+RL11.prototype.parseConfig = function(config)
+{
+ if (config && typeof config == "string") {
+ try {
+ /*
+ * The most likely source of any exception will be right here, where we're parsing
+ * this JSON-encoded data.
+ */
+ config = eval("(" + config + ")");
+ } catch (e) {
+ Component.error(this.type + " auto-mount error: " + e.message + " (" + config + ")");
+ config = null;
+ }
+ }
+ return config || {};
+};
+
/**
* setBinding(sType, sBinding, control, sValue)
*
@@ -145,7 +169,7 @@ RL11.prototype.setBinding = function(sType, sBinding, control, sValue)
};
return true;
- case "loadDrive":
+ case "loadDisk":
this.bindings[sBinding] = control;
control.onclick = function onClickLoadDrive(event) {
@@ -158,7 +182,15 @@ RL11.prototype.setBinding = function(sType, sBinding, control, sValue)
};
return true;
- case "saveDrive":
+ case "bootDisk":
+ this.bindings[sBinding] = control;
+
+ control.onclick = function onClickBootDisk(event) {
+ rl11.bootSelectedDisk();
+ };
+ return true;
+
+ case "saveDisk":
/*
* Yes, technically, this feature does not require "Local disk support" (which is really a reference
* to FileReader support), but since fLocalDisks is also false for all mobile devices, and since there
@@ -203,7 +235,7 @@ RL11.prototype.setBinding = function(sType, sBinding, control, sValue)
};
return true;
- case "mountDrive":
+ case "mountDisk":
if (!this.fLocalDisks) {
if (DEBUG) this.log("Local disk support not available");
/*
@@ -265,21 +297,7 @@ RL11.prototype.initBus = function(cmp, bus, cpu, dbg)
this.cpu = cpu;
this.dbg = dbg;
- var configMount = this.cmp.getMachineParm('autoMount');
- if (configMount) {
- if (typeof configMount == "string") {
- try {
- /*
- * The most likely source of any exception will be right here, where we're parsing
- * this JSON-encoded data.
- */
- configMount = eval("(" + configMount + ")");
- } catch (e) {
- Component.error(this.type + " auto-mount error: " + e.message + " (" + configMount + ")");
- configMount = null;
- }
- }
- }
+ var configMount = this.parseConfig(this.cmp.getMachineParm('autoMount'));
/*
* Add only drives from the machine-wide autoMount configuration that match drives managed by this component.
@@ -529,6 +547,33 @@ RL11.prototype.loadSelectedDrive = function(sDiskName, sDiskPath, file)
this.loadDrive(iDrive, sDiskName, sDiskPath, false, file);
};
+/**
+ * bootSelectedDisk()
+ *
+ * @this {RL11}
+ */
+RL11.prototype.bootSelectedDisk = function()
+{
+ var drive;
+ var controlDrives = this.bindings["listDrives"];
+ var iDrive = controlDrives && str.parseInt(controlDrives.value, 10);
+
+ if (iDrive == null || iDrive < 0 || iDrive >= this.aDrives.length || !(drive = this.aDrives[iDrive])) {
+ this.notice("Unable to boot the selected drive");
+ return;
+ }
+ if (!drive.disk) {
+ this.notice("No disk loaded in the selected drive");
+ return;
+ }
+ var err = this.readData(drive, 0, 0, 0, drive.cbSector >> 1, 0);
+ if (err) {
+ this.notice("Unable to read the boot sector (" + err + ")");
+ return;
+ }
+ this.cpu.setReset(0, true);
+};
+
/**
* loadDrive(iDrive, sDiskName, sDiskPath, fAutoMount, file)
*
@@ -639,7 +684,7 @@ RL11.prototype.finishLoadDrive = function onLoadDrive(drive, disk, sDiskName, sD
* With the addition of notify(), users are now "alerted" whenever a disk has finished loading;
* notify() is selective about its output, using print() if a print window is open, alert() otherwise.
*/
- this.notice("Mounted disk \"" + sDiskName + "\" in drive " + this.getDriveName(drive.iDrive), drive.fAutoMount || fAutoMount);
+ this.notice("Loaded disk \"" + sDiskName + "\" in drive " + this.getDriveName(drive.iDrive), drive.fAutoMount || fAutoMount);
/*
* Since you usually want the Computer to have focus again after loading a new disk, let's try automatically
@@ -901,8 +946,8 @@ RL11.prototype.initDrive = function(drive, iDrive, data)
*/
RL11.prototype.processCommand = function()
{
- var fnReadWrite;
var fInterrupt = true;
+ var fnReadWrite, sFunc = "";
var iDrive = (this.regRLCS & PDP11.RL11.RLCS.DS) >> PDP11.RL11.RLCS.SHIFT.DS;
var drive = this.aDrives[iDrive];
var disk = drive.disk;
@@ -954,11 +999,14 @@ RL11.prototype.processCommand = function()
break;
case PDP11.RL11.FUNC.RDATA:
+ sFunc = "READ";
fnReadWrite = this.readData;
/* falls through */
case PDP11.RL11.FUNC.WDATA:
+ if (!sFunc) sFunc = "WRITE";
if (!fnReadWrite) fnReadWrite = this.writeData;
+
iCylinder = this.regRLDA >> PDP11.RL11.RLDA.SHIFT.RW_CA;
iHead = (this.regRLDA & PDP11.RL11.RLDA.RW_HS)? 1 : 0;
iSector = this.regRLDA & PDP11.RL11.RLDA.RW_SA;
@@ -966,12 +1014,11 @@ RL11.prototype.processCommand = function()
this.regRLCS |= PDP11.RL11.ERRC.HNF | PDP11.RL11.RLCS.ERR;
break;
}
- addr = (((this.regRLBE & PDP11.RL11.RLBE.MASK)) << 16) | this.regRLBA; // 22 bit mode
nWords = (0x10000 - this.regRLMP) & 0xffff;
- var pos = ((((iCylinder << 1) + iHead) * drive.nSectors) + iSector) * 128;
- if (DEBUG && (this.messageEnabled(MessagesPDP11.READ) || this.messageEnabled(MessagesPDP11.WRITE))) {
- console.log((fnReadWrite == this.readData? "readData" : "writeData") + "(pos=" + pos + ",addr=" + str.toOct(addr) + ",bytes=" + (nWords * 2) + ")");
- }
+ addr = (((this.regRLBE & PDP11.RL11.RLBE.MASK)) << 16) | this.regRLBA; // 22 bit mode
+
+ if (this.messageEnabled()) this.printMessage(this.type + ": " + sFunc + "(" + iCylinder + ":" + iHead + ":" + iSector + ") @" + str.toOct(addr) + "-" + str.toOct(addr + ((nWords - 1) << 1)), true);
+
fInterrupt = fnReadWrite.call(this, drive, iCylinder, iHead, iSector, nWords, addr, this.endReadWrite.bind(this));
break;
@@ -1021,8 +1068,8 @@ RL11.prototype.endReadWrite = function(err, iCylinder, iHead, iSector, nWords, a
* @param {number} iSector
* @param {number} nWords
* @param {number} addr
- * @param {function(...)} done
- * @return {boolean} true if complete, false if queued
+ * @param {function(...)} [done]
+ * @return {boolean|number} true if complete, false if queued (or if no done() is supplied, the error code, if any)
*/
RL11.prototype.readData = function(drive, iCylinder, iHead, iSector, nWords, addr, done)
{
@@ -1091,7 +1138,7 @@ RL11.prototype.readData = function(drive, iCylinder, iHead, iSector, nWords, add
console.log("checksum: " + (checksum|0));
}
- return done(err, iCylinder, iHead, iSector, nWords, addr);
+ return done? done(err, iCylinder, iHead, iSector, nWords, addr) : err;
};
/**
@@ -1104,8 +1151,8 @@ RL11.prototype.readData = function(drive, iCylinder, iHead, iSector, nWords, add
* @param {number} iSector
* @param {number} nWords
* @param {number} addr
- * @param {function(...)} done
- * @return {boolean} true if complete, false if queued
+ * @param {function(...)} [done]
+ * @return {boolean|number} true if complete, false if queued (or if no done() is supplied, the error code, if any)
*/
RL11.prototype.writeData = function(drive, iCylinder, iHead, iSector, nWords, addr, done)
{
@@ -1173,7 +1220,7 @@ RL11.prototype.writeData = function(drive, iCylinder, iHead, iSector, nWords, ad
console.log("checksum: " + (checksum|0));
}
- return done(err, iCylinder, iHead, iSector, nWords, addr);
+ return done? done(err, iCylinder, iHead, iSector, nWords, addr) : err;
};
/**
diff --git a/pubs/pc/programming/Graphics_for_the_IBM_PC/demos/basic.xml b/pubs/pc/programming/Graphics_for_the_IBM_PC/demos/basic.xml
index 4d534c534..fef99abac 100644
--- a/pubs/pc/programming/Graphics_for_the_IBM_PC/demos/basic.xml
+++ b/pubs/pc/programming/Graphics_for_the_IBM_PC/demos/basic.xml
@@ -9,7 +9,7 @@
BASIC Programs
-
Load
+
Load
-
+