D13 support, closer to real hardward behavior.

This commit is contained in:
Will Scullin 2017-09-23 11:34:24 -07:00
parent bdb792f8fb
commit c02ea762d8

View File

@ -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,24 +72,46 @@ 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,
// var D13O = [
// 0x0, 0xa, 0x7, 0x4, 0x1, 0xb, 0x8, 0x5, 0x2, 0xc, 0x9, 0x6, 0x3
// ];
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];
0xf7, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
];
var _detrans = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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,
@ -104,10 +126,11 @@ function DiskII(io, slot, callbacks)
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];
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,
return JSON.stringify({
'type': format,
'encoding': 'base64',
'volume': cur.volume,
'data': data},
null,
pretty ? ' ' : null);
'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];
++_cur.head;
}
}
_skip = (++_skip % 4);
return result;
}
function _writeNext(val) {
if (_writeMode) {
_latch = val;
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 % 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;