More nibbling

This commit is contained in:
Denis Molony 2018-08-13 19:17:05 +10:00
parent 6eb4acc85d
commit d47af9b63c
10 changed files with 173 additions and 179 deletions

View File

@ -203,7 +203,7 @@ public class AppleDisk implements Disk
checkSectorsForData ();
}
public AppleDisk (V2dDisk disk, int tracks, int sectors)
public AppleDisk (V2dFile disk, int tracks, int sectors)
{
this.tracks = tracks;
this.sectors = sectors;
@ -218,7 +218,7 @@ public class AppleDisk implements Disk
checkSectorsForData ();
}
public AppleDisk (NibDisk disk) // not used yet
public AppleDisk (NibFile disk) // not used yet
{
tracks = 35;
trackSize = 4096;
@ -226,12 +226,12 @@ public class AppleDisk implements Disk
diskBuffer = disk.buffer;
}
public AppleDisk (WozDisk disk, int tracks, int sectors)
public AppleDisk (WozFile wozFile, int tracks, int sectors)
{
this.tracks = tracks;
this.sectors = sectors;
file = disk.file;
diskBuffer = disk.diskBuffer;
file = wozFile.file;
diskBuffer = wozFile.diskBuffer;
if (sectors == 13)
{

View File

@ -231,7 +231,7 @@ public class DiskFactory
{
try
{
WozDisk wozDisk = new WozDisk (file);
WozFile wozDisk = new WozFile (file);
if (wozDisk.getSectorsPerTrack () == 13)
{
AppleDisk appleDisk = new AppleDisk (wozDisk, 35, 13);
@ -259,7 +259,7 @@ public class DiskFactory
if (suffix.equals ("v2d"))
{
V2dDisk v2dDisk = new V2dDisk (file);
V2dFile v2dDisk = new V2dFile (file);
AppleDisk appleDisk256 = new AppleDisk (v2dDisk, 35, 16);
disk = checkDos (appleDisk256);
if (disk == null)
@ -274,7 +274,7 @@ public class DiskFactory
if (debug)
System.out.println (" ** nib **");
NibDisk nibDisk = new NibDisk (file);
NibFile nibDisk = new NibFile (file);
AppleDisk appleDisk16 = new AppleDisk (nibDisk);
disk = checkDos (appleDisk16);
return null;

View File

@ -1,14 +1,11 @@
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 };
final int sectorsPerTrack;
boolean debug = false;
// ---------------------------------------------------------------------------------//
// constructor
@ -23,11 +20,11 @@ public abstract class DiskReader
// abstract functions
// ---------------------------------------------------------------------------------//
abstract byte[] decodeSector (byte[] buffer);
abstract byte[] decodeSector (byte[] buffer) throws DiskNibbleException;
abstract byte[] encodeSector (byte[] buffer);
abstract void storeBuffer (DiskSector diskSector, byte[] diskBuffer);
abstract void storeBuffer (RawDiskSector diskSector, byte[] diskBuffer);
abstract int expectedDataSize ();
}

View File

@ -1,7 +1,5 @@
package com.bytezone.diskbrowser.disk;
import com.bytezone.diskbrowser.disk.MC3470.DiskSector;
public class DiskReader13Sector extends DiskReader
{
private static final int RAW_BUFFER_SIZE = 410;
@ -26,64 +24,56 @@ public class DiskReader13Sector extends DiskReader
// ---------------------------------------------------------------------------------//
@Override
byte[] decodeSector (byte[] buffer)
byte[] decodeSector (byte[] buffer) throws DiskNibbleException
{
byte[] decodedBuffer = new byte[BLOCK_SIZE];
int offset = 0;
try
// convert legal disk values to actual 5 bit values
for (int i = 0; i < BUFFER_WITH_CHECKSUM_SIZE; i++) // 411 bytes
decodeA[i] = (byte) (byteTranslator.decode (buffer[offset++]) << 3);
// reconstruct 410 bytes each with 5 bits
byte chk = 0;
int ptr = 0;
for (int i = 409; i >= 256; i--) // 154 bytes
chk = decodeB[i] = (byte) (decodeA[ptr++] ^ chk);
for (int i = 0; i < 256; i++) // 256 bytes
chk = decodeB[i] = (byte) (decodeA[ptr++] ^ chk);
if ((chk ^ decodeA[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--)
{
// convert legal disk values to actual 5 bit values
for (int i = 0; i < BUFFER_WITH_CHECKSUM_SIZE; i++) // 411 bytes
decodeA[i] = (byte) (byteTranslator.decode (buffer[offset++]) << 3);
for (int j = 0; j < 8; j++)
k[j] = decodeB[i + lines[j]];
// reconstruct 410 bytes each with 5 bits
byte chk = 0;
int ptr = 0;
for (int i = 409; i >= 256; i--) // 154 bytes
chk = decodeB[i] = (byte) (decodeA[ptr++] ^ chk);
for (int i = 0; i < 256; i++) // 256 bytes
chk = decodeB[i] = (byte) (decodeA[ptr++] ^ chk);
if ((chk ^ decodeA[ptr]) != 0)
throw new DiskNibbleException ("Checksum failed");
k[0] |= (k[5] & 0xE0) >>> 5;
k[1] |= (k[6] & 0xE0) >>> 5;
k[2] |= (k[7] & 0xE0) >>> 5;
// rearrange 410 bytes into 256
byte[] k = new byte[8];
final int[] lines = { 0, 51, 102, 153, 204, 256, 307, 358 }; // 255 is skipped
k[3] |= (k[5] & 0x10) >>> 2;
k[3] |= (k[6] & 0x10) >>> 3;
k[3] |= (k[7] & 0x10) >>> 4;
// 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] = decodeB[i + lines[j]];
k[4] |= (k[5] & 0x08) >>> 1;
k[4] |= (k[6] & 0x08) >>> 2;
k[4] |= (k[7] & 0x08) >>> 3;
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) (decodeB[255] | ((decodeB[409] & 0x3F) >>> 3));
}
catch (Exception e)
{
// e.printStackTrace ();
System.out.println (e);
for (int j = 0; j < 5; j++)
decodedBuffer[ptr++] = k[j];
}
// add last byte
decodedBuffer[ptr] = (byte) (decodeB[255] | ((decodeB[409] & 0x3F) >>> 3));
return decodedBuffer;
}
@ -103,7 +93,7 @@ public class DiskReader13Sector extends DiskReader
// ---------------------------------------------------------------------------------//
@Override
void storeBuffer (DiskSector diskSector, byte[] diskBuffer)
void storeBuffer (RawDiskSector diskSector, byte[] diskBuffer)
{
DiskAddressField addressField = diskSector.addressField;
byte[] sectorBuffer = diskSector.buffer;

View File

@ -1,7 +1,5 @@
package com.bytezone.diskbrowser.disk;
import com.bytezone.diskbrowser.disk.MC3470.DiskSector;
public class DiskReader16Sector extends DiskReader
{
private static final int RAW_BUFFER_SIZE = 342;
@ -32,45 +30,37 @@ public class DiskReader16Sector extends DiskReader
// ---------------------------------------------------------------------------------//
@Override
byte[] decodeSector (byte[] buffer)
byte[] decodeSector (byte[] buffer) throws DiskNibbleException
{
// rearrange 342 bytes into 256
byte[] decodedBuffer = new byte[BLOCK_SIZE]; // 256 bytes
byte[] decodedBuffer = new byte[BLOCK_SIZE]; // 256 bytes
int offset = 0;
try
// convert legal disk values to actual 6 bit values
for (int i = 0; i < BUFFER_WITH_CHECKSUM_SIZE; i++) // 343 bytes
decodeA[i] = (byte) (byteTranslator.decode (buffer[offset++]) << 2);
// reconstruct 342 bytes each with 6 bits
byte chk = 0;
for (int i = decodeB.length - 1; i >= 0; i--) // 342 bytes
chk = decodeB[i] = (byte) (decodeA[i + 1] ^ chk);
if ((chk ^ decodeA[0]) != 0)
throw new DiskNibbleException ("Checksum failed");
// move 6 bits into place
for (int i = 0; i < BLOCK_SIZE; i++)
decodedBuffer[i] = decodeB[i + 86];
// reattach each byte's last 2 bits
for (int i = 0, j = 86, k = 172; i < 86; i++, j++, k++)
{
// convert legal disk values to actual 6 bit values
for (int i = 0; i < BUFFER_WITH_CHECKSUM_SIZE; i++) // 343 bytes
decodeA[i] = (byte) (byteTranslator.decode (buffer[offset++]) << 2);
byte val = decodeB[i];
// reconstruct 342 bytes each with 6 bits
byte chk = 0;
for (int i = decodeB.length - 1; i >= 0; i--) // 342 bytes
chk = decodeB[i] = (byte) (decodeA[i + 1] ^ chk);
if ((chk ^ decodeA[0]) != 0)
throw new DiskNibbleException ("Checksum failed");
decodedBuffer[i] |= reverse ((val & 0x0C) >> 2);
decodedBuffer[j] |= reverse ((val & 0x30) >> 4);
// move 6 bits into place
for (int i = 0; i < BLOCK_SIZE; i++)
decodedBuffer[i] = decodeB[i + 86];
// reattach each byte's last 2 bits
for (int i = 0, j = 86, k = 172; i < 86; i++, j++, k++)
{
byte val = decodeB[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);
// e.printStackTrace ();
if (k < BLOCK_SIZE)
decodedBuffer[k] |= reverse ((val & 0xC0) >> 6);
}
return decodedBuffer;
@ -137,7 +127,7 @@ public class DiskReader16Sector extends DiskReader
// ---------------------------------------------------------------------------------//
@Override
void storeBuffer (DiskSector diskSector, byte[] diskBuffer)
void storeBuffer (RawDiskSector diskSector, byte[] diskBuffer)
{
DiskAddressField addressField = diskSector.addressField;
byte[] sectorBuffer = diskSector.buffer;

View File

@ -7,14 +7,15 @@ import com.bytezone.diskbrowser.utilities.HexFormatter;
class MC3470
{
private static final int EMPTY = 999;
private static final int MAX_DATA = 999;
private final boolean debug = false;
private final boolean dump = false;
private final List<DiskSector> diskSectors = new ArrayList<> ();
private List<RawDiskSector> diskSectors;
private State currentState;
private DiskSector currentDiskSector;
private RawDiskSector currentDiskSector;
private int expectedDataSize;
private boolean finished;
private boolean restarted;
@ -23,7 +24,7 @@ class MC3470
private final DiskReader diskReader16 = new DiskReader16Sector ();
private final DiskReader diskReader13 = new DiskReader13Sector ();
private final byte[] dataBuffer = new byte[EMPTY];
private final byte[] dataBuffer = new byte[MAX_DATA];
private int dataPtr = 0;
private enum State
@ -35,40 +36,46 @@ class MC3470
// readTrack
// ---------------------------------------------------------------------------------//
void readTrack (byte[] buffer, int offset, int bytesUsed, int bitCount)
List<RawDiskSector> readTrack (byte[] buffer, int offset, int bytesUsed, int bitCount)
throws DiskNibbleException
{
final int max = offset + bytesUsed;
int totalBits = 0;
int totalBytes = 0;
diskSectors.clear ();
diskSectors = new ArrayList<> ();
diskReader = null;
currentDiskSector = null;
currentState = State.OTHER;
expectedDataSize = EMPTY;
finished = false;
restarted = false;
int value = 0;
byte value = 0; // value to be stored
dataPtr = 0;
expectedDataSize = MAX_DATA;
if (debug)
{
System.out.printf ("%nOffset : %06X%n", offset);
System.out.printf ("Bytes used: %06X%n", bytesUsed);
System.out.printf ("Bit count : %06X%n", bitCount);
System.out.printf ("remaining : %06X%n", bitCount % 8);
}
int inPtr = offset; // keep offset in case we have to loop around
while (!finished && inPtr < max)
int inPtr = offset; // keep offset in case we have to loop around
while (inPtr < max && !finished)
{
int b = buffer[inPtr++] & 0xFF;
byte b = buffer[inPtr++];
if (!restarted)
totalBytes++;
for (int mask = 0x80; mask != 0; mask >>>= 1)
{
value <<= 1;
if ((b & mask) != 0)
value |= 1;
value |= 0x01;
if ((value & 0x80) != 0) // is hi-bit set?
if ((value & 0x80) != 0) // value is not valid until the hi-bit is set
{
if (dump)
{
@ -77,7 +84,7 @@ class MC3470
System.out.printf ("%02X ", value);
}
dataBuffer[dataPtr++] = (byte) value;
dataBuffer[dataPtr++] = value;
checkState (value);
value = 0;
}
@ -86,6 +93,7 @@ class MC3470
break;
}
// check for unfinished data block, we may need to restart the track
if (inPtr == max && currentState == State.DATA && !restarted)
{
inPtr = offset;
@ -95,18 +103,28 @@ class MC3470
if (debug)
{
System.out.printf ("total bits : %d%n", bitCount);
System.out.printf ("bits used : %d%n", totalBits);
System.out.println ("**************************************");
System.out.printf ("* total bits : %,5d *%n", bitCount);
System.out.printf ("* bits used : %,5d *%n", totalBits);
System.out.printf ("* total bytes : %,5d *%n", bytesUsed);
System.out.printf ("* bytes used : %,5d *%n", totalBytes);
System.out.println ("**************************************");
}
return diskSectors;
}
// ---------------------------------------------------------------------------------//
// storeSectors
// ---------------------------------------------------------------------------------//
void storeSectors (byte[] diskBuffer)
void storeSectors (List<RawDiskSector> diskSectors, byte[] diskBuffer)
throws DiskNibbleException
{
for (DiskSector diskSector : diskSectors)
if (diskReader == null)
throw new DiskNibbleException ("No DiskReader");
for (RawDiskSector diskSector : diskSectors)
diskReader.storeBuffer (diskSector, diskBuffer);
}
@ -132,11 +150,11 @@ class MC3470
// checkState
// ---------------------------------------------------------------------------------//
private void checkState (int value) throws DiskNibbleException
private void checkState (byte value) throws DiskNibbleException
{
switch (value)
{
case 0xB5:
case (byte) 0xB5:
if (isPrologue ())
{
diskReader = diskReader13;
@ -144,7 +162,7 @@ class MC3470
}
break;
case 0x96:
case (byte) 0x96:
if (isPrologue ())
{
diskReader = diskReader16;
@ -152,12 +170,12 @@ class MC3470
}
break;
case 0xAD:
case (byte) 0xAD:
if (isPrologue ())
setState (State.DATA);
break;
case 0xEB:
case (byte) 0xEB:
if (isEpilogue ())
setState (State.OTHER);
break;
@ -175,7 +193,7 @@ class MC3470
// setState
// ---------------------------------------------------------------------------------//
private void setState (State newState)
private void setState (State newState) throws DiskNibbleException
{
if (currentState == newState && currentState == State.OTHER)
return;
@ -184,13 +202,22 @@ class MC3470
switch (currentState) // this state is now finished
{
case ADDRESS:
currentDiskSector = new DiskSector (new DiskAddressField (dataBuffer));
if (currentDiskSector != null)
System.out.printf ("unused ADDRESS: %s%n", currentDiskSector);
currentDiskSector = new RawDiskSector (new DiskAddressField (dataBuffer));
if (dump)
System.out.println (currentDiskSector);
break;
case DATA:
if (currentDiskSector != null)
if (currentDiskSector == null)
{
System.out.printf ("cannot store %d DATA no ADDRESS", dataPtr);
if (debug)
System.out.println (HexFormatter.format (dataBuffer, 0, dataPtr));
}
else
{
currentDiskSector.setBuffer (diskReader.decodeSector (dataBuffer));
diskSectors.add (currentDiskSector);
@ -198,17 +225,9 @@ class MC3470
if (diskSectors.size () == diskReader.sectorsPerTrack)
finished = true;
}
else
{
if (debug)
{
System.out.printf ("cannot store %d DATA no ADDRESS", dataPtr);
System.out.println (HexFormatter.format (dataBuffer, 0, dataPtr));
}
}
break;
case OTHER:
case OTHER: // triggered by an epilogue or full address/data buffer
break;
}
@ -234,12 +253,12 @@ class MC3470
case OTHER:
if (dump)
System.out.println ("OTHER");
expectedDataSize = EMPTY; // what is the maximum filler?
expectedDataSize = MAX_DATA; // what is the maximum filler?
break;
}
currentState = newState;
dataPtr = 0; // start collecting new buffer
dataPtr = 0; // start collecting new buffer
}
// ---------------------------------------------------------------------------------//
@ -265,30 +284,4 @@ class MC3470
|| dataBuffer[dataPtr - 3] == (byte) 0xDA) // non-standard
&& dataBuffer[dataPtr - 2] == (byte) 0xAA;
}
// ---------------------------------------------------------------------------------//
// DiskSector
// ---------------------------------------------------------------------------------//
class DiskSector
{
final 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

@ -5,7 +5,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
class NibDisk
class NibFile
{
// private final Nibblizer nibbler;
@ -20,7 +20,7 @@ class NibDisk
// add 'nib' to Utility.suffixes to allow nib files to be selected
public NibDisk (File file)
public NibFile (File file)
{
this.file = file;
byte[] trackBuffer = new byte[6656];

View File

@ -0,0 +1,23 @@
package com.bytezone.diskbrowser.disk;
public class RawDiskSector
{
final DiskAddressField addressField;
byte[] buffer;
RawDiskSector (DiskAddressField addressField)
{
this.addressField = addressField;
}
void setBuffer (byte[] buffer)
{
this.buffer = buffer;
}
@Override
public String toString ()
{
return addressField.toString ();
}
}

View File

@ -30,7 +30,7 @@ import com.bytezone.diskbrowser.utilities.HexFormatter;
// Position: 0 8 1 9 2 A 3 B 4 C 5 D 6 E 7 F - Prodos (.PO disks)
// Position: 0 7 E 6 D 5 C 4 B 3 A 2 9 1 8 F - Dos (.DO disks)
class V2dDisk
class V2dFile
{
// private static int[][] interleave =
// { { 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15 },
@ -48,7 +48,7 @@ class V2dDisk
final byte[] diskBuffer = new byte[4096 * 35];
public V2dDisk (File file)
public V2dFile (File file)
{
this.file = file;
int tracks = 0;

View File

@ -4,12 +4,13 @@ import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
import com.bytezone.diskbrowser.utilities.Utility;
class WozDisk
class WozFile
{
private static final byte[] WOZ_DISK_HEADER =
private static final byte[] WOZ_FILE_HEADER =
{ 0x57, 0x4F, 0x5A, 0x31, (byte) 0xFF, 0x0a, 0x0D, 0x0A };
private static final int TRK_SIZE = 0x1A00;
private static final int INFO_SIZE = 0x3C;
@ -28,20 +29,20 @@ class WozDisk
// constructor
// ---------------------------------------------------------------------------------//
public WozDisk (File file) throws Exception
public WozFile (File file) throws Exception
{
this.file = file;
byte[] buffer = readFile ();
if (!matches (WOZ_DISK_HEADER, buffer))
if (!matches (WOZ_FILE_HEADER, buffer))
throw new Exception ("Header error");
int cs1 = readInt (buffer, 8, 4);
int cs2 = Utility.crc32 (buffer, 12, buffer.length - 12);
if (cs1 != cs2)
int checksum1 = readInt (buffer, 8, 4);
int checksum2 = Utility.crc32 (buffer, 12, buffer.length - 12);
if (checksum1 != checksum2)
{
System.out.printf ("Checksum : %08X%n", cs1);
System.out.printf ("Calculated: %08X%n", cs2);
System.out.printf ("Stored checksum : %08X%n", checksum1);
System.out.printf ("Calculated checksum : %08X%n", checksum2);
throw new Exception ("Checksum error");
}
@ -109,7 +110,8 @@ class WozDisk
try
{
mc3470.readTrack (buffer, ptr, bytesUsed, bitCount);
List<RawDiskSector> diskSectors =
mc3470.readTrack (buffer, ptr, bytesUsed, bitCount);
if (trackNo == 0) // create disk buffer
{
@ -121,17 +123,16 @@ class WozDisk
{
System.out.println ("unknown disk format");
break read;
// continue;
}
}
mc3470.storeSectors (diskBuffer);
mc3470.storeSectors (diskSectors, diskBuffer);
}
catch (Exception e)
{
// e.printStackTrace ();
System.out.println (e);
// break read;
break read;
}
ptr += TRK_SIZE;