mirror of
https://github.com/sicklittlemonkey/AppleIIGo.git
synced 2024-12-26 17:29:29 +00:00
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:
parent
c3ee6f8baa
commit
d8b391a80c
@ -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());
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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];
|
||||
|
Loading…
Reference in New Issue
Block a user