From fe27c7d1e877dc98981b43863de7f1d734391047 Mon Sep 17 00:00:00 2001 From: sicklittlemonkey Date: Mon, 10 Aug 2015 00:11:49 +1200 Subject: [PATCH] Version 1.0.10 - changes by Nick - fixed disk stepping bug for Mabel's Mansion using my code from AppleWin - patch loaded ROM's empty slots with faux-floating bus data so Mabel's Mansion works - revert CPU status bug introduced in 1.0.9 - V and R used the same bit - fixed BRK bug by adding extra PC increment --- Source/AppleIIGo.java | 11 +++- Source/DiskII.java | 131 +++++++++++++++++------------------------- Source/Em6502.java | 50 +++++++++------- Source/EmAppleII.java | 11 ++++ 4 files changed, 104 insertions(+), 99 deletions(-) diff --git a/Source/AppleIIGo.java b/Source/AppleIIGo.java index fa86d5a..7804042 100644 --- a/Source/AppleIIGo.java +++ b/Source/AppleIIGo.java @@ -2,13 +2,20 @@ /** * AppleIIGo * The Java Apple II Emulator - * Copyright 2014 by Nick Westgate (Nick.Westgate@gmail.com) + * Copyright 2015 by Nick Westgate (Nick.Westgate@gmail.com) * Copyright 2006 by Marc S. Ressl (mressl@gmail.com) * Released under the GNU General Public License version 2 * See http://www.gnu.org/licenses/ * * Change list: * + * Version 1.0.10 - changes by Nick: + * - fixed disk stepping bug for Mabel's Mansion using my code from AppleWin + * - patch loaded ROM's empty slots with faux-floating bus data so Mabel's Mansion works + * - revert CPU status bug introduced in 1.0.9 - V and R used the same bit + * - fixed BRK bug by adding extra PC increment + * - NOTE: decimal mode arithmetic fails some tests and should be fixed someday + * * Version 1.0.9 - changes by Nick: * - fixed disk speed-up bug (Sherwood Forest reads with the drive motor off) * - added check for 2IMG header ID @@ -85,7 +92,7 @@ public class AppleIIGo extends Applet implements KeyListener, ComponentListener, private static final long serialVersionUID = -3302282815441501352L; - final String version = "1.0.9"; + final String version = "1.0.10"; final String versionString = "AppleIIGo Version " + version; final String metaStart = "_meta_"; diff --git a/Source/DiskII.java b/Source/DiskII.java index e5543cc..d023f92 100644 --- a/Source/DiskII.java +++ b/Source/DiskII.java @@ -2,7 +2,7 @@ /** * AppleIIGo * Disk II Emulator - * Copyright 2014 by Nick Westgate (Nick.Westgate@gmail.com) + * Copyright 2015 by Nick Westgate (Nick.Westgate@gmail.com) * Copyright 2006 by Marc S. Ressl(mressl@gmail.com) * Released under the GPL * Based on work by Doug Kwan @@ -36,6 +36,7 @@ public class DiskII extends Peripheral { private static final int NUM_DRIVES = 2; private static final int DOS_NUM_SECTORS = 16; private static final int DOS_NUM_TRACKS = 35; + private static final int MAX_PHYS_TRACK = (2 * DOS_NUM_TRACKS) - 1; private static final int DOS_TRACK_BYTES = 256 * DOS_NUM_SECTORS; private static final int RAW_TRACK_BYTES = 0x1A00; // 0x1A00 (6656) for .NIB (was 6250) private static final int STANDARD_2IMG_HEADER_ID = 0x32494D47; @@ -44,6 +45,7 @@ public class DiskII extends Peripheral { // Disk II direct access variables private int drive = 0; + private int phases = 0; private boolean isMotorOn = false; private byte[][][] diskData = new byte[NUM_DRIVES][DOS_NUM_TRACKS][]; @@ -72,7 +74,7 @@ public class DiskII extends Peripheral { private int latchData; private boolean writeMode; private boolean loadMode; - private boolean driveSpin; + private int driveSpin; // GCR encoding and decoding tables private static final int[] gcrEncodingTable = { @@ -348,28 +350,29 @@ public class DiskII extends Peripheral { loadMode = false; if (!writeMode) { - if (!isMotorOn) - { - // simple hack to fool DOS SAMESLOT drive spin check (usually at $BD34) - driveSpin = !driveSpin; - if (driveSpin) - { - latchData = 0x7F; - return; - } - } + if (!isMotorOn) + { + // simple hack to fool RWTS SAMESLOT drive spin check (usually at $BD34) + driveSpin = (driveSpin + 1) & 0xF; + if (driveSpin == 0) + { + latchData = 0x7F; + return; + } + } // Read data: C0xE, C0xC latchData = (realTrack[currNibble] & 0xff); - // simple hack to help DOS find address prologues ($B94F) + // is RWTS looking for an address prologue? (RDADR) if (/* fastDisk && */ // TODO: fastDisk property to enable/disable apple.memoryRead(apple.PC + 3) == 0xD5 && // #$D5 - apple.memoryRead(apple.PC + 2) == 0xC9 && // CMP + apple.memoryRead(apple.PC + 2) == 0xC9 && // CMP (usually at $B94F) apple.memoryRead(apple.PC + 1) == 0xFB && // PC - 3 apple.memoryRead(apple.PC + 0) == 0x10 && // BPL latchData != 0xD5) { + // Y: find the next address prologues int count = RAW_TRACK_BYTES / 16; do { @@ -380,8 +383,8 @@ public class DiskII extends Peripheral { } while (latchData != 0xD5 && --count > 0); } - // skip invalid nibbles we padded the track buffer with - else if (latchData == 0x7F) // TODO: maybe the above covers this? + // N: skip invalid nibbles we padded the track buffer with + else if (latchData == 0x7F) { int count = RAW_TRACK_BYTES / 16; do @@ -406,68 +409,42 @@ public class DiskII extends Peripheral { } private void setPhase(int address) { - int phase; - - switch (address & 0xf) { - case 0x0: - case 0x2: - case 0x4: - case 0x6: - // Q0, Q1, Q2, Q3 off - break; - case 0x1: - // Q0 on - phase = currPhysTrack & 3; - if (phase == 1) { - if (currPhysTrack > 0) - currPhysTrack--; - } else if (phase == 3) { - if (currPhysTrack < ((2 * DOS_NUM_TRACKS) - 1)) - currPhysTrack++; - } - //System.out.println("half track=" + currPhysTrack); - realTrack = diskData[drive][currPhysTrack >> 1]; - break; - case 0x3: - // Q1 on - phase = currPhysTrack & 3; - if (phase == 2) { - if (currPhysTrack > 0) - currPhysTrack--; - } else if (phase == 0) { - if (currPhysTrack < ((2 * DOS_NUM_TRACKS) - 1)) - currPhysTrack++; - } - //System.out.println("half track=" + currPhysTrack); - realTrack = diskData[drive][currPhysTrack >> 1]; - break; - case 0x5: - // Q2 on - phase = currPhysTrack & 3; - if (phase == 3) { - if (currPhysTrack > 0) - currPhysTrack--; - } else if (phase == 1) { - if (currPhysTrack < ((2 * DOS_NUM_TRACKS) - 1)) - currPhysTrack++; - } - //System.out.println("half track=" + currPhysTrack); - realTrack = diskData[drive][currPhysTrack >> 1]; - break; - case 0x7: - // Q3 on - phase = currPhysTrack & 3; - if (phase == 0) { - if (currPhysTrack > 0) - currPhysTrack--; - } else if (phase == 2) { - if (currPhysTrack < ((2 * DOS_NUM_TRACKS) - 1)) - currPhysTrack++; - } - //System.out.println("half track=" + currPhysTrack); - realTrack = diskData[drive][currPhysTrack >> 1]; - break; + int phase = (address >> 1) & 3; + int phase_bit = (1 << phase); + + // update the magnet states + if ((address & 1) != 0) + { + // phase on + phases |= phase_bit; } + else + { + // phase off + phases &= ~phase_bit; + } + + // check for any stepping effect from a magnet + // - move only when the magnet opposite the cog is off + // - move in the direction of an adjacent magnet if one is on + // - do not move if both adjacent magnets are on + // momentum and timing are not accounted for ... maybe one day! + int direction = 0; + if ((phases & (1 << ((currPhysTrack + 1) & 3))) != 0) + direction += 1; + if ((phases & (1 << ((currPhysTrack + 3) & 3))) != 0) + direction -= 1; + + // apply magnet step, if any + if (direction != 0) + { + currPhysTrack += direction; + if (currPhysTrack < 0) + currPhysTrack = 0; + else if (currPhysTrack > MAX_PHYS_TRACK) + currPhysTrack = MAX_PHYS_TRACK; + } + realTrack = diskData[drive][currPhysTrack >> 1]; } private void setDrive(int newDrive) { diff --git a/Source/Em6502.java b/Source/Em6502.java index 68339f4..9fc6551 100644 --- a/Source/Em6502.java +++ b/Source/Em6502.java @@ -80,7 +80,7 @@ public class Em6502 { public static final int FLAG_I = (1 << 2); public static final int FLAG_D = (1 << 3); public static final int FLAG_B = (1 << 4); - public static final int FLAG_R = (1 << 6); + public static final int FLAG_R = (1 << 5); public static final int FLAG_V = (1 << 6); public static final int FLAG_N = (1 << 7); /* @@ -123,7 +123,7 @@ public class Em6502 { * Constructor */ public Em6502() { -// createRunFile(); +// createRunFile(); // TODO: for debugging - disable // Init BCD tables BCDTableAdd = new int[512]; @@ -163,7 +163,7 @@ public class Em6502 { */ private final void setN(boolean b) {if (b) P |= FLAG_N; else P &= ~FLAG_N;} private final void setV(boolean b) {if (b) P |= FLAG_V; else P &= ~FLAG_V;} - private final void setB(boolean b) {if (b) P |= FLAG_B; else P &= ~FLAG_B;} +// private final void setB(boolean b) {if (b) P |= FLAG_B; else P &= ~FLAG_B;} private final void setD(boolean b) {if (b) P |= FLAG_D; else P &= ~FLAG_D;} private final void setI(boolean b) {if (b) P |= FLAG_I; else P &= ~FLAG_I;} private final void setZ(boolean b) {if (b) P |= FLAG_Z; else P &= ~FLAG_Z;} @@ -304,38 +304,47 @@ public class Em6502 { } // private PrintWriter runFile; +// private boolean runFlag = false; +// // private void createRunFile() // { // try // { -// runFile = new PrintWriter("C:\\Users\\Public\\AppleIIGoRun.txt"); +// //runFile = new PrintWriter("C:\\Dev\\Emulators\\AppleIIGo\\AppleIIGoRun.txt"); // } // catch (Exception ex) // { // // swallow // } // } +// // private final void writeRunFile(int opcode) // { -// if ( -// (PC > 0x0500) -// && -// (PC < 0x0600) -// ) -// { -// setN(getFN()); -// setZ(getFZ()); -// setC(getFC()); +// if (PC == 0x2000) +// runFlag = true; +// if ( +// runFlag && +// (PC > 0x1000) +// && +// (PC < 0xC000) +// ) +// { +// if (runFile != null) +// { +// setN(getFN()); +// setZ(getFZ()); +// setC(getFC()); // -// runFile.printf("%04X-%02X P=%02X A=%02X\r\n", PC, opcode, P, A); -// runFile.flush(); -// } +// runFile.printf("%04X-%02X P=%02X A=%02X\r\n", PC, opcode, P, A); +// runFile.flush(); +// } +// } // } /** This executes a single instruction. */ private final void executeInstruction() { opcode = memoryRead(PC); -// writeRunFile(opcode); +// writeRunFile(opcode); // TODO: for debugging = disable PC++; switch(opcode) { @@ -569,12 +578,13 @@ public class Em6502 { break; case 0x00: // BRK + PC++; push(PC >> 8); // save PCH, PCL & P push(PC); setN(getFN()); setZ(getFZ()); setC(getFC()); - push(P); // break flag is always set + push(P); // B and R always set setI(true); PC = memoryRead(0xfffe); PC |= memoryRead(0xffff) << 8; @@ -1081,7 +1091,7 @@ public class Em6502 { break; case 0x28: // PLP - P = pop() | FLAG_B | FLAG_R; // fix bug in bit5 of P + P = pop() | FLAG_B | FLAG_R; // B and R always set setFC(getC()); setFNZ(getN(), getZ()); clock += 4; @@ -1182,7 +1192,7 @@ public class Em6502 { break; case 0x40: // RTI - P = pop() | FLAG_B | FLAG_R; // bit 5 bug of 6502 + P = pop() | FLAG_B | FLAG_R; // B and R always set setFC(getC()); setFNZ(getN(), getZ()); PC = pop(); // splitting is necessary diff --git a/Source/EmAppleII.java b/Source/EmAppleII.java index fa2059a..e1438ec 100644 --- a/Source/EmAppleII.java +++ b/Source/EmAppleII.java @@ -264,6 +264,17 @@ public class EmAppleII extends Em6502 implements Runnable { System.arraycopy(rom, offset + 0x3000, mem, MEM_ROM_INTERNAL + 0x00000, 0x01000); System.arraycopy(rom, offset + 0x3800, mem, MEM_ROM_EXTERNAL + 0x00800, 0x00800); + for (int slot = 0x100; slot <= 0x700; slot += 0x100) + { + if (mem[MEM_ROM_EXTERNAL + slot] == 0) + { + // 0 data is a bad default for empty external slots (e.g. Mabel's Mansion reboots) + // so ideally we would emulate the floating bus, but for now we just hardcode 0xA0 + for (int i = 0; i <= 0xFF; i++) + mem[MEM_ROM_EXTERNAL + slot + i] = (byte)0xA0; + } + } + return true; }