rewrote the nibble routines

This commit is contained in:
Denis Molony 2018-08-11 10:07:50 +10:00
parent aac34c9095
commit 82600b8d0b
15 changed files with 882 additions and 275 deletions

View File

@ -24,6 +24,7 @@ public class CPMDisk extends AbstractFormattedDisk
public final SectorType macSector = new SectorType ("MAC", Color.green);
private int version; // http://www.seasip.info/Cpm/format22.html
// // http://www.seasip.info/Cpm/format31.html
public CPMDisk (Disk disk)
{

View File

@ -231,30 +231,16 @@ public class AppleDisk implements Disk
this.tracks = tracks;
this.sectors = sectors;
file = disk.file;
diskBuffer = disk.diskBuffer;
if (sectors == 13)
{
trackSize = 0xD00;
sectorSize = 256;
diskBuffer = new byte[116480];
int ptr = 0;
for (int track = 0; track < 35; track++)
{
for (int sector = 0; sector < 13; sector++)
{
int ptr2 = track * 0xD00 + sector * 0x100;
System.arraycopy (disk.diskBuffer, ptr, diskBuffer, ptr2, 0x100);
// System.out.printf ("Copying %04X -> %04X%n", ptr, ptr2);
ptr += 0x100;
}
ptr += 0x300; // skip 3 sectors
}
}
else
{
trackSize = 4096;
diskBuffer = disk.diskBuffer;
trackSize = 0x1000;
sectorSize = trackSize / sectors;
}

View File

@ -0,0 +1,8 @@
package com.bytezone.diskbrowser.disk;
public abstract class ByteTranslator
{
abstract byte encode (byte b);
abstract byte decode (byte b) throws DiskNibbleException;
}

View File

@ -0,0 +1,68 @@
package com.bytezone.diskbrowser.disk;
public class ByteTranslator5and3 extends ByteTranslator
{
// 32 valid bytes that can be stored on a disk (plus 0xAA and 0xD5)
private static byte[] writeTranslateTable5and3 =
{ (byte) 0xAB, (byte) 0xAD, (byte) 0xAE, (byte) 0xAF, (byte) 0xB5, (byte) 0xB6,
(byte) 0xB7, (byte) 0xBA, (byte) 0xBB, (byte) 0xBD, (byte) 0xBE, (byte) 0xBF,
(byte) 0xD6, (byte) 0xD7, (byte) 0xDA, (byte) 0xDB, //
(byte) 0xDD, (byte) 0xDE, (byte) 0xDF, (byte) 0xEA, (byte) 0xEB, (byte) 0xED,
(byte) 0xEE, (byte) 0xEF, (byte) 0xF5, (byte) 0xF6, (byte) 0xF7, (byte) 0xFA,
(byte) 0xFB, (byte) 0xFD, (byte) 0xFE, (byte) 0xFF };
private static byte[] readTranslateTable5and3 = new byte[85]; // skip first 171 blanks
private static boolean debug = false;
static
{
for (int i = 0; i < writeTranslateTable5and3.length; i++)
{
int j = (writeTranslateTable5and3[i] & 0xFF) - 0xAB; // skip first 171 blanks
readTranslateTable5and3[j] = (byte) (i + 1); // offset by 1 to avoid zero
if (debug)
System.out.printf ("%02X %02X %02X%n", i, writeTranslateTable5and3[i], j);
}
if (debug)
for (int j = 0; j < readTranslateTable5and3.length; j++)
{
int target = readTranslateTable5and3[j] - 1;
if (target >= 0)
{
int value = writeTranslateTable5and3[target] & 0xFF;
System.out.printf ("%02X -> %02X%n", j, value);
}
else
System.out.printf ("%02X%n", j);
}
}
// ---------------------------------------------------------------------------------//
// encode
// ---------------------------------------------------------------------------------//
@Override
byte encode (byte b)
{
return 0;
}
// ---------------------------------------------------------------------------------//
// decode
// ---------------------------------------------------------------------------------//
@Override
byte decode (byte b) throws DiskNibbleException
{
int val = (b & 0xFF) - 0xAB; // 0 - 84
// assert val >= 0 && val <= 84 : "Val: " + val;
if (val < 0 || val > 84)
throw new DiskNibbleException ("Val: " + val);
byte trans = (byte) (readTranslateTable5and3[val] - 1); // 0 - 31 (5 bits)
// assert trans >= 0 && trans <= 31 : "Trans: " + trans;
if (trans < 0 || trans > 31)
throw new DiskNibbleException ("Trans: " + trans);
return (byte) (trans << 3); // left justify 5 bits
}
}

View File

@ -0,0 +1,50 @@
package com.bytezone.diskbrowser.disk;
public class ByteTranslator6and2 extends ByteTranslator
{
// 64 valid bytes that can be stored on a disk (plus 0xAA and 0xD5)
private static byte[] writeTranslateTable6and2 =
{ (byte) 0x96, (byte) 0x97, (byte) 0x9A, (byte) 0x9B, (byte) 0x9D, (byte) 0x9E,
(byte) 0x9F, (byte) 0xA6, (byte) 0xA7, (byte) 0xAB, (byte) 0xAC, (byte) 0xAD,
(byte) 0xAE, (byte) 0xAF, (byte) 0xB2, (byte) 0xB3, //
(byte) 0xB4, (byte) 0xB5, (byte) 0xB6, (byte) 0xB7, (byte) 0xB9, (byte) 0xBA,
(byte) 0xBB, (byte) 0xBC, (byte) 0xBD, (byte) 0xBE, (byte) 0xBF, (byte) 0xCB,
(byte) 0xCD, (byte) 0xCE, (byte) 0xCF, (byte) 0xD3, //
(byte) 0xD6, (byte) 0xD7, (byte) 0xD9, (byte) 0xDA, (byte) 0xDB, (byte) 0xDC,
(byte) 0xDD, (byte) 0xDE, (byte) 0xDF, (byte) 0xE5, (byte) 0xE6, (byte) 0xE7,
(byte) 0xE9, (byte) 0xEA, (byte) 0xEB, (byte) 0xEC, //
(byte) 0xED, (byte) 0xEE, (byte) 0xEF, (byte) 0xF2, (byte) 0xF3, (byte) 0xF4,
(byte) 0xF5, (byte) 0xF6, (byte) 0xF7, (byte) 0xF9, (byte) 0xFA, (byte) 0xFB,
(byte) 0xFC, (byte) 0xFD, (byte) 0xFE, (byte) 0xFF };
private static byte[] readTranslateTable6and2 = new byte[106]; // skip first 150 blanks
static
{
for (int i = 0; i < writeTranslateTable6and2.length; i++)
{
int j = (writeTranslateTable6and2[i] & 0xFF) - 0x96; // skip first 150 blanks
readTranslateTable6and2[j] = (byte) (i + 1); // offset by 1 to avoid zero
}
}
@Override
byte encode (byte b)
{
return writeTranslateTable6and2[(b & 0xFC) / 4];
}
@Override
byte decode (byte b) throws DiskNibbleException
{
int val = (b & 0xFF) - 0x96; // 0 - 105
// assert val >= 0 && val <= 105 : "Val: " + val;
if (val < 0 || val > 105)
throw new DiskNibbleException ("Val: " + val);
byte trans = (byte) (readTranslateTable6and2[val] - 1); // 0 - 63 (6 bits)
// assert trans >= 0 && trans <= 63 : "Trans: " + trans;
if (trans < 0 || trans > 63)
throw new DiskNibbleException ("Trans: " + trans);
return (byte) (trans << 2); // left justify 6 bits
}
}

View File

@ -0,0 +1,40 @@
package com.bytezone.diskbrowser.disk;
class DiskAddressField
{
int track, sector, volume, checksum;
// ---------------------------------------------------------------------------------//
// constructor
// ---------------------------------------------------------------------------------//
DiskAddressField (byte[] buffer, int offset)
{
volume = decode4and4 (buffer, offset);
track = decode4and4 (buffer, offset + 2);
sector = decode4and4 (buffer, offset + 4);
checksum = decode4and4 (buffer, offset + 6);
}
// ---------------------------------------------------------------------------------//
// decode4and4
// ---------------------------------------------------------------------------------//
int decode4and4 (byte[] buffer, int offset)
{
int odds = ((buffer[offset] & 0xFF) << 1) + 1;
int evens = buffer[offset + 1] & 0xFF;
return odds & evens;
}
// ---------------------------------------------------------------------------------//
// toString
// ---------------------------------------------------------------------------------//
@Override
public String toString ()
{
return String.format ("[volume: %02X, track: %02X, sector: %02X, checksum: %02X]",
volume, track, sector, checksum);
}
}

View File

@ -232,7 +232,7 @@ public class DiskFactory
try
{
WozDisk wozDisk = new WozDisk (file);
if (wozDisk.sectorsPerTrack == 13)
if (wozDisk.getSectorsPerTrack () == 13)
{
AppleDisk appleDisk = new AppleDisk (wozDisk, 35, 13);
disk = checkDos (appleDisk);
@ -248,7 +248,8 @@ public class DiskFactory
}
catch (Exception e)
{
System.out.println (e);
// System.out.println (e);
e.printStackTrace ();
return null;
}
}

View File

@ -0,0 +1,17 @@
package com.bytezone.diskbrowser.disk;
public class DiskNibbleException extends Exception
{
String message;
public DiskNibbleException (String message)
{
this.message = message;
}
@Override
public String toString ()
{
return message;
}
}

View File

@ -0,0 +1,33 @@
package com.bytezone.diskbrowser.disk;
import com.bytezone.diskbrowser.disk.MC3470.DiskSector;
public abstract class DiskReader
{
static final int BLOCK_SIZE = 256;
static final byte[] dataPrologue = { (byte) 0xD5, (byte) 0xAA, (byte) 0xAD };
int sectorsPerTrack;
boolean debug = false;
// ---------------------------------------------------------------------------------//
// constructor
// ---------------------------------------------------------------------------------//
DiskReader (int sectorsPerTrack)
{
this.sectorsPerTrack = sectorsPerTrack;
}
// ---------------------------------------------------------------------------------//
// abstract functions
// ---------------------------------------------------------------------------------//
abstract byte[] decodeSector (byte[] buffer, int ptr);
abstract byte[] encodeSector (byte[] buffer);
abstract void storeBuffer (DiskSector diskSector, byte[] diskBuffer);
abstract int expectedDataSize ();
}

View File

@ -0,0 +1,122 @@
package com.bytezone.diskbrowser.disk;
import com.bytezone.diskbrowser.disk.MC3470.DiskSector;
public class DiskReader13Sector extends DiskReader
{
private static final int RAW_BUFFER_SIZE_DOS_32 = 410;
private static final int BUFFER_WITH_CHECKSUM_SIZE_DOS_32 = RAW_BUFFER_SIZE_DOS_32 + 1;
private final byte[] decodeDos32a = new byte[BUFFER_WITH_CHECKSUM_SIZE_DOS_32];
private final byte[] decodeDos32b = new byte[RAW_BUFFER_SIZE_DOS_32];
private final ByteTranslator byteTranslator53 = new ByteTranslator5and3 ();
// ---------------------------------------------------------------------------------//
// constructor
// ---------------------------------------------------------------------------------//
DiskReader13Sector ()
{
super (13);
}
// ---------------------------------------------------------------------------------//
// decodeSector
// ---------------------------------------------------------------------------------//
@Override
byte[] decodeSector (byte[] buffer, int offset)
{
byte[] decodedBuffer = new byte[BLOCK_SIZE];
try
{
// convert legal disk values to actual 5 bit values
for (int i = 0; i < BUFFER_WITH_CHECKSUM_SIZE_DOS_32; i++) // 411 bytes
decodeDos32a[i] = byteTranslator53.decode (buffer[offset++]);
// reconstruct 410 bytes each with 5 bits
byte chk = 0;
int ptr = 0;
for (int i = 409; i >= 256; i--) // 154 bytes
chk = decodeDos32b[i] = (byte) (decodeDos32a[ptr++] ^ chk);
for (int i = 0; i < 256; i++) // 256 bytes
chk = decodeDos32b[i] = (byte) (decodeDos32a[ptr++] ^ chk);
if ((chk ^ decodeDos32a[ptr]) != 0)
throw new DiskNibbleException ("Checksum failed");
// rearrange 410 bytes into 256
byte[] k = new byte[8];
final int[] lines = { 0, 51, 102, 153, 204, 256, 307, 358 }; // 255 is skipped
// process 8 disk bytes at a time, giving 5 valid bytes
// do this 51 times, giving 255 bytes
ptr = 0;
for (int i = 50; i >= 0; i--)
{
for (int j = 0; j < 8; j++)
k[j] = decodeDos32b[i + lines[j]];
k[0] |= (k[5] & 0xE0) >>> 5;
k[1] |= (k[6] & 0xE0) >>> 5;
k[2] |= (k[7] & 0xE0) >>> 5;
k[3] |= (k[5] & 0x10) >>> 2;
k[3] |= (k[6] & 0x10) >>> 3;
k[3] |= (k[7] & 0x10) >>> 4;
k[4] |= (k[5] & 0x08) >>> 1;
k[4] |= (k[6] & 0x08) >>> 2;
k[4] |= (k[7] & 0x08) >>> 3;
for (int j = 0; j < 5; j++)
decodedBuffer[ptr++] = k[j];
}
// add last byte
decodedBuffer[ptr] =
(byte) (decodeDos32b[255] | ((decodeDos32b[409] & 0x3F) >>> 3));
}
catch (Exception e)
{
System.out.println (e);
}
return decodedBuffer;
}
// ---------------------------------------------------------------------------------//
// encodeSector
// ---------------------------------------------------------------------------------//
@Override
byte[] encodeSector (byte[] buffer)
{
System.out.println ("encodeSector() not written");
return null;
}
// ---------------------------------------------------------------------------------//
// storeBuffer
// ---------------------------------------------------------------------------------//
@Override
void storeBuffer (DiskSector diskSector, byte[] diskBuffer)
{
DiskAddressField addressField = diskSector.addressField;
byte[] sectorBuffer = diskSector.buffer;
int offset = addressField.track * 0x0D00 + addressField.sector * 256;
System.arraycopy (sectorBuffer, 0, diskBuffer, offset, 256);
}
// ---------------------------------------------------------------------------------//
// expectedDataSize
// ---------------------------------------------------------------------------------//
@Override
int expectedDataSize ()
{
return 411;
}
}

View File

@ -0,0 +1,163 @@
package com.bytezone.diskbrowser.disk;
import com.bytezone.diskbrowser.disk.MC3470.DiskSector;
public class DiskReader16Sector extends DiskReader
{
private static final int RAW_BUFFER_SIZE_DOS_33 = 342;
private static final int BUFFER_WITH_CHECKSUM_SIZE_DOS_33 = RAW_BUFFER_SIZE_DOS_33 + 1;
private final byte[] decodeDos33a = new byte[BUFFER_WITH_CHECKSUM_SIZE_DOS_33];
private final byte[] decodeDos33b = new byte[RAW_BUFFER_SIZE_DOS_33];
private final byte[] encodeDos33a = new byte[RAW_BUFFER_SIZE_DOS_33];
private final byte[] encodeDos33b = new byte[BUFFER_WITH_CHECKSUM_SIZE_DOS_33];
private final ByteTranslator byteTranslator62 = new ByteTranslator6and2 ();
private static int[] interleave =
{ 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15 };
// ---------------------------------------------------------------------------------//
// constructor
// ---------------------------------------------------------------------------------//
DiskReader16Sector ()
{
super (16);
}
// ---------------------------------------------------------------------------------//
// decodeSector
// ---------------------------------------------------------------------------------//
@Override
byte[] decodeSector (byte[] buffer, int offset)
{
// rearrange 342 bytes into 256
byte[] decodedBuffer = new byte[BLOCK_SIZE]; // 256 bytes
try
{
if (offset + BUFFER_WITH_CHECKSUM_SIZE_DOS_33 >= buffer.length)
throw new DiskNibbleException (
String.format ("Buffer not long enough (need %d, found %d)",
BUFFER_WITH_CHECKSUM_SIZE_DOS_33, buffer.length - offset));
// convert legal disk values to actual 6 bit values
for (int i = 0; i < BUFFER_WITH_CHECKSUM_SIZE_DOS_33; i++) // 343 bytes
{
if (offset == buffer.length)
offset = 0;
decodeDos33a[i] = byteTranslator62.decode (buffer[offset++]);
}
// reconstruct 342 bytes each with 6 bits
byte chk = 0;
for (int i = decodeDos33b.length - 1; i >= 0; i--) // 342 bytes
chk = decodeDos33b[i] = (byte) (decodeDos33a[i + 1] ^ chk);
if ((chk ^ decodeDos33a[0]) != 0)
throw new DiskNibbleException ("Checksum failed");
// move 6 bits into place
for (int i = 0; i < BLOCK_SIZE; i++)
decodedBuffer[i] = decodeDos33b[i + 86];
// reattach each byte's last 2 bits
for (int i = 0, j = 86, k = 172; i < 86; i++, j++, k++)
{
byte val = decodeDos33b[i];
decodedBuffer[i] |= reverse ((val & 0x0C) >> 2);
decodedBuffer[j] |= reverse ((val & 0x30) >> 4);
if (k < BLOCK_SIZE)
decodedBuffer[k] |= reverse ((val & 0xC0) >> 6);
}
}
catch (Exception e)
{
System.out.println (e);
}
return decodedBuffer;
}
// ---------------------------------------------------------------------------------//
// encodeSector
// ---------------------------------------------------------------------------------//
// convert 256 data bytes into 342 translated bytes plus a checksum
@Override
byte[] encodeSector (byte[] buffer)
{
byte[] encodedBuffer = new byte[BUFFER_WITH_CHECKSUM_SIZE_DOS_33];
// move data buffer down to make room for the 86 extra bytes
for (int i = 0; i < BLOCK_SIZE; i++)
encodeDos33a[i + 86] = buffer[i];
// build extra 86 bytes from the bits stripped from the data bytes
for (int i = 0; i < 86; i++)
{
int b1 = reverse (buffer[i] & 0x03) << 2;
int b2 = reverse (buffer[i + 86] & 0x03) << 4;
if (i < 84)
{
int b3 = reverse (buffer[i + 172] & 0x03) << 6;
encodeDos33a[i] = (byte) (b1 | b2 | b3);
}
else
encodeDos33a[i] = (byte) (b1 | b2);
}
// convert into checksum bytes
byte checksum = 0;
for (int i = 0; i < RAW_BUFFER_SIZE_DOS_33; i++)
{
encodeDos33b[i] = (byte) (checksum ^ encodeDos33a[i]);
checksum = encodeDos33a[i];
}
encodeDos33b[RAW_BUFFER_SIZE_DOS_33] = checksum; // add checksum to the end
// remove two bits and convert to translated bytes
for (int i = 0; i < BUFFER_WITH_CHECKSUM_SIZE_DOS_33; i++)
encodedBuffer[i] = byteTranslator62.encode (encodeDos33b[i]);
return encodedBuffer;
}
// ---------------------------------------------------------------------------------//
// reverse
// ---------------------------------------------------------------------------------//
// reverse 2 bits - 0 <= bits <= 3
private static int reverse (int bits)
{
return bits == 1 ? 2 : bits == 2 ? 1 : bits;
}
// ---------------------------------------------------------------------------------//
// storeBuffer
// ---------------------------------------------------------------------------------//
@Override
void storeBuffer (DiskSector diskSector, byte[] diskBuffer)
{
DiskAddressField addressField = diskSector.addressField;
byte[] sectorBuffer = diskSector.buffer;
int offset = addressField.track * 0x1000 + interleave[addressField.sector] * 256;
System.arraycopy (sectorBuffer, 0, diskBuffer, offset, 256);
}
// ---------------------------------------------------------------------------------//
// expectedDataSize
// ---------------------------------------------------------------------------------//
@Override
int expectedDataSize ()
{
return 343;
}
}

View File

@ -0,0 +1,229 @@
package com.bytezone.diskbrowser.disk;
import java.util.ArrayList;
import java.util.List;
class MC3470
{
private final boolean debug = false;
private final byte[] dataBuffer = new byte[411];
int dataPtr = 0;
private final List<DiskSector> diskSectors = new ArrayList<> ();
DiskReader diskReader;
State currentState;
DiskSector currentDiskSector;
int expectedDataSize;
DiskReader diskReader16 = new DiskReader16Sector ();
DiskReader diskReader13 = new DiskReader13Sector ();
enum State
{
ADDRESS, DATA, OTHER
}
// ---------------------------------------------------------------------------------//
// readTrack
// ---------------------------------------------------------------------------------//
void readTrack (byte[] buffer, int offset, int bytesUsed, int bitCount)
{
int value = 0;
final int max = offset + bytesUsed;
int totalBits = 0;
diskSectors.clear ();
currentDiskSector = null;
currentState = State.OTHER;
if (debug)
{
System.out.printf ("%nOffset : %06X%n", offset);
System.out.printf ("Bytes used: %06X%n", bytesUsed);
}
int inPtr = offset;
while (inPtr < max)
{
int b = buffer[inPtr++] & 0xFF;
for (int mask = 0x80; mask != 0; mask >>>= 1)
{
value <<= 1;
if ((b & mask) != 0)
value |= 1;
++totalBits;
if ((value & 0x80) != 0) // is hi-bit set?
{
dataBuffer[dataPtr++] = (byte) value;
checkState (value);
value = 0;
}
}
if (inPtr == max && currentState == State.DATA)
{
System.out.println ("Unfinished business");
}
}
// if (bytesUsed > outputBuffer.length)
// {
// System.out.printf ("Bytes used %,5d%n", bytesUsed);
// System.out.printf ("Buffer size %,5d%n", outPtr);
// }
if (value != 0)
System.out.printf ("********** Value not used: %01X%n", value);
}
// ---------------------------------------------------------------------------------//
// storeSectors
// ---------------------------------------------------------------------------------//
void storeSectors (byte[] diskBuffer)
{
for (DiskSector diskSector : diskSectors)
diskReader.storeBuffer (diskSector, diskBuffer);
}
// ---------------------------------------------------------------------------------//
// checkState
// ---------------------------------------------------------------------------------//
private void checkState (int value)
{
if (value == 0xB5 && isPrologue ())
{
diskReader = diskReader13;
setState (State.ADDRESS);
}
if (value == 0x96 && isPrologue ())
{
diskReader = diskReader16;
setState (State.ADDRESS);
}
if (value == 0xAD && isPrologue ())
setState (State.DATA);
if (value == 0xEB && isEpilogue ())
setState (State.OTHER);
if (dataPtr == expectedDataSize)
setState (State.OTHER);
}
// ---------------------------------------------------------------------------------//
// setState
// ---------------------------------------------------------------------------------//
private void setState (State newState)
{
if (currentState == newState && currentState == State.OTHER)
return;
assert currentState != newState;
switch (currentState) // this state is now finished
{
case ADDRESS:
currentDiskSector = new DiskSector (new DiskAddressField (dataBuffer, 0));
break;
case DATA:
currentDiskSector.setBuffer (diskReader.decodeSector (dataBuffer, 0));
diskSectors.add (currentDiskSector);
break;
case OTHER:
break;
}
currentState = newState;
dataPtr = 0; // start collecting new buffer
switch (currentState) // this state is now starting
{
case ADDRESS:
expectedDataSize = 8;
break;
case DATA:
expectedDataSize = diskReader.expectedDataSize ();
break;
case OTHER:
expectedDataSize = -1; // unspecified length
break;
}
}
// ---------------------------------------------------------------------------------//
// is13Sector
// ---------------------------------------------------------------------------------//
boolean is13Sector ()
{
return diskSectors.size () == 13 && diskReader.sectorsPerTrack == 13;
}
// ---------------------------------------------------------------------------------//
// is16Sector
// ---------------------------------------------------------------------------------//
boolean is16Sector ()
{
return diskSectors.size () == 16 && diskReader.sectorsPerTrack == 16;
}
// ---------------------------------------------------------------------------------//
// isPrologue
// ---------------------------------------------------------------------------------//
private boolean isPrologue ()
{
return dataPtr >= 3 && dataBuffer[dataPtr - 3] == (byte) 0xD5
&& dataBuffer[dataPtr - 2] == (byte) 0xAA;
}
// ---------------------------------------------------------------------------------//
// isEpilogue
// ---------------------------------------------------------------------------------//
private boolean isEpilogue ()
{
return dataPtr >= 3 && dataBuffer[dataPtr - 3] == (byte) 0xDE
&& dataBuffer[dataPtr - 2] == (byte) 0xAA;
}
// ---------------------------------------------------------------------------------//
// DiskSector
// ---------------------------------------------------------------------------------//
class DiskSector
{
DiskAddressField addressField;
byte[] buffer;
DiskSector (DiskAddressField addressField)
{
this.addressField = addressField;
}
void setBuffer (byte[] buffer)
{
this.buffer = buffer;
}
@Override
public String toString ()
{
return addressField.toString ();
}
}
}

View File

@ -2,6 +2,8 @@ package com.bytezone.diskbrowser.disk;
class Nibblizer
{
// still used by NibDisk and V2dDisk
private static byte[] addressPrologue32 = { (byte) 0xD5, (byte) 0xAA, (byte) 0xB5 };
private static byte[] addressPrologue33 = { (byte) 0xD5, (byte) 0xAA, (byte) 0x96 };
private static byte[] dataPrologue = { (byte) 0xD5, (byte) 0xAA, (byte) 0xAD };
@ -11,53 +13,13 @@ class Nibblizer
{ 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15 };
private static final int BLOCK_SIZE = 256;
private static final int TRACK_SIZE = 4096;
private static final int RAW_BUFFER_SIZE_DOS_33 = 342;
private static final int RAW_BUFFER_SIZE_DOS_32 = 410;
private static final int BUFFER_WITH_CHECKSUM_SIZE_DOS_33 = RAW_BUFFER_SIZE_DOS_33 + 1;
private static final int BUFFER_WITH_CHECKSUM_SIZE_DOS_32 = RAW_BUFFER_SIZE_DOS_32 + 1;
// 32 valid bytes that can be stored on a disk (plus 0xAA and 0xD5)
private static byte[] writeTranslateTable5and3 =
{ (byte) 0xAB, (byte) 0xAD, (byte) 0xAE, (byte) 0xAF, (byte) 0xB5, (byte) 0xB6,
(byte) 0xB7, (byte) 0xBA, (byte) 0xBB, (byte) 0xBD, (byte) 0xBE, (byte) 0xBF,
(byte) 0xD6, (byte) 0xD7, (byte) 0xDA, (byte) 0xDB, //
(byte) 0xDD, (byte) 0xDE, (byte) 0xDF, (byte) 0xEA, (byte) 0xEB, (byte) 0xED,
(byte) 0xEE, (byte) 0xEF, (byte) 0xF5, (byte) 0xF6, (byte) 0xF7, (byte) 0xFA,
(byte) 0xFB, (byte) 0xFD, (byte) 0xFE, (byte) 0xFF };
// 64 valid bytes that can be stored on a disk (plus 0xAA and 0xD5)
private static byte[] writeTranslateTable6and2 =
{ (byte) 0x96, (byte) 0x97, (byte) 0x9A, (byte) 0x9B, (byte) 0x9D, (byte) 0x9E,
(byte) 0x9F, (byte) 0xA6, (byte) 0xA7, (byte) 0xAB, (byte) 0xAC, (byte) 0xAD,
(byte) 0xAE, (byte) 0xAF, (byte) 0xB2, (byte) 0xB3, //
(byte) 0xB4, (byte) 0xB5, (byte) 0xB6, (byte) 0xB7, (byte) 0xB9, (byte) 0xBA,
(byte) 0xBB, (byte) 0xBC, (byte) 0xBD, (byte) 0xBE, (byte) 0xBF, (byte) 0xCB,
(byte) 0xCD, (byte) 0xCE, (byte) 0xCF, (byte) 0xD3, //
(byte) 0xD6, (byte) 0xD7, (byte) 0xD9, (byte) 0xDA, (byte) 0xDB, (byte) 0xDC,
(byte) 0xDD, (byte) 0xDE, (byte) 0xDF, (byte) 0xE5, (byte) 0xE6, (byte) 0xE7,
(byte) 0xE9, (byte) 0xEA, (byte) 0xEB, (byte) 0xEC, //
(byte) 0xED, (byte) 0xEE, (byte) 0xEF, (byte) 0xF2, (byte) 0xF3, (byte) 0xF4,
(byte) 0xF5, (byte) 0xF6, (byte) 0xF7, (byte) 0xF9, (byte) 0xFA, (byte) 0xFB,
(byte) 0xFC, (byte) 0xFD, (byte) 0xFE, (byte) 0xFF };
private static byte[] readTranslateTable5and3 = new byte[85]; // skip first 171 blanks
private static byte[] readTranslateTable6and2 = new byte[106]; // skip first 150 blanks
static
{
for (int i = 0; i < writeTranslateTable5and3.length; i++)
{
int j = (writeTranslateTable5and3[i] & 0xFF) - 0xAB; // skip first 171 blanks
readTranslateTable5and3[j] = (byte) (i + 1); // offset by 1 to avoid zero
}
for (int i = 0; i < writeTranslateTable6and2.length; i++)
{
int j = (writeTranslateTable6and2[i] & 0xFF) - 0x96; // skip first 150 blanks
readTranslateTable6and2[j] = (byte) (i + 1); // offset by 1 to avoid zero
}
}
private final ByteTranslator byteTranslator62 = new ByteTranslator6and2 ();
private final ByteTranslator byteTranslator53 = new ByteTranslator5and3 ();
private final byte[] decodeDos33a = new byte[BUFFER_WITH_CHECKSUM_SIZE_DOS_33];
private final byte[] decodeDos33b = new byte[RAW_BUFFER_SIZE_DOS_33];
@ -68,52 +30,35 @@ class Nibblizer
private final byte[] decodeDos32a = new byte[BUFFER_WITH_CHECKSUM_SIZE_DOS_32];
private final byte[] decodeDos32b = new byte[RAW_BUFFER_SIZE_DOS_32];
enum DosVersion
{
DOS_3_2, DOS_3_3
}
private DosVersion currentDosVersion;
int sectorsPerTrack;
private int sectorsPerTrack;
// ---------------------------------------------------------------------------------//
// processTrack
// ---------------------------------------------------------------------------------//
boolean processTrack (int trackNo, byte[] buffer, byte[] diskBuffer)
boolean processTrack (int trackNo, int maxTracks, byte[] buffer, byte[] diskBuffer)
{
int ptr = 0;
int totalSectors = 0;
boolean[] sectorsFound = new boolean[16];
sectorsPerTrack = maxTracks;
try
{
while (ptr < buffer.length)
{
int ptr2 = findBytes (buffer, ptr, addressPrologue33);
if (ptr2 >= 0)
{
currentDosVersion = DosVersion.DOS_3_3;
sectorsPerTrack = 16;
}
if (sectorsPerTrack == 13)
ptr = findBytes (buffer, ptr, addressPrologue32);
else
{
ptr2 = findBytes (buffer, ptr, addressPrologue32);
if (ptr2 >= 0)
{
currentDosVersion = DosVersion.DOS_3_2;
sectorsPerTrack = 13;
}
else
{
System.out.printf ("Track: %02X/%02X - Address prologue not found%n", trackNo,
totalSectors);
return false;
}
}
ptr = ptr2;
ptr = findBytes (buffer, ptr, addressPrologue33);
AddressField addressField = getAddressField (buffer, ptr);
if (ptr < 0)
{
System.out.printf ("Track: %02X - Address prologue not found%n", trackNo);
return false;
}
AddressField addressField = new AddressField (buffer, ptr);
if (!addressField.isValid ())
{
System.out.printf ("Track: %02X - Invalid address field%n", trackNo);
@ -145,26 +90,23 @@ class Nibblizer
return false;
}
DataField dataField = getDataField (buffer, ptr);
DataField dataField = new DataField (buffer, ptr);
if (!dataField.isValid ())
{
System.out.printf ("Track: %02X - Invalid data field%n", trackNo);
return false;
}
int offset = addressField.track * TRACK_SIZE;
if (currentDosVersion == DosVersion.DOS_3_2)
offset += addressField.sector * BLOCK_SIZE;
int offset;
if (sectorsPerTrack == 13)
offset = addressField.track * 0x0D00 + addressField.sector * BLOCK_SIZE;
else
offset += interleave[addressField.sector] * BLOCK_SIZE;
offset =
addressField.track * 0x1000 + interleave[addressField.sector] * BLOCK_SIZE;
System.arraycopy (dataField.dataBuffer, 0, diskBuffer, offset, BLOCK_SIZE);
++totalSectors;
if (currentDosVersion == DosVersion.DOS_3_2 && totalSectors == 13)
break;
if (currentDosVersion == DosVersion.DOS_3_3 && totalSectors == 16)
if (++totalSectors == sectorsPerTrack)
break;
ptr += dataField.size ();
@ -175,13 +117,7 @@ class Nibblizer
e.printStackTrace ();
}
if (currentDosVersion == DosVersion.DOS_3_2 && totalSectors != 13)
{
System.out.printf ("Track: %02X - Sectors found: %02X%n", trackNo, totalSectors);
return false;
}
if (currentDosVersion == DosVersion.DOS_3_3 && totalSectors != 16)
if (totalSectors != sectorsPerTrack)
{
System.out.printf ("Track: %02X - Sectors found: %02X%n", trackNo, totalSectors);
return false;
@ -190,24 +126,6 @@ class Nibblizer
return true;
}
// ---------------------------------------------------------------------------------//
// getAddressField
// ---------------------------------------------------------------------------------//
private AddressField getAddressField (byte[] buffer, int offset)
{
return new AddressField (buffer, offset);
}
// ---------------------------------------------------------------------------------//
// getDataField
// ---------------------------------------------------------------------------------//
private DataField getDataField (byte[] buffer, int offset)
{
return new DataField (buffer, offset);
}
// ---------------------------------------------------------------------------------//
// decode4and4
// ---------------------------------------------------------------------------------//
@ -225,113 +143,105 @@ class Nibblizer
private byte[] decode5and3 (byte[] buffer, int offset)
{
// convert legal disk values to actual 5 bit values
for (int i = 0; i < BUFFER_WITH_CHECKSUM_SIZE_DOS_32; i++) // 411 bytes
decodeDos32a[i] = getByte5and3 (buffer[offset++]);
// reconstruct 410 bytes each with 5 bits
byte chk = 0;
int ptr = 0;
for (int i = 409; i >= 256; i--) // 154 bytes
chk = decodeDos32b[i] = (byte) (decodeDos32a[ptr++] ^ chk);
for (int i = 0; i < 256; i++) // 256 bytes
chk = decodeDos32b[i] = (byte) (decodeDos32a[ptr++] ^ chk);
assert (chk ^ decodeDos32a[ptr]) == 0;
// rearrange 410 bytes into 256
byte[] decodedBuffer = new byte[BLOCK_SIZE]; // 256 bytes
byte[] k = new byte[8];
ptr = 0;
int[] lines = { 0, 51, 102, 153, 204, 256, 307, 358 }; // NB 255 is skipped
// process 8 disk bytes at a time, giving 5 valid bytes
// do this 51 times, giving 255 bytes
for (int i = 50; i >= 0; i--)
try
{
for (int j = 0; j < 8; j++)
k[j] = decodeDos32b[i + lines[j]];
// convert legal disk values to actual 5 bit values
for (int i = 0; i < BUFFER_WITH_CHECKSUM_SIZE_DOS_32; i++) // 411 bytes
{
// System.out.printf ("%,5d %02X%n", i, buffer[offset]);
decodeDos32a[i] = byteTranslator53.decode (buffer[offset++]);
}
k[0] |= (k[5] & 0xE0) >>> 5;
k[1] |= (k[6] & 0xE0) >>> 5;
k[2] |= (k[7] & 0xE0) >>> 5;
// reconstruct 410 bytes each with 5 bits
byte chk = 0;
int ptr = 0;
for (int i = 409; i >= 256; i--) // 154 bytes
chk = decodeDos32b[i] = (byte) (decodeDos32a[ptr++] ^ chk);
for (int i = 0; i < 256; i++) // 256 bytes
chk = decodeDos32b[i] = (byte) (decodeDos32a[ptr++] ^ chk);
assert (chk ^ decodeDos32a[ptr]) == 0;
k[3] |= (k[5] & 0x10) >>> 2;
k[3] |= (k[6] & 0x10) >>> 3;
k[3] |= (k[7] & 0x10) >>> 4;
byte[] k = new byte[8];
ptr = 0;
final int[] lines = { 0, 51, 102, 153, 204, 256, 307, 358 }; // 255 is skipped
k[4] |= (k[5] & 0x08) >>> 1;
k[4] |= (k[6] & 0x08) >>> 2;
k[4] |= (k[7] & 0x08) >>> 3;
// process 8 disk bytes at a time, giving 5 valid bytes
// do this 51 times, giving 255 bytes
for (int i = 50; i >= 0; i--)
{
for (int j = 0; j < 8; j++)
k[j] = decodeDos32b[i + lines[j]];
k[0] |= (k[5] & 0xE0) >>> 5;
k[1] |= (k[6] & 0xE0) >>> 5;
k[2] |= (k[7] & 0xE0) >>> 5;
k[3] |= (k[5] & 0x10) >>> 2;
k[3] |= (k[6] & 0x10) >>> 3;
k[3] |= (k[7] & 0x10) >>> 4;
k[4] |= (k[5] & 0x08) >>> 1;
k[4] |= (k[6] & 0x08) >>> 2;
k[4] |= (k[7] & 0x08) >>> 3;
for (int j = 0; j < 5; j++)
decodedBuffer[ptr++] = k[j];
}
// add last byte
decodedBuffer[255] = (byte) (decodeDos32b[255] | (decodeDos32b[409] >>> 3));
}
catch (Exception e)
{
for (int j = 0; j < 5; j++)
decodedBuffer[ptr++] = k[j];
}
// add last byte
decodedBuffer[255] = (byte) (decodeDos32b[255] | (decodeDos32b[409] >>> 3));
return decodedBuffer;
}
// ---------------------------------------------------------------------------------//
// getByte5and3
// ---------------------------------------------------------------------------------//
private byte getByte5and3 (byte b)
{
int val = (b & 0xFF) - 0xAB; // 0 - 84
assert val >= 0 && val <= 84;
byte trans = (byte) (readTranslateTable5and3[val] - 1); // 0 - 31 (5 bits)
assert trans >= 0 && trans <= 31;
return (byte) (trans << 3); // left justify 5 bits
}
// ---------------------------------------------------------------------------------//
// getByte6and2
// ---------------------------------------------------------------------------------//
private byte getByte6and2 (byte b)
{
int val = (b & 0xFF) - 0x96; // 0 - 105
assert val >= 0 && val <= 105;
byte trans = (byte) (readTranslateTable6and2[val] - 1); // 0 - 63 (6 bits)
assert trans >= 0 && trans <= 63;
return (byte) (trans << 2); // left justify 6 bits
}
// ---------------------------------------------------------------------------------//
// decode6and2
// ---------------------------------------------------------------------------------//
private byte[] decode6and2 (byte[] buffer, int offset)
{
// convert legal disk values to actual 6 bit values
for (int i = 0; i < BUFFER_WITH_CHECKSUM_SIZE_DOS_33; i++) // 343 bytes
decodeDos33a[i] = getByte6and2 (buffer[offset++]);
// reconstruct 342 bytes each with 6 bits
byte chk = 0;
for (int i = decodeDos33b.length - 1; i >= 0; i--) // 342 bytes
chk = decodeDos33b[i] = (byte) (decodeDos33a[i + 1] ^ chk);
assert (chk ^ decodeDos33a[0]) == 0;
// rearrange 342 bytes into 256
byte[] decodedBuffer = new byte[BLOCK_SIZE]; // 256 bytes
// move 6 bits into place
for (int i = 0; i < BLOCK_SIZE; i++)
decodedBuffer[i] = decodeDos33b[i + 86];
// reattach each byte's last 2 bits
for (int i = 0, j = 86, k = 172; i < 86; i++, j++, k++)
try
{
byte val = decodeDos33b[i];
// convert legal disk values to actual 6 bit values
for (int i = 0; i < BUFFER_WITH_CHECKSUM_SIZE_DOS_33; i++) // 343 bytes
decodeDos33a[i] = byteTranslator62.decode (buffer[offset++]);
decodedBuffer[i] |= reverse ((val & 0x0C) >> 2);
decodedBuffer[j] |= reverse ((val & 0x30) >> 4);
// reconstruct 342 bytes each with 6 bits
byte chk = 0;
for (int i = decodeDos33b.length - 1; i >= 0; i--) // 342 bytes
chk = decodeDos33b[i] = (byte) (decodeDos33a[i + 1] ^ chk);
assert (chk ^ decodeDos33a[0]) == 0;
// move 6 bits into place
for (int i = 0; i < BLOCK_SIZE; i++)
decodedBuffer[i] = decodeDos33b[i + 86];
// reattach each byte's last 2 bits
for (int i = 0, j = 86, k = 172; i < 86; i++, j++, k++)
{
byte val = decodeDos33b[i];
decodedBuffer[i] |= reverse ((val & 0x0C) >> 2);
decodedBuffer[j] |= reverse ((val & 0x30) >> 4);
if (k < BLOCK_SIZE)
decodedBuffer[k] |= reverse ((val & 0xC0) >> 6);
}
}
catch (Exception e)
{
if (k < BLOCK_SIZE)
decodedBuffer[k] |= reverse ((val & 0xC0) >> 6);
}
return decodedBuffer;
@ -376,7 +286,8 @@ class Nibblizer
// remove two bits and convert to translated bytes
for (int i = 0; i < BUFFER_WITH_CHECKSUM_SIZE_DOS_33; i++)
encodedBuffer[i] = writeTranslateTable6and2[(encodeDos33b[i] & 0xFC) / 4];
// encodedBuffer[i] = writeTranslateTable6and2[(encodeDos33b[i] & 0xFC) / 4];
encodedBuffer[i] = byteTranslator62.encode (encodeDos33b[i]);
return encodedBuffer;
}
@ -496,17 +407,11 @@ class Nibblizer
{
super (buffer, offset);
// if (matchBytes (buffer, offset, addressPrologue33))
// // && matchBytes (buffer, offset + 11, epilogue))
// {
volume = decode4and4 (buffer, offset + 3);
track = decode4and4 (buffer, offset + 5);
sector = decode4and4 (buffer, offset + 7);
checksum = decode4and4 (buffer, offset + 9);
valid = true;
// }
// else
// System.out.println (listBytes (buffer, offset, 14));
length = 14;
}
@ -534,10 +439,10 @@ class Nibblizer
if (matchBytes (buffer, offset, dataPrologue))
{
valid = true;
if (currentDosVersion == DosVersion.DOS_3_3)
dataBuffer = decode6and2 (buffer, offset + 3);
else if (currentDosVersion == DosVersion.DOS_3_2)
if (sectorsPerTrack == 13)
dataBuffer = decode5and3 (buffer, offset + 3);
else
dataBuffer = decode6and2 (buffer, offset + 3);
}
else
{

View File

@ -85,7 +85,7 @@ class V2dDisk
int halfTrackNo = trackNumber % 4;
if (halfTrackNo == 0) // only process full tracks
nibbler.processTrack (fullTrackNo, trackData, diskBuffer);
nibbler.processTrack (fullTrackNo, 16, trackData, diskBuffer);
else
System.out.printf ("%s skipping half track %02X / %02X%n", file.getName (),
fullTrackNo, halfTrackNo);

View File

@ -10,18 +10,20 @@ import com.bytezone.diskbrowser.utilities.Utility;
class WozDisk
{
private static final byte[] WOZ_DISK_HEADER =
{ 0x57, 0x4F, 0x5A, 0x31, (byte) 0xFF, 0x0a, 0x0D, 0x0A };
private static final int TRK_SIZE = 0x1A00;
private static final int INFO_SIZE = 0x3C;
private static final int TMAP_SIZE = 0xA0;
private static final int DATA_SIZE = TRK_SIZE - 10;
private static byte[] header =
{ 0x57, 0x4F, 0x5A, 0x31, (byte) 0xFF, 0x0a, 0x0D, 0x0A };
private final boolean debug = false;
private int diskType; // 5.25 or 3.5
int sectorsPerTrack;
final File file;
final byte[] diskBuffer = new byte[4096 * 35];
byte[] diskBuffer;
private final MC3470 mc3470 = new MC3470 ();
// ---------------------------------------------------------------------------------//
// constructor
@ -30,10 +32,9 @@ class WozDisk
public WozDisk (File file) throws Exception
{
this.file = file;
Nibblizer nibbler = new Nibblizer ();
byte[] buffer = readFile ();
if (!matches (header, buffer))
if (!matches (WOZ_DISK_HEADER, buffer))
throw new Exception ("Header error");
int cs1 = readInt (buffer, 8, 4);
@ -88,7 +89,8 @@ class WozDisk
if (debug)
System.out.println ("Reading TRKS");
int tracks = chunkSize / TRK_SIZE;
for (int track = 0; track < tracks; track++)
for (int trackNo = 0; trackNo < tracks; trackNo++)
{
int bytesUsed = readInt (buffer, ptr + DATA_SIZE, 2);
int bitCount = readInt (buffer, ptr + DATA_SIZE + 2, 2);
@ -99,22 +101,37 @@ class WozDisk
System.out.printf ("Bit count .... %,6d%n", bitCount);
}
byte[] trackData = readTrack (buffer, ptr, bytesUsed, bitCount);
if (!nibbler.processTrack (track, trackData, diskBuffer))
try
{
System.out.println ("Nibblizer failure");
if (debug)
System.out.println (HexFormatter.format (trackData));
break read;
mc3470.readTrack (buffer, ptr, bytesUsed, bitCount);
if (trackNo == 0)
{
if (mc3470.is13Sector ())
diskBuffer = new byte[35 * 13 * 256];
else if (mc3470.is16Sector ())
diskBuffer = new byte[35 * 16 * 256];
else
{
System.out.println ("unknown disk format");
break read;
}
}
mc3470.storeSectors (diskBuffer);
}
catch (Exception e)
{
e.printStackTrace ();
}
ptr += TRK_SIZE;
if (track == 0)
sectorsPerTrack = nibbler.sectorsPerTrack;
}
}
else if ("META".equals (chunkId))
{
System.out.printf ("[%s] %08X%n", chunkId, chunkSize);
System.out.println (HexFormatter.format (buffer, ptr, chunkSize));
ptr += chunkSize;
}
else
@ -125,6 +142,15 @@ class WozDisk
}
}
// ---------------------------------------------------------------------------------//
// getSectorsPerTrack
// ---------------------------------------------------------------------------------//
int getSectorsPerTrack ()
{
return mc3470.is13Sector () ? 13 : 16;
}
// ---------------------------------------------------------------------------------//
// readInt
// ---------------------------------------------------------------------------------//
@ -141,48 +167,6 @@ class WozDisk
return value;
}
// ---------------------------------------------------------------------------------//
// readTrack
// ---------------------------------------------------------------------------------//
private byte[] readTrack (byte[] buffer, int offset, int bytesUsed, int bitCount)
{
byte[] trackData = new byte[bytesUsed];
int value = 0;
int ptr = 0;
final int max = offset + bytesUsed;
int count = 0;
for (int i = offset; i < max; i++)
{
int b = buffer[i] & 0xFF;
for (int mask = 0x80; mask > 0; mask >>>= 1)
{
value <<= 1;
if ((b & mask) != 0)
value |= 1;
++count;
if ((value & 0x80) != 0) // is hi-bit set?
{
trackData[ptr++] = (byte) value;
value = 0;
}
}
}
if (value != 0)
System.out.printf ("********** Value not used: %01X%n", value);
if (debug && bitCount != count)
{
System.out.printf ("BitCount: %,4d%n", bitCount);
System.out.printf ("Actual : %,4d%n", count);
}
return trackData;
}
// ---------------------------------------------------------------------------------//
// readFile
// ---------------------------------------------------------------------------------//