]> Shamusworld >> Repos - apple2/blobdiff - src/floppydrive.cpp
Miscellaneous bugfixes.
[apple2] / src / floppydrive.cpp
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);
 }
-