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:
*
* 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:
*
* - 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,
MouseListener, MouseMotionListener {
final String version = "1.0.4";
final String version = "1.0.5";
final String versionString = "AppleIIGo Version " + version;
// Class instances
@ -136,7 +141,7 @@ public class AppleIIGo extends Applet implements KeyListener, ComponentListener,
apple.speaker.setVolume(new Integer(getAppletParameter("speakerVolume", "6")).intValue());
// Peripherals
disk = new DiskII();
disk = new DiskII(apple);
apple.setPeripheral(disk, 6);
// Initialize disk drives
@ -230,7 +235,13 @@ public class AppleIIGo extends Applet implements KeyListener, ComponentListener,
InputStream is = null;
if (OutFilename != null)
{
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 {
URL url = new URL(getCodeBase(), resource);
@ -247,19 +258,10 @@ public class AppleIIGo extends Applet implements KeyListener, ComponentListener,
ZipEntry entry = ((ZipInputStream)is).getNextEntry();
if (OutFilename != null)
{
OutFilename.setLength(0);
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) {
debug("Exeption: " + e.getLocalizedMessage());
}
@ -326,10 +328,8 @@ public class AppleIIGo extends Applet implements KeyListener, ComponentListener,
StringBuffer diskname = new StringBuffer();
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();
} catch (Exception e) {
debug("Exeption: " + e.getLocalizedMessage());

View File

@ -3,6 +3,7 @@
* AppleIIGo
* Disk II Emulator
* (C) 2006 by Marc S. Ressl(ressl@lonetree.com)
* (C) 2009 by Nick Westgate (Nick.Westgate@gmail.com)
* Released under the GPL
* 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_TRACKS = 35;
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
private int drive = 0;
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 int currPhysTrack;
@ -79,7 +80,7 @@ public class DiskII extends Peripheral {
0xED, 0xEE, 0xEF, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6,
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[] gcrBuffer = new int[256];
private int[] gcrBuffer2 = new int[86];
@ -98,16 +99,17 @@ public class DiskII extends Peripheral {
private byte[] gcrNibbles = new byte[RAW_TRACK_BYTES];
private int gcrNibblesPos;
EmAppleII apple;
/**
* Constructor
*/
public DiskII() {
public DiskII(EmAppleII apple) {
super();
this.apple = apple;
readDisk(0, null, 254, true, false);
readDisk(1, null, 254, true, false);
readDisk(0, null, "", false);
readDisk(1, null, "", false);
}
/**
@ -135,7 +137,7 @@ public class DiskII extends Peripheral {
if (currPhysTrack < ((2 * DOS_NUM_TRACKS) - 1))
currPhysTrack++;
}
realTrack = disk[drive][currPhysTrack >> 1];
realTrack = diskData[drive][currPhysTrack >> 1];
break;
case 0x3:
// Q1 on
@ -147,7 +149,7 @@ public class DiskII extends Peripheral {
if (currPhysTrack < ((2 * DOS_NUM_TRACKS) - 1))
currPhysTrack++;
}
realTrack = disk[drive][currPhysTrack >> 1];
realTrack = diskData[drive][currPhysTrack >> 1];
break;
case 0x5:
// Q2 on
@ -159,7 +161,7 @@ public class DiskII extends Peripheral {
if (currPhysTrack < ((2 * DOS_NUM_TRACKS) - 1))
currPhysTrack++;
}
realTrack = disk[drive][currPhysTrack >> 1];
realTrack = diskData[drive][currPhysTrack >> 1];
break;
case 0x7:
// Q3 on
@ -171,7 +173,7 @@ public class DiskII extends Peripheral {
if (currPhysTrack < ((2 * DOS_NUM_TRACKS) - 1))
currPhysTrack++;
}
realTrack = disk[drive][currPhysTrack >> 1];
realTrack = diskData[drive][currPhysTrack >> 1];
break;
case 0x8:
// Motor off
@ -187,7 +189,7 @@ public class DiskII extends Peripheral {
drive = 0;
currPhysTrack = driveCurrPhysTrack[drive];
realTrack = disk[drive][currPhysTrack >> 1];
realTrack = diskData[drive][currPhysTrack >> 1];
break;
case 0xb:
// Drive 2
@ -195,7 +197,7 @@ public class DiskII extends Peripheral {
drive = 1;
currPhysTrack = driveCurrPhysTrack[drive];
realTrack = disk[drive][currPhysTrack >> 1];
realTrack = diskData[drive][currPhysTrack >> 1];
break;
case 0xc:
return ioLatchC();
@ -270,20 +272,31 @@ public class DiskII extends Peripheral {
* @param is InputStream
* @param drive Disk II drive
*/
public boolean readDisk(int drive, DataInputStream is, int volume, boolean dos, boolean isWriteProtected) {
byte[] track = new byte[RAW_TRACK_BYTES];
public boolean readDisk(int drive, DataInputStream is, String name, boolean isWriteProtected) {
byte[] track = new byte[DOS_TRACK_BYTES];
String lowerDiskname = name.toLowerCase();
boolean proDos = lowerDiskname.indexOf(".po") != -1;
boolean nib = lowerDiskname.indexOf(".nib") != -1;
try {
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 (nib)
{
is.readFully(diskData[drive][trackNum], 0, RAW_TRACK_BYTES);
}
else
{
is.readFully(track, 0, DOS_TRACK_BYTES);
trackToNibbles(track, disk[drive][trackNum], volume, trackNum, dos);
trackToNibbles(track, diskData[drive][trackNum], 254, trackNum, !proDos);
}
}
}
this.realTrack = disk[drive][currPhysTrack >> 1];
this.realTrack = diskData[drive][currPhysTrack >> 1];
this.isWriteProtected[drive] = isWriteProtected;
return true;
@ -318,18 +331,60 @@ public class DiskII extends Peripheral {
* @param address Address
*/
private int ioLatchC() {
latchAddress = 0xc;
if (writeMode)
{
// Write data: C0xD, C0xC
realTrack[currNibble] = (byte) latchData;
}
else
{
// Read data: C0xE, C0xC
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++;
if (currNibble >= RAW_TRACK_BYTES)
currNibble = 0;
latchAddress = 0xc;
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
*/
private final void writeSync(int length) {
while(length > 0) {
length--;
gcrWriteNibble(0xff);
}
writeNibbles(0xff, length);
}
/**
@ -504,6 +568,6 @@ public class DiskII extends Peripheral {
writeSync(8);
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
*/
public void Em6502() {
public Em6502() {
// Init BCD tables
BCDTableAdd = 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 boolean getN() {return ((P & FLAG_N) != 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 getI() {return ((P & FLAG_I) != 0);}
private final boolean getZ() {return ((P & FLAG_Z) != 0);}
@ -232,9 +232,9 @@ public class Em6502 {
// return easp1 + Y;
return eaabs() + Y;
}
private final int eaabsyNC() {
return eaabs() + Y;
}
// private final int eaabsyNC() {
// return eaabs() + Y;
// }
/*
* Indirect addressing
@ -258,11 +258,11 @@ public class Em6502 {
// return easp2 + Y;
return easp2 + (zeroPageRead((easp1 + 1) & 0xff) << 8) + Y;
}
private final int eazpindyNC() {
easp1 = eaimm();
easp2 = zeroPageRead(easp1);
return easp2 + (zeroPageRead((easp1 + 1) & 0xff) << 8) + Y;
}
// private final int eazpindyNC() {
// easp1 = eaimm();
// easp2 = zeroPageRead(easp1);
// return easp2 + (zeroPageRead((easp1 + 1) & 0xff) << 8) + Y;
// }
/*
* New 65C02 addressing mode

View File

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