Numerous changes to make paper tape configurations more consistent with disk configurations. This allows all devices to share the machine-wide "autoMount" configuration object, now that the PC11 has a proper device name ("PTR"), making its properties distinguishable from those for RK11 and RL11 drives (eg, "RK0", "RL0", etc). And all the tape/disk components now use "Load" functions to connect a tape or disk to a device ("Attach" is deprecated). And finally, all tape/disk components now support operations to deposit their media directly into memory -- although in this case, the names of the operations are necessarily different: "Read" for tape images, "Boot" for disk images. The difference is partly historical convention but also reflects the fact that a "Boot" operation is more limited: paper tapes were designed to be completely loaded into memory, whereas bootable disks are designed for only the first sector to be loaded and executed. Also, paper tape images are now flagged as non-auto-starting, because they often require some user action (eg, loading another tape, setting some switches, etc), whereas disk boot sectors are flagged as auto-starting (see the fStart parameter of the loadImage() interface in the RAM component).

This commit is contained in:
Jeff Parsons 2016-12-03 14:49:51 -08:00 committed by Jeff Parsons
commit b54253acf9
41 changed files with 383 additions and 211 deletions

View file

@ -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");
/*

View file

@ -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 + "...");

View file

@ -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

View file

@ -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();
}
}
};

View file

@ -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);
};

View file

@ -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;
};

View file

@ -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;
};
/**

View file

@ -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;
};
/**