Version 1.0.5 - changes by Nick

- added support for .NIB (nibble) disk images  (also inside ZIP archives)
- added disk speedup hacks for DOS (expect ~2x faster reads)
This commit is contained in:
sicklittlemonkey 2015-08-01 19:38:06 +12:00
parent c3ee6f8baa
commit d8b391a80c
4 changed files with 117 additions and 53 deletions

View File

@ -8,6 +8,11 @@
* *
* Change list: * Change list:
* *
* Version 1.0.5 - changes by Nick:
*
* - added support for .NIB (nibble) disk images (also inside ZIP archives)
* - added disk speedup hacks for DOS (expect ~2x faster reads)
*
* Version 1.0.4 - changes by Nick: * Version 1.0.4 - changes by Nick:
* *
* - added support for .PO (ProDOS order) disk images (also inside ZIP archives) * - added support for .PO (ProDOS order) disk images (also inside ZIP archives)
@ -55,7 +60,7 @@ import java.util.zip.ZipInputStream;
public class AppleIIGo extends Applet implements KeyListener, ComponentListener, public class AppleIIGo extends Applet implements KeyListener, ComponentListener,
MouseListener, MouseMotionListener { MouseListener, MouseMotionListener {
final String version = "1.0.4"; final String version = "1.0.5";
final String versionString = "AppleIIGo Version " + version; final String versionString = "AppleIIGo Version " + version;
// Class instances // Class instances
@ -136,7 +141,7 @@ public class AppleIIGo extends Applet implements KeyListener, ComponentListener,
apple.speaker.setVolume(new Integer(getAppletParameter("speakerVolume", "6")).intValue()); apple.speaker.setVolume(new Integer(getAppletParameter("speakerVolume", "6")).intValue());
// Peripherals // Peripherals
disk = new DiskII(); disk = new DiskII(apple);
apple.setPeripheral(disk, 6); apple.setPeripheral(disk, 6);
// Initialize disk drives // Initialize disk drives
@ -230,7 +235,13 @@ public class AppleIIGo extends Applet implements KeyListener, ComponentListener,
InputStream is = null; InputStream is = null;
if (OutFilename != null) if (OutFilename != null)
{
OutFilename.setLength(0); OutFilename.setLength(0);
int slashPos = resource.lastIndexOf('/');
int backslashPos = resource.lastIndexOf('\\');
int index = Math.max(slashPos, backslashPos);
OutFilename.append(resource.substring((index > 0) ? index : 0));
}
try { try {
URL url = new URL(getCodeBase(), resource); URL url = new URL(getCodeBase(), resource);
@ -247,19 +258,10 @@ public class AppleIIGo extends Applet implements KeyListener, ComponentListener,
ZipEntry entry = ((ZipInputStream)is).getNextEntry(); ZipEntry entry = ((ZipInputStream)is).getNextEntry();
if (OutFilename != null) if (OutFilename != null)
{ {
OutFilename.setLength(0);
OutFilename.append(entry.getName()); OutFilename.append(entry.getName());
} }
} }
else
{
if (OutFilename != null)
{
int slashPos = resource.lastIndexOf('/');
int backslashPos = resource.lastIndexOf('\\');
int index = Math.max(slashPos, backslashPos);
OutFilename.append(resource.substring((index > 0) ? index : 0));
}
}
} catch (Exception e) { } catch (Exception e) {
debug("Exeption: " + e.getLocalizedMessage()); debug("Exeption: " + e.getLocalizedMessage());
} }
@ -326,10 +328,8 @@ public class AppleIIGo extends Applet implements KeyListener, ComponentListener,
StringBuffer diskname = new StringBuffer(); StringBuffer diskname = new StringBuffer();
DataInputStream is = openInputStream(resource, diskname); DataInputStream is = openInputStream(resource, diskname);
String lowerDiskname = diskname.toString().toLowerCase();
boolean dos = lowerDiskname.indexOf(".po") == -1;
success = disk.readDisk(drive, is, 254, dos, false); success = disk.readDisk(drive, is, diskname.toString(), false);
is.close(); is.close();
} catch (Exception e) { } catch (Exception e) {
debug("Exeption: " + e.getLocalizedMessage()); debug("Exeption: " + e.getLocalizedMessage());

View File

@ -3,6 +3,7 @@
* AppleIIGo * AppleIIGo
* Disk II Emulator * Disk II Emulator
* (C) 2006 by Marc S. Ressl(ressl@lonetree.com) * (C) 2006 by Marc S. Ressl(ressl@lonetree.com)
* (C) 2009 by Nick Westgate (Nick.Westgate@gmail.com)
* Released under the GPL * Released under the GPL
* Based on work by Doug Kwan * Based on work by Doug Kwan
*/ */
@ -35,13 +36,13 @@ public class DiskII extends Peripheral {
private static final int DOS_NUM_SECTORS = 16; private static final int DOS_NUM_SECTORS = 16;
private static final int DOS_NUM_TRACKS = 35; private static final int DOS_NUM_TRACKS = 35;
private static final int DOS_TRACK_BYTES = 256 * DOS_NUM_SECTORS; private static final int DOS_TRACK_BYTES = 256 * DOS_NUM_SECTORS;
private static final int RAW_TRACK_BYTES = 6250; private static final int RAW_TRACK_BYTES = 0x1A00; // 0x1A00 (6656) for .NIB (was 6250)
// Disk II direct access variables // Disk II direct access variables
private int drive = 0; private int drive = 0;
private boolean isMotorOn = false; private boolean isMotorOn = false;
private byte[][][] disk = new byte[NUM_DRIVES][DOS_NUM_TRACKS][]; private byte[][][] diskData = new byte[NUM_DRIVES][DOS_NUM_TRACKS][];
private boolean[] isWriteProtected = new boolean[NUM_DRIVES]; private boolean[] isWriteProtected = new boolean[NUM_DRIVES];
private int currPhysTrack; private int currPhysTrack;
@ -79,7 +80,7 @@ public class DiskII extends Peripheral {
0xED, 0xEE, 0xEF, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xED, 0xEE, 0xEF, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6,
0xF7, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0xF7, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
}; };
private int[] gcrDecodingTable = new int[256]; //private int[] gcrDecodingTable = new int[256];
private int[] gcrSwapBit = {0, 2, 1, 3}; private int[] gcrSwapBit = {0, 2, 1, 3};
private int[] gcrBuffer = new int[256]; private int[] gcrBuffer = new int[256];
private int[] gcrBuffer2 = new int[86]; private int[] gcrBuffer2 = new int[86];
@ -98,16 +99,17 @@ public class DiskII extends Peripheral {
private byte[] gcrNibbles = new byte[RAW_TRACK_BYTES]; private byte[] gcrNibbles = new byte[RAW_TRACK_BYTES];
private int gcrNibblesPos; private int gcrNibblesPos;
EmAppleII apple;
/** /**
* Constructor * Constructor
*/ */
public DiskII() { public DiskII(EmAppleII apple) {
super(); super();
this.apple = apple;
readDisk(0, null, 254, true, false); readDisk(0, null, "", false);
readDisk(1, null, 254, true, false); readDisk(1, null, "", false);
} }
/** /**
@ -135,7 +137,7 @@ public class DiskII extends Peripheral {
if (currPhysTrack < ((2 * DOS_NUM_TRACKS) - 1)) if (currPhysTrack < ((2 * DOS_NUM_TRACKS) - 1))
currPhysTrack++; currPhysTrack++;
} }
realTrack = disk[drive][currPhysTrack >> 1]; realTrack = diskData[drive][currPhysTrack >> 1];
break; break;
case 0x3: case 0x3:
// Q1 on // Q1 on
@ -147,7 +149,7 @@ public class DiskII extends Peripheral {
if (currPhysTrack < ((2 * DOS_NUM_TRACKS) - 1)) if (currPhysTrack < ((2 * DOS_NUM_TRACKS) - 1))
currPhysTrack++; currPhysTrack++;
} }
realTrack = disk[drive][currPhysTrack >> 1]; realTrack = diskData[drive][currPhysTrack >> 1];
break; break;
case 0x5: case 0x5:
// Q2 on // Q2 on
@ -159,7 +161,7 @@ public class DiskII extends Peripheral {
if (currPhysTrack < ((2 * DOS_NUM_TRACKS) - 1)) if (currPhysTrack < ((2 * DOS_NUM_TRACKS) - 1))
currPhysTrack++; currPhysTrack++;
} }
realTrack = disk[drive][currPhysTrack >> 1]; realTrack = diskData[drive][currPhysTrack >> 1];
break; break;
case 0x7: case 0x7:
// Q3 on // Q3 on
@ -171,7 +173,7 @@ public class DiskII extends Peripheral {
if (currPhysTrack < ((2 * DOS_NUM_TRACKS) - 1)) if (currPhysTrack < ((2 * DOS_NUM_TRACKS) - 1))
currPhysTrack++; currPhysTrack++;
} }
realTrack = disk[drive][currPhysTrack >> 1]; realTrack = diskData[drive][currPhysTrack >> 1];
break; break;
case 0x8: case 0x8:
// Motor off // Motor off
@ -187,7 +189,7 @@ public class DiskII extends Peripheral {
drive = 0; drive = 0;
currPhysTrack = driveCurrPhysTrack[drive]; currPhysTrack = driveCurrPhysTrack[drive];
realTrack = disk[drive][currPhysTrack >> 1]; realTrack = diskData[drive][currPhysTrack >> 1];
break; break;
case 0xb: case 0xb:
// Drive 2 // Drive 2
@ -195,7 +197,7 @@ public class DiskII extends Peripheral {
drive = 1; drive = 1;
currPhysTrack = driveCurrPhysTrack[drive]; currPhysTrack = driveCurrPhysTrack[drive];
realTrack = disk[drive][currPhysTrack >> 1]; realTrack = diskData[drive][currPhysTrack >> 1];
break; break;
case 0xc: case 0xc:
return ioLatchC(); return ioLatchC();
@ -270,20 +272,31 @@ public class DiskII extends Peripheral {
* @param is InputStream * @param is InputStream
* @param drive Disk II drive * @param drive Disk II drive
*/ */
public boolean readDisk(int drive, DataInputStream is, int volume, boolean dos, boolean isWriteProtected) { public boolean readDisk(int drive, DataInputStream is, String name, boolean isWriteProtected) {
byte[] track = new byte[RAW_TRACK_BYTES]; byte[] track = new byte[DOS_TRACK_BYTES];
String lowerDiskname = name.toLowerCase();
boolean proDos = lowerDiskname.indexOf(".po") != -1;
boolean nib = lowerDiskname.indexOf(".nib") != -1;
try { try {
for (int trackNum = 0; trackNum < DOS_NUM_TRACKS; trackNum++) { for (int trackNum = 0; trackNum < DOS_NUM_TRACKS; trackNum++) {
disk[drive][trackNum] = new byte[RAW_TRACK_BYTES]; diskData[drive][trackNum] = new byte[RAW_TRACK_BYTES];
if (is != null) { if (is != null) {
is.readFully(track, 0, DOS_TRACK_BYTES); if (nib)
trackToNibbles(track, disk[drive][trackNum], volume, trackNum, dos); {
is.readFully(diskData[drive][trackNum], 0, RAW_TRACK_BYTES);
}
else
{
is.readFully(track, 0, DOS_TRACK_BYTES);
trackToNibbles(track, diskData[drive][trackNum], 254, trackNum, !proDos);
}
} }
} }
this.realTrack = disk[drive][currPhysTrack >> 1]; this.realTrack = diskData[drive][currPhysTrack >> 1];
this.isWriteProtected[drive] = isWriteProtected; this.isWriteProtected[drive] = isWriteProtected;
return true; return true;
@ -318,18 +331,60 @@ public class DiskII extends Peripheral {
* @param address Address * @param address Address
*/ */
private int ioLatchC() { private int ioLatchC() {
latchAddress = 0xc;
if (writeMode) if (writeMode)
{
// Write data: C0xD, C0xC // Write data: C0xD, C0xC
realTrack[currNibble] = (byte) latchData; realTrack[currNibble] = (byte) latchData;
}
else else
{
// Read data: C0xE, C0xC // Read data: C0xE, C0xC
latchData = (realTrack[currNibble] & 0xff); latchData = (realTrack[currNibble] & 0xff);
// simple hack to help DOS find address prologues ($B94F)
if (apple.memoryRead(apple.PC + 3) == 0xD5 && // #$D5
latchData != 0xD5 &&
apple.memoryRead(apple.PC + 2) == 0xC9 && // CMP
apple.memoryRead(apple.PC + 1) == 0xFB && // PC - 3
apple.memoryRead(apple.PC + 0) == 0x10) // BPL
{
int count = RAW_TRACK_BYTES / 16;
do
{
currNibble++;
if (currNibble >= RAW_TRACK_BYTES)
currNibble = 0;
latchData = (realTrack[currNibble] & 0xff);
}
while (latchData != 0xD5 && --count > 0);
}
// simple hack to fool DOS drive spin detect routine ($BD34)
else if (apple.memoryRead(apple.PC - 3) == 0xDD && // CMP $C08C,X
apple.memoryRead(apple.PC + 1) == 0x03 && // PC + 3
apple.memoryRead(apple.PC + 0) == 0xD0) // BNE
{
return 0x7F;
}
// skip invalid nibbles we padded the track buffer with
else if (latchData == 0x7F)
{
int count = RAW_TRACK_BYTES / 16;
do
{
currNibble++;
if (currNibble >= RAW_TRACK_BYTES)
currNibble = 0;
latchData = (realTrack[currNibble] & 0xff);
}
while (latchData == 0x7F && --count > 0);
}
}
currNibble++; currNibble++;
if (currNibble >= RAW_TRACK_BYTES) if (currNibble >= RAW_TRACK_BYTES)
currNibble = 0; currNibble = 0;
latchAddress = 0xc;
return latchData; return latchData;
} }
@ -389,15 +444,24 @@ public class DiskII extends Peripheral {
} }
/** /**
* Writes sync bits * Writes nibbles
*
* @param length Number of bits
*/
private final void writeNibbles(int nibble, int length) {
while(length > 0) {
length--;
gcrWriteNibble(nibble);
}
}
/**
* Writes sync nibbles
* *
* @param length Number of bits * @param length Number of bits
*/ */
private final void writeSync(int length) { private final void writeSync(int length) {
while(length > 0) { writeNibbles(0xff, length);
length--;
gcrWriteNibble(0xff);
}
} }
/** /**
@ -504,6 +568,6 @@ public class DiskII extends Peripheral {
writeSync(8); writeSync(8);
writeDataField(); writeDataField();
} }
writeSync(RAW_TRACK_BYTES - gcrNibblesPos); writeNibbles(0x7F, RAW_TRACK_BYTES - gcrNibblesPos); // invalid nibbles to skip on read
} }
} }

View File

@ -119,7 +119,7 @@ public class Em6502 {
/** /**
* Constructor * Constructor
*/ */
public void Em6502() { public Em6502() {
// Init BCD tables // Init BCD tables
BCDTableAdd = new int[512]; BCDTableAdd = new int[512];
BCDTableSub = new int[512]; BCDTableSub = new int[512];
@ -161,7 +161,7 @@ public class Em6502 {
private final void setC(boolean b) {if (b) P |= FLAG_C; else P &= ~FLAG_C;} private final void setC(boolean b) {if (b) P |= FLAG_C; else P &= ~FLAG_C;}
private final boolean getN() {return ((P & FLAG_N) != 0);} private final boolean getN() {return ((P & FLAG_N) != 0);}
private final boolean getV() {return ((P & FLAG_V) != 0);} private final boolean getV() {return ((P & FLAG_V) != 0);}
private final boolean getB() {return ((P & FLAG_B) != 0);} // private final boolean getB() {return ((P & FLAG_B) != 0);}
private final boolean getD() {return ((P & FLAG_D) != 0);} private final boolean getD() {return ((P & FLAG_D) != 0);}
private final boolean getI() {return ((P & FLAG_I) != 0);} private final boolean getI() {return ((P & FLAG_I) != 0);}
private final boolean getZ() {return ((P & FLAG_Z) != 0);} private final boolean getZ() {return ((P & FLAG_Z) != 0);}
@ -232,9 +232,9 @@ public class Em6502 {
// return easp1 + Y; // return easp1 + Y;
return eaabs() + Y; return eaabs() + Y;
} }
private final int eaabsyNC() { // private final int eaabsyNC() {
return eaabs() + Y; // return eaabs() + Y;
} // }
/* /*
* Indirect addressing * Indirect addressing
@ -258,11 +258,11 @@ public class Em6502 {
// return easp2 + Y; // return easp2 + Y;
return easp2 + (zeroPageRead((easp1 + 1) & 0xff) << 8) + Y; return easp2 + (zeroPageRead((easp1 + 1) & 0xff) << 8) + Y;
} }
private final int eazpindyNC() { // private final int eazpindyNC() {
easp1 = eaimm(); // easp1 = eaimm();
easp2 = zeroPageRead(easp1); // easp2 = zeroPageRead(easp1);
return easp2 + (zeroPageRead((easp1 + 1) & 0xff) << 8) + Y; // return easp2 + (zeroPageRead((easp1 + 1) & 0xff) << 8) + Y;
} // }
/* /*
* New 65C02 addressing mode * New 65C02 addressing mode

View File

@ -188,7 +188,7 @@ public class EmAppleII extends Em6502 implements Runnable {
* Apple II class constructor * Apple II class constructor
*/ */
public EmAppleII() { public EmAppleII() {
Em6502(); super();
// Allocate compute memory // Allocate compute memory
mem = new byte[MEM_END]; mem = new byte[MEM_END];