]> Shamusworld >> Repos - apple2/commitdiff
Miscellaneous bugfixes.
authorShamus Hammons <jlhamm@acm.org>
Fri, 12 Aug 2022 16:12:40 +0000 (11:12 -0500)
committerShamus Hammons <jlhamm@acm.org>
Fri, 12 Aug 2022 16:12:40 +0000 (11:12 -0500)
Once again, 4am's Total Replay uncovered a bug in the emulation when its
replay of Firebug would lock up the emulation.  This was caused by the
MMU not returning floating bus values from certain $C0xx soft switches.
Also, there was a bug in floppydrive.cpp which would cause the bitstream
to slip even when the simulated drive head never moved.  This allows
Bard's Tale II to boot.  Also, some minor fixes to allow the LSS to
honor a WOZ2 disk's "optimal bit timing" field.  Border Zone & other
similar disks *still* don't work, so there's work still to be done
there...

Again, almost a year since the last commit.  How the time does fly.  :-/

src/apple2.cpp
src/fileio.cpp
src/firmware/firmware.cpp
src/firmware/firmware.h
src/floppydrive.cpp
src/floppydrive.h
src/gui/diskselector.cpp
src/gui/gui.cpp
src/harddrive.cpp
src/mmu.cpp
src/v65c02.cpp

index e97363afdf68a4ea4555c383645fdc4b81e20f70..be5a16d1e805f74c0f9828c7eed6f68ee44a2085 100644 (file)
@@ -278,7 +278,6 @@ WriteLog("CPU: SDL_mutexV(cpuMutex);\n");
 }
 #endif
 
-
 //
 // Request a change in the power state of the emulated Apple
 //
@@ -287,7 +286,6 @@ void SetPowerState(void)
        powerStateChangeRequested = true;
 }
 
-
 //
 // Load a file into RAM/ROM image space
 //
@@ -304,7 +302,6 @@ bool LoadImg(char * filename, uint8_t * ram, int size)
        return true;
 }
 
-
 const uint8_t stateHeader[19] = "APPLE2SAVESTATE1.2";
 static void SaveApple2State(const char * filename)
 {
@@ -358,7 +355,6 @@ static void SaveApple2State(const char * filename)
        fclose(file);
 }
 
-
 static bool LoadApple2State(const char * filename)
 {
        WriteLog("Main: Loading Apple2 state...\n");
@@ -427,7 +423,6 @@ static bool LoadApple2State(const char * filename)
        return true;
 }
 
-
 static void ResetApple2State(void)
 {
        keyDown = false;
@@ -453,7 +448,6 @@ static void ResetApple2State(void)
        mainCPU.cpuFlags |= V65C02_ASSERT_LINE_RESET;
 }
 
-
 static double cyclesForSample = 0;
 static void AppleTimer(uint16_t cycles)
 {
@@ -481,7 +475,6 @@ lastSampleClock = sampleClock;
 #endif
 }
 
-
 #ifdef CPU_CLOCK_CHECKING
 uint8_t counter = 0;
 uint32_t totalCPU = 0;
@@ -666,8 +659,8 @@ WriteLog("Main: SDL_DestroyCond(cpuCond);\n");
 #if 0
 #include "dis65c02.h"
 static char disbuf[80];
-uint16_t pc=0x801;
-while (pc < 0x9FF)
+uint16_t pc=0xA000;
+while (pc < 0xA3FF)
 {
        pc += Decode65C02(&mainCPU, disbuf, pc);
        WriteLog("%s\n", disbuf);
@@ -682,7 +675,6 @@ while (pc < 0x9FF)
        return 0;
 }
 
-
 //
 // Apple //e scancodes. Tables are normal (0), +CTRL (1), +SHIFT (2),
 // +CTRL+SHIFT (3). Order of keys is:
@@ -1147,7 +1139,6 @@ if (counter == 60)
 #endif
 }
 
-
 static void BlinkTimer(void)
 {
        // Set up blinking at 1/4 sec intervals
@@ -1155,7 +1146,6 @@ static void BlinkTimer(void)
        SetCallbackTime(BlinkTimer, 250000);
 }
 
-
 /*
 Next problem is this: How to have events occur and synchronize with the rest
 of the threads?
@@ -1181,4 +1171,3 @@ while (!done)
                time = 20;
 }
 */
-
index cc2ef48bc7e88ad4d2fd80b56fbf26b3b4dfb9dd..1048be90dfc26fac4996535d310f53f36d78a078 100644 (file)
@@ -205,7 +205,8 @@ bool CheckWOZIntegrity(const uint8_t * wozData, uint32_t wozSize)
        else if (wozCRC == 0)
                WriteLog("FILEIO: Warning--WOZ file has no CRC...\n");
 
-#if 0 // Need to fix this so it works with both 1 & 2 (works with only 1 ATM)
+#if 1
+       // Need to fix this so it works with both 1 & 2 (works with only 1 ATM)
        WriteLog("Track map:\n");
        WriteLog("                                        1   1   1   1   1   1   1   1\n");
        WriteLog("0.,.1.,.2.,.3.,.4.,.5.,.6.,.7.,.8.,.9.,.0.,.1.,.2.,.3.,.4.,.5.,.6.,.7.,.\n");
@@ -248,6 +249,7 @@ bool CheckWOZIntegrity(const uint8_t * wozData, uint32_t wozSize)
 
        WriteLog("\n");
 
+#if 0
        uint8_t numTracks = woz.trksSize / sizeof(WOZ1Track);
 
        // N.B.: Need to check the track in tmap[] to have this tell the correct track...  Right now, it doesn't
@@ -255,6 +257,7 @@ bool CheckWOZIntegrity(const uint8_t * wozData, uint32_t wozSize)
        {
                WriteLog("WOZ: Stream %u: %d bits (packed into %d bytes)\n", i, woz.track[i].bitCount, (woz.track[i].bitCount + 7) / 8);
        }
+#endif
 #endif
 
        WriteLog("FILEIO: Well formed WOZ file found\n");
index 54d25104d262d46934db98e53c00eaec57867d78..fbd0f28bea52ec0d83f13ffbba0fce61fba0372e 100644 (file)
@@ -4,26 +4,83 @@
 
 #include "firmware.h"
 
+//
+// 16-sector bootstrap driver for disk controller
+//
+uint8_t diskROM[0x100] = {
+       0xA2, 0x20, 0xA0, 0x00, 0xA2, 0x03, 0x86, 0x3C,
+       0x8A, 0x0A, 0x24, 0x3C, 0xF0, 0x10, 0x05, 0x3C,
+       0x49, 0xFF, 0x29, 0x7E, 0xB0, 0x08, 0x4A, 0xD0,
+       0xFB, 0x98, 0x9D, 0x56, 0x03, 0xC8, 0xE8, 0x10,
+       0xE5, 0x20, 0x58, 0xFF, 0xBA, 0xBD, 0x00, 0x01,
+       0x0A, 0x0A, 0x0A, 0x0A, 0x85, 0x2B, 0xAA, 0xBD,
+       0x8E, 0xC0, 0xBD, 0x8C, 0xC0, 0xBD, 0x8A, 0xC0,
+       0xBD, 0x89, 0xC0, 0xA0, 0x50, 0xBD, 0x80, 0xC0,
+       0x98, 0x29, 0x03, 0x0A, 0x05, 0x2B, 0xAA, 0xBD,
+       0x81, 0xC0, 0xA9, 0x56, 0x20, 0xA8, 0xFC, 0x88,
+       0x10, 0xEB, 0x85, 0x26, 0x85, 0x3D, 0x85, 0x41,
+       0xA9, 0x08, 0x85, 0x27, 0x18, 0x08, 0xBD, 0x8C,
+       0xC0, 0x10, 0xFB, 0x49, 0xD5, 0xD0, 0xF7, 0xBD,
+       0x8C, 0xC0, 0x10, 0xFB, 0xC9, 0xAA, 0xD0, 0xF3,
+       0xEA, 0xBD, 0x8C, 0xC0, 0x10, 0xFB, 0xC9, 0x96,
+       0xF0, 0x09, 0x28, 0x90, 0xDF, 0x49, 0xAD, 0xF0,
+       0x25, 0xD0, 0xD9, 0xA0, 0x03, 0x85, 0x40, 0xBD,
+       0x8C, 0xC0, 0x10, 0xFB, 0x2A, 0x85, 0x3C, 0xBD,
+       0x8C, 0xC0, 0x10, 0xFB, 0x25, 0x3C, 0x88, 0xD0,
+       0xEC, 0x28, 0xC5, 0x3D, 0xD0, 0xBE, 0xA5, 0x40,
+       0xC5, 0x41, 0xD0, 0xB8, 0xB0, 0xB7, 0xA0, 0x56,
+       0x84, 0x3C, 0xBC, 0x8C, 0xC0, 0x10, 0xFB, 0x59,
+       0xD6, 0x02, 0xA4, 0x3C, 0x88, 0x99, 0x00, 0x03,
+       0xD0, 0xEE, 0x84, 0x3C, 0xBC, 0x8C, 0xC0, 0x10,
+       0xFB, 0x59, 0xD6, 0x02, 0xA4, 0x3C, 0x91, 0x26,
+       0xC8, 0xD0, 0xEF, 0xBC, 0x8C, 0xC0, 0x10, 0xFB,
+       0x59, 0xD6, 0x02, 0xD0, 0x87, 0xA0, 0x00, 0xA2,
+       0x56, 0xCA, 0x30, 0xFB, 0xB1, 0x26, 0x5E, 0x00,
+       0x03, 0x2A, 0x5E, 0x00, 0x03, 0x2A, 0x91, 0x26,
+       0xC8, 0xD0, 0xEE, 0xE6, 0x27, 0xE6, 0x3D, 0xA5,
+       0x3D, 0xCD, 0x00, 0x08, 0xA6, 0x2B, 0x90, 0xDB,
+       0x4C, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00
+};
 
-uint8_t diskROM[0x100] = {             // Loads at $C600 (slot 6)
-       0xA2, 0x20, 0xA0, 0x00, 0xA2, 0x03, 0x86, 0x3C, 0x8A, 0x0A, 0x24, 0x3C, 0xF0, 0x10, 0x05, 0x3C,
-       0x49, 0xFF, 0x29, 0x7E, 0xB0, 0x08, 0x4A, 0xD0, 0xFB, 0x98, 0x9D, 0x56, 0x03, 0xC8, 0xE8, 0x10,
-       0xE5, 0x20, 0x58, 0xFF, 0xBA, 0xBD, 0x00, 0x01, 0x0A, 0x0A, 0x0A, 0x0A, 0x85, 0x2B, 0xAA, 0xBD,
-       0x8E, 0xC0, 0xBD, 0x8C, 0xC0, 0xBD, 0x8A, 0xC0, 0xBD, 0x89, 0xC0, 0xA0, 0x50, 0xBD, 0x80, 0xC0,
-       0x98, 0x29, 0x03, 0x0A, 0x05, 0x2B, 0xAA, 0xBD, 0x81, 0xC0, 0xA9, 0x56, 0x20, 0xA8, 0xFC, 0x88,
-       0x10, 0xEB, 0x85, 0x26, 0x85, 0x3D, 0x85, 0x41, 0xA9, 0x08, 0x85, 0x27, 0x18, 0x08, 0xBD, 0x8C,
-       0xC0, 0x10, 0xFB, 0x49, 0xD5, 0xD0, 0xF7, 0xBD, 0x8C, 0xC0, 0x10, 0xFB, 0xC9, 0xAA, 0xD0, 0xF3,
-       0xEA, 0xBD, 0x8C, 0xC0, 0x10, 0xFB, 0xC9, 0x96, 0xF0, 0x09, 0x28, 0x90, 0xDF, 0x49, 0xAD, 0xF0,
-       0x25, 0xD0, 0xD9, 0xA0, 0x03, 0x85, 0x40, 0xBD, 0x8C, 0xC0, 0x10, 0xFB, 0x2A, 0x85, 0x3C, 0xBD,
-       0x8C, 0xC0, 0x10, 0xFB, 0x25, 0x3C, 0x88, 0xD0, 0xEC, 0x28, 0xC5, 0x3D, 0xD0, 0xBE, 0xA5, 0x40,
-       0xC5, 0x41, 0xD0, 0xB8, 0xB0, 0xB7, 0xA0, 0x56, 0x84, 0x3C, 0xBC, 0x8C, 0xC0, 0x10, 0xFB, 0x59,
-       0xD6, 0x02, 0xA4, 0x3C, 0x88, 0x99, 0x00, 0x03, 0xD0, 0xEE, 0x84, 0x3C, 0xBC, 0x8C, 0xC0, 0x10,
-       0xFB, 0x59, 0xD6, 0x02, 0xA4, 0x3C, 0x91, 0x26, 0xC8, 0xD0, 0xEF, 0xBC, 0x8C, 0xC0, 0x10, 0xFB,
-       0x59, 0xD6, 0x02, 0xD0, 0x87, 0xA0, 0x00, 0xA2, 0x56, 0xCA, 0x30, 0xFB, 0xB1, 0x26, 0x5E, 0x00,
-       0x03, 0x2A, 0x5E, 0x00, 0x03, 0x2A, 0x91, 0x26, 0xC8, 0xD0, 0xEE, 0xE6, 0x27, 0xE6, 0x3D, 0xA5,
-       0x3D, 0xCD, 0x00, 0x08, 0xA6, 0x2B, 0x90, 0xDB, 0x4C, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00
+//
+// 13-sector bootstrap driver for disk controller
+//
+uint8_t diskROM13[0x100] = {
+       0xA2, 0x20, 0xA0, 0x00, 0xA9, 0x03, 0x85, 0x3C,
+       0x18, 0x88, 0x98, 0x24, 0x3C, 0xF0, 0xF5, 0x26,
+       0x3C, 0x90, 0xF8, 0xC0, 0xD5, 0xF0, 0xED, 0xCA,
+       0x8A, 0x99, 0x00, 0x08, 0xD0, 0xE6, 0x20, 0x58,
+       0xFF, 0xBA, 0xBD, 0x00, 0x01, 0x48, 0x0A, 0x0A,
+       0x0A, 0x0A, 0x85, 0x2B, 0xAA, 0xA9, 0xD0, 0x48,
+       0xBD, 0x8E, 0xC0, 0xBD, 0x8C, 0xC0, 0xBD, 0x8A,
+       0xC0, 0xBD, 0x89, 0xC0, 0xA0, 0x50, 0xBD, 0x80,
+       0xC0, 0x98, 0x29, 0x03, 0x0A, 0x05, 0x2B, 0xAA,
+       0xBD, 0x81, 0xC0, 0xA9, 0x56, 0x20, 0xA8, 0xFC,
+       0x88, 0x10, 0xEB, 0xA9, 0x03, 0x85, 0x27, 0xA9,
+       0x00, 0x85, 0x26, 0x85, 0x3D, 0x18, 0x08, 0xBD,
+       0x8C, 0xC0, 0x10, 0xFB, 0x49, 0xD5, 0xD0, 0xF7,
+       0xBD, 0x8C, 0xC0, 0x10, 0xFB, 0xC9, 0xAA, 0xD0,
+       0xF3, 0xEA, 0xBD, 0x8C, 0xC0, 0x10, 0xFB, 0xC9,
+       0xB5, 0xF0, 0x09, 0x28, 0x90, 0xDF, 0x49, 0xAD,
+       0xF0, 0x1F, 0xD0, 0xD9, 0xA0, 0x03, 0x84, 0x2A,
+       0xBD, 0x8C, 0xC0, 0x10, 0xFB, 0x2A, 0x85, 0x3C,
+       0xBD, 0x8C, 0xC0, 0x10, 0xFB, 0x25, 0x3C, 0x88,
+       0xD0, 0xEE, 0x28, 0xC5, 0x3D, 0xD0, 0xBE, 0xB0,
+       0xBD, 0xA0, 0x9A, 0x84, 0x3C, 0xBC, 0x8C, 0xC0,
+       0x10, 0xFB, 0x59, 0x00, 0x08, 0xA4, 0x3C, 0x88,
+       0x99, 0x00, 0x08, 0xD0, 0xEE, 0x84, 0x3C, 0xBC,
+       0x8C, 0xC0, 0x10, 0xFB, 0x59, 0x00, 0x08, 0xA4,
+       0x3C, 0x91, 0x26, 0xC8, 0xD0, 0xEF, 0xBC, 0x8C,
+       0xC0, 0x10, 0xFB, 0x59, 0x00, 0x08, 0xD0, 0x8D,
+       0x60, 0xA8, 0xA2, 0x00, 0xB9, 0x00, 0x08, 0x4A,
+       0x3E, 0xCC, 0x03, 0x4A, 0x3E, 0x99, 0x03, 0x85,
+       0x3C, 0xB1, 0x26, 0x0A, 0x0A, 0x0A, 0x05, 0x3C,
+       0x91, 0x26, 0xC8, 0xE8, 0xE0, 0x33, 0xD0, 0xE4,
+       0xC6, 0x2A, 0xD0, 0xDE, 0xCC, 0x00, 0x03, 0xD0,
+       0x03, 0x4C, 0x01, 0x03, 0x4C, 0x2D, 0xFF, 0xFF
 };
 
+// Looks like this is unused...
 uint8_t hdROM[0x100] = {               // Loads at $C700 (slot 7)
        0xA9, 0x20, 0xA9, 0x00, 0xA9, 0x03, 0xA9, 0x3C, 0xA9, 0x00, 0x8D, 0xF2, 0xC0, 0xA9, 0x70, 0x8D,
        0xF3, 0xC0, 0xAD, 0xF0, 0xC0, 0x48, 0xAD, 0xF1, 0xC0, 0x18, 0xC9, 0x01, 0xD0, 0x01, 0x38, 0x68,
index caac1abd8fbd426df26d3ea6e581f35ccbeaf492..3a869f8763445cba98c6885b031cb1e04b85790d 100644 (file)
@@ -3,8 +3,9 @@
 
 #include <stdint.h>
 
-extern uint8_t diskROM[0x100]; // Loads at $C600 (slot 6)
-extern uint8_t hdROM[0x100];   // Loads at $C700 (slot 7)
+extern uint8_t diskROM[0x100];
+extern uint8_t diskROM13[0x100];
+extern uint8_t hdROM[0x100];   // Loads at $C700 (slot 7) [unused]
 extern uint8_t parallelROM[0x100];// (slot 1)
 //Not sure what the heck this is...
 extern uint8_t slot2e[0x100];
index ffae0634bdb405cfd86181aeb4439843ea0e4fe4..92917191dd10e16c5bb9a57c3a96fae444f3e437 100644 (file)
@@ -26,6 +26,9 @@
 #include "video.h"             // For message spawning... Though there's probably a
                                                // better approach than this!
 
+// For testing 13-sector disk FW
+//#define TEST13
+
 // Useful enums
 
 enum { IO_MODE_READ, IO_MODE_WRITE };
@@ -33,28 +36,153 @@ enum { IO_MODE_READ, IO_MODE_WRITE };
 // Misc. arrays (read only) that are needed
 
 static const uint8_t bitMask[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
+
 static const uint8_t sequencerROM[256] = {
-       0x18, 0x18, 0x18, 0x18, 0x0A, 0x0A, 0x0A, 0x0A, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x2D, 0x38, 0x2D, 0x38, 0x0A, 0x0A, 0x0A, 0x0A, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
-       0x38, 0x28, 0xD8, 0x08, 0x0A, 0x0A, 0x0A, 0x0A, 0x39, 0x39, 0x39, 0x39, 0x3B, 0x3B, 0x3B, 0x3B,
-       0x48, 0x48, 0xD8, 0x48, 0x0A, 0x0A, 0x0A, 0x0A, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
-       0x58, 0x58, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
-       0x68, 0x68, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68,
-       0x78, 0x78, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
-       0x88, 0x88, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0x08, 0x88, 0x08, 0x88, 0x08, 0x88, 0x08, 0x88,
-       0x98, 0x98, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
-       0x29, 0xA8, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8,
-       0xBD, 0xB8, 0xCD, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0xB9, 0xB9, 0xB9, 0xB9, 0xBB, 0xBB, 0xBB, 0xBB,
-       0x59, 0xC8, 0xD9, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8,
-       0xD9, 0xA0, 0xD9, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8,
-       0x08, 0xE8, 0xD8, 0xE8, 0x0A, 0x0A, 0x0A, 0x0A, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
-       0xFD, 0xF8, 0xFD, 0xF8, 0x0A, 0x0A, 0x0A, 0x0A, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8,
-       0x4D, 0xE0, 0xDD, 0xE0, 0x0A, 0x0A, 0x0A, 0x0A, 0x88, 0x08, 0x88, 0x08, 0x88, 0x08, 0x88, 0x08
+       0x18, 0x18, 0x18, 0x18, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, // $00
+       0x2D, 0x38, 0x2D, 0x38, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, // $10
+       0x38, 0x28, 0xD8, 0x08, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x39, 0x39, 0x39, 0x39, 0x3B, 0x3B, 0x3B, 0x3B, // $20
+       0x48, 0x48, 0xD8, 0x48, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, // $30
+       0x58, 0x58, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, // $40
+       0x68, 0x68, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, // $50
+       0x78, 0x78, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, // $60
+       0x88, 0x88, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x08, 0x88, 0x08, 0x88, 0x08, 0x88, 0x08, 0x88, // $70
+       0x98, 0x98, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, // $80
+       0x29, 0xA8, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, // $90
+       0xBD, 0xB8, 0xCD, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0xB9, 0xB9, 0xB9, 0xB9, 0xBB, 0xBB, 0xBB, 0xBB, // $A0
+       0x59, 0xC8, 0xD9, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, // $B0
+       0xD9, 0xA0, 0xD9, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, // $C0
+       0x08, 0xE8, 0xD8, 0xE8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, // $D0
+       0xFD, 0xF8, 0xFD, 0xF8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, // $E0
+       0x4D, 0xE0, 0xDD, 0xE0, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x88, 0x08, 0x88, 0x08, 0x88, 0x08, 0x88, 0x08  // $F0
 };
 
+#if 1 // From UTA2E, but need to double check...
+static const uint8_t sequencerROM13[256] = {
+//                    vvvv (2, 4, 1, 3)
+       0x18, 0x08, 0xD8, 0x18, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, // $00
+       0x28, 0x28, 0xD8, 0x28, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, // $10
+       0x38, 0x38, 0xD8, 0x38, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x39, 0x39, 0x39, 0x39, 0x3B, 0x3B, 0x3B, 0x3B, // $20
+       0x48, 0x48, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, // $30
+       0x58, 0x58, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, // $40
+       0x68, 0x68, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, // $50
+       0x78, 0x78, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, // $60
+       0x88, 0x88, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x08, 0x88, 0x08, 0x88, 0x08, 0x88, 0x08, 0x88, // $70
+       0x98, 0x98, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, // $80
+       0x09, 0xA8, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, // $90
+       0xBD, 0xB8, 0xCD, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0xB9, 0xB9, 0xB9, 0xB9, 0xBB, 0xBB, 0xBB, 0xBB, // $A0
+       0x39, 0xC8, 0xD9, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, // $B0
+       0xD9, 0xA0, 0xD9, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, // $C0
+       0x0D, 0xE8, 0x1D, 0xE8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, // $D0
+       0xFD, 0xF8, 0xFD, 0xF8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, // $E0
+       0x4D, 0xE0, 0xDD, 0xE0, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x88, 0x08, 0x88, 0x08, 0x88, 0x08, 0x88, 0x08  // $F0
+};
+#endif
+#if 0
+static const uint8_t sequencerROM13[256] = {
+       0x18, 0x08, 0xD8, 0x18, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x98, 0x98, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+       0x38, 0x38, 0xD8, 0x38, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x39, 0x39, 0x39, 0x39, 0x3B, 0x3B, 0x3B, 0x3B,
+       0xBD, 0xB8, 0xCD, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0xB9, 0xB9, 0xB9, 0xB9, 0xBB, 0xBB, 0xBB, 0xBB,
+       0x58, 0x58, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+       0xD9, 0xA0, 0xD9, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8,
+       0x78, 0x78, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
+       0xFD, 0xF8, 0xFD, 0xF8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8,
+       0x28, 0x28, 0xD8, 0x28, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+       0x09, 0xA8, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8,
+       0x48, 0x48, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+       0x39, 0xC8, 0xD9, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8,
+       0x68, 0x68, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68,
+       0x0D, 0xE8, 0x1D, 0xE8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
+       0x88, 0x88, 0xD8, 0xD8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x08, 0x88, 0x08, 0x88, 0x08, 0x88, 0x08, 0x88,
+       0x4D, 0xE0, 0xDD, 0xE0, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x88, 0x08, 0x88, 0x08, 0x88, 0x08, 0x88, 0x08
+};
+#endif
+#if 0
+static const uint8_t sequencerROM13[256] = {
+       0x88, 0x08, 0xB8, 0x88, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, // $00
+       0x98, 0x98, 0xB8, 0xB8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, // $10
+       0xC8, 0xC8, 0xB8, 0xC8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0xC9, 0xC9, 0xC9, 0xC9, 0xCB, 0xCB, 0xCB, 0xCB, // $20
+       0xDD, 0xD8, 0x3D, 0xB8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0xD9, 0xD9, 0xD9, 0xD9, 0xDB, 0xDB, 0xDB, 0xDB, // $30
+       0xA8, 0xA8, 0xB8, 0xB8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, // $40
+       0xB9, 0x50, 0xB9, 0xB8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, // $50
+       0xE8, 0xE8, 0xB8, 0xB8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, // $60
+       0xFD, 0xF8, 0xFD, 0xF8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, // $70
+       0x48, 0x48, 0xB8, 0x48, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, // $80
+       0x09, 0x58, 0xB8, 0xB8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, // $90
+       0x28, 0x28, 0xB8, 0xB8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, // $A0
+       0xC9, 0x38, 0xB9, 0xB8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, // $B0
+       0x68, 0x68, 0xB8, 0xB8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, // $C0
+       0x0D, 0x78, 0x8D, 0x78, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, // $D0
+       0x18, 0x18, 0xB8, 0xB8, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x08, 0x18, 0x08, 0x18, 0x08, 0x18, 0x08, 0x18, // $E0
+       0x2D, 0x70, 0xBD, 0x70, 0x0A, 0x0A, 0x0A, 0x0A,
+       0x18, 0x08, 0x18, 0x08, 0x18, 0x08, 0x18, 0x08  // $F0
+};
+#endif
 static char nameBuf[MAX_PATH];
 
-
 // Static in-line functions, for clarity & speed, for swapping variables
 static inline void Swap(uint8_t & a, uint8_t & b)
 {
@@ -63,7 +191,6 @@ static inline void Swap(uint8_t & a, uint8_t & b)
        b = t;
 }
 
-
 static inline void Swap(uint32_t & a, uint32_t & b)
 {
        uint32_t t = a;
@@ -71,7 +198,6 @@ static inline void Swap(uint32_t & a, uint32_t & b)
        b = t;
 }
 
-
 static inline void Swap(bool & a, bool & b)
 {
        bool t = a;
@@ -79,7 +205,6 @@ static inline void Swap(bool & a, bool & b)
        b = t;
 }
 
-
 static inline void Swap(uint8_t * & a, uint8_t * & b)
 {
        uint8_t * t = a;
@@ -87,9 +212,9 @@ static inline void Swap(uint8_t * & a, uint8_t * & b)
        b = t;
 }
 
-
+//
 // FloppyDrive class implementation...
-
+//
 FloppyDrive::FloppyDrive(): motorOn(0), activeDrive(0), ioMode(IO_MODE_READ),  ioHappened(false), diskImageReady(false)
 {
        phase[0] = phase[1] = 0;
@@ -102,7 +227,6 @@ FloppyDrive::FloppyDrive(): motorOn(0), activeDrive(0), ioMode(IO_MODE_READ),  i
        imageName[0][0] = imageName[1][0] = 0;                  // Zero out filenames
 }
 
-
 FloppyDrive::~FloppyDrive()
 {
        if (disk[0])
@@ -112,7 +236,6 @@ FloppyDrive::~FloppyDrive()
                free(disk[1]);
 }
 
-
 bool FloppyDrive::LoadImage(const char * filename, uint8_t driveNum/*= 0*/)
 {
        WriteLog("FLOPPY: Attempting to load image '%s' in drive #%u.\n", filename, driveNum);
@@ -149,7 +272,6 @@ bool FloppyDrive::LoadImage(const char * filename, uint8_t driveNum/*= 0*/)
        return true;
 }
 
-
 bool FloppyDrive::SaveImage(uint8_t driveNum/*= 0*/)
 {
        // Various sanity checks...
@@ -179,7 +301,6 @@ bool FloppyDrive::SaveImage(uint8_t driveNum/*= 0*/)
        return SaveWOZ(imageName[driveNum], (WOZ2 *)disk[driveNum], diskSize[driveNum]);
 }
 
-
 bool FloppyDrive::SaveImageAs(const char * filename, uint8_t driveNum/*= 0*/)
 {
        strncpy(imageName[driveNum], filename, MAX_PATH);
@@ -189,7 +310,6 @@ bool FloppyDrive::SaveImageAs(const char * filename, uint8_t driveNum/*= 0*/)
        return SaveImage(driveNum);
 }
 
-
 void FloppyDrive::CreateBlankImage(uint8_t driveNum/*= 0*/)
 {
        if (disk[driveNum] != NULL)
@@ -201,7 +321,6 @@ void FloppyDrive::CreateBlankImage(uint8_t driveNum/*= 0*/)
        SpawnMessage("New blank image inserted in drive %u...", driveNum);
 }
 
-
 void FloppyDrive::SwapImages(void)
 {
        char imageNameTmp[MAX_PATH];
@@ -221,7 +340,6 @@ void FloppyDrive::SwapImages(void)
 SpawnMessage("Drive 0: %s...", imageName[0]);
 }
 
-
 /*
 Need to add some type of error checking here, so we can report back on bad images, etc. (basically, it does by returning DFT_UNKNOWN, but we could do better)
 */
@@ -248,6 +366,7 @@ void FloppyDrive::DetectImageType(const char * filename, uint8_t driveNum)
                        WriteLog("FLOPPY: Upconverted WOZ type 1 to type 2...\n");
                }
 
+               WriteLog("FLOPPY: OBT is %d\n", ((WOZ2 *)disk[driveNum])->optimalBitTmg);
                diskType[driveNum] = DT_WOZ;
        }
        else if (diskSize[driveNum] == 143360)
@@ -310,7 +429,6 @@ void FloppyDrive::DetectImageType(const char * filename, uint8_t driveNum)
                "DOS 3.3 (headered)" : (diskType[driveNum] == DT_PRODOS ? "ProDOS" : (diskType[driveNum] == DT_WOZ ? "WOZ" : "unknown")))));
 }
 
-
 //
 // Write a bitstream (source left justified to bit 7) to destination buffer.
 // Writes 'bits' number of bits to 'dest', starting at bit position 'dstPtr',
@@ -334,7 +452,6 @@ void FloppyDrive::WriteBits(uint8_t * dest, const uint8_t * src, uint16_t bits,
        }
 }
 
-
 void FloppyDrive::WOZifyImage(uint8_t driveNum)
 {
        // hdr (21) + nybbles (343) + footer (48) = 412 bytes per sector
@@ -458,7 +575,6 @@ void FloppyDrive::WOZifyImage(uint8_t driveNum)
        free(tmpDisk);
 }
 
-
 const char * FloppyDrive::ImageName(uint8_t driveNum/*= 0*/)
 {
        // Set up a zero-length string for return value
@@ -495,7 +611,6 @@ const char * FloppyDrive::ImageName(uint8_t driveNum/*= 0*/)
        return nameBuf;
 }
 
-
 void FloppyDrive::EjectImage(uint8_t driveNum/*= 0*/)
 {
        // Sanity check
@@ -516,7 +631,6 @@ void FloppyDrive::EjectImage(uint8_t driveNum/*= 0*/)
        imageName[driveNum][0] = 0;                     // Zero out filenames
 }
 
-
 bool FloppyDrive::IsEmpty(uint8_t driveNum/*= 0*/)
 {
        if (driveNum > 1)
@@ -528,7 +642,6 @@ bool FloppyDrive::IsEmpty(uint8_t driveNum/*= 0*/)
        return (diskType[driveNum] == DT_EMPTY ? true : false);
 }
 
-
 bool FloppyDrive::IsWriteProtected(uint8_t driveNum/*= 0*/)
 {
        if (driveNum > 1)
@@ -541,7 +654,6 @@ bool FloppyDrive::IsWriteProtected(uint8_t driveNum/*= 0*/)
        return (bool)woz.writeProtected;
 }
 
-
 void FloppyDrive::SetWriteProtect(bool state, uint8_t driveNum/*= 0*/)
 {
        if (driveNum > 1)
@@ -554,7 +666,6 @@ void FloppyDrive::SetWriteProtect(bool state, uint8_t driveNum/*= 0*/)
        woz.writeProtected = (uint8_t)state;
 }
 
-
 int FloppyDrive::DriveLightStatus(uint8_t driveNum/*= 0*/)
 {
        int retval = DLS_OFF;
@@ -569,7 +680,6 @@ int FloppyDrive::DriveLightStatus(uint8_t driveNum/*= 0*/)
        return retval;
 }
 
-
 void FloppyDrive::SaveState(FILE * file)
 {
        // Internal state vars
@@ -610,7 +720,6 @@ void FloppyDrive::SaveState(FILE * file)
                WriteLong(file, 0);
 }
 
-
 void FloppyDrive::LoadState(FILE * file)
 {
        // Eject images if they're loaded
@@ -653,7 +762,6 @@ void FloppyDrive::LoadState(FILE * file)
        }
 }
 
-
 uint32_t FloppyDrive::ReadLong(FILE * file)
 {
        uint32_t r = 0;
@@ -664,7 +772,6 @@ uint32_t FloppyDrive::ReadLong(FILE * file)
        return r;
 }
 
-
 void FloppyDrive::WriteLong(FILE * file, uint32_t l)
 {
        for(int i=0; i<4; i++)
@@ -674,7 +781,6 @@ void FloppyDrive::WriteLong(FILE * file, uint32_t l)
        }
 }
 
-
 // Memory mapped I/O functions + Logic State Sequencer
 
 /*
@@ -754,11 +860,13 @@ If it ever *does* become a problem, doing the physical modeling of the head movi
        else
                phase[activeDrive] &= ~phaseBit;
 
-       uint8_t oldHeadPos = headPos[activeDrive] & 0x07;
-       int16_t newStep = step[phase[activeDrive]][oldHeadPos];
+       int16_t oldHeadPos = headPos[activeDrive];
+       int16_t newStep = step[phase[activeDrive]][oldHeadPos & 0x07];
        int16_t newHeadPos = (int16_t)headPos[activeDrive] + newStep;
+WriteLog("\nFLOPPY: oldHeadPos=%u, newHeadPos=%i, newStep=%i\n", oldHeadPos, newHeadPos, newStep);
 
        // Sanity check
+       // N.B.: This is wrong for 3.5" disks
        if ((newHeadPos >= 0) && (newHeadPos <= 140))
                headPos[activeDrive] = (uint8_t)newHeadPos;
 
@@ -772,7 +880,9 @@ If it ever *does* become a problem, doing the physical modeling of the head movi
                uint8_t oldTIdx = woz.tmap[oldHeadPos];
                float oldBitLen = (oldTIdx == 0xFF
                        ? 51200.0f : Uint16LE(woz.track[oldTIdx].bitCount));
+WriteLog("FLOPPY: Current pos pre: %u, ", currentPos[activeDrive]);
                currentPos[activeDrive] = (uint32_t)((float)currentPos[activeDrive] * (newBitLen / oldBitLen));
+WriteLog("post: %u; newBitLen/old = %.1f/%.1f\n", currentPos[activeDrive], newBitLen, oldBitLen);
 
                trackLength[activeDrive] = (uint16_t)newBitLen;
                SpawnMessage("Stepping to track %u...", headPos[activeDrive] >> 2);
@@ -787,7 +897,6 @@ if (addr & 0x01)
 WriteLog("FLOPPY: Stepper phase %d set to %s [%c%c%c%c] (track=%2.2f) [%u]\n", (addr >> 1) & 0x03, (addr & 0x01 ? "ON " : "off"), (phase[activeDrive] & 0x08 ? '|' : '.'), (phase[activeDrive] & 0x04 ? '|' : '.'), (phase[activeDrive] & 0x02 ? '|' : '.'), (phase[activeDrive] & 0x01 ? '|' : '.'), (float)headPos[activeDrive] / 4.0f, mainCPU.clock & 0xFFFFFFFF);
 }
 
-
 void FloppyDrive::ControlMotor(uint8_t addr)
 {
        // $C0E8 - 9
@@ -801,7 +910,6 @@ void FloppyDrive::ControlMotor(uint8_t addr)
 WriteLog("FLOPPY: Turning drive motor %s\n", (motorOn ? "ON" : "off"));
 }
 
-
 void FloppyDrive::DriveEnable(uint8_t addr)
 {
        // $C0EA - B
@@ -809,7 +917,6 @@ void FloppyDrive::DriveEnable(uint8_t addr)
 WriteLog("FLOPPY: Selecting drive #%hhd\n", addr + 1);
 }
 
-
 /*
 So for $C08C-F, we have two switches (Q6 & Q7) which combine to make four states ($C-D is off/on for Q6, $E-F is off/on for Q7).
 
@@ -825,21 +932,18 @@ Looks like reads from even addresses in $C080-F block transfer data from the seq
 
 */
 
-
 void FloppyDrive::SetShiftLoadSwitch(uint8_t state)
 {
        // $C0EC - D
        slSwitch = state;
 }
 
-
 void FloppyDrive::SetReadWriteSwitch(uint8_t state)
 {
        // $C0EE - F
        rwSwitch = state;
 }
 
-
 // MMIO: Reads from $C08x to $C0XX on even addresses
 uint8_t FloppyDrive::DataRegister(void)
 {
@@ -858,15 +962,14 @@ uint8_t FloppyDrive::DataRegister(void)
 if ((seenReadSinceStep == false) && (slSwitch == false) && (rwSwitch == false) && ((iorAddr & 0x0F) == 0x0C))
 {
        seenReadSinceStep = true;
-       WriteLog("%u:Reading $%02X from track %u, sector %u (delta since seek: %lu cycles) [%u]...\n",
-               activeDrive, dataRegister, headPos[activeDrive] >> 2, (uint32_t)(((float)currentPos[activeDrive] / (float)bitLen) * 16.0f), mainCPU.clock - stepperTime, mainCPU.clock & 0xFFFFFFFF);
+       WriteLog("%u:Reading $%02X from track %2.2f, sector %u (delta since seek: %lu cycles) [%u]...\n",
+               activeDrive, dataRegister, (float)headPos[activeDrive] / 4.0f, (uint32_t)(((float)currentPos[activeDrive] / (float)bitLen) * 16.0f), mainCPU.clock - stepperTime, mainCPU.clock & 0xFFFFFFFF);
 }
        }
 
        return dataRegister;
 }
 
-
 // MMIO: Writes from $C08x to $C0XX on odd addresses
 void FloppyDrive::DataRegister(uint8_t data)
 {
@@ -875,7 +978,6 @@ void FloppyDrive::DataRegister(uint8_t data)
        ioHappened = true;
 }
 
-
 /*
         OFF switches                ON switches
 Switch  Addr   Func                 Addr   Func
@@ -948,9 +1050,11 @@ $5A:    File structure damaged
 //       which will make the simulated drive run in the neighborhood of around
 //       306 RPM.  Should be close enough to get away with it.  :-)  (And it
 //       seems to run OK, for the most part.)
-
+//
+//       According to EDD 4 the drive is running at 299.1 RPM...  :-/
 
 static bool logSeq = false;
+char sequence[1024];
 //
 // Logic State Sequencer & Data Register
 //
@@ -974,6 +1078,9 @@ void FloppyDrive::RunSequencer(uint32_t cyclesToRun)
        WOZ2 & woz = *((WOZ2 *)disk[activeDrive]);
        uint8_t tIdx = woz.tmap[headPos[activeDrive]];
        uint8_t * tdata = disk[activeDrive] + (Uint16LE(woz.track[tIdx].startingBlock) * 512);
+       // We have to divide the optimal bit timing by 4 because we only have a 0.5µs granularity here (with the doubling of the "cyclesToRun").  The OBT has a granularity of 0.125µs.  Not sure how to fix that--have to separate the pulse handling from the sequencer?
+       // N.B.: Border Zone has an OBT of 28, when divides evenly by 4, but it still fails...
+       uint8_t pulseTiming = woz.optimalBitTmg / 4;
 
        // It's x2 because the sequencer clock runs twice as fast as the CPU clock.
        cyclesToRun *= 2;
@@ -990,7 +1097,8 @@ if (logSeq)
        while (cyclesToRun-- > 0)
        {
 //             pulseClock = (pulseClock + 1) & 0x07;
-               pulseClock = (pulseClock + 1) % 8;
+//             pulseClock = (pulseClock + 1) % 8;
+               pulseClock = (pulseClock + 1) % pulseTiming;
 // 7 doesn't work...  Is that 3.5µs?  Seems to be.  Which means to get a 0.25µs granularity here, we need to double the # of cycles to run...
 //             pulseClock = (pulseClock + 1) % 7;
 
@@ -998,6 +1106,7 @@ if (logSeq)
                {
                        uint16_t bytePos = currentPos[activeDrive] / 8;
                        uint8_t bitPos = currentPos[activeDrive] % 8;
+                       window <<= 1;
 
                        if (tIdx != 0xFF)
                        {
@@ -1005,14 +1114,17 @@ if (logSeq)
                                {
                                        // According to Jim Sather (Understanding the Apple II),
                                        // the Read Pulse, when it happens, is 1µs long, which is 2
-                                       // sequencer clock pulses long.
-                                       readPulse = 2;
+                                       // sequencer clock pulses long.  (Not sure where, elsewhere, on pg. 9-29 it says it lasts one *sequencer* clock pulse.)
+                                       readPulse = 1;//2;
                                        zeroBitCount = 0;
+                                       window |= 0x01;
                                }
                                else
                                        zeroBitCount++;
+//WriteLog("[%d]", tdata[bytePos] & bitMask[bitPos] ? 1 : 0);
                        }
 
+                       readPulse = (window >> 1) & 0x01; // Read pulse delayed by about 5µs
                        currentPos[activeDrive] = (currentPos[activeDrive] + 1) % trackLength[activeDrive];
 
                        // If we hit more than 2 zero bits in a row, simulate the disk head
@@ -1022,13 +1134,14 @@ if (logSeq)
 /*
 N.B.: Had to up this to 3 because Up N' Down had some weird sync bytes (FE10).  May have to up it some more.
 */
-                       if ((zeroBitCount > 3) || (tIdx == 0xFF))
+//                     if ((zeroBitCount > 3) || (tIdx == 0xFF))
+                       if (((window & 0x0F) == 0) || (tIdx == 0xFF))
                        {
                                if (prng & 0x00001)
                                {
                                        // This PRNG is called the "Galois configuration".
                                        prng ^= 0x24000;
-                                       readPulse = 2;
+                                       readPulse = 1;//2;
                                }
 
                                prng >>= 1;
@@ -1042,23 +1155,40 @@ N.B.: Had to up this to 3 because Up N' Down had some weird sync bytes (FE10).
 if (logSeq)
        WriteLog("[%02X:%02X]%s", sequencerState, nextState, (chop == 15 ? "\n" : ""));
 chop = (chop + 1) % 20;
+#ifndef TEST13
+               sequencerState = sequencerROM[nextState];
+#else
+//             sequencerState = sequencerROM13[nextState];
                sequencerState = sequencerROM[nextState];
+#endif
+
+#if 0
+uint32_t seqLen = strlen(sequence);
+
+if (seqLen + 7 > 1023)
+{
+       sequence[0] = 0;
+       seqLen = 0;
+}
+
+sprintf(&sequence[seqLen], "(%02X)%02X ", nextState, sequencerState);
+#endif
 
                switch (sequencerState & 0x0F)
                {
                case 0x00:
-               case 0x01:
-               case 0x02:
-               case 0x03:
-               case 0x04:
-               case 0x05:
-               case 0x06:
-               case 0x07:
-                       // CLR (clear data register)
+//             case 0x01:
+//             case 0x02:
+//             case 0x03:
+//             case 0x04:
+//             case 0x05:
+//             case 0x06:
+//             case 0x07:
+                       // CLR (clear data register; 0)
                        dataRegister = 0;
                        break;
                case 0x08:
-               case 0x0C:
+//             case 0x0C:
                        // NOP (no operation)
                        break;
                case 0x09:
@@ -1096,13 +1226,13 @@ lastPos = currentPos[activeDrive];
 }
                        break;
                case 0x0A:
-               case 0x0E:
+//             case 0x0E:
                        // SR (shift right write protect bit)
                        dataRegister >>= 1;
                        dataRegister |= (woz.writeProtected ? 0x80 : 0x00);
                        break;
                case 0x0B:
-               case 0x0F:
+//             case 0x0F:
                        // LD (load data register from data bus)
                        dataRegister = cpuDataBus;
 //if (!stopWriting)
@@ -1133,6 +1263,9 @@ lastPos = currentPos[activeDrive];
                        dataRegister <<= 1;
                        dataRegister |= 0x01;
                        break;
+               default:
+                       // 1-7, $C, $E, & $F are all invalid opcodes
+                       WriteLog("Invalid LSS state encountered! (opcode: $%X [full state: $%02X])\n", sequencerState & 0x0F, sequencerState);
                }
 
                if (readPulse > 0)
@@ -1143,7 +1276,6 @@ if (logSeq)
        WriteLog("\n");
 }
 
-
 FloppyDrive floppyDrive[2];
 
 static uint8_t SlotIOR(uint16_t address)
@@ -1187,7 +1319,6 @@ iorAddr = address;
        return (address & 0x01 ? ReadFloatingBus(0) : floppyDrive[0].DataRegister());
 }
 
-
 static void SlotIOW(uint16_t address, uint8_t byte)
 {
        uint8_t state = address & 0x0F;
@@ -1233,13 +1364,15 @@ static void SlotIOW(uint16_t address, uint8_t byte)
 // of FloppyDrive
 static uint8_t SlotROM(uint16_t address)
 {
+#ifndef TEST13
        return diskROM[address];
+#else
+       return diskROM13[address];
+#endif
 }
 
-
 void InstallFloppy(uint8_t slot)
 {
        SlotData disk = { SlotIOR, SlotIOW, SlotROM, 0, 0, 0 };
        InstallSlotHandler(slot, &disk);
 }
-
index d463a79d33ac30899ba161d48cb79c55ad4678ae..15290d33df4703ab9c93411103032f9a9bc069a9 100644 (file)
@@ -76,7 +76,9 @@ class FloppyDrive
                uint8_t motorOn;
                uint8_t activeDrive;
                uint8_t ioMode;
+       public: // temp, for testing...  :-P
                uint8_t dataRegister;
+       private:
                uint8_t phase[2];
                uint8_t headPos[2];
                bool ioHappened;
@@ -85,19 +87,22 @@ class FloppyDrive
                uint32_t currentPos[2];
 
                uint8_t cpuDataBus;
-               uint8_t slSwitch;                       // Shift/Load soft switch
-               uint8_t rwSwitch;                       // Read/Write soft switch
-               uint8_t readPulse;                      // Disk read head "pulse" signal
-               uint8_t pulseClock;                     // Disk read head bitstream "pulse clock"
+               uint8_t slSwitch;               // Shift/Load soft switch
+               uint8_t rwSwitch;               // Read/Write soft switch
+               uint8_t readPulse;              // Disk read head "pulse" signal
+               uint8_t pulseClock;             // Disk read head bitstream "pulse clock"
                uint8_t sequencerState;
                uint32_t driveOffTimeout;
                uint8_t zeroBitCount;
                uint16_t trackLength[2];
+//             uint8_t pulseTiming;    // WOZ disk "optimal" pulse timing (in 0.25µs)
+               uint8_t window;
 };
 
 // Exported functions/variables
 void InstallFloppy(uint8_t slot);
 extern FloppyDrive floppyDrive[];
+extern char sequence[];
 
 #endif // __FLOPPY_H__
 
index 57014b5e3cb1986a6798a9f91058d9bc4d8e14f1..f73e4cdb64a42d4e3378ee85c7a8e9e4ce270b37 100644 (file)
@@ -210,7 +210,7 @@ void DiskSelector::FindDisks(const char * path)
                                && (strcmp(ent->d_name, ".") != 0))
                        {
                                // Check to see if this is a special directory with a manifest
-                               char buf2[0x10000];
+                               char buf2[0x10000 + 13];
                                sprintf(buf2, "%s/manifest.txt", buf);
                                FILE * fp = fopen(buf2, "r");
 
index 6960a9675cf87f4b8d5916f8a666507069730654..b0386acc1cfbac55e516119d47a19f8fde0e2b32 100644 (file)
@@ -249,6 +249,7 @@ void GUI::MouseDown(int32_t x, int32_t y, uint32_t buttons)
        case 1:
                SpawnMessage("*** DISK #1 ***");
 
+#if 0
                if (disk1EjectHovered && !floppyDrive[0].IsEmpty(0))
                {
                        floppyDrive[0].EjectImage(0);
@@ -261,6 +262,32 @@ void GUI::MouseDown(int32_t x, int32_t y, uint32_t buttons)
                        Config::HideWindow();
                        DiskSelector::ShowWindow(0);
                }
+#else
+               if (disk1EjectHovered)
+               {
+                       if (!floppyDrive[0].IsEmpty(0))
+                       {
+                               floppyDrive[0].EjectImage(0);
+                               SpawnMessage("*** DISK #1 EJECTED ***");
+                       }
+               }
+               else
+               {
+                       if (disk1NewDiskHovered)
+                       {
+                               if (!floppyDrive[0].IsEmpty(0))
+                                       floppyDrive[0].EjectImage(0);
+
+                               floppyDrive[0].CreateBlankImage(0);
+                       }
+                       else
+                       {
+                               // Load the disk selector
+                               Config::HideWindow();
+                               DiskSelector::ShowWindow(0);
+                       }
+               }
+#endif
 
                break;
        // Disk #2
@@ -574,7 +601,7 @@ void GUI::DrawString(SDL_Renderer * renderer, int x, int y, const char * s, bool
 
 
 //
-// N.B.: This draws a char at an abosulte X/Y position, not on a grid
+// N.B.: This draws a char at an absolute X/Y position, not on a grid
 //
 void GUI::DrawStringVert(SDL_Renderer * renderer, int x, int y, const char * s, bool invert/*= false*/)
 {
index e0fae03773d84576fccc97b370b3dfaa8d241e9e..8dede0d5073ea0925f6de69e8645ea478506e648 100644 (file)
@@ -618,7 +618,7 @@ void InstallHardDrive(uint8_t slot)
 {
        SlotData hd = { SlotIOR, SlotIOW, SlotROM, 0, SlotIOExtraR, SlotIOExtraW };
        InstallSlotHandler(slot, &hd);
-       char fnBuf[MAX_PATH + 1];
+       char fnBuf[(MAX_PATH * 2) + 1];
 
        // If this fails to read the file, the pointer is set to NULL
        uint32_t size = 0, skip = (uint32_t)-1;
index 77578d42271c63c2803da523275ebfeaf9ef6f6b..326451091748a04c4aa44407b7751ee51a15832a 100644 (file)
@@ -829,7 +829,9 @@ void WriteKeyStrobe(uint16_t, uint8_t)
 uint8_t ReadSpeaker(uint16_t)
 {
        ToggleSpeaker();
-       return 0;
+//     return 0;
+       // Seems this is needed for some things...
+       return ReadFloatingBus(0);
 }
 
 void WriteSpeaker(uint16_t, uint8_t)
@@ -841,7 +843,9 @@ uint8_t SwitchLCR(uint16_t address)
 {
        lcState = address & 0x0B;
        SwitchLC();
-       return 0;
+//     return 0;
+       // Seems this is needed for some things...
+       return ReadFloatingBus(0);
 }
 
 void SwitchLCW(uint16_t address, uint8_t)
@@ -929,7 +933,9 @@ uint8_t SwitchTEXTR(uint16_t address)
 {
 WriteLog("Setting TEXT to %s...\n", (address & 0x01 ? "ON" : "off"));
        textMode = (bool)(address & 0x01);
-       return 0;
+//     return 0;
+       // Seems this is needed for some things...
+       return ReadFloatingBus(0);
 }
 
 void SwitchTEXTW(uint16_t address, uint8_t)
@@ -942,7 +948,9 @@ uint8_t SwitchMIXEDR(uint16_t address)
 {
 WriteLog("Setting MIXED to %s...\n", (address & 0x01 ? "ON" : "off"));
        mixedMode = (bool)(address & 0x01);
-       return 0;
+//     return 0;
+       // Seems this is needed for some things...
+       return ReadFloatingBus(0);
 }
 
 void SwitchMIXEDW(uint16_t address, uint8_t)
@@ -951,6 +959,9 @@ WriteLog("Setting MIXED to %s...\n", (address & 0x01 ? "ON" : "off"));
        mixedMode = (bool)(address & 0x01);
 }
 
+/*
+80STORE, PAGE2, and HIRES bank switch the primary display pages, $400--$7FF and $2000--$3FFF, between motherboard RAM and auxiliary card RAM.  If 80STORE is set and HIRES is reset, then PAGE2 switches between motherboard RAM and auxiliary card RAM for reading and writing in the $400--$7FF range.  If 80STORE is set and HIRES is set, then PAGE2 switches between motherboard RAM and auxiliary card RAM for reading and writing in the $400--$7FF and $2000--$3FFF ranges.  PAGE2 set selects auxiliary card RAM, and PAGE2 reset selects motherboard RAM.  If 80STORE is reset, then RAMRD and RAMWRT will bank switch the $400-$7FF and $2000--$3FFF ranges along with the rest of the $200--$BFFF range.
+*/
 uint8_t SwitchPAGE2R(uint16_t address)
 {
 WriteLog("Setting PAGE2 to %s...\n", (address & 0x01 ? "ON" : "off"));
@@ -960,11 +971,16 @@ WriteLog("Setting PAGE2 to %s...\n", (address & 0x01 ? "ON" : "off"));
        {
                mainMemoryTextR = (displayPage2 ? &ram2[0x0400] : &ram[0x0400]);
                mainMemoryTextW = (displayPage2 ? &ram2[0x0400] : &ram[0x0400]);
-               mainMemoryHGRR = (displayPage2 ? &ram2[0x2000] : &ram[0x2000]);
-               mainMemoryHGRW = (displayPage2 ? &ram2[0x2000] : &ram[0x2000]);
+
+               if (hiRes)
+               {
+                       mainMemoryHGRR = (displayPage2 ? &ram2[0x2000] : &ram[0x2000]);
+                       mainMemoryHGRW = (displayPage2 ? &ram2[0x2000] : &ram[0x2000]);
+               }
        }
 
-       return 0;
+       // Seems this is needed for some things...
+       return ReadFloatingBus(0);
 }
 
 void SwitchPAGE2W(uint16_t address, uint8_t)
@@ -976,8 +992,12 @@ WriteLog("Setting PAGE2 to %s...\n", (address & 0x01 ? "ON" : "off"));
        {
                mainMemoryTextR = (displayPage2 ? &ram2[0x0400] : &ram[0x0400]);
                mainMemoryTextW = (displayPage2 ? &ram2[0x0400] : &ram[0x0400]);
-               mainMemoryHGRR = (displayPage2 ? &ram2[0x2000] : &ram[0x2000]);
-               mainMemoryHGRW = (displayPage2 ? &ram2[0x2000] : &ram[0x2000]);
+
+               if (hiRes)
+               {
+                       mainMemoryHGRR = (displayPage2 ? &ram2[0x2000] : &ram[0x2000]);
+                       mainMemoryHGRW = (displayPage2 ? &ram2[0x2000] : &ram[0x2000]);
+               }
        }
 }
 
@@ -985,7 +1005,9 @@ uint8_t SwitchHIRESR(uint16_t address)
 {
 WriteLog("Setting HIRES to %s...\n", (address & 0x01 ? "ON" : "off"));
        hiRes = (bool)(address & 0x01);
-       return 0;
+//     return 0;
+       // Seems this is needed for some things...
+       return ReadFloatingBus(0);
 }
 
 void SwitchHIRESW(uint16_t address, uint8_t)
@@ -1001,7 +1023,9 @@ WriteLog("Setting DHIRES to %s (ioudis = %s)...\n", ((address & 0x01) ^ 0x01 ? "
        if (ioudis)
                dhires = !((bool)(address & 0x01));
 
-       return 0;
+//     return 0;
+       // Seems this is needed for some things...
+       return ReadFloatingBus(0);
 }
 
 void SwitchDHIRESW(uint16_t address, uint8_t)
index f0a589da31b7bb4eaecec7e68864a977d668eca3..82158c81ec3011322fed13643a4d7d263c8e2935 100644 (file)
@@ -28,6 +28,7 @@
 #ifdef __DEBUG__
 #include <string.h>
 #include "dis65c02.h"
+#include "floppydrive.h"
 #include "log.h"
 #endif
 
@@ -2218,7 +2219,6 @@ static void Op__(void)
        regs->cpuFlags |= V65C02_STATE_ILLEGAL_INST;
 }
 
-
 //
 // Ok, the exec_op[] array is globally defined here basically to save
 // a LOT of unnecessary typing.  Sure it's ugly, but hey, it works!
@@ -2283,7 +2283,6 @@ V65C02REGS btQueue[BACKTRACE_SIZE];
 uint8_t btQueueInst[BACKTRACE_SIZE][4];
 #endif
 
-
 //
 // Function to execute 65C02 for "cycles" cycles
 //
@@ -2297,6 +2296,196 @@ void Execute65C02(V65C02REGS * context, uint32_t cycles)
 
        while (regs->clock < endCycles)
        {
+// Ultima I (WTF? This *used* to work! >:-U) [Now it does...  :-P]
+// Turns out it was a problem with PAGE2 changing too much (it ignored the HIRES switch when switching memory, causing code at $2141 to be swapped out with zeroes).
+/*if (regs->pc == 0xC311)
+       dumpDis = true;
+else if (regs->pc == 0x2141)
+       dumpDis = false;*/
+
+#if 1
+// Bard's Tale II
+static bool hitGo = false;
+
+if (regs->pc == 0xA000)
+{
+       dumpDis = true;
+       hitGo = true;
+}
+
+// $FCA8 also needs to be silenced too ($FCB3 is exit point)
+if (regs->pc == 0xA181 && hitGo)
+{
+       dumpDis = false;
+       WriteLog("*** BT2 DELAY\n");
+}
+else if (regs->pc == 0xA18B && hitGo)
+{
+       dumpDis = true;
+}
+else if (regs->pc == 0xFCA8 && hitGo)
+{
+       dumpDis = false;
+       WriteLog("*** MONITOR DELAY ($FCA8)\n");
+}
+else if (regs->pc == 0xFCB3 && hitGo)
+{
+       dumpDis = true;
+}
+else if (regs->pc == 0xBD11 && hitGo)
+{
+       dumpDis = false;
+       WriteLog("*** BT2 DELAY $BD11\n");
+}
+else if (regs->pc == 0xDB1E && hitGo)
+{
+       dumpDis = true;
+}
+else if (regs->pc == 0xA003 && hitGo)
+{
+       dumpDis = false;
+       WriteLog("*** BT2 CHECK FOR $B7s\n");
+}
+else if (regs->pc == 0xA063 && hitGo)
+{
+       dumpDis = true;
+}
+else if (regs->pc == 0xA0FE && hitGo)
+{
+       dumpDis = false;
+       WriteLog("*** BT2 CHECK FOR $D5 $AA $96 HEADER\n");
+}
+else if (regs->pc == 0xA112 && hitGo)
+{
+       dumpDis = true;
+       WriteLog("*** BT2 LOOK FOR HEADER FAILED\n");
+}
+else if (regs->pc == 0xA14B && hitGo)
+{
+       dumpDis = true;
+}
+else if (regs->pc == 0xA254 && hitGo)
+{
+       // This is where it hits a BRK and goes BOOM
+       dumpDis = false;
+       hitGo = false;
+}
+else if (regs->pc == 0xA155)
+{
+       WriteLog("*** $A2E2 is %02X...\n", regs->RdMem(0xA2E2));
+}
+else if (regs->pc == 0xA1C2)
+{
+       static char bcName[13][5] = { "JMP", "JMPA", "BNE", "LDI", "JSR", "LDA", "SUB", "STA", "RTS", "JMPA", "INC", "CRSH", "ILDA" };
+       static int bcLen[13] = { 2, 2, 2, 1, 2, 2, 1, 2, 0, 2, 2, 0, 2 };
+
+       uint16_t addr = RdMemWZP(0x52) + regs->y;
+       uint8_t bytecode = regs->RdMem(addr);
+       uint16_t bcAddr = ((regs->RdMem(addr + 2) ^ 0xD9) << 8) | (regs->RdMem(addr + 1) ^ 0x03);
+       uint8_t bcVal = regs->RdMem(addr + 1) ^ 0x4C;
+
+       WriteLog("\n*** bc %04X: %s ", addr, bcName[bytecode]);
+
+       if (bcLen[bytecode] == 1)
+               WriteLog("$%02X", bcVal);
+       else if (bcLen[bytecode] == 2)
+               WriteLog("$%04X", bcAddr);
+
+       WriteLog("\n\n");
+}
+#endif
+
+#if 0
+// Border Zone timing...
+static bool inDelay1 = false;
+static bool inDelay2 = false;
+static bool inRead1 = false;
+static bool hitGo = false;
+if (regs->pc == 0xF0B1)
+       WriteLog("*** $F09C ($6F,70) -> $%02X%02X\n", regs->RdMem(0x70), regs->RdMem(0x6F));
+
+if (regs->pc == 0xC8F2)
+       hitGo = true;
+
+// Delay is $D20D to $D21D...
+if (regs->pc == 0xD20D && hitGo && !inDelay1)
+{
+       dumpDis = false;
+       inDelay1 = true;
+       WriteLog("*** DELAY\n");
+}
+else if (regs->pc == 0xD21D && inDelay1)
+{
+       dumpDis = true;
+       inDelay1 = false;
+}
+
+// Next delay starts @ $D356 - $D36A
+else if (regs->pc == 0xD356 && hitGo && !inDelay2)
+{
+       dumpDis = false;
+       inDelay2 = true;
+       WriteLog("*** DELAY #2\n");
+}
+else if (regs->pc == 0xD36A && inDelay2)
+{
+       dumpDis = true;
+       inDelay2 = false;
+}
+else if (regs->pc == 0xD486 && hitGo && !inRead1)
+{
+       dumpDis = false;
+       inRead1 = true;
+       WriteLog("\n*** FAST READ ROUTINE (!!!)\n\n");
+}
+else if (regs->pc == 0xD4B1 && inRead1)
+{
+       dumpDis = true;
+       inRead1 = false;
+}
+#endif
+#if 0
+// 13-sector disk debugging
+// start with the slot ROM
+static bool inDelay = false;
+static bool inBell = false;
+static bool inReadSector = false;
+static bool inSlotROM = false;
+if (regs->pc == 0xFCA8)// && !inSlotROM)//!inBell && !inReadSector)
+{
+       dumpDis = false;
+       inDelay = true;
+       WriteLog("*** DELAY\n");
+}
+else if (regs->pc == 0xFCB3 && inDelay && inSlotROM)//&& !inBell && !inReadSector)
+{
+       dumpDis = true;
+       inDelay = false;
+}
+if (regs->pc == 0xFBD9)
+{
+       dumpDis = false;
+       inBell = true;
+       WriteLog("*** BELL1\n");
+}
+else if (regs->pc == 0xFBEF && inBell)
+{
+//     dumpDis = true;
+       inBell = false;
+}
+//else if (regs->pc == 0xC664)
+else if (regs->pc == 0xC663)
+{
+       dumpDis = true;
+       inSlotROM = true;
+       WriteLog("*** DISK @ $C600\n");
+}
+else if (regs->pc == 0x801)
+{
+       WriteLog("*** DISK @ $801\n");
+       dumpDis = true;
+}
+#endif
 // Hard disk debugging
 #if 0
 if (first && (regs->pc == 0x801))
@@ -2651,6 +2840,10 @@ btQueuePtr = (btQueuePtr + 1) % BACKTRACE_SIZE;
 #endif
 #endif
 #ifdef __DEBUG__
+static uint16_t spc, ppc = 0;
+static bool seenHi = false;
+static uint64_t oldClock = 0;
+spc = regs->pc;
 static char disbuf[80];
 if (dumpDis)
 {
@@ -2662,9 +2855,15 @@ if (dumpDis)
 
 #if 0
 if (opcode == 0)
+//if (regs->pc == 0xA255)
+//static bool seenBT = false;
+//if (hitGo && !seenBT)
+//if (dobacktrace)
 {
+//seenBT = true;
        static char disbuf[80];
-       uint32_t btStart = btQueuePtr - 12 + (btQueuePtr < 12 ? BACKTRACE_SIZE : 0);
+//     uint32_t btStart = btQueuePtr - 12 + (btQueuePtr < 12 ? BACKTRACE_SIZE : 0);
+       uint32_t btStart = 0;
 
        for(uint32_t i=btStart; i<btQueuePtr; i++)
        {
@@ -2676,26 +2875,51 @@ if (opcode == 0)
 //if (!(regs->cpuFlags & V65C02_STATE_ILLEGAL_INST))
 //instCount[opcode]++;
 
+               if (regs->Timer)
+                       regs->Timer(CPUCycles[opcode]);
+
+               uint64_t clockSave = regs->clock + CPUCycles[opcode];
+
                // We need this because the opcode function could add 1 or 2 cycles
-               // which aren't accounted for in CPUCycles[].
-               uint64_t clockSave = regs->clock;
+               // to regs->clock which aren't accounted for in CPUCycles[].
+//             uint64_t clockSave = regs->clock;
 
                // Execute that opcode...
                exec_op[opcode]();
                regs->clock += CPUCycles[opcode];
 
                // Tell the timer function (if any) how many PHI2s have elapsed...
-               if (regs->Timer)
+//             if (regs->Timer)
+               if (regs->Timer && (regs->clock - clockSave) > 0)
                        regs->Timer(regs->clock - clockSave);
 
 #ifdef __DEBUG__
 if (dumpDis)
-       WriteLog(" [SP=01%02X, CC=%s%s.%s%s%s%s%s, A=%02X, X=%02X, Y=%02X](%d)\n",
+{
+       WriteLog(" [SP=01%02X, CC=%s%s.%s%s%s%s%s, A=%02X, X=%02X, Y=%02X](%d)[%02X]\n",//<%s>\n",
                regs->sp,
                (regs->cc & FLAG_N ? "N" : "-"), (regs->cc & FLAG_V ? "V" : "-"),
                (regs->cc & FLAG_B ? "B" : "-"), (regs->cc & FLAG_D ? "D" : "-"),
                (regs->cc & FLAG_I ? "I" : "-"), (regs->cc & FLAG_Z ? "Z" : "-"),
-               (regs->cc & FLAG_C ? "C" : "-"), regs->a, regs->x, regs->y, regs->clock - clockSave);
+               (regs->cc & FLAG_C ? "C" : "-"), regs->a, regs->x, regs->y, regs->clock - clockSave + CPUCycles[opcode], floppyDrive[0].dataRegister);//, sequence);
+       sequence[0] = 0;
+
+       if (((spc == 0xD4D1) || (spc == 0xD4E2)) && (floppyDrive[0].dataRegister & 0x80))
+               seenHi = true;
+
+       if ((spc == 0xD4CE) || (spc == 0xD4DF))
+       {
+               WriteLog(" (%d)\n", regs->clock - oldClock);
+
+               if ((regs->y & 0x80) == 0 && seenHi && ((ppc == 0xD4D1) || (ppc == 0xD4E2)))
+                       WriteLog("\n***** MISS! *****\n\n");
+
+               seenHi = false;
+               oldClock = regs->clock;
+       }
+
+       ppc = spc;
+}
 #endif
 
 #ifdef __DEBUGMON__
@@ -2777,4 +3001,3 @@ WriteLog("Clock=$%X\n", regs->clock);
        // to exit from it.
        regs->overflow = regs->clock - endCycles;
 }
-