]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
"Also, the last word in a disk-read DMA operation may not come in (that is, one less...
authorToni Wilen <twilen@winuae.net>
Sat, 18 Nov 2023 14:34:07 +0000 (16:34 +0200)
committerToni Wilen <twilen@winuae.net>
Sat, 18 Nov 2023 14:34:07 +0000 (16:34 +0200)
custom.cpp
disk.cpp
include/disk.h

index 4c3456d8ebc62ff7d1a983ad26450e11e377fc67..57b40812d556b1049987c56d33d7a92b2e22cbef 100644 (file)
@@ -12645,6 +12645,7 @@ static void dmal_emu(uae_u32 val)
                AUDxDAT(nr, dat, pt);
        } else if (dmalpos >= 0 && dmalpos < 6) {
                uae_u16 dat = 0;
+               int s = (dmalpos / 2);
                int w = (dmalbits & 3) == 3;
                // disk_fifostatus() needed in >100% disk speed modes
                if (w) {
@@ -12679,7 +12680,7 @@ static void dmal_emu(uae_u32 val)
                        // read from disk
                        if (disk_fifostatus() >= 0) {
                                uaecptr pt = disk_getpt();
-                               dat = DSKDATR();
+                               dat = DSKDATR(s);
                                if (dmal_ce) {
 #ifdef DEBUGGER
                                        if (debug_dma) {
index b010932fd18a2ffc0276f87d67b86b8fa306cba7..7211f4fca7460cfbf882adfd50440efa016e9cf2 100644 (file)
--- a/disk.cpp
+++ b/disk.cpp
@@ -22,6 +22,7 @@ int disk_debug_track = -1;
 
 #define REVOLUTION_DEBUG 0
 #define MFM_VALIDATOR 0
+#define DISK_DEBUG_X 0
 
 #include "uae.h"
 #include "options.h"
@@ -111,17 +112,17 @@ static uae_u8 writesecheadbuffer[16 * MAX_SECTORS];
 
 #define DISK_INDEXSYNC 1
 #define DISK_WORDSYNC 2
-#define DISK_REVOLUTION 4 /* 8,16,32,64 */
+#define DISK_DMAEND 4
+#define DISK_REVOLUTION 8 /* 8,16,32,64 */
 
 #define DSKREADY_UP_TIME 18
 #define DSKREADY_DOWN_TIME 24
 
 #define DSKDMA_OFF 0
-#define DSKDMA_INIT 1
 #define DSKDMA_READ 2
 #define DSKDMA_WRITE 3
 
-static int dskdmaen, dsklength, dsklength2, dsklen;
+static int dskdmaen, dsklength, dsklength2, dsklen, dsklen2;
 static uae_u16 dskbytr_val, dskbytr_val_prev;
 static bool dskbytr_delay;
 static uae_u32 dskpt;
@@ -132,7 +133,7 @@ static int dma_enable, bitoffset, syncoffset;
 static uae_u16 word, dsksync;
 static bool dsksync_on;
 /* Always carried through to the next line.  */
-int disk_hpos;
+static int disk_hpos;
 static int disk_jitter;
 static int indexdecay;
 static uae_u8 prev_data;
@@ -3818,7 +3819,7 @@ void dumpdisk (const TCHAR *name)
                side, dskdmaen, bitoffset, word, dskpt, dsklen, dskbytr_val, adkcon, dsksync);
 }
 
-static void disk_dmafinished (void)
+static void disk_dmafinished(void)
 {
        INTREQ_INT(1, 0);
        if (floppy_writemode > 0)
@@ -3833,6 +3834,13 @@ static void disk_dmafinished (void)
                        write_log (_T("%d%s"), floppy[dr].mfmpos, dr < MAX_FLOPPY_DRIVES - 1 ? _T(",") : _T(""));
                write_log (_T("\n"));
        }
+       for (int i = 0; i < 3; i++) {
+               fifo_inuse[i] = false;
+       }
+       fifo_filled = 0;
+#if DISK_DEBUG_X
+       write_log("dma finished %d %08x\n", floppy[0].mfmpos, M68K_GETPC);
+#endif
 }
 
 static void fetchnextrevolution (drive *drv)
@@ -3874,6 +3882,54 @@ static void fetchnextrevolution (drive *drv)
        }
 }
 
+STATIC_INLINE bool iswrite(void)
+{
+       return dskdmaen == DSKDMA_WRITE;
+}
+
+void DSKDAT(uae_u16 v)
+{
+       if (fifo_inuse[2]) {
+               write_log(_T("DSKDAT: FIFO overflow!\n"));
+               return;
+       }
+       fifo_inuse[2] = fifo_inuse[1];
+       fifo[2] = fifo[1];
+       fifo_inuse[1] = fifo_inuse[0];
+       fifo[1] = fifo[0];
+       fifo_inuse[0] = iswrite() ? 2 : 1;
+       fifo[0] = v;
+       fifo_filled = 1;
+}
+
+uae_u16 DSKDATR(int slot)
+{
+       int i;
+       uae_u16 v = 0;
+       
+       for (i = 2; i >= 0; i--) {
+               if (fifo_inuse[i]) {
+                       fifo_inuse[i] = 0;
+                       v = fifo[i];
+                       break;
+               }
+       }
+
+#if DISK_DEBUG_X > 1
+       write_log("datr %d %d\n", dsklength, floppy[0].mfmpos);
+#endif
+
+       if (i < 0) {
+               write_log(_T("DSKDATR: FIFO underflow!\n"));
+       } else  if (dskdmaen == DSKDMA_READ && dsklength == 0) {
+               // len==0 and (all slots empty or last slot read and one slot in use)
+               if (disk_fifostatus() < 0 || (slot == 2 && fifo_inuse[0] && !fifo_inuse[1] && !fifo_inuse[2])) {
+                       disk_dmafinished();
+               }
+       }
+       return v;
+}
+
 static void do_disk_index (void)
 {
 #if REVOLUTION_DEBUG
@@ -3889,9 +3945,9 @@ void event_DISK_handler(uae_u32 data)
 {
        int flag = data & 255;
        int disk_sync_cycle = data >> 8;
-       int hpos = current_hpos();
 
        DISK_update(disk_sync_cycle);
+
        if (!dskdmaen) {
                if (flag & (DISK_REVOLUTION << 0))
                        fetchnextrevolution(&floppy[0]);
@@ -3933,7 +3989,7 @@ static bool canloaddskbytr(void)
        return (bitoffset & 7) == 7;
 }
 
-static void disk_doupdate_write(int floppybits, int trackspeed)
+static int disk_doupdate_write(int floppybits, int trackspeed)
 {
        int dr;
        int drives[4];
@@ -3971,11 +4027,11 @@ static void disk_doupdate_write(int floppybits, int trackspeed)
                                                dskpt += 2;
                                        }
                                }
-                               if (disk_fifostatus () >= 0) {
+                               if (disk_fifostatus() >= 0) {
 #ifdef FLOPPYBRIDGE
                                        bool wasBridge = false;
 #endif
-                                       uae_u16 w = DSKDATR ();
+                                       uae_u16 w = DSKDATR(0);
                                        for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
                                                drive *drv2 = &floppy[dr];
                                                if (drives[dr]) {
@@ -4022,6 +4078,7 @@ static void disk_doupdate_write(int floppybits, int trackspeed)
                }
                floppybits -= trackspeed;
        }
+       return floppybits;
 }
 
 static void update_jitter (void)
@@ -4062,12 +4119,14 @@ static void disk_doupdate_predict (int startcycle)
 
        for (int dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
                drive *drv = &floppy[dr];
+               
                if (drv->motoroff)
                        continue;
                if (!drv->trackspeed)
                        continue;
                if ((selected | disabled) & (1 << dr))
                        continue;
+               
                bool isempty = drive_empty(drv);
                bool isunformatted = unformatted(drv);
                int mfmpos = drv->mfmpos;
@@ -4078,11 +4137,13 @@ static void disk_doupdate_predict (int startcycle)
                uae_u32 tword = word;
                noselected = false;
                int countcycle = startcycle;
+               int tdsklength = dsklength;
+               int tbitoffset = bitoffset;
+
                while (countcycle < (maxhpos << 8)) {
                        int inc = nextbit(drv);
                        if (drv->tracktiming[0])
                                updatetrackspeed (drv, mfmpos);
-                       countcycle += drv->trackspeed;
                        if (dskdmaen != DSKDMA_WRITE || (dskdmaen == DSKDMA_WRITE && !dma_enable)) {
                                tword <<= 1;
                                if (!isempty) {
@@ -4121,6 +4182,37 @@ static void disk_doupdate_predict (int startcycle)
                                        }
                                }
                        }
+
+                       bool skipbit = false;
+                       // MSBSYNC
+                       if (adkcon & 0x200) {
+                               if ((tword & 0x0001) == 0 && tbitoffset == 0) {
+                                       tword = 0;
+                                       skipbit = true;
+                               }
+                               if ((tword & 0x0001) == 0 && tbitoffset == 8) {
+                                       tword >>= 1;
+                                       skipbit = true;
+                               }
+                       }
+
+                       if (!skipbit) {
+                               tbitoffset++;
+                               tbitoffset &= 15;
+
+                               if (dmaen(DMA_DISK) && tbitoffset == 0 && dskdmaen == DSKDMA_READ) {
+                                       tdsklength--;
+                                       if (tdsklength == 0) {
+#if DISK_DEBUG_X
+                                               write_log("word skip predicted %d %d->%d %d %d\n", countcycle >> 8, drv->mfmpos, mfmpos, tdsklength, disk_fifostatus());
+#endif
+                                               diskevent_flag |= DISK_DMAEND;
+                                       }
+                               }
+                       }
+
+                       countcycle += drv->trackspeed;
+
                        if (diskevent_flag)
                                break;
                }
@@ -4145,32 +4237,40 @@ int disk_fifostatus (void)
        return 0;
 }
 
-static int doreaddma (void)
+static int doreaddma(void)
 {
-       if (dmaen(DMA_DISK) && dmaen(DMA_MASTER) && bitoffset == 15 && dma_enable && dskdmaen == DSKDMA_READ && dsklength >= 0) {
+       if (dmaen(DMA_DISK) && bitoffset == 15 && dma_enable && dskdmaen == DSKDMA_READ && dsklength >= 0) {
+               if (dsklength == 0) {
+                       disk_dmafinished();
+                       return 1;
+               }
                if (dsklength > 0) {
                        // DSKLEN == 1: finish without DMA transfer.
                        if (dsklength == 1 && dsklength2 == 1) {
-                               disk_dmafinished ();
+                               disk_dmafinished();
                                return 0;
                        }
                        // fast disk modes, just flush the fifo
                        if (currprefs.floppy_speed > 100 && fifo_inuse[0] && fifo_inuse[1] && fifo_inuse[2]) {
                                while (fifo_inuse[0]) {
-                                       uae_u16 w = DSKDATR ();
+                                       uae_u16 w = DSKDATR(0);
                                        chipmem_wput_indirect (dskpt, w);
                                        dskpt += 2;
                                }
                        }
-                       if (disk_fifostatus () > 0) {
+                       if (disk_fifostatus() > 0) {
                                return -1;
                        } else {
-                               DSKDAT (word);
                                dsklength--;
-#if 0
-                               if (dsklength < 1 && (adkcon & 0x200))
-                                       activate_debugger();
+                               // Paula bug: when dsklength reaches zero, FIFO status is checked too early.
+                               if (disk_fifostatus() < 0 && dsklength == 0) {
+                                       disk_dmafinished();
+                               } else {
+                                       DSKDAT(word);
+#if DISK_DEBUG_X > 1
+                                       write_log("buffer load %d %d\n", floppy[0].mfmpos, dsklength);
 #endif
+                               }
                        }
                }
                return 1;
@@ -4181,7 +4281,15 @@ static int doreaddma (void)
 static void wordsync_detected(bool startup)
 {
        if (dskdmaen != DSKDMA_OFF) {
-               if (disk_debug_logging && dma_enable == 0) {
+               int prev_dma_enabled = dma_enable;
+               if (!startup) {
+                       dma_enable = 1;
+               }
+               if (!dsksync_on) {
+                       INTREQ_INT(12, 0);
+                       dsksync_on = true;
+               }
+               if ((disk_debug_logging && dma_enable == 0)) {
                        int pos = -1;
                        for (int i = 0; i < MAX_FLOPPY_DRIVES; i++) {
                                drive *drv = &floppy[i];
@@ -4190,16 +4298,11 @@ static void wordsync_detected(bool startup)
                                        break;
                                }
                        }
-                       write_log(_T("Sync match %04x mfmpos %d enable %d wordsync %d\n"), dsksync, pos, dma_enable, (adkcon & 0x0400) != 0);
+                       write_log(_T("Sync match %04x mfmpos %d enable %d->%d bcnt %d wordsync %d\n"),
+                               dsksync, pos, prev_dma_enabled, dma_enable, bitoffset, (adkcon & 0x0400) != 0);
                        if (disk_debug_logging > 1)
                                dumpdisk(_T("SYNC"));
                }
-               if (!startup)
-                       dma_enable = 1;
-               if (!dsksync_on) {
-                       INTREQ_INT(12, 0);
-                       dsksync_on = true;
-               }
        }
        if (adkcon & 0x0400) { // WORDSYNC
                bitoffset = 15;
@@ -4276,7 +4379,7 @@ static void disk_doupdate_read_nothing(int floppybits)
        }
 }
 
-static void disk_doupdate_read (drive *drv, int floppybits)
+static int disk_doupdate_read(drive *drv, int floppybits)
 {
        /*
        uae_u16 *mfmbuf = drv->bigmfmbuf;
@@ -4296,6 +4399,7 @@ static void disk_doupdate_read (drive *drv, int floppybits)
        mfmbuf[6] = 0x4444;
        mfmbuf[7] = 0x4444;
        */
+
        bool isempty = drive_empty(drv);
        bool isunformatted = unformatted(drv);
        while (floppybits >= drv->trackspeed) {
@@ -4315,9 +4419,9 @@ static void disk_doupdate_read (drive *drv, int floppybits)
                }
 
                //write_log (_T("%08X bo=%d so=%d mfmpos=%d dma=%d\n"), (word & 0xffffff), bitoffset, syncoffset, drv->mfmpos, dma_enable);
-               if (doreaddma () < 0) {
+               if (doreaddma() < 0) {
                        word >>= 1;
-                       return;
+                       return floppybits;
                }
                int pmfmpos = drv->mfmpos;
                drv->mfmpos += inc;
@@ -4374,6 +4478,9 @@ static void disk_doupdate_read (drive *drv, int floppybits)
                }
                if (!(adkcon & 0x200) && word == dsksync) {
                        wordsync_detected(false);
+#if DISK_DEBUG_X
+                       write_log("%d %d %08x\n", dskdmaen, drv->mfmpos, M68K_GETPC);
+#endif
                }
 
                if (!skipbit) {
@@ -4383,6 +4490,7 @@ static void disk_doupdate_read (drive *drv, int floppybits)
 
                floppybits -= drv->trackspeed;
        }
+       return floppybits;
 }
 
 static void disk_dma_debugmsg (void)
@@ -4411,7 +4519,7 @@ uae_u16 DSKBYTR(int hpos)
                        dumpdisk(_T("DSKBYTR SYNC"));
                }
        }
-       if (dskdmaen != DSKDMA_OFF && dmaen(DMA_DISK) && dmaen(DMA_MASTER))
+       if (dskdmaen != DSKDMA_OFF && dmaen(DMA_DISK))
                v |= 0x4000;
        if (dsklen & 0x4000)
                v |= 0x2000;
@@ -4467,6 +4575,10 @@ static void DISK_start(void)
                        int tr = drv->cyl * 2 + side;
                        trackid *ti = drv->trackdata + tr;
 
+#if DISK_DEBUG_X
+                       write_log("DMA start %d %08x %08x\n", drv->mfmpos, dskpt, M68K_GETPC);
+#endif
+
                        if (drv->dskchange_time == -1) {
                                drv->dskchange_time = -2;
                                write_log(_T("Accessing state restored non-existing disk '%s'!\n"), drv->newname);
@@ -4564,12 +4676,14 @@ void DISK_hsync (void)
 
 
        }
-       if (indexdecay)
+       if (indexdecay) {
                indexdecay--;
+       }
        if (linecounter) {
                linecounter--;
-               if (! linecounter)
-                       disk_dmafinished ();
+               if (! linecounter) {
+                       disk_dmafinished();
+               }
                return;
        }
        DISK_update (maxhpos);
@@ -4592,12 +4706,6 @@ void DISK_update (int tohpos)
        }
 
        cycles = (tohpos << 8) - disk_hpos;
-#if 0
-       if (tohpos == 228)
-               write_log (_T("x"));
-       if (tohpos != maxhpos || cycles / 256 != maxhpos)
-               write_log (_T("%d %d %d\n"), tohpos, cycles / 256, disk_hpos / 256);
-#endif
        if (cycles <= 0) {
                return;
        }
@@ -4606,6 +4714,7 @@ void DISK_update (int tohpos)
        if (disk_hpos >= (maxhpos << 8)) {
                disk_hpos %= 1 << 8;
        }
+
        dskbytr_delay = false;
 
        for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
@@ -4645,12 +4754,11 @@ void DISK_update (int tohpos)
                }
                /* write dma and wordsync enabled: read until wordsync match found */
                if (dskdmaen == DSKDMA_WRITE && dma_enable) {
-                       disk_doupdate_write(drv->floppybitcounter, drv->trackspeed);
+                       drv->floppybitcounter = disk_doupdate_write(drv->floppybitcounter, drv->trackspeed);
                } else {
-                       disk_doupdate_read(drv, drv->floppybitcounter);
+                       drv->floppybitcounter = disk_doupdate_read(drv, drv->floppybitcounter);
                }
 
-               drv->floppybitcounter %= drv->trackspeed;
                didaccess = 1;
        }
        if (!didaccess) {
@@ -4673,33 +4781,41 @@ void DISK_update (int tohpos)
        }
 
        /* instantly finish dma if dsklen==0 and wordsync detected */
-       if (dskdmaen != DSKDMA_OFF && dma_enable && dsklength2 == 0 && dsklength == 0)
-               disk_dmafinished ();
+       if (dskdmaen != DSKDMA_OFF && dma_enable && dsklength2 == 0 && dsklength == 0) {
+               disk_dmafinished();
+       }
 
        if (!done_jitter) {
                update_jitter();
                done_jitter = true;
        }
+       // predict events in next line
        disk_doupdate_predict (disk_hpos);
 }
 
 void DSKLEN (uae_u16 v, int hpos)
 {
        int dr;
-       int prevlen = dsklen;
+       int prevlen = dsklen2;
        int prevdatalen = dsklength;
        int noselected = 0;
        int motormask;
 
        DISK_update (hpos);
 
-       dsklen = v;
+       dsklen2 = dsklen = v;
        dsklength2 = dsklength = dsklen & 0x3fff;
+       if (0 && dsklength > 1) {
+               dsklength++;
+               dsklength2++;
+       }
 
        if ((v & 0x8000) && (prevlen & 0x8000)) {
                if (dskdmaen == DSKDMA_READ && !(v & 0x4000)) {
                        // update only currently active DMA length, don't change DMA state
-                       write_log(_T("warning: Disk read DMA length rewrite %d -> %d. (%04x) PC=%08x\n"), prevlen & 0x3fff, v & 0x3fff, v, M68K_GETPC);
+                       if ((prevlen & 0x3fff) != (v & 0x3fff)) {
+                               write_log(_T("warning: Disk read DMA length rewrite %d -> %d. (%04x) PC=%08x\n"), prevlen & 0x3fff, v & 0x3fff, v, M68K_GETPC);
+                       }
                        return;
                }
                dskdmaen = DSKDMA_READ;
@@ -4728,7 +4844,7 @@ void DSKLEN (uae_u16 v, int hpos)
                return;
 
        if (dsklength == 0 && dma_enable) {
-               disk_dmafinished ();
+               disk_dmafinished();
                return;
        }
 
@@ -4736,7 +4852,7 @@ void DSKLEN (uae_u16 v, int hpos)
                if (dsklength == 0)
                        return;
                if (dsklength == 1) {
-                       disk_dmafinished ();
+                       disk_dmafinished();
                        return;
                }
                if (dskdmaen == DSKDMA_WRITE) {
@@ -4995,45 +5111,6 @@ void DSKSYNC(int hpos, uae_u16 v)
        }
 }
 
-STATIC_INLINE bool iswrite(void)
-{
-       return dskdmaen == DSKDMA_WRITE;
-}
-
-void DSKDAT(uae_u16 v)
-{
-       if (fifo_inuse[2]) {
-               write_log(_T("DSKDAT: FIFO overflow!\n"));
-               return;
-       }
-       fifo_inuse[2] = fifo_inuse[1];
-       fifo[2] = fifo[1];
-       fifo_inuse[1] = fifo_inuse[0];
-       fifo[1] = fifo[0];
-       fifo_inuse[0] = iswrite() ? 2 : 1;
-       fifo[0] = v;
-       fifo_filled = 1;
-}
-
-uae_u16 DSKDATR(void)
-{
-       int i;
-       uae_u16 v = 0;
-       for (i = 2; i >= 0; i--) {
-               if (fifo_inuse[i]) {
-                       fifo_inuse[i] = 0;
-                       v = fifo[i];
-                       break;
-               }
-       }
-       if (i < 0) {
-               write_log(_T("DSKDATR: FIFO underflow!\n"));
-       } else  if (dskdmaen > 0 && dskdmaen < 3 && dsklength <= 0 && disk_fifostatus() < 0) {
-               disk_dmafinished();
-       }
-       return v;
-}
-
 uae_u16 disk_dmal(void)
 {
        uae_u16 dmal = 0;
index fc2814ec699b654d09e2724fa2a01493191491b2..d9fd67cd62b5b774d0cee943e61861e278716d55 100644 (file)
@@ -104,7 +104,7 @@ extern void DSKSYNC (int, uae_u16);
 extern void DSKPTL (uae_u16);
 extern void DSKPTH (uae_u16);
 extern void DSKDAT (uae_u16);
-extern uae_u16 DSKDATR (void);
+extern uae_u16 DSKDATR (int);
 extern uae_u16 disk_dmal (void);
 extern uaecptr disk_getpt (void);
 extern int disk_fifostatus (void);