Tuesday, 12 October 2021

[Rpcemu] [PATCH 2/4] Abstract disc image handling from FDC code

diff -r d2affb36a0db -r 592604520b7e src/ArmDynarec.c
--- a/src/ArmDynarec.c    Wed Oct 06 21:34:59 2021 +0100
+++ b/src/ArmDynarec.c    Sat Oct 09 14:01:30 2021 +0100
@@ -48,6 +48,7 @@
 #include "arm.h"
 #include "cp15.h"
 #include "fdc.h"
+#include "disc_adf.h"
 
 #if defined __amd64__
 #    include "codegen_amd64.h"
@@ -61,7 +62,6 @@
     
 ARMState arm;
 
-static int fdci=0;
 static int cycles;
 int prefabort;
 uint32_t inscount;
@@ -940,14 +940,8 @@
                 callbackide();
             }
         }
-        if (motoron) {
-            fdci--;
-            if (fdci <= 0) {
-                fdci = 20000;
-                iomd.irqa.status |= IOMD_IRQA_FLOPPY_INDEX;
-                updateirqs();
-            }
-        }
+        if (motoron)
+            disc_poll();
         cycles -= 1000;
     }
 }
diff -r d2affb36a0db -r 592604520b7e src/arm.c
--- a/src/arm.c    Wed Oct 06 21:34:59 2021 +0100
+++ b/src/arm.c    Sat Oct 09 14:01:30 2021 +0100
@@ -54,11 +54,11 @@
 #include "keyboard.h"
 #include "fdc.h"
 #include "ide.h"
+#include "disc_adf.h"
 
 ARMState arm;
 
 int blockend;
-static int fdci=0;
 static int cycles;
 int prefabort;
 uint32_t inscount;
@@ -1975,14 +1975,8 @@
                 callbackide();
             }
         }
-        if (motoron) {
-            fdci--;
-            if (fdci <= 0) {
-                fdci = 20000;
-                iomd.irqa.status |= IOMD_IRQA_FLOPPY_INDEX;
-                updateirqs();
-            }
-        }
+        if (motoron)
+            disc_poll();
         // cyc=(oldcyc-cycles);
         cycles -= 200;
     }
diff -r d2affb36a0db -r 592604520b7e src/disc_adf.c
--- /dev/null    Thu Jan 01 00:00:00 1970 +0000
+++ b/src/disc_adf.c    Sat Oct 09 14:01:30 2021 +0100
@@ -0,0 +1,279 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include "rpcemu.h"
+#include "disc_adf.h"
+#include "fdc.h"
+
+static struct {
+        FILE *f;
+        uint8_t track_data[2][20*1024];
+
+        int dblside;
+        int sectors, size, track;
+        int dblstep;
+        int density;
+        int maxsector;
+        int skew;
+        int write_prot;
+} adf[4];
+
+static struct {
+    int sector;
+    int track;
+    int side;
+    int drive;
+
+    int readpos;
+
+    int inread;
+    int inwrite;
+    int inreadaddr;
+    int informat;
+
+    int notfound;
+    int cur_sector;
+
+    int pause;
+    int index;
+} adf_state;
+
+void adf_init(void)
+{
+        memset(adf, 0, sizeof(adf));
+        memset(&adf_state, 0, sizeof(adf_state));
+}
+
+void adf_load(int drive, const char *fn, int sectors, int size, int sides, int dblstep, int density, int skew)
+{
+//    rpclog("adf_load: drive=%i fn=%s\n", drive, fn);
+        adf[drive].write_prot = 0;
+        adf[drive].f = fopen(fn, "rb+");
+        if (!adf[drive].f) {
+                adf[drive].f = fopen(fn, "rb");
+                if (!adf[drive].f) {
+            rpclog("adf_load: failed!\n");
+                    return;
+        }
+                adf[drive].write_prot = 1;
+        }
+        fseek(adf[drive].f, -1, SEEK_END);
+
+        adf[drive].sectors = sectors;
+        adf[drive].size = size;
+        adf[drive].dblside = sides;
+        adf[drive].dblstep = dblstep;
+        adf[drive].density = density;
+        adf[drive].maxsector = (ftell(adf[drive].f)+1 ) / size;
+        adf[drive].skew = skew;
+
+        adf_seek(drive, 0);
+}
+
+
+void adf_close(int drive)
+{
+        if (adf[drive].f)
+            fclose(adf[drive].f);
+        adf[drive].f = NULL;
+}
+
+void adf_seek(int drive, int track)
+{
+        if (!adf[drive].f)
+                return;
+//        rpclog("Seek %i %i\n", drive, track);
+        if (adf[drive].dblstep)
+                track /= 2;
+        adf[drive].track = track;
+        if (adf[drive].dblside) {
+                fseek(adf[drive].f, track * adf[drive].sectors * adf[drive].size * 2, SEEK_SET);
+                fread(adf[drive].track_data[0], adf[drive].sectors * adf[drive].size, 1, adf[drive].f);
+                fread(adf[drive].track_data[1], adf[drive].sectors * adf[drive].size, 1, adf[drive].f);
+        } else {
+                fseek(adf[drive].f, track * adf[drive].sectors * adf[drive].size, SEEK_SET);
+                fread(adf[drive].track_data[0], adf[drive].sectors * adf[drive].size, 1, adf[drive].f);
+        }
+}
+void adf_writeback(int drive, int track)
+{
+        if (!adf[drive].f)
+                return;
+
+        if (adf[drive].dblstep)
+                track /= 2;
+
+        if (adf[drive].dblside) {
+                fseek(adf[drive].f, track * adf[drive].sectors * adf[drive].size * 2, SEEK_SET);
+                fwrite(adf[drive].track_data[0], adf[drive].sectors * adf[drive].size, 1, adf[drive].f);
+                fwrite(adf[drive].track_data[1], adf[drive].sectors * adf[drive].size, 1, adf[drive].f);
+        } else {
+                fseek(adf[drive].f, track *  adf[drive].sectors * adf[drive].size, SEEK_SET);
+                fwrite(adf[drive].track_data[0], adf[drive].sectors * adf[drive].size, 1, adf[drive].f);
+        }
+}
+
+void adf_readsector(int drive, int sector, int track, int side, int density)
+{
+        int sector_nr = (sector - adf[drive].skew) + adf[drive].sectors * (track * (adf[drive].dblside ? 2 : 1) + (side ? 1 : 0));
+
+//    rpclog("adf_readsector: drive=%i sector=%i track=%i side=%i density=%i\n", drive, sector, track, side, density);
+        adf_state.sector = sector - adf[drive].skew;
+        adf_state.track  = track;
+        adf_state.side   = side;
+        adf_state.drive  = drive;
+
+        if (!adf[drive].f || (side && !adf[drive].dblside) || (density != adf[drive].density) ||
+                (track != adf[drive].track) || (sector_nr >= adf[drive].maxsector) ||
+                (adf_state.sector > adf[drive].sectors)) {
+                adf_state.notfound=500;
+                return;
+        }
+
+        adf_state.inread  = 1;
+        adf_state.readpos = 0;
+}
+
+void adf_writesector(int drive, int sector, int track, int side, int density)
+{
+        int sector_nr = (sector - adf[drive].skew) + adf[drive].sectors * (track * (adf[drive].dblside ? 2 : 1) + (side ? 1 : 0));
+
+//    rpclog("adf_writesector: drive=%i sector=%i track=%i side=%i density=%i\n", drive, sector, track, side, density);
+        adf_state.sector = sector - adf[drive].skew;
+        adf_state.track  = track;
+        adf_state.side   = side;
+        adf_state.drive  = drive;
+
+        if (!adf[drive].f || (side && !adf[drive].dblside) || (density != adf[drive].density) ||
+                (track != adf[drive].track) || (sector_nr >= adf[drive].maxsector) ||
+                (adf_state.sector > adf[drive].sectors)) {
+                adf_state.notfound = 500;
+                return;
+        }
+        adf_state.inwrite = 1;
+        adf_state.readpos = 0;
+}
+
+void adf_readaddress(int drive, int track, int side, int density)
+{
+        if (adf[drive].dblstep)
+                track /= 2;
+
+//    rpclog("adf_readaddress: drive=%i track=%i side=%i density=%i\n", drive, track, side, density);
+        adf_state.drive = drive;
+        adf_state.track = track;
+        adf_state.side  = side;
+
+        if (!adf[drive].f || (side && !adf[drive].dblside) ||
+                (density != adf[drive].density) || (track != adf[drive].track)) {
+                adf_state.notfound=500;
+                return;
+        }
+        adf_state.inreadaddr = 1;
+        adf_state.readpos    = 0;
+        adf_state.pause = 100;//500;
+}
+
+void adf_format(int drive, int track, int side, int density)
+{
+        if (adf[drive].dblstep)
+                track /= 2;
+
+        adf_state.drive = drive;
+        adf_state.track = track;
+        adf_state.side  = side;
+
+        if (!adf[drive].f || (side && !adf[drive].dblside) || (density != adf[drive].density) ||
+                track != adf[drive].track) {
+                adf_state.notfound = 500;
+                return;
+        }
+        adf_state.sector  = 0;
+        adf_state.readpos = 0;
+        adf_state.informat  = 1;
+}
+
+void adf_stop(void)
+{
+//    rpclog("adf_stop\n");
+
+        adf_state.pause = 0;
+        adf_state.notfound = 0;
+        adf_state.inread = 0;
+        adf_state.inwrite = 0;
+        adf_state.inreadaddr = 0;
+        adf_state.informat = 0;
+}
+
+void adf_poll(void)
+{
+        int c;
+
+        adf_state.index--;
+        if (adf_state.index <= 0) {
+                adf_state.index = 6250;
+                fdc_indexpulse();
+        }
+
+        if (adf_state.pause) {
+                adf_state.pause--;
+                if (adf_state.pause)
+                    return;
+        }
+
+        if (adf_state.notfound) {
+                adf_state.notfound--;
+                if (!adf_state.notfound)
+                        fdc_notfound();
+        }
+        if (adf_state.inread && adf[adf_state.drive].f) {
+                fdc_data(adf[adf_state.drive].track_data[adf_state.side][(adf_state.sector * adf[adf_state.drive].size) + adf_state.readpos]);
+                adf_state.readpos++;
+                if (adf_state.readpos == adf[adf_state.drive].size) {
+                        adf_state.inread = 0;
+                        fdc_finishread();
+                }
+        }
+        if (adf_state.inwrite && adf[adf_state.drive].f) {
+                if (adf[adf_state.drive].write_prot) {
+                        fdc_writeprotect();
+                        adf_state.inwrite = 0;
+                        return;
+                }
+                c = fdc_getdata(adf_state.readpos == (adf[adf_state.drive].size - 1));
+                if (c == -1)
+                          return;
+                adf[adf_state.drive].track_data[adf_state.side][(adf_state.sector * adf[adf_state.drive].size) + adf_state.readpos] = c;
+                adf_state.readpos++;
+                if (adf_state.readpos == adf[adf_state.drive].size) {
+                        adf_state.inwrite = 0;
+                        fdc_finishread();
+                        adf_writeback(adf_state.drive, adf_state.track);
+                }
+        }
+        if (adf_state.inreadaddr && adf[adf_state.drive].f) {
+                fdc_sectorid(adf_state.track, adf_state.side, adf_state.sector + adf[adf_state.drive].skew, (adf[adf_state.drive].size == 256) ? 1 : ((adf[adf_state.drive].size == 512) ? 2 : 3));
+                adf_state.inreadaddr = 0;
+                adf_state.sector++;
+                if (adf_state.sector >= adf[adf_state.drive].sectors)
+                        adf_state.sector=0;
+        }
+        if (adf_state.informat && adf[adf_state.drive].f) {
+                if (adf[adf_state.drive].write_prot) {
+                        fdc_writeprotect();
+                        adf_state.informat = 0;
+                        return;
+                }
+                adf[adf_state.drive].track_data[adf_state.side][(adf_state.sector * adf[adf_state.drive].size) + adf_state.readpos] = 0;
+                adf_state.readpos++;
+                if (adf_state.readpos == adf[adf_state.drive].size) {
+                        adf_state.readpos = 0;
+                        adf_state.sector++;
+                        if (adf_state.sector == adf[adf_state.drive].sectors) {
+                                adf_state.informat = 0;
+                                fdc_finishread();
+                                adf_writeback(adf_state.drive, adf_state.track);
+                        }
+                }
+        }
+}
diff -r d2affb36a0db -r 592604520b7e src/disc_adf.h
--- /dev/null    Thu Jan 01 00:00:00 1970 +0000
+++ b/src/disc_adf.h    Sat Oct 09 14:01:30 2021 +0100
@@ -0,0 +1,20 @@
+extern void adf_init(void);
+
+extern void adf_load(int drive, const char *fn, int sectors, int size, int dblside, int dblstep, int density, int skew);
+
+extern void adf_close(int drive);
+extern void adf_seek(int drive, int track);
+extern void adf_readsector(int drive, int sector, int track, int side, int density);
+extern void adf_writesector(int drive, int sector, int track, int side, int density);
+extern void adf_readaddress(int drive, int sector, int side, int density);
+extern void adf_format(int drive, int sector, int side, int density);
+extern void adf_stop(void);
+extern void adf_poll(void);
+
+#define disc_seek        adf_seek
+#define disc_readsector  adf_readsector
+#define disc_writesector adf_writesector
+#define disc_readaddress adf_readaddress
+#define disc_format      adf_format
+#define disc_stop        adf_stop
+#define disc_poll        adf_poll
\ No newline at end of file
diff -r d2affb36a0db -r 592604520b7e src/fdc.c
--- a/src/fdc.c    Wed Oct 06 21:34:59 2021 +0100
+++ b/src/fdc.c    Sat Oct 09 14:01:30 2021 +0100
@@ -32,6 +32,7 @@
 #include "iomd.h"
 #include "ide.h"
 #include "arm.h"
+#include "disc_adf.h"
 
 /* FDC commands */
 enum {
@@ -63,7 +64,6 @@
     uint8_t st1;
     uint8_t st2;
     uint8_t st3;
-    int commandpos;
     int track;
     int sector;
     int side;
@@ -76,6 +76,12 @@
     int oldpos;
     uint8_t results[16];
     int result_rp, result_wp;
+    int drive;
+    int density;
+    int tc;
+    int data_ready;
+    int written;
+    int in_read;
 } fdc;
 
 /* This enumeration must be kept in sync with the formats[] array */
@@ -109,19 +115,6 @@
     { "DOS 1440KB",       "img", 2, 80, 18,  512, 1, 0 }
 };
 
-/**
- * Structure to hold information about a specific floppy drive and the disc
- * image inside it
- */
-typedef struct {
-    uint8_t disc[2][80][19][1024]; /**< side, Track, Sector (+ max skew), Bytes, large enough to hold all format variants */
-    const Format *format;
-    int discchanged;
-} Drive;
-
-/** Floppy controller has two disc drives attached */
-static Drive drives[2];
-
 int fdccallback = 0;
 int motoron = 0;
 
@@ -153,26 +146,6 @@
     updateirqs();
 }
 
-/**
- * Calculate the size code for a given length of sector
- *
- * @param sectorsize size of one sector on disc (in bytes)
- * @return code used to represent that sectorsize
- */
-static uint8_t
-fdc_size_code_from_sector_size(int sectorsize)
-{
-    switch (sectorsize) {
-    case  128: return 0;
-    case  256: return 1;
-    case  512: return 2;
-    case 1024: return 3;
-    }
-
-    UNIMPLEMENTED("fdc", "Unsupported sectorsize %d", sectorsize);
-    return 0;
-}
-
 void
 fdc_reset(void)
 {
@@ -185,12 +158,6 @@
 void
 fdc_init(void)
 {
-    int d;
-
-    for (d = 0; d < 2; d++) {
-        // Configure a default format
-        drives[d].format = &formats[DISC_FORMAT_ADFS_DE_800K];
-    }
 }
 
 /**
@@ -204,9 +171,9 @@
 fdc_image_load(const char *fn, int drive)
 {
     FILE *f;
-    int h, t, s, b;
     const char *extension;
     long len;
+    static const Format *format;
 
     assert(drive == 0 || drive == 1); // Only support two drives
     assert(fn != NULL); // Must have filename
@@ -235,94 +202,39 @@
 
     if (strcasecmp(extension, ".adf") == 0) {
         if (len > 1000000) {
-            drives[drive].format = &formats[DISC_FORMAT_ADFS_F_1600K];
+            format = &formats[DISC_FORMAT_ADFS_F_1600K];
         } else {
-            drives[drive].format = &formats[DISC_FORMAT_ADFS_DE_800K];
+            format = &formats[DISC_FORMAT_ADFS_DE_800K];
         }
     } else if (strcasecmp(extension, ".adl") == 0) {
-        drives[drive].format = &formats[DISC_FORMAT_ADFS_L_640K];
+        format = &formats[DISC_FORMAT_ADFS_L_640K];
     } else if (strcasecmp(extension, ".img") == 0) {
         if (len > 1250000) {
-            drives[drive].format = &formats[DISC_FORMAT_DOS_1440K];
+            format = &formats[DISC_FORMAT_DOS_1440K];
         } else if (len > 400000) {
-            drives[drive].format = &formats[DISC_FORMAT_DOS_720K];
+            format = &formats[DISC_FORMAT_DOS_720K];
         } else {
-            drives[drive].format = &formats[DISC_FORMAT_DOS_360K];
+            format = &formats[DISC_FORMAT_DOS_360K];
         }
     } else {
         error("Unknown disc image file extension '%s', must be .adf or .adl", extension);
         fclose(f);
         return;
     }
-
-    rpclog("fdc_image_load: %s (%ld) loaded as '%s'\n", fn, len, drives[drive].format->name);
-
-    drives[drive].discchanged = 0;
-    rewind(f);
+    fclose(f);
 
-    for (t = 0; t < drives[drive].format->tracks ; t++) {
-        for (h = 0; h < drives[drive].format->sides; h++) {
-            for (s = drives[drive].format->sectorskew; s < drives[drive].format->sectors + drives[drive].format->sectorskew; s++) {
-                for (b = 0; b < drives[drive].format->sectorsize; b++) {
-                    drives[drive].disc[h][t][s][b] = fgetc(f);
-                }
-            }
-        }
-    }
-
-    // reset the sector to the first valid one
-    fdc.sector = drives[drive].format->sectorskew;
-
-    fclose(f);
+    rpclog("fdc_image_load: %s (%ld) loaded as '%s'\n", fn, len, format->name);
+    adf_load(drive, fn, format->sectors, format->sectorsize, format->sides, format->tracks == 40,
+            format->density ? 1 : 2, format->sectorskew);
 }
 
-/**
- * Save a disc image from one of the two virtual floppy
- * disc drives to host disc.
- *
- * @param fn    Filename of disc image to load (including .adf .adl extension)
- * @param drive Which drive to save image from 0 or 1
- */
 void
 fdc_image_save(const char *fn, int drive)
 {
-    FILE *f;
-    int h, t, s, b;
-
-    assert(drive == 0 || drive == 1); // Only support two drives
-    assert(fn != NULL); // Must have filename
-
-    if (!drives[drive].discchanged) {
-        return;
-    }
-
-    // must be at least a.ext
-    if (strlen(fn) < 5 || fn[strlen(fn) - 4] != '.') {
-        error("Disc image filename must include a file extension (.adf,.adl)");
-        return;
-    }
-
-    f = fopen(fn, "wb");
-    if (f == NULL) {
-//        error("Unable to open disc image '%s'", fn);
-        return;
-    }
-    drives[drive].discchanged = 0;
-
-    for (t = 0; t < drives[drive].format->tracks; t++) {
-        for (h = 0; h < drives[drive].format->sides; h++) {
-            for (s = drives[drive].format->sectorskew; s < drives[drive].format->sectors + drives[drive].format->sectorskew; s++) {
-                for (b = 0; b < drives[drive].format->sectorsize; b++) {
-                    putc(drives[drive].disc[h][t][s][b], f);
-                }
-            }
-        }
-    }
-
-    fclose(f);
+    (void)fn;
+    adf_close(drive);
 }
 
-
 void
 fdc_write(uint32_t addr, uint32_t val)
 {
@@ -347,6 +259,9 @@
 
             if (fdc.curparam == fdc.params) {
                 fdc.status &= ~0x80;
+                fdc.tc = 0;
+                fdc.data_ready = 0;
+                fdc.in_read = 0;
                 switch (fdc.command) {
                 case FD_CMD_SPECIFY:
                     fdccallback = 100;
@@ -357,9 +272,15 @@
                     break;
 
                 case FD_CMD_RECALIBRATE:
+                    fdccallback = 500;
+                    fdc.status |= 1;
+                    disc_seek(fdc.parameters[0] & 1, 0);
+                    break;
+
                 case FD_CMD_SEEK:
                     fdccallback = 500;
                     fdc.status |= 1;
+                    disc_seek(fdc.parameters[0] & 1, fdc.parameters[1]);
                     break;
 
                 case FD_CMD_CONFIGURE:
@@ -367,54 +288,51 @@
                     break;
 
                 case FD_CMD_WRITE_DATA_MFM:
-                    fdc.commandpos = 0;
-                    fdccallback    = 1000;
                     fdc.st0        = fdc.parameters[0] & 7;
                     fdc.st1        = 0;
                     fdc.st2        = 0;
                     fdc.track      = fdc.parameters[1];
                     fdc.side       = fdc.parameters[2];
                     fdc.sector     = fdc.parameters[3];
-                    drives[fdc.st0 & 1].discchanged = 1;
+                    fdc.drive      = fdc.st0 & 1;
+                    disc_writesector(fdc.st0 & 1, fdc.sector, fdc.track, fdc.side, fdc.density);
+                    fdc_dma_raise();
                     break;
 
                 case FD_CMD_READ_DATA_MFM:
+                    fdc.in_read = 1;
                 case FD_CMD_VERIFY_DATA_MFM:
-                    fdc.commandpos = 0;
-                    fdccallback    = 1000;
                     fdc.st0        = fdc.parameters[0] & 7;
                     fdc.st1        = 0;
                     fdc.st2        = 0;
                     fdc.track      = fdc.parameters[1];
                     fdc.side       = fdc.parameters[2];
                     fdc.sector     = fdc.parameters[3];
+                    fdc.drive      = fdc.st0 & 1;
+                    disc_readsector(fdc.st0 & 1, fdc.sector, fdc.track, fdc.side, fdc.density);
                     break;
 
                 case FD_CMD_READ_ID_MFM:
-                    fdc.commandpos = 0;
+                    fdc.st0        = fdc.parameters[0] & 7;
+                    fdc.st1        = 0;
+                    fdc.st2        = 0;
+                    fdc.drive      = fdc.st0 & 1;
+                    disc_readaddress(fdc.st0 & 1, fdc.track, fdc.side, fdc.density);
+                    break;
+
+                case FD_CMD_READ_ID_FM:
                     fdccallback    = 4000;
                     fdc.st0        = fdc.parameters[0] & 7;
                     fdc.st1        = 0;
                     fdc.st2        = 0;
-                    if (fdc.rate != drives[fdc.st0 & 1].format->density) {
-                        fdc.command = FD_CMD_READ_ID_FM;
-                    }
+                    fdc.drive      = fdc.st0 & 1;
                     break;
 
-                case FD_CMD_READ_ID_FM:
-                    fdc.commandpos = 0;
-                    fdccallback    = 4000;
+                case FD_CMD_FORMAT_TRACK_MFM:
                     fdc.st0        = fdc.parameters[0] & 7;
                     fdc.st1        = 0;
                     fdc.st2        = 0;
-                    break;
-
-                case FD_CMD_FORMAT_TRACK_MFM:
-                    fdc.commandpos = 0;
-                    fdc.st0        = fdc.parameters[0] & 7;
-                    fdc.st1        = 0;
-                    fdc.st2        = 0;
-                    fdccallback    = 1000;
+                    fdc.drive      = fdc.st0 & 1;
                     break;
 
                 default:
@@ -430,7 +348,6 @@
             fatal("FDC already in command\n");
         }
         fdc.incommand  = 1;
-        fdc.commandpos = 0;
         fdc.command    = val;
 
         switch (fdc.command) {
@@ -508,6 +425,17 @@
 
     case 0x3f7: /* Configuration Control Register (CCR) */
         fdc.rate = val & 3;
+        switch (val & 3) {
+                case 0:
+                    fdc.density = 2;
+                    break;
+                case 1: case 2:
+                    fdc.density = 1;
+                    break;
+                case 3:
+                    fdc.density = 3;
+                    break;
+                }
         break;
 
     default:
@@ -556,11 +484,13 @@
     fdc.result_wp++;
 }
 
-static void
-fdcsenddata(uint8_t val)
+static void fdc_end_command(void)
 {
-    fdc.dmadat = val;
-    fdc_dma_raise();
+    fdc.status = 0xD0;
+    fdc.incommand = 0;
+    fdc.params = 0;
+    fdccallback = 0;
+    fdc_irq_raise();
 }
 
 void
@@ -646,19 +576,17 @@
         break;
 
     case FD_CMD_WRITE_DATA_MFM:
-        if (fdc.commandpos == 2048) { // DMA Write
-            drives[fdc.st0 & 1].disc[fdc.side][fdc.track][fdc.sector][fdc.oldpos - 1] = fdc.dmadat;
-            fdc.commandpos = drives[fdc.st0 & 1].format->sectorsize + 1;
-            fdccallback    = 500;
-            fdc.sector++;
-        } else if (fdc.commandpos >= (drives[fdc.st0 & 1].format->sectorsize + 1)) {
+        fdc.sector++;
+        if (fdc.sector > fdc.parameters[5])
+            fdc.tc = 1;
+        if (fdc.tc) {
             fdcsend(fdc.st0);
             fdcsend(fdc.st1);
             fdcsend(fdc.st2);
             fdcsend(fdc.track);
             fdcsend((fdc.parameters[0] & 4) ? 1 : 0);
             fdcsend(fdc.sector);
-            fdcsend(fdc_size_code_from_sector_size(drives[fdc.st0 & 1].format->sectorsize));
+            fdcsend(fdc.parameters[4]);
             fdc.status = 0xD0;
             fdc_irq_raise();
             fdc.incommand = 0;
@@ -666,36 +594,23 @@
             fdc.curparam  = 0;
             fdccallback   = 0;
         } else {
-            if (fdc.commandpos) {
-                drives[fdc.st0 & 1].disc[fdc.side][fdc.track][fdc.sector][fdc.commandpos - 1] = fdc.dmadat;
-            }
-            fdc.commandpos++;
-            if (fdc.commandpos == drives[fdc.st0 & 1].format->sectorsize + 1) {
-                fdc.sector++;
-                if (fdc.sector <= fdc.parameters[5]) {
-                    fdc.commandpos = 0;
-                    fdccallback = 100;
-                    return;
-                } else {
-                    fdccallback = 100;
-                    return;
-                }
-            } else {
-                fdc_dma_raise();
-            }
-            fdccallback = 0;
+            disc_writesector(fdc.drive, fdc.sector, fdc.track, fdc.side, fdc.density);
+            fdc_dma_raise();
         }
         break;
 
     case FD_CMD_READ_DATA_MFM:
-        if (fdc.commandpos >= drives[fdc.st0 & 1].format->sectorsize) {
+        fdc.sector++;
+        if (fdc.sector > fdc.parameters[5])
+            fdc.tc = 1;
+        if (fdc.tc) {
             fdcsend(fdc.st0);
             fdcsend(fdc.st1);
             fdcsend(fdc.st2);
             fdcsend(fdc.track);
             fdcsend((fdc.parameters[0] & 4) ? 1 : 0);
             fdcsend(fdc.sector);
-            fdcsend(fdc_size_code_from_sector_size(drives[fdc.st0 & 1].format->sectorsize));
+            fdcsend(fdc.parameters[4]);
             fdc.status = 0xD0;
             fdc_irq_raise();
             fdc.incommand = 0;
@@ -703,49 +618,10 @@
             fdc.curparam  = 0;
             fdccallback   = 0;
         } else {
-            fdcsenddata(drives[fdc.st0 & 1].disc[fdc.side][fdc.track][fdc.sector][fdc.commandpos]);
-            fdc.commandpos++;
-            if (fdc.commandpos == drives[fdc.st0 & 1].format->sectorsize) {
-                fdc.sector++;
-                if (fdc.sector <= fdc.parameters[5]) {
-                    fdc.commandpos = 0;
-                }
-                /*
-                else {
-                    // printf("End of read op\n");
-                    fdc.sector = 1;
-                }
-                */
-            }
-            fdccallback = 0;
+            disc_readsector(fdc.drive, fdc.sector, fdc.track, fdc.side, fdc.density);
         }
         break;
 
-    case FD_CMD_READ_ID_MFM:
-        if (fdc.sector >= drives[fdc.st0 & 1].format->sectors + drives[fdc.st0 & 1].format->sectorskew) {
-            // Reset back to first valid sector
-            fdc.sector = drives[fdc.st0 & 1].format->sectorskew;
-        }
-        fdcsend(fdc.st0);
-        fdcsend(fdc.st1);
-        fdcsend(fdc.st2);
-        fdcsend(fdc.track);
-        fdcsend((fdc.parameters[0] & 4) ? 1 : 0);
-        fdcsend(fdc.sector);
-        fdcsend(fdc_size_code_from_sector_size(drives[fdc.st0 & 1].format->sectorsize));
-        fdc.status = 0xD0;
-        fdc_irq_raise();
-
-        fdc.incommand = 0;
-        fdc.sector++;
-        if (fdc.sector >= drives[fdc.st0 & 1].format->sectors  + drives[fdc.st0 & 1].format->sectorskew) {
-            // Reset back to first valid sector
-            fdc.sector = drives[fdc.st0 & 1].format->sectorskew;
-        }
-        fdc.params   = 0;
-        fdc.curparam = 0;
-        break;
-
     case FD_CMD_READ_ID_FM:
         fdc.st0       = 0x40 | (fdc.parameters[0] & 7);
         fdc.st1       = 1;
@@ -784,7 +660,7 @@
         fdcsend(fdc.track);
         fdcsend((fdc.parameters[0] & 4) ? 1 : 0);
         fdcsend(fdc.sector);
-        fdcsend(fdc_size_code_from_sector_size(drives[fdc.st0 & 1].format->sectorsize));
+        fdcsend(fdc.parameters[4]);
         fdc.status = 0xD0;
         fdc_irq_raise();
         fdc.incommand = 0;
@@ -794,16 +670,125 @@
     }
 }
 
+static void fdc_overrun(void)
+{
+        disc_stop();
+
+        fdcsend(0x40 | (fdc.side ? 4 : 0) | fdc.drive);
+        fdcsend(0x10); /*Overrun*/
+        fdcsend(0);
+        fdcsend(fdc.track);
+        fdcsend(fdc.side);
+        fdcsend(fdc.sector);
+        fdcsend(fdc.parameters[4]);
+    fdc_end_command();
+}
+
+void fdc_data(uint8_t dat)
+{
+        if (fdc.tc || !fdc.in_read)
+                return;
+
+        if (fdc.data_ready) {
+                fdc_overrun();
+        } else {
+                fdc.dmadat = dat;
+                fdc.data_ready = 1;
+                fdc_dma_raise();
+        }
+}
+
+void fdc_finishread(void)
+{
+    fdccallback = 25;
+}
+
+void fdc_notfound(void)
+{
+        fdcsend(0x40 | (fdc.side ? 4 : 0) | fdc.drive);
+        fdcsend(5);
+        fdcsend(0);
+        fdcsend(0);
+        fdcsend(0);
+        fdcsend(0);
+        fdcsend(0);
+    fdc_end_command();
+}
+
+void fdc_datacrcerror(void)
+{
+        fdcsend(0x40 | (fdc.side ? 4 : 0) | fdc.drive);
+        fdcsend(0x20); /*Data error*/
+        fdcsend(0x20); /*Data error in data field*/
+        fdcsend(fdc.track);
+        fdcsend(fdc.side);
+        fdcsend(fdc.sector);
+        fdcsend(fdc.parameters[4]);
+    fdc_end_command();
+}
+
+void fdc_headercrcerror(void)
+{
+        fdcsend(0x40 | (fdc.side ? 4 : 0) | fdc.drive);
+        fdcsend(0x20); /*Data error*/
+        fdcsend(0);
+        fdcsend(fdc.track);
+        fdcsend(fdc.side);
+        fdcsend(fdc.sector);
+        fdcsend(fdc.parameters[4]);
+    fdc_end_command();
+}
+
+void fdc_writeprotect(void)
+{
+        fdcsend(0x40 | (fdc.side ? 4 : 0) | fdc.drive);
+        fdcsend(0x02); /*Not writeable*/
+        fdcsend(0);
+        fdcsend(0);
+        fdcsend(0);
+        fdcsend(0);
+        fdcsend(0);
+        fdc_end_command();
+}
+
+int fdc_getdata(int last)
+{
+        uint8_t temp;
+
+        if (!fdc.written && !fdc.tc)
+                return -1;
+        if (!last && !fdc.tc)
+            fdc_dma_raise();
+        fdc.written = 0;
+        temp = fdc.dmadat;
+        return temp;
+}
+
+void fdc_sectorid(uint8_t track, uint8_t side, uint8_t sector, uint8_t size)
+{
+        fdcsend((fdc.side ? 4 : 0) | fdc.drive);
+        fdcsend(0);
+        fdcsend(0);
+        fdcsend(track);
+        fdcsend(side);
+        fdcsend(sector);
+        fdcsend(size);
+    fdc_end_command();
+}
+
+void fdc_indexpulse(void)
+{
+    iomd.irqa.status |= IOMD_IRQA_FLOPPY_INDEX;
+    updateirqs();
+}
+
 uint8_t
 fdc_dma_read(uint32_t addr)
 {
     fdc_dma_lower();
-    fdccallback = 100;
-    if (!fdc.commandpos) {
-        fdccallback = 2000;
-    }
+    fdc.data_ready = 0;
     if (addr == 0x302a000) {
-        fdc.commandpos = drives[fdc.st0 & 1].format->sectorsize;
-         fdccallback    = 2000;
+        fdc.tc = 1;
         fdc.st0        = 0;
     }
@@ -814,15 +799,11 @@
 fdc_dma_write(uint32_t addr, uint8_t val)
 {
     fdc_dma_lower();
-    fdccallback = 200;
-    if (!fdc.commandpos) {
-        fdccallback = 2000;
-    }
     if (addr == 0x302a000) {
-        fdc.oldpos     = fdc.commandpos;
-        fdc.commandpos = 2048;
-         fdccallback    = 2000;
+        fdc.tc = 1;
         fdc.st0        = 0;
     }
+    fdc.written = 1;
     fdc.dmadat = val;
 }
diff -r d2affb36a0db -r 592604520b7e src/fdc.h
--- a/src/fdc.h    Wed Oct 06 21:34:59 2021 +0100
+++ b/src/fdc.h    Sat Oct 09 14:01:30 2021 +0100
@@ -34,4 +34,14 @@
 extern int fdccallback;
 extern int motoron;
 
+extern void fdc_data(uint8_t dat);
+extern void fdc_finishread(void);
+extern void fdc_notfound(void);
+extern void fdc_datacrcerror(void);
+extern void fdc_headercrcerror(void);
+extern void fdc_writeprotect(void);
+extern int fdc_getdata(int last);
+extern void fdc_sectorid(uint8_t track, uint8_t side, uint8_t sector, uint8_t size);
+extern void fdc_indexpulse(void);
+
 

No comments:

Post a Comment