Woz 3.5" disks, display preferences

This commit is contained in:
Denis Molony 2019-09-05 06:44:43 +10:00
parent 696393799a
commit 19386e5c8e
17 changed files with 364 additions and 109 deletions

View File

@ -556,7 +556,7 @@ public class ApplesoftBasicProgram extends BasicProgram
this.length = length; this.length = length;
byte b = buffer[startPtr]; byte b = buffer[startPtr];
if (isToken (b)) if (isHighBitSet (b))
{ {
switch (b) switch (b)
{ {
@ -637,7 +637,7 @@ public class ApplesoftBasicProgram extends BasicProgram
private boolean isImpliedGoto () private boolean isImpliedGoto ()
{ {
byte b = buffer[startPtr]; byte b = buffer[startPtr];
if (isToken (b)) if (isHighBitSet (b))
return false; return false;
return (isDigit (b)); return (isDigit (b));
} }
@ -677,7 +677,7 @@ public class ApplesoftBasicProgram extends BasicProgram
{ {
// ignore first byte, check the rest for tokens // ignore first byte, check the rest for tokens
for (int p = startPtr + 1, max = startPtr + length; p < max; p++) for (int p = startPtr + 1, max = startPtr + length; p < max; p++)
if (isToken (buffer[p])) if (isHighBitSet (buffer[p]))
return true; return true;
return false; return false;
} }
@ -740,7 +740,7 @@ public class ApplesoftBasicProgram extends BasicProgram
for (int p = startPtr; p <= max; p++) for (int p = startPtr; p <= max; p++)
{ {
byte b = buffer[p]; byte b = buffer[p];
if (isToken (b)) if (isHighBitSet (b))
{ {
if (line.length () > 0 && line.charAt (line.length () - 1) != ' ') if (line.length () > 0 && line.charAt (line.length () - 1) != ' ')
line.append (' '); line.append (' ');

View File

@ -9,13 +9,14 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import com.bytezone.common.Utility;
import com.bytezone.diskbrowser.gui.AssemblerPreferences; import com.bytezone.diskbrowser.gui.AssemblerPreferences;
import com.bytezone.diskbrowser.gui.DiskBrowser; import com.bytezone.diskbrowser.gui.DiskBrowser;
import com.bytezone.diskbrowser.utilities.HexFormatter; import com.bytezone.diskbrowser.utilities.HexFormatter;
public class AssemblerProgram extends AbstractFile public class AssemblerProgram extends AbstractFile
{ {
static AssemblerPreferences assemblerPreferences; // set by MenuHandler
private static Map<Integer, String> equates; private static Map<Integer, String> equates;
private final int loadAddress; private final int loadAddress;
@ -26,8 +27,6 @@ public class AssemblerProgram extends AbstractFile
private List<Integer> entryPoints; private List<Integer> entryPoints;
private List<StringLocation> stringLocations; private List<StringLocation> stringLocations;
static AssemblerPreferences assemblerPreferences;
public static void setAssemblerPreferences (AssemblerPreferences assemblerPreferences) public static void setAssemblerPreferences (AssemblerPreferences assemblerPreferences)
{ {
AssemblerProgram.assemblerPreferences = assemblerPreferences; AssemblerProgram.assemblerPreferences = assemblerPreferences;
@ -81,6 +80,7 @@ public class AssemblerProgram extends AbstractFile
{ {
if (buffer == null) if (buffer == null)
return "No buffer"; return "No buffer";
if (assembler == null) if (assembler == null)
this.assembler = new AssemblerProgram (name, buffer, loadAddress); this.assembler = new AssemblerProgram (name, buffer, loadAddress);
@ -94,19 +94,25 @@ public class AssemblerProgram extends AbstractFile
return assembler.getText () + "\n\n" + assemblerProgram.getText (); return assembler.getText () + "\n\n" + assemblerProgram.getText ();
} }
@Override private void addHeader (StringBuilder pgm)
public String getText ()
{ {
StringBuilder pgm = new StringBuilder ();
pgm.append (String.format ("Name : %s%n", name)); pgm.append (String.format ("Name : %s%n", name));
pgm.append (String.format ("Length : $%04X (%,d)%n", buffer.length, buffer.length)); pgm.append (String.format ("Length : $%04X (%,d)%n", buffer.length, buffer.length));
pgm.append (String.format ("Load at : $%04X (%,d)%n", loadAddress, loadAddress)); pgm.append (String.format ("Load at : $%04X (%,d)%n", loadAddress, loadAddress));
if (executeOffset > 0) if (executeOffset > 0)
pgm.append (String.format ("Entry : $%04X%n", (loadAddress + executeOffset))); pgm.append (String.format ("Entry : $%04X%n", (loadAddress + executeOffset)));
pgm.append ("\n"); pgm.append ("\n");
}
@Override
public String getText ()
{
StringBuilder pgm = new StringBuilder ();
if (assemblerPreferences.showHeader)
addHeader (pgm);
pgm.append (getListing ()); pgm.append (getListing ());
if (assemblerPreferences.showStrings) if (assemblerPreferences.showStrings)
@ -250,7 +256,7 @@ public class AssemblerProgram extends AbstractFile
{ {
int address = stringLocation.offset + loadAddress; int address = stringLocation.offset + loadAddress;
text.append (String.format ("%s %04X - %04X %s %n", text.append (String.format ("%s %04X - %04X %s %n",
entryPoints.contains (stringLocation.offset + loadAddress) ? "*" : " ", address, entryPoints.contains (stringLocation.offset) ? "*" : " ", address,
address + stringLocation.length, stringLocation)); address + stringLocation.length, stringLocation));
} }
@ -266,19 +272,8 @@ public class AssemblerProgram extends AbstractFile
stringLocations = new ArrayList<> (); stringLocations = new ArrayList<> ();
int start = 0; int start = 0;
int max = buffer.length - 2;
for (int ptr = 0; ptr < buffer.length; ptr++) for (int ptr = 0; ptr < buffer.length; ptr++)
{ {
if ((buffer[ptr] == (byte) 0xBD // LDA Absolute,X
|| buffer[ptr] == (byte) 0xB9 // LDA Absolute,Y
|| buffer[ptr] == (byte) 0xAD) // LDA Absolute
&& (ptr < max))
{
int address = Utility.getWord (buffer, ptr + 1);
if (address >= loadAddress && address < loadAddress + buffer.length)
entryPoints.add (address);
}
if ((buffer[ptr] & 0x80) != 0) // hi bit set if ((buffer[ptr] & 0x80) != 0) // hi bit set
continue; continue;
@ -290,6 +285,15 @@ public class AssemblerProgram extends AbstractFile
if (buffer.length - start > 3) if (buffer.length - start > 3)
stringLocations.add (new StringLocation (start, buffer.length - 1)); stringLocations.add (new StringLocation (start, buffer.length - 1));
int max = buffer.length - 2;
for (StringLocation stringLocation : stringLocations)
for (int ptr = 0; ptr < max; ptr++)
if (stringLocation.matches (buffer, ptr))
{
entryPoints.add (stringLocation.offset);
break;
}
} }
private String getArrow (AssemblerStatement cmd) private String getArrow (AssemblerStatement cmd)
@ -350,6 +354,7 @@ public class AssemblerProgram extends AbstractFile
class StringLocation class StringLocation
{ {
int offset; int offset;
byte hi, lo;
int length; int length;
boolean zeroTerminated; boolean zeroTerminated;
boolean lowTerminated; boolean lowTerminated;
@ -364,12 +369,20 @@ public class AssemblerProgram extends AbstractFile
{ {
offset = first; offset = first;
length = last - offset + 1; length = last - offset + 1;
int end = last + 1; int end = last + 1;
zeroTerminated = end < buffer.length && buffer[end] == 0; zeroTerminated = end < buffer.length && buffer[end] == 0;
lowTerminated = end < buffer.length && buffer[end] >= 32 && buffer[end] < 127; lowTerminated = end < buffer.length && buffer[end] >= 32 && buffer[end] < 127;
hasLengthByte = first > 0 && (buffer[first] & 0xFF) == length;
if (first > 0 && (buffer[first] & 0xFF) == length + 1)
{
hasLengthByte = true;
--offset;
++length;
}
hi = (byte) ((offset + loadAddress) >>> 8);
lo = (byte) ((offset + loadAddress) & 0x00FF);
for (int i = offset; i < offset + length; i++) for (int i = offset; i < offset + length; i++)
{ {
@ -389,11 +402,21 @@ public class AssemblerProgram extends AbstractFile
} }
} }
boolean matches (byte[] buffer, int ptr)
{
return lo == buffer[ptr] && hi == buffer[ptr + 1];
}
boolean likelyString () boolean likelyString ()
{ {
return spaces > 0 || letters > punctuation; return spaces > 0 || letters > punctuation;
} }
public String address ()
{
return String.format ("%04X %02X %02X", offset, hi, lo);
}
public String toStatisticsString () public String toStatisticsString ()
{ {
return String.format ("%2d, %2d, %2d, %2d, %2d", digits, letters, punctuation, return String.format ("%2d, %2d, %2d, %2d, %2d", digits, letters, punctuation,

View File

@ -9,11 +9,11 @@ public abstract class BasicProgram extends AbstractFile
static final byte ASCII_SEMI_COLON = 0x3B; static final byte ASCII_SEMI_COLON = 0x3B;
static final byte ASCII_CARET = 0x5E; static final byte ASCII_CARET = 0x5E;
static BasicPreferences basicPreferences; static BasicPreferences basicPreferences; // set by MenuHandler
public static void setBasicPreferences (BasicPreferences basicPreferences) public static void setBasicPreferences (BasicPreferences basicPreferences)
{ {
ApplesoftBasicProgram.basicPreferences = basicPreferences; BasicProgram.basicPreferences = basicPreferences;
} }
public BasicProgram (String name, byte[] buffer) public BasicProgram (String name, byte[] buffer)
@ -21,14 +21,15 @@ public abstract class BasicProgram extends AbstractFile
super (name, buffer); super (name, buffer);
} }
boolean isToken (byte value) boolean isHighBitSet (byte value)
{ {
return (value & 0x80) != 0; return (value & 0x80) != 0;
} }
boolean isControlCharacter (byte value) boolean isControlCharacter (byte value)
{ {
return (value & 0xFF) < 32; int val = value & 0xFF;
return val > 0 && val < 32;
} }
boolean isDigit (byte value) boolean isDigit (byte value)

View File

@ -136,7 +136,7 @@ public class BasicProgramGS extends BasicProgram
while (ptr < max) while (ptr < max)
{ {
byte b1 = buffer[ptr++]; byte b1 = buffer[ptr++];
if (isToken (b1)) if (isHighBitSet (b1))
ptr = tokenOrNumber (b1, text, ptr); ptr = tokenOrNumber (b1, text, ptr);
else else
text.append ((b1 & 0xFF) < 32 ? '.' : (char) b1); text.append ((b1 & 0xFF) < 32 ? '.' : (char) b1);

View File

@ -10,6 +10,7 @@ public class BootSector extends AbstractSector
private static final byte[] skew = { 0x00, 0x0D, 0x0B, 0x09, 0x07, 0x05, 0x03, 0x01, private static final byte[] skew = { 0x00, 0x0D, 0x0B, 0x09, 0x07, 0x05, 0x03, 0x01,
0x0E, 0x0C, 0x0A, 0x08, 0x06, 0x04, 0x02, 0x0F }; 0x0E, 0x0C, 0x0A, 0x08, 0x06, 0x04, 0x02, 0x0F };
private static final int SKEW_OFFSET = 0x4D; private static final int SKEW_OFFSET = 0x4D;
private static final int SKEW_OFFSET_2 = 0x3C; // DOS 4.x
AssemblerProgram assembler1; AssemblerProgram assembler1;
AssemblerProgram assembler2; AssemblerProgram assembler2;
@ -34,7 +35,7 @@ public class BootSector extends AbstractSector
if (assembler1 == null) if (assembler1 == null)
{ {
int flag = buffer[0] & 0xFF; int flag = buffer[0] & 0xFF; // how many blocks to load
if (flag == 1) // apple II if (flag == 1) // apple II
{ {
if (matches (buffer, SKEW_OFFSET, skew)) if (matches (buffer, SKEW_OFFSET, skew))
@ -53,8 +54,8 @@ public class BootSector extends AbstractSector
} }
else // apple III (SOS) else // apple III (SOS)
{ {
byte[] newBuffer = new byte[buffer.length * 2]; // byte[] newBuffer = new byte[buffer.length * 2];
System.arraycopy (buffer, 0, newBuffer, 0, buffer.length); // System.arraycopy (buffer, 0, newBuffer, 0, buffer.length);
// byte[] buf = disk.readSector (1); // byte[] buf = disk.readSector (1);
// System.arraycopy (buf, 0, newBuffer, buf.length, buf.length); // System.arraycopy (buf, 0, newBuffer, buf.length, buf.length);
@ -66,6 +67,7 @@ public class BootSector extends AbstractSector
} }
text.append (assembler1.getText ()); text.append (assembler1.getText ());
if (assembler2 != null) if (assembler2 != null)
{ {
text.append ("\n\n"); text.append ("\n\n");

View File

@ -247,13 +247,30 @@ public class DiskFactory
if (wozFile.getSectorsPerTrack () == 16) if (wozFile.getSectorsPerTrack () == 16)
{ {
AppleDisk appleDisk256 = new AppleDisk (wozFile, wozFile.getTracks (), 16); if (wozFile.getDiskType () == 2)
disk = checkDos (appleDisk256); {
if (disk == null) if (debug)
disk = checkProdos (new AppleDisk (wozFile, 35, 8)); System.out.println ("Checking woz 3.5");
if (disk == null) AppleDisk disk800 = new AppleDisk (wozFile, 200, 8);
disk = new DataDisk (appleDisk256); if (ProdosDisk.isCorrectFormat (disk800))
{
if (debug)
System.out.println (" --> PRODOS hard disk");
return new ProdosDisk (disk800);
}
disk = new DataDisk (disk800);
}
else
{
AppleDisk appleDisk256 = new AppleDisk (wozFile, wozFile.getTracks (), 16);
disk = checkDos (appleDisk256);
if (disk == null)
disk = checkProdos (new AppleDisk (wozFile, 35, 8));
if (disk == null)
disk = new DataDisk (appleDisk256);
}
} }
return disk; return disk;
} }
catch (Exception e) catch (Exception e)

View File

@ -5,6 +5,7 @@ public class AssemblerPreferences
public boolean showTargets = true; public boolean showTargets = true;
public boolean showStrings = true; public boolean showStrings = true;
public boolean offsetFromZero = false; public boolean offsetFromZero = false;
public boolean showHeader = true;
@Override @Override
public String toString () public String toString ()
@ -14,6 +15,7 @@ public class AssemblerPreferences
text.append (String.format ("Show targets .......... %s%n", showTargets)); text.append (String.format ("Show targets .......... %s%n", showTargets));
text.append (String.format ("Show strings .......... %s%n", showStrings)); text.append (String.format ("Show strings .......... %s%n", showStrings));
text.append (String.format ("Offset from zero ...... %s%n", offsetFromZero)); text.append (String.format ("Offset from zero ...... %s%n", offsetFromZero));
text.append (String.format ("Show header ........... %s%n", showHeader));
return text.toString (); return text.toString ();
} }

View File

@ -35,6 +35,7 @@ public class MenuHandler
private static final String PREFS_SHOW_ASSEMBLER_TARGETS = "showAssemblerTargets"; private static final String PREFS_SHOW_ASSEMBLER_TARGETS = "showAssemblerTargets";
private static final String PREFS_SHOW_ASSEMBLER_STRINGS = "showAssemblerStrings"; private static final String PREFS_SHOW_ASSEMBLER_STRINGS = "showAssemblerStrings";
private static final String PREFS_SHOW_ASSEMBLER_HEADER = "showAssemblerHeader";
// private static final String PREFS_DEBUGGING = "debugging"; // private static final String PREFS_DEBUGGING = "debugging";
private static final String PREFS_PALETTE = "palette"; private static final String PREFS_PALETTE = "palette";
@ -99,6 +100,7 @@ public class MenuHandler
// Assembler menu items // Assembler menu items
final JMenuItem showAssemblerTargetsItem = new JCheckBoxMenuItem ("Show targets"); final JMenuItem showAssemblerTargetsItem = new JCheckBoxMenuItem ("Show targets");
final JMenuItem showAssemblerStringsItem = new JCheckBoxMenuItem ("Show strings"); final JMenuItem showAssemblerStringsItem = new JCheckBoxMenuItem ("Show strings");
final JMenuItem showAssemblerHeaderItem = new JCheckBoxMenuItem ("Show header");
ButtonGroup paletteGroup = new ButtonGroup (); ButtonGroup paletteGroup = new ButtonGroup ();
@ -174,6 +176,7 @@ public class MenuHandler
assemblerMenu.add (showAssemblerTargetsItem); assemblerMenu.add (showAssemblerTargetsItem);
assemblerMenu.add (showAssemblerStringsItem); assemblerMenu.add (showAssemblerStringsItem);
assemblerMenu.add (showAssemblerHeaderItem);
ActionListener basicPreferencesAction = new ActionListener () ActionListener basicPreferencesAction = new ActionListener ()
{ {
@ -204,6 +207,7 @@ public class MenuHandler
showAssemblerTargetsItem.addActionListener (assemblerPreferencesAction); showAssemblerTargetsItem.addActionListener (assemblerPreferencesAction);
showAssemblerStringsItem.addActionListener (assemblerPreferencesAction); showAssemblerStringsItem.addActionListener (assemblerPreferencesAction);
showAssemblerHeaderItem.addActionListener (assemblerPreferencesAction);
helpMenu.add (new JMenuItem (new EnvironmentAction ())); helpMenu.add (new JMenuItem (new EnvironmentAction ()));
@ -255,6 +259,7 @@ public class MenuHandler
{ {
assemblerPreferences.showTargets = showAssemblerTargetsItem.isSelected (); assemblerPreferences.showTargets = showAssemblerTargetsItem.isSelected ();
assemblerPreferences.showStrings = showAssemblerStringsItem.isSelected (); assemblerPreferences.showStrings = showAssemblerStringsItem.isSelected ();
assemblerPreferences.showHeader = showAssemblerHeaderItem.isSelected ();
AssemblerProgram.setAssemblerPreferences (assemblerPreferences); AssemblerProgram.setAssemblerPreferences (assemblerPreferences);
} }
@ -323,6 +328,7 @@ public class MenuHandler
showAssemblerTargetsItem.isSelected ()); showAssemblerTargetsItem.isSelected ());
prefs.putBoolean (PREFS_SHOW_ASSEMBLER_STRINGS, prefs.putBoolean (PREFS_SHOW_ASSEMBLER_STRINGS,
showAssemblerStringsItem.isSelected ()); showAssemblerStringsItem.isSelected ());
prefs.putBoolean (PREFS_SHOW_ASSEMBLER_HEADER, showAssemblerHeaderItem.isSelected ());
} }
@Override @Override
@ -334,6 +340,7 @@ public class MenuHandler
showFreeSectorsItem.setSelected (prefs.getBoolean (PREFS_SHOW_FREE_SECTORS, false)); showFreeSectorsItem.setSelected (prefs.getBoolean (PREFS_SHOW_FREE_SECTORS, false));
colourQuirksItem.setSelected (prefs.getBoolean (PREFS_COLOUR_QUIRKS, false)); colourQuirksItem.setSelected (prefs.getBoolean (PREFS_COLOUR_QUIRKS, false));
monochromeItem.setSelected (prefs.getBoolean (PREFS_MONOCHROME, false)); monochromeItem.setSelected (prefs.getBoolean (PREFS_MONOCHROME, false));
// debuggingItem.setSelected (prefs.getBoolean (PREFS_DEBUGGING, false)); // debuggingItem.setSelected (prefs.getBoolean (PREFS_DEBUGGING, false));
splitRemarkItem.setSelected (prefs.getBoolean (PREFS_SPLIT_REMARKS, false)); splitRemarkItem.setSelected (prefs.getBoolean (PREFS_SPLIT_REMARKS, false));
@ -348,6 +355,8 @@ public class MenuHandler
.setSelected (prefs.getBoolean (PREFS_SHOW_ASSEMBLER_TARGETS, true)); .setSelected (prefs.getBoolean (PREFS_SHOW_ASSEMBLER_TARGETS, true));
showAssemblerStringsItem showAssemblerStringsItem
.setSelected (prefs.getBoolean (PREFS_SHOW_ASSEMBLER_STRINGS, true)); .setSelected (prefs.getBoolean (PREFS_SHOW_ASSEMBLER_STRINGS, true));
showAssemblerHeaderItem
.setSelected (prefs.getBoolean (PREFS_SHOW_ASSEMBLER_HEADER, true));
setBasicPreferences (); setBasicPreferences ();
setAssemblerPreferences (); setAssemblerPreferences ();

View File

@ -1,8 +1,14 @@
package com.bytezone.diskbrowser.nib; package com.bytezone.diskbrowser.nib;
public interface ByteTranslator // -----------------------------------------------------------------------------------//
interface ByteTranslator
// -----------------------------------------------------------------------------------//
{ {
// ---------------------------------------------------------------------------------//
abstract byte encode (byte b); abstract byte encode (byte b);
// ---------------------------------------------------------------------------------//
// ---------------------------------------------------------------------------------//
abstract byte decode (byte b) throws DiskNibbleException; abstract byte decode (byte b) throws DiskNibbleException;
// ---------------------------------------------------------------------------------//
} }

View File

@ -1,6 +1,8 @@
package com.bytezone.diskbrowser.nib; package com.bytezone.diskbrowser.nib;
public class ByteTranslator5and3 implements ByteTranslator // -----------------------------------------------------------------------------------//
class ByteTranslator5and3 implements ByteTranslator
// -----------------------------------------------------------------------------------//
{ {
// 32 valid bytes that can be stored on a disk (plus 0xAA and 0xD5) // 32 valid bytes that can be stored on a disk (plus 0xAA and 0xD5)
private static byte[] writeTranslateTable5and3 = private static byte[] writeTranslateTable5and3 =
@ -11,14 +13,16 @@ public class ByteTranslator5and3 implements ByteTranslator
(byte) 0xEE, (byte) 0xEF, (byte) 0xF5, (byte) 0xF6, (byte) 0xF7, (byte) 0xFA, (byte) 0xEE, (byte) 0xEF, (byte) 0xF5, (byte) 0xF6, (byte) 0xF7, (byte) 0xFA,
(byte) 0xFB, (byte) 0xFD, (byte) 0xFE, (byte) 0xFF }; (byte) 0xFB, (byte) 0xFD, (byte) 0xFE, (byte) 0xFF };
private static byte[] readTranslateTable5and3 = new byte[85]; // skip first 171 blanks private static final int SKIP = 0xAB;
private static byte[] readTranslateTable5and3 = new byte[256 - SKIP];
private static boolean debug = false; private static boolean debug = false;
static static
{ {
for (int i = 0; i < writeTranslateTable5and3.length; i++) for (int i = 0; i < writeTranslateTable5and3.length; i++)
{ {
int j = (writeTranslateTable5and3[i] & 0xFF) - 0xAB; // skip first 171 blanks int j = (writeTranslateTable5and3[i] & 0xFF) - SKIP; // skip first 171 blanks
readTranslateTable5and3[j] = (byte) (i + 1); // offset by 1 to avoid zero readTranslateTable5and3[j] = (byte) (i + 1); // offset by 1 to avoid zero
if (debug) if (debug)
System.out.printf ("%02X %02X %02X%n", i, writeTranslateTable5and3[i], j); System.out.printf ("%02X %02X %02X%n", i, writeTranslateTable5and3[i], j);
@ -38,24 +42,20 @@ public class ByteTranslator5and3 implements ByteTranslator
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
// encode
// ---------------------------------------------------------------------------------//
@Override @Override
public byte encode (byte b) public byte encode (byte b)
// ---------------------------------------------------------------------------------//
{ {
System.out.println ("encode() not written"); System.out.println ("encode() not written");
return 0; return 0;
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
// decode
// ---------------------------------------------------------------------------------//
@Override @Override
public byte decode (byte b) throws DiskNibbleException public byte decode (byte b) throws DiskNibbleException
// ---------------------------------------------------------------------------------//
{ {
int val = (b & 0xFF) - 0xAB; // 0 - 84 int val = (b & 0xFF) - SKIP; // 0 - 84
if (val < 0 || val > 84) if (val < 0 || val > 84)
throw new DiskNibbleException ("5&3 val: " + val); throw new DiskNibbleException ("5&3 val: " + val);
byte trans = (byte) (readTranslateTable5and3[val] - 1); // 0 - 31 (5 bits) byte trans = (byte) (readTranslateTable5and3[val] - 1); // 0 - 31 (5 bits)

View File

@ -1,6 +1,8 @@
package com.bytezone.diskbrowser.nib; package com.bytezone.diskbrowser.nib;
public class ByteTranslator6and2 implements ByteTranslator // -----------------------------------------------------------------------------------//
class ByteTranslator6and2 implements ByteTranslator
// -----------------------------------------------------------------------------------//
{ {
// 64 valid bytes that can be stored on a disk (plus 0xAA and 0xD5) // 64 valid bytes that can be stored on a disk (plus 0xAA and 0xD5)
private static byte[] writeTranslateTable6and2 = private static byte[] writeTranslateTable6and2 =
@ -17,35 +19,36 @@ public class ByteTranslator6and2 implements ByteTranslator
(byte) 0xF5, (byte) 0xF6, (byte) 0xF7, (byte) 0xF9, (byte) 0xFA, (byte) 0xFB, (byte) 0xF5, (byte) 0xF6, (byte) 0xF7, (byte) 0xF9, (byte) 0xFA, (byte) 0xFB,
(byte) 0xFC, (byte) 0xFD, (byte) 0xFE, (byte) 0xFF }; (byte) 0xFC, (byte) 0xFD, (byte) 0xFE, (byte) 0xFF };
private static byte[] readTranslateTable6and2 = new byte[106]; // skip first 150 blanks private static final int SKIP = 0x96;
private static byte[] readTranslateTable6and2 = new byte[256 - SKIP];
static static
{ {
for (int i = 0; i < writeTranslateTable6and2.length; i++) for (int i = 0; i < writeTranslateTable6and2.length; i++)
{ {
int j = (writeTranslateTable6and2[i] & 0xFF) - 0x96; // skip first 150 blanks int j = (writeTranslateTable6and2[i] & 0xFF) - SKIP; // skip first 150 blanks
readTranslateTable6and2[j] = (byte) (i + 1); // offset by 1 to avoid zero readTranslateTable6and2[j] = (byte) (i + 1); // offset by 1 to avoid zero
} }
if (false)
for (int i = 0; i < readTranslateTable6and2.length; i++)
System.out.printf ("%02X %02X%n", i + SKIP, readTranslateTable6and2[i] - 1);
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
// encode
// ---------------------------------------------------------------------------------//
@Override @Override
public byte encode (byte b) public byte encode (byte b)
// ---------------------------------------------------------------------------------//
{ {
return writeTranslateTable6and2[(b & 0xFC)]; return writeTranslateTable6and2[(b & 0xFC)];
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
// decode
// ---------------------------------------------------------------------------------//
@Override @Override
public byte decode (byte b) throws DiskNibbleException public byte decode (byte b) throws DiskNibbleException
// ---------------------------------------------------------------------------------//
{ {
int val = (b & 0xFF) - 0x96; // 0 - 105 int val = (b & 0xFF) - SKIP; // 0 - 105
if (val < 0 || val > 105) if (val < 0 || val > 105)
throw new DiskNibbleException ("6&2 val: " + val); throw new DiskNibbleException ("6&2 val: " + val);
byte trans = (byte) (readTranslateTable6and2[val] - 1); // 0 - 63 (6 bits) byte trans = (byte) (readTranslateTable6and2[val] - 1); // 0 - 63 (6 bits)

View File

@ -1,16 +1,22 @@
package com.bytezone.diskbrowser.nib; package com.bytezone.diskbrowser.nib;
public class DiskNibbleException extends Exception // -----------------------------------------------------------------------------------//
class DiskNibbleException extends Exception
// -----------------------------------------------------------------------------------//
{ {
String message; String message;
// ---------------------------------------------------------------------------------//
public DiskNibbleException (String message) public DiskNibbleException (String message)
// ---------------------------------------------------------------------------------//
{ {
this.message = message; this.message = message;
} }
// ---------------------------------------------------------------------------------//
@Override @Override
public String toString () public String toString ()
// ---------------------------------------------------------------------------------//
{ {
return message; return message;
} }

View File

@ -1,14 +1,15 @@
package com.bytezone.diskbrowser.nib; package com.bytezone.diskbrowser.nib;
// ---------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
public abstract class DiskReader abstract class DiskReader
// ---------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
static final int BLOCK_SIZE = 256; static final int BLOCK_SIZE = 256;
static final byte[] dataPrologue = { (byte) 0xD5, (byte) 0xAA, (byte) 0xAD }; static final byte[] dataPrologue = { (byte) 0xD5, (byte) 0xAA, (byte) 0xAD };
static DiskReader reader13; static DiskReader reader13;
static DiskReader reader16; static DiskReader reader16;
static DiskReader readerGRC;
final int sectorsPerTrack; final int sectorsPerTrack;
@ -23,21 +24,26 @@ public abstract class DiskReader
static DiskReader getInstance (int sectors) static DiskReader getInstance (int sectors)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
if (sectors == 13) switch (sectors)
{ {
if (reader13 == null) case 13:
reader13 = new DiskReader13Sector (); if (reader13 == null)
return reader13; reader13 = new DiskReader13Sector ();
} return reader13;
if (sectors == 16) case 16:
{ if (reader16 == null)
if (reader16 == null) reader16 = new DiskReader16Sector ();
reader16 = new DiskReader16Sector (); return reader16;
return reader16;
}
return null; case 0:
if (readerGRC == null)
readerGRC = new DiskReaderGRC ();
return readerGRC;
default:
return null;
}
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -55,7 +61,5 @@ public abstract class DiskReader
abstract byte[] encodeSector (byte[] buffer); abstract byte[] encodeSector (byte[] buffer);
// abstract void storeBuffer (RawDiskSector diskSector, byte[] diskBuffer);
abstract int expectedDataSize (); abstract int expectedDataSize ();
} }

View File

@ -1,7 +1,7 @@
package com.bytezone.diskbrowser.nib; package com.bytezone.diskbrowser.nib;
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
public class DiskReader13Sector extends DiskReader class DiskReader13Sector extends DiskReader
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
private static final int RAW_BUFFER_SIZE = 410; private static final int RAW_BUFFER_SIZE = 410;

View File

@ -1,7 +1,7 @@
package com.bytezone.diskbrowser.nib; package com.bytezone.diskbrowser.nib;
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
public class DiskReader16Sector extends DiskReader class DiskReader16Sector extends DiskReader
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
private static final int RAW_BUFFER_SIZE = 342; private static final int RAW_BUFFER_SIZE = 342;

View File

@ -0,0 +1,99 @@
package com.bytezone.diskbrowser.nib;
// -----------------------------------------------------------------------------------//
public class DiskReaderGRC extends DiskReader
// -----------------------------------------------------------------------------------//
{
private final ByteTranslator byteTranslator = new ByteTranslator6and2 ();
// ---------------------------------------------------------------------------------//
DiskReaderGRC ()
// ---------------------------------------------------------------------------------//
{
super (0);
}
// ---------------------------------------------------------------------------------//
@Override
byte[] decodeSector (byte[] buffer, int ptr) throws DiskNibbleException
// ---------------------------------------------------------------------------------//
{
byte[] outBuffer = new byte[BLOCK_SIZE * 2 + 12]; // 524 bytes
int outPtr = 0;
int[] checksums = new int[3];
for (int j = 0; j < 175; j++)
{
checksums[0] = (checksums[0] & 0xFF) << 1; // ROL
if ((checksums[0] > 0xFF))
++checksums[0];
byte d3 = byteTranslator.decode (buffer[ptr++]); // composite byte
byte d0 = byteTranslator.decode (buffer[ptr++]);
byte d1 = byteTranslator.decode (buffer[ptr++]);
byte b0 = (byte) ((d0 & 0x3F) | ((d3 & 0x30) << 2));
byte b1 = (byte) ((d1 & 0x3F) | ((d3 & 0x0C) << 4));
outBuffer[outPtr++] = checksum (b0, checksums, 0, 2);
outBuffer[outPtr++] = checksum (b1, checksums, 2, 1);
if (j < 174)
{
byte d2 = byteTranslator.decode (buffer[ptr++]);
byte b2 = (byte) ((d2 & 0x3F) | ((d3 & 0x03) << 6));
outBuffer[outPtr++] = checksum (b2, checksums, 1, 0);
}
}
byte d3 = byteTranslator.decode (buffer[ptr++]); // composite byte
byte d0 = byteTranslator.decode (buffer[ptr++]);
byte d1 = byteTranslator.decode (buffer[ptr++]);
byte d2 = byteTranslator.decode (buffer[ptr++]);
byte b0 = (byte) ((d0 & 0x3F) | ((d3 & 0x30) << 2));
byte b1 = (byte) ((d1 & 0x3F) | ((d3 & 0x0C) << 4));
byte b2 = (byte) ((d2 & 0x3F) | ((d3 & 0x03) << 6));
if ((checksums[0] & 0xFF) != (b2 & 0xFF) //
|| (checksums[1] & 0xFF) != (b1 & 0xFF) //
|| (checksums[2] & 0xFF) != (b0 & 0xFF))
throw new DiskNibbleException ("Checksum failed");
return outBuffer;
}
// ---------------------------------------------------------------------------------//
private byte checksum (byte b, int[] checksums, int c1, int c2)
// ---------------------------------------------------------------------------------//
{
int val = (b ^ checksums[c1]) & 0xFF;
checksums[c2] += val;
if (checksums[c1] > 0xFF)
{
++checksums[c2];
checksums[c1] &= 0xFF;
}
return (byte) val;
}
// ---------------------------------------------------------------------------------//
@Override
byte[] encodeSector (byte[] buffer)
// ---------------------------------------------------------------------------------//
{
return null;
}
// ---------------------------------------------------------------------------------//
@Override
int expectedDataSize ()
// ---------------------------------------------------------------------------------//
{
assert false;
return 0;
}
}

View File

@ -5,6 +5,7 @@ import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@ -44,6 +45,8 @@ public class WozFile
private final boolean debug1 = false; private final boolean debug1 = false;
private final boolean showTracks = false; private final boolean showTracks = false;
private final ByteTranslator6and2 byteTranslator6and2 = new ByteTranslator6and2 ();
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public WozFile (File file) throws DiskNibbleException public WozFile (File file) throws DiskNibbleException
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -101,7 +104,23 @@ public class WozFile
diskBuffer = new byte[tracks.size () * diskSectors * SECTOR_SIZE]; diskBuffer = new byte[tracks.size () * diskSectors * SECTOR_SIZE];
for (Track track : tracks) for (Track track : tracks)
track.pack (diskBuffer); track.packType1 (diskBuffer);
}
else if (info.diskType == 2) // 3.5"
{
List<Sector> sectors = new ArrayList<> ();
for (Track track : tracks)
sectors.addAll (track.sectors);
Collections.sort (sectors);
diskBuffer = new byte[800 * info.sides * SECTOR_SIZE * 2];
ptr = 0;
for (Sector sector : sectors)
{
sector.pack (diskBuffer, ptr);
ptr += 512;
}
} }
} }
@ -112,6 +131,13 @@ public class WozFile
return diskBuffer; return diskBuffer;
} }
// ---------------------------------------------------------------------------------//
public int getDiskType ()
// ---------------------------------------------------------------------------------//
{
return info.diskType;
}
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public int getTracks () public int getTracks ()
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -368,9 +394,6 @@ public class WozFile
this.rawBuffer = rawBuffer; this.rawBuffer = rawBuffer;
this.trackNo = trackNo; this.trackNo = trackNo;
// if (debug1)
// System.out.println (HexFormatter.format (rawBuffer, ptr, 1024, ptr));
if (info.wozVersion == 1) if (info.wozVersion == 1)
{ {
bytesUsed = val16 (rawBuffer, ptr + DATA_SIZE); bytesUsed = val16 (rawBuffer, ptr + DATA_SIZE);
@ -413,18 +436,21 @@ public class WozFile
break; break;
Sector sector = new Sector (this, offset); Sector sector = new Sector (this, offset);
checkDuplicates (sector); if (isDuplicate (sector))
break;
sectors.add (sector); sectors.add (sector);
} }
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
private void checkDuplicates (Sector newSector) private boolean isDuplicate (Sector newSector)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
for (Sector sector : sectors) for (Sector sector : sectors)
if (sector.isDuplicate (newSector)) if (sector.sectorNo == newSector.sectorNo)
System.out.printf ("Duplicate: %s%n", newSector); return true;
return false;
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -483,7 +509,7 @@ public class WozFile
return; return;
int max = (bitCount - 1) / 8 + 1; int max = (bitCount - 1) / 8 + 1;
max += 520; max += 600;
newBuffer = new byte[max]; newBuffer = new byte[max];
for (int i = 0; i < max; i++) for (int i = 0; i < max; i++)
@ -509,7 +535,7 @@ public class WozFile
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
void pack (byte[] diskBuffer) throws DiskNibbleException void packType1 (byte[] diskBuffer) throws DiskNibbleException
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
int ndx = diskSectors == 13 ? 0 : 1; int ndx = diskSectors == 13 ? 0 : 1;
@ -517,8 +543,29 @@ public class WozFile
for (Sector sector : sectors) for (Sector sector : sectors)
if (sector.dataOffset > 0) if (sector.dataOffset > 0)
sector.pack (diskReader, diskBuffer, SECTOR_SIZE {
* (sector.trackNo * diskSectors + interleave[ndx][sector.sectorNo])); byte[] decodedBuffer =
diskReader.decodeSector (newBuffer, sector.dataOffset + 3);
int ptr = SECTOR_SIZE
* (sector.trackNo * diskSectors + interleave[ndx][sector.sectorNo]);
System.arraycopy (decodedBuffer, 0, diskBuffer, ptr, decodedBuffer.length);
}
}
// ---------------------------------------------------------------------------------//
int packType2 (byte[] diskBuffer, int ptr) throws DiskNibbleException
// ---------------------------------------------------------------------------------//
{
DiskReader diskReader = DiskReader.getInstance (0);
for (Sector sector : sectors)
if (sector.dataOffset > 0)
{
byte[] decodedBuffer =
diskReader.decodeSector (newBuffer, sector.dataOffset + 4);
System.arraycopy (decodedBuffer, 12, diskBuffer, ptr, 512);
ptr += 512;
}
return ptr;
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -552,11 +599,11 @@ public class WozFile
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public class Sector public class Sector implements Comparable<Sector>
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
private final Track track; private final Track track;
private final int trackNo, sectorNo, volume, checksum; private int trackNo, sectorNo, volume, checksum;
private final int addressOffset; private final int addressOffset;
private int dataOffset; private int dataOffset;
@ -566,10 +613,37 @@ public class WozFile
{ {
this.track = track; this.track = track;
volume = decode4and4 (track.newBuffer, addressOffset + 3); if (info.diskType == 1)
trackNo = decode4and4 (track.newBuffer, addressOffset + 5); {
sectorNo = decode4and4 (track.newBuffer, addressOffset + 7); volume = decode4and4 (track.newBuffer, addressOffset + 3);
checksum = decode4and4 (track.newBuffer, addressOffset + 9); trackNo = decode4and4 (track.newBuffer, addressOffset + 5);
sectorNo = decode4and4 (track.newBuffer, addressOffset + 7);
checksum = decode4and4 (track.newBuffer, addressOffset + 9);
}
else
{
// http://apple2.guidero.us/doku.php/articles/iicplus_smartport_secrets
// SWIM Chip User's Ref pp 6
// uPD72070.pdf
try
{
int b1 = byteTranslator6and2.decode (track.newBuffer[addressOffset + 3]);
sectorNo = byteTranslator6and2.decode (track.newBuffer[addressOffset + 4]);
int b3 = byteTranslator6and2.decode (track.newBuffer[addressOffset + 5]);
int format = byteTranslator6and2.decode (track.newBuffer[addressOffset + 6]);
checksum = byteTranslator6and2.decode (track.newBuffer[addressOffset + 7]);
trackNo = (b1 & 0x3F) | ((b3 & 0x1F) << 6);
volume = (b3 & 0x20) >>> 5; // side
int chk = b1 ^ sectorNo ^ b3 ^ format;
assert chk == checksum;
}
catch (DiskNibbleException e)
{
e.printStackTrace ();
}
}
// int epiloguePtr = track.findNext (epilogue, addressOffset + 11); // int epiloguePtr = track.findNext (epilogue, addressOffset + 11);
// assert epiloguePtr == addressOffset + 11; // assert epiloguePtr == addressOffset + 11;
@ -581,18 +655,13 @@ public class WozFile
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
boolean isDuplicate (Sector sector) void pack (byte[] diskBuffer, int ptr) throws DiskNibbleException
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
return this.sectorNo == sector.sectorNo; DiskReader diskReader = DiskReader.getInstance (0);
}
// ---------------------------------------------------------------------------------// byte[] decodedBuffer = diskReader.decodeSector (track.newBuffer, dataOffset + 4);
void pack (DiskReader diskReader, byte[] buffer, int ptr) throws DiskNibbleException System.arraycopy (decodedBuffer, 12, diskBuffer, ptr, 512);
// ---------------------------------------------------------------------------------//
{
byte[] decodedBuffer = diskReader.decodeSector (track.newBuffer, dataOffset + 3);
System.arraycopy (decodedBuffer, 0, buffer, ptr, decodedBuffer.length);
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -600,10 +669,24 @@ public class WozFile
public String toString () public String toString ()
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
String fld = info.diskType == 1 ? "Vol" : info.diskType == 2 ? "Sde" : "???";
String dataOffsetText = dataOffset < 0 ? "" : String.format ("%04X", dataOffset); String dataOffsetText = dataOffset < 0 ? "" : String.format ("%04X", dataOffset);
return String.format ( return String.format (
"Vol: %02X Trk: %02X Sct: %02X Chk: %02X Add: %04X Dat: %s", volume, "%s: %02X Trk: %02X Sct: %02X Chk: %02X Add: %04X Dat: %s", fld, volume,
trackNo, sectorNo, checksum, addressOffset, dataOffsetText); trackNo, sectorNo, checksum, addressOffset, dataOffsetText);
} }
// ---------------------------------------------------------------------------------//
@Override
public int compareTo (Sector o)
// ---------------------------------------------------------------------------------//
{
if (this.trackNo != o.trackNo)
return this.trackNo - o.trackNo;
if (this.volume != o.volume)
return this.volume - o.volume;
return this.sectorNo - o.sectorNo;
}
} }
} }