From c02ea762d8ffb50075b1bf69392455717e6cdfd3 Mon Sep 17 00:00:00 2001 From: Will Scullin Date: Sat, 23 Sep 2017 11:34:24 -0700 Subject: [PATCH] D13 support, closer to real hardward behavior. --- js/cards/disk2.js | 354 +++++++++++++++++++++++++++++++++------------- 1 file changed, 256 insertions(+), 98 deletions(-) diff --git a/js/cards/disk2.js b/js/cards/disk2.js index 40ee31c..392047c 100644 --- a/js/cards/disk2.js +++ b/js/cards/disk2.js @@ -10,7 +10,7 @@ */ /*exported DiskII */ -/*globals bytify: false, debug: false +/*globals bytify: false, debug: false, toHex: false base64_decode: false, base64_encode: false Uint8Array: false */ @@ -72,42 +72,65 @@ function DiskII(io, slot, callbacks) // var DO = [0x0,0x7,0xE,0x6,0xD,0x5,0xC,0x4, // 0xB,0x3,0xA,0x2,0x9,0x1,0x8,0xF]; - var _DO = [0x0,0xD,0xB,0x9,0x7,0x5,0x3,0x1, - 0xE,0xC,0xA,0x8,0x6,0x4,0x2,0xF]; + var _DO = [ + 0x0,0xD,0xB,0x9,0x7,0x5,0x3,0x1, + 0xE,0xC,0xA,0x8,0x6,0x4,0x2,0xF + ]; // var PO = [0x0,0x8,0x1,0x9,0x2,0xa,0x3,0xb, // 0x4,0xc,0x5,0xd,0x6,0xe,0x7,0xf]; - var _PO = [0x0,0x2,0x4,0x6,0x8,0xa,0xc,0xe, - 0x1,0x3,0x5,0x7,0x9,0xb,0xd,0xf]; + var _PO = [ + 0x0,0x2,0x4,0x6,0x8,0xa,0xc,0xe, + 0x1,0x3,0x5,0x7,0x9,0xb,0xd,0xf + ]; - var _trans = [0x96, 0x97, 0x9a, 0x9b, 0x9d, 0x9e, 0x9f, 0xa6, - 0xa7, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb2, 0xb3, - 0xb4, 0xb5, 0xb6, 0xb7, 0xb9, 0xba, 0xbb, 0xbc, - 0xbd, 0xbe, 0xbf, 0xcb, 0xcd, 0xce, 0xcf, 0xd3, - 0xd6, 0xd7, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, - 0xdf, 0xe5, 0xe6, 0xe7, 0xe9, 0xea, 0xeb, 0xec, - 0xed, 0xee, 0xef, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, - 0xf7, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff]; + // var D13O = [ + // 0x0, 0xa, 0x7, 0x4, 0x1, 0xb, 0x8, 0x5, 0x2, 0xc, 0x9, 0x6, 0x3 + // ]; - var _detrans = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x02, 0x03, 0x00, 0x04, 0x05, 0x06, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x08, - 0x00, 0x00, 0x00, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, - 0x00, 0x00, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, - 0x00, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x1B, 0x00, 0x1C, 0x1D, 0x1E, - 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x20, 0x21, - 0x00, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x2A, 0x2B, - 0x00, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, - 0x00, 0x00, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, - 0x00, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F]; + var _D13O = [ + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc + ]; + + var _trans53 = [ + 0xab, 0xad, 0xae, 0xaf, 0xb5, 0xb6, 0xb7, 0xba, + 0xbb, 0xbd, 0xbe, 0xbf, 0xd6, 0xd7, 0xda, 0xdb, + 0xdd, 0xde, 0xdf, 0xea, 0xeb, 0xed, 0xee, 0xef, + 0xf5, 0xf6, 0xf7, 0xfa, 0xfb, 0xfd, 0xfe, 0xff + ]; + + var _trans62 = [ + 0x96, 0x97, 0x9a, 0x9b, 0x9d, 0x9e, 0x9f, 0xa6, + 0xa7, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, 0xb9, 0xba, 0xbb, 0xbc, + 0xbd, 0xbe, 0xbf, 0xcb, 0xcd, 0xce, 0xcf, 0xd3, + 0xd6, 0xd7, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, + 0xdf, 0xe5, 0xe6, 0xe7, 0xe9, 0xea, 0xeb, 0xec, + 0xed, 0xee, 0xef, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, + 0xf7, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff + ]; + + var _detrans62 = [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x02, 0x03, 0x00, 0x04, 0x05, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x08, + 0x00, 0x00, 0x00, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, + 0x00, 0x00, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, + 0x00, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1B, 0x00, 0x1C, 0x1D, 0x1E, + 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x20, 0x21, + 0x00, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x2A, 0x2B, + 0x00, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, + 0x00, 0x00, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, + 0x00, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F + ]; function _debug() { - // debug.apply(this, arguments); + console.log.apply(this, arguments); } function _init() { @@ -133,7 +156,7 @@ function DiskII(io, slot, callbacks) return ((xx << 1) | 0x01) & yy; } - function _explodeSector(volume, track, sector, data) { + function _explodeSector16(volume, track, sector, data) { var checksum; var buf = [], idx; @@ -209,10 +232,113 @@ function DiskII(io, slot, callbacks) var last = 0; for (idx = 0; idx < 0x156; idx++) { var val = nibbles[idx]; - buf.push(_trans[last ^ val]); + buf.push(_trans62[last ^ val]); last = val; } - buf.push(_trans[last]); + buf.push(_trans62[last]); + + buf = buf.concat([0xde, 0xaa, 0xf2]); // Epilog DE AA F2 + + /* + * Gap 3 + */ + + buf.push(0xff); + + return buf; + } + + function _explodeSector13(volume, track, sector, data) { + var checksum; + + var buf = [], idx; + + var gap; + + /* + * Gap 1/3 (40/0x28 bytes) + */ + + if (sector === 0) // Gap 1 + gap = 0x80; + else { // Gap 3 + gap = track === 0 ? 0x28 : 0x26; + } + + for (idx = 0; idx < gap; idx++) { + buf.push(0xff); + } + + /* + * Address Field + */ + + checksum = volume ^ track ^ sector; + buf = buf.concat([0xd5, 0xaa, 0xb5]); // Address Prolog D5 AA B5 + buf = buf.concat(_fourXfour(volume)); + buf = buf.concat(_fourXfour(track)); + buf = buf.concat(_fourXfour(sector)); + buf = buf.concat(_fourXfour(checksum)); + buf = buf.concat([0xde, 0xaa, 0xeb]); // Epilog DE AA EB + + /* + * Gap 2 (5 bytes) + */ + + for (idx = 0; idx < 0x05; idx++) { + buf.push(0xff); + } + + /* + * Data Field + */ + + buf = buf.concat([0xd5, 0xaa, 0xad]); // Data Prolog D5 AA AD + + var nibbles = []; + + var jdx = 0; + for (idx = 0x32; idx >= 0; idx--) { + var a5 = data[jdx] >> 3; + var a3 = data[jdx] & 0x07; + jdx++; + var b5 = data[jdx] >> 3; + var b3 = data[jdx] & 0x07; + jdx++; + var c5 = data[jdx] >> 3; + var c3 = data[jdx] & 0x07; + jdx++; + var d5 = data[jdx] >> 3; + var d3 = data[jdx] & 0x07; + jdx++; + var e5 = data[jdx] >> 3; + var e3 = data[jdx] & 0x07; + jdx++; + nibbles[idx + 0x00] = a5; + nibbles[idx + 0x33] = b5; + nibbles[idx + 0x66] = c5; + nibbles[idx + 0x99] = d5; + nibbles[idx + 0xcc] = e5; + nibbles[idx + 0x100] = a3 << 2 | (d3 & 0x4) >> 1 | (e3 & 0x4) >> 2; + nibbles[idx + 0x133] = b3 << 2 | (d3 & 0x2) | (e3 & 0x2) >> 1; + nibbles[idx + 0x166] = c3 << 2 | (d3 & 0x1) << 1 | (e3 & 0x1); + } + nibbles[0xff] = data[jdx] >> 3; + nibbles[0x199] = data[jdx] & 0x07; + + var val; + var last = 0; + for (idx = 0x199; idx >= 0x100; idx--) { + val = nibbles[idx]; + buf.push(_trans53[last ^ val]); + last = val; + } + for (idx = 0x0; idx < 0x100; idx++) { + val = nibbles[idx]; + buf.push(_trans53[last ^ val]); + last = val; + } + buf.push(_trans53[last]); buf = buf.concat([0xde, 0xaa, 0xeb]); // Epilog DE AA EB @@ -240,12 +366,12 @@ function DiskII(io, slot, callbacks) } } } - return JSON.stringify({'type': format, - 'encoding': 'base64', - 'volume': cur.volume, - 'data': data}, - null, - pretty ? ' ' : null); + return JSON.stringify({ + 'type': format, + 'encoding': 'base64', + 'volume': cur.volume, + 'data': data + }, null, pretty ? ' ' : null); } function _json_decode(drive, data) { @@ -258,7 +384,7 @@ function DiskII(io, slot, callbacks) for (var s = 0; s < json.data[t].length; s++) { var _s = 15 - s; var d = base64_decode(json.data[t][_s]); - track = track.concat(_explodeSector(v, t, _DO[_s], d)); + track = track.concat(_explodeSector16(v, t, _DO[_s], d)); } tracks[t] = bytify(track); } @@ -267,33 +393,31 @@ function DiskII(io, slot, callbacks) _cur.tracks = tracks; } - function _readNext() { - var result = 0; + function _readWriteNext() { if (_skip || _writeMode) { - var t = _cur.tracks[_cur.track >> 1]; - if (t && t.length) { - if (_cur.head >= t.length) + var track = _cur.tracks[_cur.track >> 1]; + if (track && track.length) { + if (_cur.head >= track.length) { _cur.head = 0; + } if (_writeMode) { - t[_cur.head] = _latch; - } else - result = t[_cur.head]; + if (!_cur.readOnly) { + track[_cur.head] = _latch; + if (!_cur.dirty) { + _updateDirty(_drive, true); + } + } + } else { + _latch = track[_cur.head]; + } ++_cur.head; } + } else { + _latch = 0; } - _skip = (++_skip % 4); - return result; - } - - function _writeNext(val) { - if (_writeMode) { - _latch = val; - if (!_cur.dirty) { - _updateDirty(_drive, true); - } - } + _skip = (++_skip % 2); } function _readSector(drive, track, sector) { @@ -345,12 +469,12 @@ function DiskII(io, slot, callbacks) var data2 = []; var last = 0; for (jdx = 0x55; jdx >= 0; jdx--) { - val = _detrans[_readNext() - 0x80] ^ last; + val = _detrans62[_readNext() - 0x80] ^ last; data2[jdx] = val; last = val; } for (jdx = 0; jdx < 0x100; jdx++) { - val = _detrans[_readNext() - 0x80] ^ last; + val = _detrans62[_readNext() - 0x80] ^ last; data[jdx] = val; last = val; } @@ -388,7 +512,7 @@ function DiskII(io, slot, callbacks) [ 1,-2,-1, 0]]; function setPhase(phase, on) { - _debug('phase ' + phase + (on ? ' on' : ' off')); + // _debug('phase ' + phase + (on ? ' on' : ' off')); if (on) { _cur.track += _phase_delta[_cur.phase][phase]; _cur.phase = phase; @@ -407,44 +531,46 @@ function DiskII(io, slot, callbacks) function _access(off, val) { var result = 0; + var readMode = val === undefined; + switch (off & 0x8f) { - case LOC.PHASE0OFF: + case LOC.PHASE0OFF: // 0x00 setPhase(0, false); break; - case LOC.PHASE0ON: + case LOC.PHASE0ON: // 0x01 setPhase(0, true); break; - case LOC.PHASE1OFF: + case LOC.PHASE1OFF: // 0x02 setPhase(1, false); break; - case LOC.PHASE1ON: + case LOC.PHASE1ON: // 0x03 setPhase(1, true); break; - case LOC.PHASE2OFF: + case LOC.PHASE2OFF: // 0x04 setPhase(2, false); break; - case LOC.PHASE2ON: + case LOC.PHASE2ON: // 0x05 setPhase(2, true); break; - case LOC.PHASE3OFF: + case LOC.PHASE3OFF: // 0x06 setPhase(3, false); break; - case LOC.PHASE3ON: + case LOC.PHASE3ON: // 0x07 setPhase(3, true); break; - case LOC.DRIVEOFF: + case LOC.DRIVEOFF: // 0x08 _debug('Drive Off'); _on = false; if (callbacks.driveLight) { callbacks.driveLight(_drive, false); } break; - case LOC.DRIVEON: + case LOC.DRIVEON: // 0x09 _debug('Drive On'); _on = true; if (callbacks.driveLight) { callbacks.driveLight(_drive, true); } break; - case LOC.DRIVE1: + case LOC.DRIVE1: // 0x0a _debug('Disk 1'); _drive = 1; _cur = _drives[_drive - 1]; @@ -453,7 +579,7 @@ function DiskII(io, slot, callbacks) callbacks.driveLight(1, true); } break; - case LOC.DRIVE2: + case LOC.DRIVE2: // 0x0b _debug('Disk 2'); _drive = 2; _cur = _drives[_drive - 1]; @@ -463,29 +589,46 @@ function DiskII(io, slot, callbacks) } break; - case LOC.DRIVEREAD: - result = _readNext(); - // _debug('read: ' + toHex(result)); + case LOC.DRIVEREAD: // 0x0c + _readWriteNext(); break; - case LOC.DRIVEWRITE: - // _debug('write: ' + toHex(val)); - if (val !== undefined) { - _writeNext(val); + case LOC.DRIVEWRITE: // 0x0d + if (readMode && !_writeMode) { + if (_cur.readOnly) { + _latch = _latch | 0x80; + _debug('Setting readOnly'); + } else { + _latch = _latch & 0x7f; + _debug('Clearing readOnly'); + } } break; - case LOC.DRIVEREADMODE: + + case LOC.DRIVEREADMODE: // 0x0e _debug('Read Mode'); _writeMode = false; - result = (_readNext() & 0x7f) | (_cur.readOnly ? 0x80 : 0x00); break; - case LOC.DRIVEWRITEMODE: + case LOC.DRIVEWRITEMODE: // 0x0f _debug('Write Mode'); _writeMode = true; break; + default: break; } + + if (readMode) { + if ((off & 0x01) === 0) { + result = _latch; + // _debug('Read', toHex(result)); + } else { + result = 0; + } + } else if (_writeMode) { + _latch = val; + } + return result; } @@ -563,7 +706,6 @@ function DiskII(io, slot, callbacks) 0x03,0x4c,0x01,0x03,0x4c,0x2d,0xff,0xff ]; */ - _init(); return { @@ -645,12 +787,13 @@ function DiskII(io, slot, callbacks) _cur = _drives[_drive - 1]; }, rwts: function disk2_rwts(disk, track, sector) { - return _readSector(disk, track, sector); + var s = _drives[disk - 1].fmt == 'po' ? _PO[sector] : _DO[sector]; + return _readSector(disk, track, s); }, setDisk: function disk2_setDisk(drive, disk) { var fmt = disk.type, readOnly = disk.readOnly; - var data, t, s; + var data, t, s, _s; if (disk.encoding == 'base64') { data = []; for (t = 0; t < disk.data.length; t++) { @@ -682,20 +825,26 @@ function DiskII(io, slot, callbacks) var track = []; if (fmt === 'nib') { track = data[t]; + } else if (fmt === 'd13') { // DOS 3.2 Order + for (s = 0; s < data[t].length; s++) { + track = track.concat( + _explodeSector13(v, t, _D13O[s], data[t][_D13O[s]]) + ); + } } else { for (s = 0; s < data[t].length; s++) { - var _s = 15 - s; + _s = 15 - s; if (fmt === 'po') { // ProDOS Order track = track.concat( - _explodeSector(v, t, _PO[s], data[t][s]) + _explodeSector16(v, t, _PO[s], data[t][s]) ); - } else if (fmt === 'dsk') { // DOS Order + } else if (fmt === 'dsk') { // DOS 3.3 Order track = track.concat( - _explodeSector(v, t, _DO[_s], data[t][_s]) + _explodeSector16(v, t, _DO[_s], data[t][_s]) ); } else { // flat track = track.concat( - _explodeSector(v, t, s, data[t][s]) + _explodeSector16(v, t, s, data[t][s]) ); } } @@ -752,25 +901,34 @@ function DiskII(io, slot, callbacks) } } for (var t = 0; t < 35; t++) { - var track, off, d; + var track, off, d, s, _s; if (fmt === 'nib') { off = t * 0x1a00; track = new Uint8Array(data.slice(off, off + 0x1a00)); + } else if (fmt == 'd13') { // DOS 3.2 Order + track = []; + for (s = 0; s < 13; s++) { + off = (13 * t + _D13O[s]) * 256; + d = new Uint8Array(data.slice(off, off + 256)); + track = track.concat( + _explodeSector13(v, t, _D13O[s], d) + ); + } } else { track = []; - for (var s = 0; s < 16; s++) { - var _s = 15 - s; + for (s = 0; s < 16; s++) { + _s = 15 - s; if (fmt == 'po') { // ProDOS Order off = (16 * t + s) * 256; d = new Uint8Array(data.slice(off, off + 256)); track = track.concat( - _explodeSector(v, t, _PO[s], d) + _explodeSector16(v, t, _PO[s], d) ); - } else if (fmt == 'dsk') { // DOS Order + } else if (fmt == 'dsk') { // DOS 3.3 Order off = (16 * t + _s) * 256; d = new Uint8Array(data.slice(off, off + 256)); track = track.concat( - _explodeSector(v, t, _DO[_s], d) + _explodeSector16(v, t, _DO[_s], d) ); } else { return false;