Skip to content
This repository has been archived by the owner on Dec 24, 2020. It is now read-only.

Commit

Permalink
Integrated CD-ROM disk control with FDC diskette control to provide g…
Browse files Browse the repository at this point in the history
…eneral-purpose removable media control
  • Loading branch information
jeffpar committed May 25, 2019
1 parent 802cb3b commit eda9847
Show file tree
Hide file tree
Showing 21 changed files with 893 additions and 571 deletions.
2 changes: 1 addition & 1 deletion disks-cds/cds001
13 changes: 8 additions & 5 deletions disks/pcx86/cpm/1.1b/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,18 @@ This is an OEM version of CP/M-86 by Eagle Computer. On startup, it reports:

Eagle CP/M-86 Ver 1.1B 05/20/83

The PCjs Disk Archives include the two Eagle Computer distribution diskettes, along with two related disks from our
private collection that contain [Useful CP/M-86 Utilities](#useful-cpm-86-utilities). [Directory Listings](#directory-listings)
are provided below.
The [PCjs Disk Library](/disks/pcx86/) includes the two Eagle Computer distribution diskettes,
along with two related disks from our private collection:

The machine below is also available with a [Debugger](debugger/).
- [PCjs CP/M-86 (Disk 1)](#directory-of-pcjs-cpm-86-disk-1)
- [PCjs CP/M-86 (Disk 2)](#directory-of-pcjs-cpm-86-disk-2)

which contain assorted [Useful CP/M-86 Utilities](#useful-cpm-86-utilities). [Directory Listings](#directory-listings) are provided below.

{% include machine.html id="cpm-mda-256k" %}

The above machine is also available with a [Debugger](debugger/).

Directory Listings
------------------

Expand Down Expand Up @@ -208,4 +212,3 @@ Useful CP/M-86 Utilities

8086/8088 WORDMASTER Release 1.00 serial # WM9999XX
COPYRIGHT (C) 1981 MICROPRO INTERNATIONAL CORPORATION

6 changes: 5 additions & 1 deletion disks/pcx86/drives/cdrom/machine.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@
<debugger id="debugger" messages="fault" commands=""/>
<panel ref="/devices/pcx86/panel/wide.xml"/>
<hdc ref="/disks/pcx86/drives/20mb/pcdos330-empty-at2.xml"/>
<hdc id="cdrom" type="ATAPI" drives='[{name:"CD-ROM"}]'/>
<hdc id="cdrom" type="ATAPI" drives='[{name:"CD",path:"/disks-cds/cds001/microsoft/leisure/PandorasBox/cdrom"}]'>
<control type="list" binding="listDisks" style="display:none">
<disk path="/disks-cds/cds001/microsoft/leisure/PandorasBox/cdrom">Pandora's Box</disk>
</control>
</hdc>
<chipset id="chipset" model="5170" floppies="[1440,1200]"/>
<serial id="com1" adapter="1"/>
<serial id="com2" adapter="2" binding="print"/>
Expand Down
7 changes: 6 additions & 1 deletion modules/devices/led.js
Original file line number Diff line number Diff line change
Expand Up @@ -1283,8 +1283,13 @@ LED.SYMBOL_SEGMENTS = {
'7': ['A','B','C'],
'8': ['A','B','C','D','E','F','G'],
'9': ['A','B','C','D','F','G'],
'-': ['G'],
'A': ['A','B','C','E','F','G'],
'B': ['C','D','E','F','G'], // NOTE: this shape is a lower-case 'b', but 'B' must be distinguishable from '8'
'C': ['A','D','E','F'],
'D': ['B','C','D','E','G'], // NOTE: this shape is a lower-case 'd', but 'D' must be distinguishable from '0'
'E': ['A','D','E','F','G'],
'F': ['A','E','F','G'],
'-': ['G'],
'.': ['P']
};

Expand Down
131 changes: 124 additions & 7 deletions modules/pcx86/lib/fdc.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,14 @@ class FDC extends Component {
*/
this.fLocalDisks = (!Web.isMobile() && window && 'FileReader' in window);

/*
* If the HDC component is configured for removable discs (ie, if it's configured as a CD-ROM drive),
* it may prefer to overload our drive control for easier disc selection, in which case this will contain
* drive name properties mapped to external disc lists.
*/
this.externalDrives = {};
this.externalActive = null;

/*
* The remainder of FDC initialization now takes place in our initBus() handler, largely because we
* want initController() to have access to the ChipSet component, so that it can query switches and/or CMOS
Expand Down Expand Up @@ -337,7 +345,12 @@ class FDC extends Component {
case "loadDisk":
this.bindings[sBinding] = control;
control.onclick = function onClickLoadDisk(event) {
fdc.loadSelectedDisk();
if (!fdc.externalActive) {
fdc.loadSelectedDisk();
} else {
let externalDrive = fdc.externalDrives[fdc.externalActive];
externalDrive.controller.loadSelectedDisk(externalDrive.iDrive, externalDrive.controlDisks);
}
};
return true;

Expand Down Expand Up @@ -598,6 +611,20 @@ class FDC extends Component {
if (!fPowerUp) this.resetDriveList();
}

/**
* addDrive(name, iDrive, controller, controlDisks)
*
* @this {FDC}
* @param {string} name
* @param {number} iDrive
* @param {Component} controller
* @param {HTMLSelectElement} controlDisks
*/
addDrive(name, iDrive, controller, controlDisks)
{
this.externalDrives[name] = {iDrive, controller, controlDisks};
}

/**
* resetDriveList()
*
Expand All @@ -613,8 +640,9 @@ class FDC extends Component {
while (controlDrives.firstChild) {
controlDrives.removeChild(controlDrives.firstChild);
}
let iDrive = 0;
controlDrives.value = "";
for (let iDrive = 0; iDrive < this.nDrives; iDrive++) {
while (iDrive < this.nDrives) {
let controlOption = document.createElement("option");
controlOption.value = iDrive.toString();
controlOption.text = String.fromCharCode(0x41 + iDrive) + ":";
Expand All @@ -627,6 +655,14 @@ class FDC extends Component {
controlOption.text = String.fromCharCode(0x41 + iDrive) + "*";
controlOption.title = "write-protected"; // NOTE: this "tooltip" attribute does not work on all browsers (eg, Chrome)
controlDrives.appendChild(controlOption);
iDrive++;
}
for (let name in this.externalDrives) {
let controlOption = document.createElement("option");
controlOption.value = iDrive.toString();
controlOption.text = name;
controlDrives.appendChild(controlOption);
iDrive++;
}
if (this.nDrives > 0) {
controlDrives.value = "0";
Expand Down Expand Up @@ -1540,6 +1576,90 @@ class FDC extends Component {
return "";
}

/**
* getDiskList(controlDrives)
*
* In "the old days", the HTML control containing the list of all available diskettes was stored in:
*
* this.bindings["listDisks"]
*
* and it still is. But now, if the HDC component decides to overload our drive list with one or more
* of its own drives (eg, "CD"), then our drive/diskette controls must be thought of as general-purpose
* "Removable Media" controls that the FDC just happens to manage for historical reasons. This avoids
* cluttering the UI with multiple drop-downs when there are multiple types of removable disk drives.
*
* To detect that situation, the name of the selected drive must be checked against the list of external
* drives, and if there's a match, then we "swap" the disks control normally used by the FDC with the one
* provided by the HDC; similarly, if there's no longer a match BUT externalActive is set, when we know
* that a swap is still active and that we must "unswap" them, putting the FDC's original diskette control
* back in place.
*
* TODO: It would be nice to generalize this someday, and support separate diskette lists for separate
* diskette drive types; for example, if a machine wants to have a 1.2Mb floppy drive for A: and a 360Kb
* or 1.44Mb floppy drive for B:, it would be nice to have the diskettes segregated by type as well.
* The FDC will try to alert you whenever you attempt to mount a diskette in a drive that can't support it,
* but it would be even better if those diskette images weren't listed for that drive in the first place.
*
* @this {FDC}
* @param {HTMLSelectElement} controlDrives
* @return {HTMLSelectElement|undefined}
*/
getDiskList(controlDrives)
{
let controlDisks1, controlDisks2;
if (controlDrives && controlDrives.options) {
controlDisks1 = this.bindings["listDisks"];
let option = controlDrives.options[controlDrives.selectedIndex];
if (option) {
let driveName = option.textContent;
if (this.externalDrives[driveName]) {
if (!this.externalActive) {
controlDisks2 = this.externalDrives[driveName].controlDisks;
this.externalActive = driveName;
}
} else {
if (this.externalActive) {
controlDisks2 = controlDisks1;
controlDisks1 = this.externalDrives[this.externalActive].controlDisks;
this.externalActive = null;
}
}
}
}
if (controlDisks1 && controlDisks2) {
// swap controlDisks1 and controlDisks2
// save the location of controlDisks2
let next2 = controlDisks2.nextSibling;
let parent2 = controlDisks2.parentNode;
// special case for controlDisks1 is the next sibling of controlDisks2
if (next2 === controlDisks1) {
// just put controlDisks1 before controlDisks2
parent2.insertBefore(controlDisks1, controlDisks2);
} else {
// insert controlDisks2 right before controlDisks1
controlDisks1.parentNode.insertBefore(controlDisks2, controlDisks1);
// now insert controlDisks1 where controlDisks2 was
if (next2) {
// if there was an element after controlDisks2, then insert controlDisks1 right before that
parent2.insertBefore(controlDisks1, next2);
} else {
// otherwise, just append as last child
parent2.appendChild(controlDisks1);
}
}
/*
* Propagate the actual width (scrollWidth) of the currently visible control to the control we're about
* to make visible in its place, so that there's no detectable change in the overall layout.
*/
controlDisks2.style.width = controlDisks1.scrollWidth + "px";
controlDisks1.style.display = "none";
controlDisks2.style.display = "inline-block";
controlDisks1 = controlDisks2;
}
if (!controlDisks1.options) controlDisks1 = undefined;
return controlDisks1;
}

/**
* displayDiskette(iDrive, fDriveChange)
*
Expand All @@ -1554,12 +1674,9 @@ class FDC extends Component {
*/
if (iDrive >= 0 && iDrive < this.aDrives.length) {
let drive = this.aDrives[iDrive];
let controlDisks = this.bindings["listDisks"];
let controlDrives = this.bindings["listDrives"];
/*
* Next, make sure controls for both drives and disks exist.
*/
if (controlDisks && controlDrives && controlDisks.options && controlDrives.options) {
let controlDisks = this.getDiskList(controlDrives);
if (controlDisks) {
/*
* Next, make sure the drive whose disk we're updating is the currently selected drive.
*/
Expand Down
27 changes: 26 additions & 1 deletion modules/pcx86/lib/hdc.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@ class HDC extends Component {

switch (sBinding) {

case "listDisks":
this.bindings[sBinding] = control;
break;

case "saveHD0":
case "saveHD1":
/*
Expand Down Expand Up @@ -316,6 +320,14 @@ class HDC extends Component {
this.iDriveTypeDefault = 2;
}

this.fdc = cmp.getMachineComponent("FDC");
if (this.fdc && this.bindings["listDisks"]) {
for (let iDrive = 0; iDrive < this.aDriveConfigs.length; iDrive++) {
let driveConfig = this.aDriveConfigs[iDrive];
this.fdc.addDrive(driveConfig['name'], iDrive, this, this.bindings["listDisks"]);
}
}

cpu.addIntNotify(Interrupts.DISK, this.intBIOSDisk.bind(this));
cpu.addIntNotify(Interrupts.ALT_DISK, this.intBIOSDiskette.bind(this));

Expand Down Expand Up @@ -973,6 +985,19 @@ class HDC extends Component {
return false;
}

/**
* loadSelectedDisk(iDrive, controlDisks)
*
* @this {HDC}
* @param {number} iDrive
* @param {HTMLSelectElement} controlDisks
*/
loadSelectedDisk(iDrive, controlDisks)
{
let drive = this.aDrives[iDrive];
drive.path = controlDisks.options[controlDisks.selectedIndex].value;
}

/**
* doneLoadDisk(drive, disk, sDiskName, sDiskPath)
*
Expand Down Expand Up @@ -2699,7 +2724,7 @@ class HDC extends Component {
};
let readChunk = function(iChunk, offChunk, lenChunk, offBuffer) {
nChunks++;
Web.getResource(Str.sprintf("/disks-cds/cds001/microsoft/leisure/MSLEISURE-CD001-PANDORA/x%05d", iChunk), "arraybuffer", true, function(url, data, error) {
Web.getResource(Str.sprintf("%s/x%05d", drive.path, iChunk), "arraybuffer", true, function(url, data, error) {
if (data) {
let bytes = new Uint8Array(data);
while (offChunk < bytes.byteLength && lenChunk--) {
Expand Down
7 changes: 6 additions & 1 deletion versions/devices/1.20/leds-uncompiled.js
Original file line number Diff line number Diff line change
Expand Up @@ -3219,8 +3219,13 @@ LED.SYMBOL_SEGMENTS = {
'7': ['A','B','C'],
'8': ['A','B','C','D','E','F','G'],
'9': ['A','B','C','D','F','G'],
'-': ['G'],
'A': ['A','B','C','E','F','G'],
'B': ['C','D','E','F','G'], // NOTE: this shape is a lower-case 'b', but 'B' must be distinguishable from '8'
'C': ['A','D','E','F'],
'D': ['B','C','D','E','G'], // NOTE: this shape is a lower-case 'd', but 'D' must be distinguishable from '0'
'E': ['A','D','E','F','G'],
'F': ['A','E','F','G'],
'-': ['G'],
'.': ['P']
};

Expand Down
3 changes: 2 additions & 1 deletion versions/devices/1.20/leds.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion versions/devices/1.20/leds.js.map

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion versions/devices/1.20/ti42-uncompiled.js
Original file line number Diff line number Diff line change
Expand Up @@ -3219,8 +3219,13 @@ LED.SYMBOL_SEGMENTS = {
'7': ['A','B','C'],
'8': ['A','B','C','D','E','F','G'],
'9': ['A','B','C','D','F','G'],
'-': ['G'],
'A': ['A','B','C','E','F','G'],
'B': ['C','D','E','F','G'], // NOTE: this shape is a lower-case 'b', but 'B' must be distinguishable from '8'
'C': ['A','D','E','F'],
'D': ['B','C','D','E','G'], // NOTE: this shape is a lower-case 'd', but 'D' must be distinguishable from '0'
'E': ['A','D','E','F','G'],
'F': ['A','E','F','G'],
'-': ['G'],
'.': ['P']
};

Expand Down
Loading

0 comments on commit eda9847

Please sign in to comment.