New ChipSet parameter ('floppies') used to specify number and capacity of installed floppy drives
This commit is contained in:
parent
c33afed14c
commit
ae6dc3bd12
122 changed files with 923 additions and 853 deletions
|
|
@ -51,9 +51,9 @@ if (typeof module !== 'undefined') {
|
|||
* sw2: 8-character binary string representing the SW2 DIP switches (SW2[1-8]) (MODEL_5150 only)
|
||||
* sound: true to enable (experimental) sound support (default); false to disable
|
||||
* scaleTimers: true to divide timer cycle counts by the CPU's cycle multiplier (default is false)
|
||||
* fdrives: 0-4 floppy drives (default is 2 if no sw1 value provided)
|
||||
* monitor: none|tv|color|mono (default is mono if no sw1 value provided)
|
||||
* rtcDate: optional RTC date to be used on resets; use the ISO 8601 format; eg: "2014-10-01T08:00:00-0700"
|
||||
* floppies: array of floppy drive sizes in Kb (default is "[360, 360]" if no sw1 value provided)
|
||||
* monitor: none|tv|color|mono (if no sw1 value provided, default is "ega" for 5170, "mono" otherwise)
|
||||
* rtcDate: optional RTC date/time (in GMT) to use on reset; use the ISO 8601 format; eg: "2014-10-01T08:00:00"
|
||||
*
|
||||
* The conventions used for the sw1 and sw2 strings are that the left-most character represents DIP switch [1],
|
||||
* the right-most character represents DIP switch [8], and "1" means the DIP switch is ON and "0" means it is OFF.
|
||||
|
|
@ -155,7 +155,7 @@ function ChipSet(parmsChipSet)
|
|||
/*
|
||||
* SW1 describes the number of floppy drives, the amount of base memory, the primary monitor type,
|
||||
* and (on the MODEL_5160) whether or not a coprocessor is installed. If no SW1 settings are provided,
|
||||
* we look for individual 'fdrives' and 'monitor' settings and build a default SW1 value.
|
||||
* we look for individual 'floppies' and 'monitor' settings and build a default SW1 value.
|
||||
*
|
||||
* The defaults below select max memory, monochrome monitor (EGA monitor for MODEL_5170), and two floppies.
|
||||
* Don't get too excited about "max memory" either: on a MODEL_5150, the max was 64Kb, and on a MODEL_5160,
|
||||
|
|
@ -171,7 +171,10 @@ function ChipSet(parmsChipSet)
|
|||
if (sw1) {
|
||||
this.sw1Init = this.parseSwitches(sw1, ChipSet.PPI_SW.MEMORY.X4 | ChipSet.PPI_SW.MONITOR.MONO);
|
||||
} else {
|
||||
var nDrives = parmsChipSet['fdrives'] || 2;
|
||||
this.aFloppyDrives = [360, 360];
|
||||
var aFloppyDrives = parmsChipSet['floppies'];
|
||||
if (aFloppyDrives && aFloppyDrives.length !== undefined) this.aFloppyDrives = aFloppyDrives;
|
||||
var nDrives = this.aFloppyDrives.length;
|
||||
if (nDrives) {
|
||||
this.sw1Init |= ChipSet.PPI_SW.FDRIVE.IPL;
|
||||
nDrives--;
|
||||
|
|
@ -806,8 +809,16 @@ ChipSet.CMOS = {
|
|||
D0_MASK: 0xF0, // Drive 0 type in high nibble
|
||||
D1_MASK: 0x0F, // Drive 1 type in lower nibble
|
||||
NONE: 0, // no drive
|
||||
DSDD: 1, // double-sided double-density drive (48 TPI, 40 tracks, 360Kb max)
|
||||
DSHD: 2 // double-sided high-density drive (96 TPI, 80 tracks, 1.2Mb max)
|
||||
/*
|
||||
* There's at least one floppy drive type that IBM didn't bother defining a CMOS drive type for:
|
||||
* single-sided drives that were only capable of storing 160Kb (or 180Kb when using 9 sectors/track).
|
||||
* So, as you can see in getSWFloppyDriveType(), we lump all standard diskette capacities <= 360Kb
|
||||
* into the FD360 bucket.
|
||||
*/
|
||||
FD360: 1, // 5.25-inch double-sided double-density (DSDD 48TPI) drive: 40 tracks, 9 sectors/track, 360Kb max
|
||||
FD1200: 2, // 5.25-inch double-sided high-density (DSHD 96TPI) drive: 80 tracks, 15 sectors/track, 1200Kb max
|
||||
FD720: 3, // 3.5-inch drive capable of storing 80 tracks and up to 9 sectors/track, 720Kb max
|
||||
FD1440: 4 // 3.5-inch drive capable of storing 80 tracks and up to 18 sectors/track, 1440Kb max
|
||||
},
|
||||
/*
|
||||
* HDRIVE types are defined by table in the HDC component, which uses setCMOSDriveType() to update the CMOS
|
||||
|
|
@ -1129,14 +1140,17 @@ ChipSet.prototype.initRTCDate = function(sDate)
|
|||
/*
|
||||
* Example of a valid Date string:
|
||||
*
|
||||
* 2014-10-01T08:00:00-0700
|
||||
* 2014-10-01T08:00:00 (interpreted as GMT, resulting in "Wed Oct 01 2014 01:00:00 GMT-0700 (PDT)")
|
||||
*
|
||||
* Example of an INVALID Date string:
|
||||
* Examples of INVALID Date strings:
|
||||
*
|
||||
* 2014-10-01T08:00:00PST
|
||||
* 2014-10-01T08:00:00-0700 (actually, this DOES work in Chrome, but NOT in Safari)
|
||||
*
|
||||
* In the second example, the Date object is invalid, but it wasn't obvious (to me) how to detect that.
|
||||
* So here's a test from StackOverflow (http://stackoverflow.com/questions/1353684/detecting-an-invalid-date-date-instance-in-javascript).
|
||||
* In the case of INVALID Date strings, the Date object is invalid, but there's no obvious test for an "invalid"
|
||||
* object, so I've adapted the following test from StackOverflow.
|
||||
*
|
||||
* See http://stackoverflow.com/questions/1353684/detecting-an-invalid-date-date-instance-in-javascript
|
||||
*/
|
||||
if (Object.prototype.toString.call(date) !== "[object Date]" || isNaN(date.getTime())) {
|
||||
date = new Date();
|
||||
|
|
@ -1398,9 +1412,11 @@ ChipSet.prototype.addCMOSMemory = function(addr, size)
|
|||
*
|
||||
* For use by the HDC component, to update the CMOS drive configuration to match HDC's internal configuration.
|
||||
*
|
||||
* TODO: Extend this to support FDC drive updates, so that FDC can eventually specify diskette drive types
|
||||
* (ie, DSDD or DSHD) in the same way that HDC does; currently, MODEL_5170 diskette drives always default to DSHD
|
||||
* (see getSWFloppyDriveType()).
|
||||
* TODO: Consider extending this to support FDC drive updates, so that the FDC can specify diskette drive types
|
||||
* (ie, FD360 or FD1200) in the same way that HDC does. However, historically, the ChipSet has been responsible for
|
||||
* floppy drive configuration, at least in terms of *number* of drives, through the use of SW1 settings, and we've
|
||||
* continued that tradition with the addition of the ChipSet 'floppies' parameter, which allows both the number *and*
|
||||
* capacity of drives to be specified with a simple array (eg, [360, 360] for two 360Kb drives).
|
||||
*
|
||||
* @this {ChipSet}
|
||||
* @param {number} iDrive
|
||||
|
|
@ -1806,19 +1822,55 @@ ChipSet.prototype.getSWFloppyDrives = function(fInit)
|
|||
*
|
||||
* @this {ChipSet}
|
||||
* @param {number} iDrive (0-based)
|
||||
* @return {number} one of the ChipSet.CMOS.FDRIVE values (ie, NONE: 0, DSDD: 1, DSHD: 2)
|
||||
* @return {number} one of the ChipSet.CMOS.FDRIVE.FD* values (FD360, FD1200, etc)
|
||||
*/
|
||||
ChipSet.prototype.getSWFloppyDriveType = function(iDrive)
|
||||
{
|
||||
/*
|
||||
* TODO: For MODEL_5170, we default all floppy drive types to DSHD, but more control would be nice.
|
||||
*/
|
||||
if (iDrive < this.getSWFloppyDrives()) {
|
||||
return (this.model < ChipSet.MODEL_5170? ChipSet.CMOS.FDRIVE.DSDD : ChipSet.CMOS.FDRIVE.DSHD);
|
||||
if (!this.aFloppyDrives) {
|
||||
return ChipSet.CMOS.FDRIVE.FD360;
|
||||
}
|
||||
if (iDrive < this.aFloppyDrives.length) {
|
||||
switch(this.aFloppyDrives[iDrive]) {
|
||||
case 160:
|
||||
case 180:
|
||||
case 320:
|
||||
case 360:
|
||||
return ChipSet.CMOS.FDRIVE.FD360;
|
||||
case 720:
|
||||
return ChipSet.CMOS.FDRIVE.FD720;
|
||||
case 1200:
|
||||
return ChipSet.CMOS.FDRIVE.FD1200;
|
||||
case 1440:
|
||||
return ChipSet.CMOS.FDRIVE.FD1440;
|
||||
}
|
||||
}
|
||||
Component.assert(false); // we should never get here (else something is out of out sync)
|
||||
}
|
||||
return ChipSet.CMOS.FDRIVE.NONE;
|
||||
};
|
||||
|
||||
/**
|
||||
* getSWFloppyDriveSize(iDrive)
|
||||
*
|
||||
* @this {ChipSet}
|
||||
* @param {number} iDrive (0-based)
|
||||
* @return {number} capacity of drive in Kb (eg, 360, 1200, 1440, etc), or 0 if none
|
||||
*/
|
||||
ChipSet.prototype.getSWFloppyDriveSize = function(iDrive)
|
||||
{
|
||||
if (iDrive < this.getSWFloppyDrives()) {
|
||||
if (!this.aFloppyDrives) {
|
||||
return 360;
|
||||
}
|
||||
if (iDrive < this.aFloppyDrives.length) {
|
||||
return this.aFloppyDrives[iDrive];
|
||||
}
|
||||
Component.assert(false); // we should never get here (else something is out of out sync)
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* getSWVideoMonitor(fInit)
|
||||
*
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ function Computer(parmsComputer, parmsMachine, fSuspended) {
|
|||
}
|
||||
}
|
||||
|
||||
this.println("PREFETCH: " + PREFETCH + ", TYPEDARRAYS: " + TYPEDARRAYS);
|
||||
if (DEBUG) this.println("PREFETCH: " + PREFETCH + ", TYPEDARRAYS: " + TYPEDARRAYS);
|
||||
|
||||
/*
|
||||
* Iterate through all the components again and call their initBus() handler, if any
|
||||
|
|
|
|||
|
|
@ -4203,7 +4203,8 @@ if (DEBUGGER) {
|
|||
return;
|
||||
}
|
||||
this.cpu.updateCPU();
|
||||
this.println("updated registers:");
|
||||
this.println("\nupdated registers:");
|
||||
fCompact = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -742,19 +742,34 @@ FDC.prototype.initController = function(data)
|
|||
var drive = this.aDrives[iDrive];
|
||||
if (drive === undefined) {
|
||||
/*
|
||||
* The first time each drive is initialized, obtain its type (from switches or CMOS) and the physical limits
|
||||
* of the drive (ie, max tracks and max sectors/track). As for max heads, initDrive() assumes that all drives
|
||||
* have two heads, and in any case, there's no way to configure/specify a single-sided floppy drive.
|
||||
*
|
||||
* TODO: Provide a configuration option for single-sided drives, in case someone really wants to simulate that.
|
||||
* The first time each drive is initialized, we query its capacity (based on switches or CMOS) and set
|
||||
* the drive's physical limits accordingly (ie, max tracks, max heads, and max sectors/track).
|
||||
*/
|
||||
drive = this.aDrives[iDrive] = {};
|
||||
drive.bType = this.chipset.getSWFloppyDriveType(iDrive);
|
||||
drive.nCylinders = 40;
|
||||
drive.nSectors = 9;
|
||||
if (drive.bType == ChipSet.CMOS.FDRIVE.DSHD) {
|
||||
var nKb = (this.chipset? this.chipset.getSWFloppyDriveSize(iDrive) : 0);
|
||||
switch(nKb) {
|
||||
case 160:
|
||||
case 180:
|
||||
drive.nHeads = 1; // required for single-sided drives only (all others default to double-sided)
|
||||
/* falls through */
|
||||
case 320:
|
||||
case 360:
|
||||
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
|
||||
break;
|
||||
case 720:
|
||||
drive.nCylinders = 80;
|
||||
drive.nSectors = 18; // 15 for 1.2Mb diskettes, 18 for 1.44Mb diskettes, 8/9 for everything else
|
||||
drive.nSectors = 9;
|
||||
break;
|
||||
case 1200:
|
||||
drive.nCylinders = 80;
|
||||
drive.nSectors = 15;
|
||||
break;
|
||||
case 1440:
|
||||
drive.nCylinders = 80;
|
||||
drive.nSectors = 18;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!this.initDrive(drive, iDrive, dataDrives[iDrive])) {
|
||||
|
|
@ -1194,8 +1209,8 @@ FDC.prototype.mountDiskette = function(drive, disk, sDisketteName, sDiskettePath
|
|||
|
||||
if (disk) {
|
||||
/*
|
||||
* We shouldn't mount the diskette unless the drive is able to handle it; for example, DSDD (40-track)
|
||||
* drives cannot read DSHD (80-track) diskettes. However, I no longer require that the diskette's
|
||||
* We shouldn't mount the diskette unless the drive is able to handle it; for example, FD360 (40-track)
|
||||
* drives cannot read FD1200 (80-track) diskettes. However, I no longer require that the diskette's
|
||||
* sectors/track fall within the drive's standard maximum, because XDF diskettes use 19 physical sectors/track
|
||||
* on the first cylinder (1 more than the typical 18 sectors/track found on 1.44Mb diskettes) but declare
|
||||
* a larger logical size (23 512-byte sectors/track) to reflect the actual capacity of XDF tracks beyond the
|
||||
|
|
@ -1459,7 +1474,7 @@ FDC.prototype.outFDCOutput = function(port, bOut, addrFrom)
|
|||
* MODEL_5170 boot code. Here's why:
|
||||
*
|
||||
* Unlike previous models, the MODEL_5170 BIOS probes all installed diskette drives to determine drive type;
|
||||
* ie, DSDD (40-track) or DSHD (80-track). So if there are two drives, the last selected drive will be drive 1.
|
||||
* ie, FD360 (40-track) or FD1200 (80-track). So if there are two drives, the last selected drive will be drive 1.
|
||||
* Immediately before booting, the BIOS issues an INT 0x13/AH=0 reset, which writes regOutput two times: first
|
||||
* with FDC.REG_OUTPUT.ENABLE clear, and then with it set. However, both times, it ALSO loads the last selected
|
||||
* drive number into regOutput's "drive select" bits.
|
||||
|
|
|
|||
|
|
@ -48,7 +48,8 @@ if (typeof module !== 'undefined') {
|
|||
*
|
||||
* The HDC component simulates an STC-506/412 interface to an IBM-compatible fixed disk drive. The first
|
||||
* such drive was a 10Mb 5.25-inch drive containing two platters and 4 heads. Data spanned 306 cylinders
|
||||
* for a total of 1224 tracks, with 17 sectors/track and 512 bytes/sector.
|
||||
* for a total of 1224 tracks, with 17 sectors/track and 512 bytes/sector. Support has since been expanded
|
||||
* to include the original PC AT Western Digital controller.
|
||||
*
|
||||
* HDC supports the following component-specific properties:
|
||||
*
|
||||
|
|
@ -90,7 +91,7 @@ function HDC(parmsHDC) {
|
|||
try {
|
||||
/*
|
||||
* The most likely source of any exception will be right here, where we're parsing
|
||||
* the JSON-encoded disk data.
|
||||
* the JSON-encoded drive data.
|
||||
*/
|
||||
this.aDriveConfigs = eval("(" + parmsHDC['drives'] + ")");
|
||||
/*
|
||||
|
|
@ -202,7 +203,7 @@ HDC.aDriveTypes = [
|
|||
*
|
||||
* Without the "DUAL" bit set, when it came time later to report the diskette drive type, the "DISK_TYPE" function
|
||||
* (@F000:273D) would branch to one of two almost-identical blocks of code -- specifically, a block that disallowed
|
||||
* diskette drive types >= 2 (ChipSet.CMOS.FDRIVE.DSDD) instead of >= 3 (ChipSet.CMOS.FDRIVE.DSHD).
|
||||
* diskette drive types >= 2 (ChipSet.CMOS.FDRIVE.FD360) instead of >= 3 (ChipSet.CMOS.FDRIVE.FD1200).
|
||||
*
|
||||
* In other words, the "Fixed Disk" portion of the HFCOMBO controller has to be present and operational if the user
|
||||
* wants to use high-capacity (80-track) diskettes with "Diskette Drive" portion of the controller. This may not be
|
||||
|
|
|
|||
|
|
@ -571,10 +571,10 @@
|
|||
<xsl:otherwise>false</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="fdrives">
|
||||
<xsl:variable name="floppies">
|
||||
<xsl:choose>
|
||||
<xsl:when test="@fdrives"><xsl:value-of select="@fdrives"/></xsl:when>
|
||||
<xsl:otherwise>0</xsl:otherwise>
|
||||
<xsl:when test="@floppies"><xsl:value-of select="@floppies"/></xsl:when>
|
||||
<xsl:otherwise>{}</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="monitor">
|
||||
|
|
@ -592,7 +592,7 @@
|
|||
<xsl:call-template name="component">
|
||||
<xsl:with-param name="machine" select="$machine"/>
|
||||
<xsl:with-param name="class">chipset</xsl:with-param>
|
||||
<xsl:with-param name="parms">,model:'<xsl:value-of select="$model"/>',scaleTimers:<xsl:value-of select="$scaletimers"/>,sw1:'<xsl:value-of select="$sw1"/>',sw2:'<xsl:value-of select="$sw2"/>',sound:<xsl:value-of select="$sound"/>,fdrives:<xsl:value-of select="$fdrives"/>,monitor:'<xsl:value-of select="$monitor"/>',rtcDate:'<xsl:value-of select="$rtcdate"/>'</xsl:with-param>
|
||||
<xsl:with-param name="parms">,model:'<xsl:value-of select="$model"/>',scaleTimers:<xsl:value-of select="$scaletimers"/>,sw1:'<xsl:value-of select="$sw1"/>',sw2:'<xsl:value-of select="$sw2"/>',sound:<xsl:value-of select="$sound"/>,floppies:<xsl:value-of select="$floppies"/>,monitor:'<xsl:value-of select="$monitor"/>',rtcDate:'<xsl:value-of select="$rtcdate"/>'</xsl:with-param>
|
||||
</xsl:call-template>
|
||||
</xsl:template>
|
||||
|
||||
|
|
@ -963,4 +963,4 @@
|
|||
</xsl:call-template>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
</xsl:stylesheet>
|
||||
|
|
|
|||
Loading…
Reference in a new issue