Fixed PC-DOS 7.00 CPU detection logic (see SGDT)

This commit is contained in:
Jeff Parsons 2014-10-23 16:46:58 -07:00 • committed by jeffpar
commit 0173492ef2
12 changed files with 198 additions and 93 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -6,19 +6,22 @@
<type>DOS</type>
<category>Operating System</category>
<author>IBM</author>
<disk id="disk00" size="1474560" chs="80:2:18" img="private/PCDOS700.img" href="/disks/pc/dos/ibm/7.00/PCDOS700.json" md5="72f453733c6d4a102fdad4366a7daf1f" md5json="fcbc9523367a18ee0efa0dccace722c2">
<name>PC-DOS 7.00 (Boot Disk)</name>
</disk>
<disk id="disk01" size="1474560" chs="80:2:18" img="private/PCDOS700-DISK1.img" href="/disks/pc/dos/ibm/7.00/PCDOS700-DISK1.json" md5="2a3736d2acbb7730965b7cb6d3f16d00" md5json="97fc896b5679dabbadfa13ed6a1dc681">
<name>PC-DOS 7.00 (Disk 1)</name>
<name>PC-DOS 7.00 (SETUP Disk 1)</name>
</disk>
<disk id="disk02" size="1884160" chs="80:2:23" img="private/PCDOS700-DISK2.xdf" href="/disks/pc/dos/ibm/7.00/PCDOS700-DISK2.json" md5="b21b98aca8fafbdd1a7b9db77e7dc60d" md5json="e01a29ace42aef1c65e7f9794271e6d8">
<name>PC-DOS 7.00 (XDF Disk 2)</name>
<disk id="disk02" size="1884160" chs="80:2:23" img="private/PCDOS700-DISK2.xdf" href="/disks/pc/dos/ibm/7.00/PCDOS700-DISK2.json" md5="b21b98aca8fafbdd1a7b9db77e7dc60d" md5json="95b075274808e24f6e67fc05d999ff01">
<name>PC-DOS 7.00 (SETUP Disk 2)</name>
</disk>
<disk id="disk03" size="1884160" chs="80:2:23" img="private/PCDOS700-DISK3.xdf" href="/disks/pc/dos/ibm/7.00/PCDOS700-DISK3.json" md5="e45111515901b951dc5ff33434b47a0a" md5json="b439c1f270e35afa4597bec59d80e1d2">
<name>PC-DOS 7.00 (XDF Disk 3)</name>
<disk id="disk03" size="1884160" chs="80:2:23" img="private/PCDOS700-DISK3.xdf" href="/disks/pc/dos/ibm/7.00/PCDOS700-DISK3.json" md5="e45111515901b951dc5ff33434b47a0a" md5json="7bae36688f85046d2564b0240b931117">
<name>PC-DOS 7.00 (SETUP Disk 3)</name>
</disk>
<disk id="disk04" size="1884160" chs="80:2:23" img="private/PCDOS700-DISK4.xdf" href="/disks/pc/dos/ibm/7.00/PCDOS700-DISK4.json" md5="1ea1b92938a40cbb5089c30c86165c7a" md5json="e8d58a70a5849ce180c2ef00afc7143b">
<name>PC-DOS 7.00 (XDF Disk 4)</name>
<disk id="disk04" size="1884160" chs="80:2:23" img="private/PCDOS700-DISK4.xdf" href="/disks/pc/dos/ibm/7.00/PCDOS700-DISK4.json" md5="1ea1b92938a40cbb5089c30c86165c7a" md5json="ecf1eb5628c30f0c766c44395ce38c0d">
<name>PC-DOS 7.00 (SETUP Disk 4)</name>
</disk>
<disk id="disk05" size="1884160" chs="80:2:23" img="private/PCDOS700-DISK5.xdf" href="/disks/pc/dos/ibm/7.00/PCDOS700-DISK5.json" md5="e613544f161d0857fc3adf6a13eb9371" md5json="83f094d61b5d52ea8bd315de15f14f48">
<name>PC-DOS 7.00 (XDF Disk 5)</name>
<disk id="disk05" size="1884160" chs="80:2:23" img="private/PCDOS700-DISK5.xdf" href="/disks/pc/dos/ibm/7.00/PCDOS700-DISK5.json" md5="e613544f161d0857fc3adf6a13eb9371" md5json="aaf6eca0bf684565e935f3121e8ff705">
<name>PC-DOS 7.00 (SETUP Disk 5)</name>
</disk>
</manifest>

View file

@ -778,7 +778,7 @@ DiskDump.prototype.isExcluded = function(sName)
DiskDump.prototype.loadFile = function(done)
{
/*
* When the 'encoding' property of the 'options' object is null (or when the 'options'
* When the 'encoding' property of the 'options' object is null (or the 'options'
* object is omitted altogether), the callback's 2nd parameter will be a Buffer object
* rather than a String.
*/
@ -2128,10 +2128,11 @@ DiskDump.prototype.convertToJSON = function()
nHeads = nHeadsBPB;
nCylinders = Math.floor(nSectorsTotalBPB / nSectorsPerCylinderBPB);
nSectorsPerTrack = nSectorsPerTrackBPB;
/*
* OK, great, the disk appears to contain a valid BPB. But so do XDF disk images, which are
* diskette images with tracks containing:
*
*
* 1 8Kb sector (equivalent of 16 512-byte sectors)
* 1 2Kb sector (equivalent of 4 512-byte sectors)
* 1 1Kb sector (equivalent of 2 512-byte sectors)
@ -2140,19 +2141,19 @@ DiskDump.prototype.convertToJSON = function()
* for a total of the equivalent of 23 512-byte sectors, or 11776 (0x2E00) bytes per track.
* For an 80-track diskette with 2 sides, that works out to a total of 3680 512-byte sectors,
* or 1884160 bytes, or 1.84Mb, which is the exact size of the (only) XDF diskette images we
* currently support.
*
* Moreover, the first two tracks (ie, the first cylinder) contain only 19 sectors, rather than
* 23, but the XDF format still pads those tracks with 4 unused sectors.
*
* currently (try to) support.
*
* Moreover, the first two tracks (ie, the first cylinder) contain only 19 sectors each,
* rather than 23, but the XDF format still pads those tracks with 4 unused sectors.
*
* So, data for the first track contains 1 boot sector ending at 512 (0x200), 11 FAT sectors
* ending at 6144 (0x1800), and 7 "micro-disk" sectors ending at 9728 (0x2600). Then there's
* 4 sectors (probably of "garbage") that end at 11776 (0x2E00).
*
* 4 sectors (presumably of "garbage") that end at 11776 (0x2E00).
*
* Data for the second track contains 7 root directory sectors ending at 15360 (0x3C00), followed
* by disk data.
*
* For more details, check out this very helpful article: http://www.os2museum.com/wp/the-xdf-diskette-format/
*
* For more details, check out this helpful article: http://www.os2museum.com/wp/the-xdf-diskette-format/
*/
if (nSectorsTotalBPB == 3680) fXDF = true;
}
@ -2248,27 +2249,78 @@ DiskDump.prototype.convertToJSON = function()
json += this.dumpLine(2, "[", "head:" + this.sJSONWhitespace + iHead + ", track:" + this.sJSONWhitespace + iCylinder);
}
/*
* For most disks, the size of every sector and the number of sectors/track are consistent, and the
* sector number encoded in every sector (nSector) matches the 1-based sector index (iSector) we use
* to "track" our progress through the current track. However, for XDF disk images, the above is
* NOT true beyond cylinder 0, which is why we have all these *ThisTrack variables, which would otherwise
* be unnecessary.
*/
var cbSectorThisTrack = cbSector;
var nSectorsThisTrack = nSectorsPerTrack;
/*
* Notes regarding XDF track layouts, from http://forum.kryoflux.com/viewtopic.php?f=3&t=234:
*
* Track 0, side 0: 19x512 bytes per sector, with standard numbering for the first 8 sectors, then custom numbering
* Track 0, side 1: 19x512 bytes per sector, with interleaved sector numbering 0x81...0x93
*
* Track 1 and up, side 0, 4 sectors per track:
* 1x1024, 1x512, 1x2048, 1x8192 bytes per sector (0x83, 0x82, 084, 0x86 as sector numbers)
*
* Track 1 and up, side 1, 4 sectors per track:
* 1x2048, 1x512, 1x1024, 1x8192 bytes per sector (0x84, 0x82, 083, 0x86 as sector numbers)
*
* Notes regarding the order in which XDF sectors are read (from http://mail.netbridge.at/cgi-bin/info2www?(fdutils)XDF),
* where each position column represents a (roughly) 128-byte section of the track:
*
* 1 2 3 4
* 1234567890123456789012345678901234567890 (position)
* ----------------------------------------
* 6633332244444446666666666666666666666666 (side 0)
* 6666444444422333366666666666666666666666 (side 1)
*
* where 2's contain a 512-byte sector, 3's contain a 1Kb sector, 4's contains a 2Kb sector, and 6's contain an 8Kb sector.
*
* Reading all the data on an XDF cylinder occurs in the following order, from the specified start to end positions:
*
* sector head start end
* 3 0 3 7
* 4 0 9 16
* 6 1 18 5 (1st wrap around)
* 2 0 7 9
* 2 1 12 14
* 6 0 16 3 (2nd wrap around)
* 4 1 5 12
* 3 1 14 18
*/
if (fXDF) nSectorsThisTrack = (iCylinder? 4 : 19);
for (var iSector=1, offSector=0; iSector <= nSectorsThisTrack && offSector < cbTrack; iSector++, offSector += cbSectorThisTrack) {
var sector = {};
if (fXDF && iCylinder) cbSectorThisTrack = (iSector == 1? 8192 : (iSector == 2? 2048 : (iSector == 3? 1024 : 512)));
var nSector = iSector;
if (fXDF && iCylinder) {
if (!iHead) {
cbSectorThisTrack = (iSector == 1? 1024 : (iSector == 2? 512 : (iSector == 3? 2048 : 8192)));
} else {
cbSectorThisTrack = (iSector == 1? 8192 : (iSector == 2? 2048 : (iSector == 3? 1024 : 512)));
}
nSector = (cbSectorThisTrack == 512? 2 : (cbSectorThisTrack == 1024? 3 : (cbSectorThisTrack == 2048? 4 : 6)));
}
bufSector = bufTrack.slice(offSector, offSector + cbSectorThisTrack);
if (this.fJSONNative) {
sector['sector'] = iSector;
sector['sector'] = nSector;
sector['length'] = cbSectorThisTrack;
} else {
json += (iSector == 1? this.dumpLine(2, "{") : "");
json += this.dumpLine(0, '"sector":' + this.sJSONWhitespace + iSector + ",");
json += this.dumpLine(0, '"sector":' + this.sJSONWhitespace + nSector + ",");
json += this.dumpLine(0, '"length":' + this.sJSONWhitespace + cbSectorThisTrack + ",");
}
var aTrim = this.trimSector(bufSector, cbSectorThisTrack);
var dwPattern = aTrim[0];
var cbBuffer = cbSectorThisTrack;
@ -2280,7 +2332,7 @@ DiskDump.prototype.convertToJSON = function()
json += this.dumpLine(0, '"pattern":' + this.sJSONWhitespace + dwPattern + ",");
}
}
if (this.fJSONNative) {
var dataSector = [];
sector['data'] = dataSector;
@ -2307,12 +2359,14 @@ DiskDump.prototype.convertToJSON = function()
offTrack += offHead; // end of cylinder {iCylinder}
}
/*
* Here's where we could output the following comment:
* Here's where I used to output the following comment:
*
* // write-protected
*
* as the first line of the JSON stream if the disk was marked write-protected (ie, if (bByte0 & 0x1) != 0).
* But I'd rather folks just name their JSON disk images with a "-readonly" suffix (another, better, work-around).
*
* But since that makes JSON.parse() sad, the preferred solution is to name read-only JSON disk images with a
* "-readonly" suffix.
*/
if (this.fJSONNative) {
json = JSON.stringify(this.dataDisk);
@ -2338,7 +2392,7 @@ DiskDump.prototype.convertToJSON = function()
* like so:
*
* [ [ {
* trackSig:'CW',
* trackSig:"CW",
* trackNum:0x01,
* trackType:0x58,
* trackLoad:0xnnnn,
@ -2346,21 +2400,21 @@ DiskDump.prototype.convertToJSON = function()
* { sectorSig:0x76,
* sectorNum:0x01,
* sectorPages:0x01,
* sectorEndSig:'GS',
* sectorEndSig:"GS",
* sectorData: [0x52,0x41,0x43,0x4b,...]
* },...
* ]
* },
* {
* trackSig:'CW',
* trackSig:"CW",
* ...
* }
* ] ]
*
* TODO: If we ever add support for OSI drives/disk images with more than one head, we should change the disk image
* format to match that used by DOS disk images and PCjs; ie, an array of cylinders, each containing an array of heads,
* each containing an array of tracks. It's largely just a matter of reversing the meaning of the two outermost array
* elements, here and in the C1Pjs disk module.
* each containing an array of tracks. It's largely just a matter of swapping the two outermost array elements, both
* here and in the C1Pjs disk module.
*
* @this {DiskDump}
* @return {string|null} containing a JSON representation of the disk image, or null if unrecognized/malformed

View file

@ -1346,7 +1346,7 @@ Disk.prototype.save = function()
for (var iHead = 0; iHead < aDiskData[iCylinder].length; iHead++) {
for (var iSector = 0; iSector < aDiskData[iCylinder][iHead].length; iSector++) {
var sector = aDiskData[iCylinder][iHead][iSector];
if (sector.cModify) {
if (sector && sector.cModify) {
var mods = [], n = 0;
var iModify = sector.iModify, iModifyLimit = sector.iModify + sector.cModify;
while (iModify < iModifyLimit) {
@ -1443,6 +1443,7 @@ Disk.prototype.restore = function(deltas)
var mods = mod[m++];
var iModifyLimit = iModify + mods.length;
var sector = this.aDiskData[iCylinder][iHead][iSector];
if (!sector) continue;
/*
* Since write() now deals with empty/partial sectors, we no longer need to completely "inflate" the sector prior
* to applying modifications. So let's just make sure that the sector is "inflated" up to iModify.

View file

@ -812,7 +812,10 @@ X86CPU.prototype.resetRegs = function()
* at both 0x0F0000 and 0xFF0000; see the ROM component's "alias" parameter).
*/
if (this.model >= X86.MODEL_80286) {
this.addrGDT = this.addrGDTLimit = 0; // GDTR
/*
* TODO: Verify what the 80286 actually sets addrGDT and addrGDTLimit to on reset (or if it leaves them alone).
*/
this.addrGDT = 0; this.addrGDTLimit = 0xFFFF; // GDTR
this.segLDT = new X86Seg(this, "LDT", true); // LDTR
this.segTSS = new X86Seg(this, "TSS", true); // TR
this.segVER = new X86Seg(this, "VER", true); // a scratch segment register for VERR and VERW instructions

View file

@ -210,9 +210,44 @@ var X86Op0F = {
if (this.regEA < 0) {
X86Help.opInvalid.call(this);
} else {
this.setWord(this.regEA + 2, this.addrGDT);
this.setByte(this.regEA + 4, this.addrGDT >> 16);
/*
* We don't need to setWord() the first word of the operand, because the ModRM group decoder that calls
* us does that automatically with the value we return (dst).
*/
dst = this.addrGDTLimit - this.addrGDT;
this.setWord(this.regEA + 2, this.addrGDT);
/*
* We previously left the 6th byte of the target operand "undefined". But it turns out we have to set
* it to *something*, because there's processor detection in PC-DOS 7.0 (at least in the SETUP portion)
* that looks like this:
*
* 145E:4B84 9C PUSHF
* 145E:4B85 55 PUSH BP
* 145E:4B86 8BEC MOV BP,SP
* 145E:4B88 B80000 MOV AX,0000
* 145E:4B8B 50 PUSH AX
* 145E:4B8C 9D POPF
* 145E:4B8D 9C PUSHF
* 145E:4B8E 58 POP AX
* 145E:4B8F 2500F0 AND AX,F000
* 145E:4B92 3D00F0 CMP AX,F000
* 145E:4B95 7511 JNZ 4BA8
* 145E:4BA8 C8060000 ENTER 0006,00
* 145E:4BAC 0F0146FA SGDT [BP-06]
* 145E:4BB0 807EFFFF CMP [BP-01],FF
* 145E:4BB4 C9 LEAVE
* 145E:4BB5 BA8603 MOV DX,0386
* 145E:4BB8 7503 JNZ 4BBD
* 145E:4BBA BA8602 MOV DX,0286
* 145E:4BBD 89163004 MOV [0430],DX
* 145E:4BC1 5D POP BP
* 145E:4BC2 9D POPF
* 145E:4BC3 CB RETF
*
* This code is expecting SGDT on an 80286 to set the 6th "undefined" byte to 0xFF. So we use setWord()
* instead of setByte() and force the upper byte to 0xFF. TODO: Remove the 0xFF00 on post-80286 processors.
*/
this.setWord(this.regEA + 4, 0xFF00 | (this.addrGDT >> 16));
this.nStepCycles -= 11;
}
return dst;
@ -227,9 +262,17 @@ var X86Op0F = {
if (this.regEA < 0) {
X86Help.opInvalid.call(this);
} else {
this.setWord(this.regEA + 2, this.addrIDT);
this.setByte(this.regEA + 4, this.addrIDT >> 16);
/*
* We don't need to setWord() the first word of the operand, because the ModRM group decoder that calls
* us does that automatically with the value we return (dst).
*/
dst = this.addrIDTLimit - this.addrIDT;
this.setWord(this.regEA + 2, this.addrIDT);
/*
* As with SGDT, the 6th byte is technically "undefined" on an 80286, but given that SGDT now sets it to 0xFF,
* we mimic SGDT.
*/
this.setWord(this.regEA + 4, 0xFF00 | (this.addrIDT >> 16));
this.nStepCycles -= 12;
}
return dst;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long