#define REVOLUTION_DEBUG 0
#define MFM_VALIDATOR 0
+#define DISK_DEBUG_X 0
#include "uae.h"
#include "options.h"
#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;
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;
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)
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)
}
}
+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
{
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]);
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];
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]) {
}
floppybits -= trackspeed;
}
+ return floppybits;
}
static void update_jitter (void)
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;
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) {
}
}
}
+
+ 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;
}
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;
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];
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;
}
}
-static void disk_doupdate_read (drive *drv, int floppybits)
+static int disk_doupdate_read(drive *drv, int floppybits)
{
/*
uae_u16 *mfmbuf = drv->bigmfmbuf;
mfmbuf[6] = 0x4444;
mfmbuf[7] = 0x4444;
*/
+
bool isempty = drive_empty(drv);
bool isunformatted = unformatted(drv);
while (floppybits >= drv->trackspeed) {
}
//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;
}
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) {
floppybits -= drv->trackspeed;
}
+ return floppybits;
}
static void disk_dma_debugmsg (void)
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;
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);
}
- if (indexdecay)
+ if (indexdecay) {
indexdecay--;
+ }
if (linecounter) {
linecounter--;
- if (! linecounter)
- disk_dmafinished ();
+ if (! linecounter) {
+ disk_dmafinished();
+ }
return;
}
DISK_update (maxhpos);
}
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;
}
if (disk_hpos >= (maxhpos << 8)) {
disk_hpos %= 1 << 8;
}
+
dskbytr_delay = false;
for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
}
/* 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) {
}
/* 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;
return;
if (dsklength == 0 && dma_enable) {
- disk_dmafinished ();
+ disk_dmafinished();
return;
}
if (dsklength == 0)
return;
if (dsklength == 1) {
- disk_dmafinished ();
+ disk_dmafinished();
return;
}
if (dskdmaen == DSKDMA_WRITE) {
}
}
-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;