Tuesday, 12 October 2021

[Rpcemu] [PATCH 4/4] Add HFE disc image support

diff -r ca4be2ca9a9a -r 3c256b7d0551 src/disc_hfe.c
--- /dev/null    Thu Jan 01 00:00:00 1970 +0000
+++ b/src/disc_hfe.c    Sat Oct 09 17:47:01 2021 +0100
@@ -0,0 +1,339 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include "rpcemu.h"
+#include "disc.h"
+#include "disc_hfe.h"
+#include "disc_mfm_common.h"
+
+static disc_funcs hfe_disc_funcs;
+
+static void hfe_writeback(int drive);
+
+#define TRACK_ENCODING_ISOIBM_MFM 0x00
+#define TRACK_ENCODING_AMIGA_MFM  0x01
+#define TRACK_ENCODING_ISOIBM_FM  0x02
+#define TRACK_ENCODING_EMU_FM     0x03
+
+typedef struct hfe_header_t {
+        char signature[8]; /*Should be HXCPICFE*/
+        uint8_t revision;
+        uint8_t nr_of_tracks;
+        uint8_t nr_of_sides;
+        uint8_t track_encoding;
+        uint16_t bitrate;
+        uint16_t floppy_rpm;
+        uint8_t floppy_interface_mode;
+        uint8_t dnu;
+        uint16_t track_list_offset;
+        uint8_t write_allowed;
+        uint8_t single_step;
+        uint8_t track0s0_altencoding;
+        uint8_t track0s0_encoding;
+        uint8_t track0s1_altencoding;
+        uint8_t track0s1_encoding;
+} hfe_header_t;
+
+typedef struct hfe_track_t {
+        uint16_t offset;
+        uint16_t track_len;
+} hfe_track_t;
+
+typedef struct hfe_t {
+        hfe_header_t header;
+        hfe_track_t *tracks;
+        mfm_t mfm;
+        FILE *f;
+        int current_track;
+        int write_prot;
+} hfe_t;
+
+static hfe_t hfe[4];
+
+static int hfe_drive;
+
+static int hfe_load_header(hfe_t *hfe)
+{
+        hfe_header_t *header = &hfe->header;
+
+        fread(header->signature, 8, 1, hfe->f);
+        header->revision = getc(hfe->f);
+        header->nr_of_tracks = getc(hfe->f);
+        header->nr_of_sides = getc(hfe->f);
+        header->track_encoding = getc(hfe->f);
+        fread(&header->bitrate, 2, 1, hfe->f);
+        fread(&header->floppy_rpm, 2, 1, hfe->f);
+        header->floppy_interface_mode = getc(hfe->f);
+        header->dnu = getc(hfe->f);
+        fread(&header->track_list_offset, 2, 1, hfe->f);
+        header->write_allowed = getc(hfe->f);
+        header->single_step = getc(hfe->f);
+        header->track0s0_altencoding = getc(hfe->f);
+        header->track0s0_encoding = getc(hfe->f);
+        header->track0s1_altencoding = getc(hfe->f);
+        header->track0s1_encoding = getc(hfe->f);
+
+        if (strncmp(header->signature, "HXCPICFE", 8)) {
+                rpclog("HFE signature does not match\n");
+                return -1;
+        }
+        if (header->revision != 0) {
+                rpclog("HFE revision %i unsupported\n", header->revision);
+                return -1;
+        }
+
+//        rpclog("HFE: %i tracks, %i sides\n", header->nr_of_tracks, header->nr_of_sides);
+//        rpclog("  track_list_offset: %i\n", header->track_list_offset);
+        hfe->tracks = malloc(header->nr_of_tracks * header->nr_of_sides * sizeof(hfe_track_t));
+        fseek(hfe->f, header->track_list_offset * 0x200, SEEK_SET);
+        fread(hfe->tracks, header->nr_of_tracks * header->nr_of_sides * sizeof(hfe_track_t), 1, hfe->f);
+
+        return 0;
+}
+
+void hfe_init()
+{
+//        printf("hfe reset\n");
+        memset(hfe, 0, sizeof(hfe));
+}
+
+void hfe_load(int drive, const char *fn)
+{
+        hfe[drive].write_prot = 0;
+        memset(&hfe[drive], 0, sizeof(hfe_t));
+        hfe[drive].f = fopen(fn, "rb+");
+        if (!hfe[drive].f) {
+                hfe[drive].f = fopen(fn, "rb");
+                if (!hfe[drive].f)
+                        return;
+                hfe[drive].write_prot = 1;
+        }
+        hfe_load_header(&hfe[drive]);
+        hfe[drive].mfm.write_protected = hfe[drive].write_prot;
+        hfe[drive].mfm.writeback = hfe_writeback;
+
+        drive_funcs[drive] = &hfe_disc_funcs;
+        //rpclog("Loaded as hfe\n");
+
+        drive_funcs[drive]->seek(drive, disc_get_current_track(drive));
+}
+
+static void hfe_close(int drive)
+{
+        if (hfe[drive].tracks) {
+                free(hfe[drive].tracks);
+                hfe[drive].tracks = NULL;
+        }
+        if (hfe[drive].f) {
+                fclose(hfe[drive].f);
+                hfe[drive].f = NULL;
+        }
+}
+
+static void do_bitswap(uint8_t *data, int size)
+{
+        int c;
+
+        for (c = 0; c < size; c++) {
+                uint8_t new_val = 0;
+
+                if (data[c] & 0x01)
+                        new_val |= 0x80;
+                if (data[c] & 0x02)
+                        new_val |= 0x40;
+                if (data[c] & 0x04)
+                        new_val |= 0x20;
+                if (data[c] & 0x08)
+                        new_val |= 0x10;
+                if (data[c] & 0x10)
+                        new_val |= 0x08;
+                if (data[c] & 0x20)
+                        new_val |= 0x04;
+                if (data[c] & 0x40)
+                        new_val |= 0x02;
+                if (data[c] & 0x80)
+                        new_val |= 0x01;
+
+                data[c] = new_val;
+        }
+}
+
+static void upsample_track(uint8_t *data, int size)
+{
+        int c;
+
+        for (c = size-1; c >= 0; c--) {
+                uint8_t new_data = 0;
+
+                if (data[c] & 0x08)
+                        new_data |= 0x80;
+                if (data[c] & 0x04)
+                        new_data |= 0x20;
+                if (data[c] & 0x02)
+                        new_data |= 0x08;
+                if (data[c] & 0x01)
+                        new_data |= 0x02;
+                data[c*2+1] = new_data;
+
+                new_data = 0;
+                if (data[c] & 0x80)
+                        new_data |= 0x80;
+                if (data[c] & 0x40)
+                        new_data |= 0x20;
+                if (data[c] & 0x20)
+                        new_data |= 0x08;
+                if (data[c] & 0x10)
+                        new_data |= 0x02;
+                data[c*2] = new_data;
+        }
+}
+
+static void downsample_track(uint8_t *data, int size)
+{
+        int c;
+
+        for (c = 0; c < size; c++) {
+                uint8_t new_data = 0;
+
+                if (data[c*2+1] & 0x80)
+                        new_data |= 0x08;
+                if (data[c*2+1] & 0x20)
+                        new_data |= 0x04;
+                if (data[c*2+1] & 0x08)
+                        new_data |= 0x02;
+                if (data[c*2+1] & 0x02)
+                        new_data |= 0x01;
+                if (data[c*2] & 0x80)
+                        new_data |= 0x80;
+                if (data[c*2] & 0x20)
+                        new_data |= 0x40;
+                if (data[c*2] & 0x08)
+                        new_data |= 0x20;
+                if (data[c*2] & 0x02)
+                        new_data |= 0x10;
+                data[c] = new_data;
+        }
+}
+
+static void hfe_seek(int drive, int track)
+{
+        hfe_header_t *header = &hfe[drive].header;
+        mfm_t *mfm = &hfe[drive].mfm;
+        int c;
+
+        if (!hfe[drive].f) {
+                memset(mfm->track_data[0], 0, 65536);
+                memset(mfm->track_data[1], 0, 65536);
+                return;
+        }
+//        printf("Track start %i\n",track);
+        if (track < 0)
+                track = 0;
+        if (track >= header->nr_of_tracks)
+                track = header->nr_of_tracks - 1;
+
+        hfe->current_track = track;
+
+//        rpclog("hfe_seek: drive=%i track=%i\n", drive, track);
+//        rpclog("  offset=%04x size=%04x\n", hfe[drive].tracks[track].offset, hfe[drive].tracks[track].track_len);
+        fseek(hfe[drive].f, hfe[drive].tracks[track].offset * 0x200, SEEK_SET);
+//        rpclog("  start=%06x\n", ftell(hfe[drive].f));
+        for (c = 0; c < (hfe[drive].tracks[track].track_len/2); c += 0x100) {
+                fread(&mfm->track_data[0][c], 256, 1, hfe[drive].f);
+                fread(&mfm->track_data[1][c], 256, 1, hfe[drive].f);
+        }
+//        rpclog("  end=%06x\n", ftell(hfe[drive].f));
+        mfm->track_index[0] = 0;
+        mfm->track_index[1] = 0;
+        mfm->track_len[0] = (hfe[drive].tracks[track].track_len*8)/2;
+        mfm->track_len[1] = (hfe[drive].tracks[track].track_len*8)/2;
+        do_bitswap(mfm->track_data[0], (mfm->track_len[0] + 7) / 8);
+        do_bitswap(mfm->track_data[1], (mfm->track_len[1] + 7) / 8);
+
+        if (header->bitrate < 400) {
+                upsample_track(mfm->track_data[0], (mfm->track_len[0] + 7) / 8);
+                upsample_track(mfm->track_data[1], (mfm->track_len[1] + 7) / 8);
+                mfm->track_len[0] *= 2;
+                mfm->track_len[1] *= 2;
+        }
+
+//        rpclog(" SD side 0 Track %i Len %i Index %i\n", track, mfm->track_len[0][0], mfm->track_index[0][0]);
+//        rpclog(" SD side 1 Track %i Len %i Index %i\n", track, mfm->track_len[1][0], mfm->track_index[1][0]);
+//        rpclog(" DD side 0 Track %i Len %i Index %i\n", track, mfm->track_len[0], mfm->track_index[0]);
+//        rpclog(" DD side 1 Track %i Len %i Index %i\n", track, mfm->track_len[1], mfm->track_index[1]);
+}
+
+static void hfe_writeback(int drive)
+{
+        hfe_header_t *header = &hfe[drive].header;
+        mfm_t *mfm = &hfe[drive].mfm;
+        int track = hfe[drive].current_track;
+        uint8_t track_data[2][65536];
+        int c;
+
+//        rpclog("hfe_writeback: drive=%i track=%i\n", drive, track);
+
+        for (c = 0; c < 2; c++) {
+                int track_len = mfm->track_len[c];
+                memcpy(track_data[c], mfm->track_data[c], (track_len + 7) / 8);
+
+                if (header->bitrate < 400) {
+                        downsample_track(track_data[c], (track_len + 7) / 8);
+                        track_len /= 2;
+                }
+                do_bitswap(track_data[c], (track_len + 7) / 8);
+        }
+
+        fseek(hfe[drive].f, hfe[drive].tracks[track].offset * 0x200, SEEK_SET);
+//        rpclog(" at %06x\n", ftell(hfe[drive].f));
+        for (c = 0; c < (hfe[drive].tracks[track].track_len/2); c += 0x100) {
+                fwrite(&track_data[0][c], 256, 1, hfe[drive].f);
+                fwrite(&track_data[1][c], 256, 1, hfe[drive].f);
+        }
+}
+
+static void hfe_readsector(int drive, int sector, int track, int side, int density)
+{
+        hfe_drive = drive;
+        mfm_readsector(&hfe[drive].mfm, drive, sector, track, side, density);
+}
+
+static void hfe_writesector(int drive, int sector, int track, int side, int density)
+{
+        hfe_drive = drive;
+        mfm_writesector(&hfe[drive].mfm, drive, sector, track, side, density);
+}
+
+static void hfe_readaddress(int drive, int track, int side, int density)
+{
+        hfe_drive = drive;
+        mfm_readaddress(&hfe[drive].mfm, drive, track, side, density);
+}
+
+static void hfe_format(int drive, int track, int side, int density)
+{
+        hfe_drive = drive;
+        mfm_format(&hfe[drive].mfm, drive, track, side, density);
+}
+
+static void hfe_stop()
+{
+        mfm_stop(&hfe[hfe_drive].mfm);
+}
+
+static void hfe_poll()
+{
+        mfm_common_poll(&hfe[hfe_drive].mfm);
+}
+
+static disc_funcs hfe_disc_funcs = {
+    .seek        = hfe_seek,
+        .readsector  = hfe_readsector,
+        .writesector = hfe_writesector,
+        .readaddress = hfe_readaddress,
+        .poll        = hfe_poll,
+        .format      = hfe_format,
+        .stop        = hfe_stop,
+        .close       = hfe_close
+};
\ No newline at end of file
diff -r ca4be2ca9a9a -r 3c256b7d0551 src/disc_hfe.h
--- /dev/null    Thu Jan 01 00:00:00 1970 +0000
+++ b/src/disc_hfe.h    Sat Oct 09 17:47:01 2021 +0100
@@ -0,0 +1,2 @@
+extern void hfe_init();
+extern void hfe_load(int drive, const char *fn);
diff -r ca4be2ca9a9a -r 3c256b7d0551 src/disc_mfm_common.c
--- /dev/null    Thu Jan 01 00:00:00 1970 +0000
+++ b/src/disc_mfm_common.c    Sat Oct 09 17:47:01 2021 +0100
@@ -0,0 +1,470 @@
+/*Common handling for raw FM/MFM bitstreams*/
+#include <stdint.h>
+#include "rpcemu.h"
+#include "disc.h"
+#include "disc_mfm_common.h"
+#include "fdc.h"
+
+static uint16_t CRCTable[256];
+
+static void mfm_setupcrc(uint16_t poly)
+{
+    int c = 256, bc;
+    uint16_t crctemp;
+
+    while(c--) {
+        crctemp = c << 8;
+        bc = 8;
+
+        while(bc--) {
+            if(crctemp & 0x8000)
+                crctemp = (crctemp << 1) ^ poly;
+            else
+                crctemp <<= 1;
+        }
+
+        CRCTable[c] = crctemp;
+    }
+}
+
+void mfm_init(void)
+{
+        mfm_setupcrc(0x1021);
+}
+
+
+void mfm_readsector(mfm_t *mfm, int drive, int sector, int track, int side, int density)
+{
+        mfm->revs = 0;
+        mfm->sector  = sector;
+        mfm->track   = track;
+        mfm->side    = side;
+        mfm->drive   = drive;
+        mfm->density = density;
+        //rpclog("mfm Read sector %i %i %i %i %i\n",drive,side,track,sector, density);
+
+        mfm->in_read  = 1;
+        mfm->sync_required = (density != 2);
+}
+
+void mfm_writesector(mfm_t *mfm, int drive, int sector, int track, int side, int density)
+{
+        mfm->revs = 0;
+        mfm->sector = sector;
+        mfm->track  = track;
+        mfm->side   = side;
+        mfm->drive  = drive;
+        //rpclog("Write sector %i %i %i %i %i\n",drive,side,track,sector,density);
+
+        mfm->in_write = 1;
+        mfm->sync_required = (density != 2);
+}
+
+void mfm_readaddress(mfm_t *mfm, int drive, int track, int side, int density)
+{
+        mfm->revs = 0;
+        mfm->track   = track;
+        mfm->side    = side;
+        mfm->density = density;
+        mfm->drive   = drive;
+        //rpclog("Read address %i %i %i %i\n",drive,side,track,density);
+
+        mfm->in_readaddr = 1;
+        mfm->sync_required = (density != 2);
+}
+
+void mfm_format(mfm_t *mfm, int drive, int track, int side, int density)
+{
+        mfm->revs = 0;
+        mfm->track   = track;
+        mfm->side    = side;
+        mfm->density = density;
+        mfm->drive   = drive;
+//        printf("Format %i %i %i\n",drive,side,track);
+
+        mfm->in_format = 1;
+        mfm->sync_required = 0;
+}
+
+void mfm_stop(mfm_t *mfm)
+{
+        mfm->in_read = mfm->in_write = mfm->in_readaddr = mfm->in_format = 0;
+        mfm->nextsector = mfm->ddidbitsleft = mfm->pollbitsleft = 0;
+}
+
+
+static void calccrc(mfm_t *mfm, uint8_t byte)
+{
+    mfm->crc = (mfm->crc << 8) ^ CRCTable[(mfm->crc >> 8) ^ byte];
+}
+
+static uint16_t pack_2us(uint32_t in_data)
+{
+        uint16_t out_data = 0;
+        int c;
+
+        for (c = 0; c < 16; c++) {
+                if (in_data & (2 << c*2))
+                        out_data |= (1 << c);
+        }
+
+        return out_data;
+}
+static uint16_t pack_4us(uint64_t in_data)
+{
+        uint16_t out_data = 0;
+        int c;
+
+        for (c = 0; c < 16; c++) {
+                if (in_data & (8ull << c*4))
+                        out_data |= (1 << c);
+        }
+
+        return out_data;
+}
+
+static uint8_t decodefm(uint16_t dat)
+{
+        uint8_t temp;
+        temp = 0;
+        if (dat & 0x0001) temp |= 1;
+        if (dat & 0x0004) temp |= 2;
+        if (dat & 0x0010) temp |= 4;
+        if (dat & 0x0040) temp |= 8;
+        if (dat & 0x0100) temp |= 16;
+        if (dat & 0x0400) temp |= 32;
+        if (dat & 0x1000) temp |= 64;
+        if (dat & 0x4000) temp |= 128;
+        return temp;
+}
+
+static uint64_t encode_fm_4us(uint8_t data)
+{
+        uint64_t fm_data = 0x8080808080808080ull; /*Clock bits*/
+        int c;
+
+        for (c = 7; c >= 0; c--) {
+                if (data & (1 << c))
+                        fm_data |= 8ull << (c*8);
+        }
+
+        return fm_data;
+}
+
+static uint32_t encode_mfm_2us(mfm_t *mfm, uint8_t data)
+{
+        uint32_t mfm_data = 0;
+        int c;
+
+        for (c = 7; c >= 0; c--) {
+                if (data & (1 << c))
+                        mfm_data |= 2 << (c*4);
+                else if (!mfm->last_bit)
+                        mfm_data |= 8 << (c*4);
+
+                mfm->last_bit = data & (1 << c);
+        }
+
+        return mfm_data;
+}
+
+static uint16_t encode_mfm_1us(mfm_t *mfm, uint8_t data)
+{
+        uint16_t mfm_data = 0;
+        int c;
+
+        for (c = 7; c >= 0; c--) {
+                if (data & (1 << c))
+                        mfm_data |= 1 << (c*2);
+                else if (!mfm->last_bit)
+                        mfm_data |= 2 << (c*2);
+
+                mfm->last_bit = data & (1 << c);
+        }
+
+        return mfm_data;
+}
+
+static void next_bit(mfm_t *mfm)
+{
+        mfm->pos++;
+
+        if (mfm->pos >= mfm->track_len[mfm->side]) {
+//                rpclog("disc loop %i  index %i\n", mfm->pos,mfm->track_index[mfm->side]);
+                mfm->pos = 0;
+        }
+
+        if (mfm->pos == mfm->track_index[mfm->side]) {
+//                rpclog("disc index %i  %i\n", mfm->pos, mfm->indextime_blank);
+                if (mfm->track_len[mfm->side]) {
+                        fdc_indexpulse();
+                        if (mfm->in_read || mfm->in_readaddr || mfm->in_write)
+                                mfm->revs++;
+                } else {
+                        mfm->indextime_blank--;
+                        if (mfm->indextime_blank <= 0) {
+                                mfm->indextime_blank = 6250 * 8;
+                                fdc_indexpulse();
+                                if (mfm->in_read || mfm->in_readaddr || mfm->in_write)
+                                        mfm->revs++;
+                        }
+                }
+                if ((mfm->in_read || mfm->in_readaddr || mfm->in_write) && mfm->revs == 3) {
+//                                        rpclog("hfe_poll: Not found!\n");
+                        fdc_notfound();
+                        mfm->in_read = mfm->in_readaddr = mfm->in_write = 0;
+                }
+        }
+}
+
+void mfm_common_poll(mfm_t *mfm)
+{
+        int tempi, c, polls;
+        int nr_bits = 4 >> mfm->density;
+
+        if (mfm->density == 3) {
+                for (polls = 0; polls < 8; polls++)
+                        next_bit(mfm);
+                return;
+        }
+
+        for (polls = 0; polls < 16; polls++) {
+                uint16_t new_data;
+
+                if (mfm->sync_required) {
+                        if (mfm->density == 0) {
+                                for (c = 0; c < nr_bits; c++) {
+                                        int tempi = mfm->track_data[mfm->side][(mfm->pos >> 3) & 0xFFFF] & (1 << (7-(mfm->pos & 7)));
+                                        mfm->buffer <<= 1;
+                                        mfm->buffer |= (tempi ? 1 : 0);
+                                        next_bit(mfm);
+
+                                        if ((mfm->buffer & 0x8080808080808080ull) == 0x8080808080808080ull &&
+                                            !(mfm->buffer & 0x7777777777777777ull)) {
+                                                mfm->sync_required = 0;
+                                                break;
+                                        }
+                                }
+                        }
+                        else if (mfm->density == 1) {
+                                for (c = 0; c < nr_bits; c++) {
+                                        int tempi = mfm->track_data[mfm->side][(mfm->pos >> 3) & 0xFFFF] & (1 << (7-(mfm->pos & 7)));
+                                        mfm->buffer <<= 1;
+                                        mfm->buffer |= (tempi ? 1 : 0);
+                                        next_bit(mfm);
+
+                                        if ((mfm->buffer & 0xffff) == 0x8888) {
+                                                mfm->sync_required = 0;
+                                                break;
+                                        }
+                                }
+                        }
+
+                        if (mfm->sync_required)
+                                continue;
+                }
+
+                if (mfm->in_format) {
+                        mfm->in_format = 0;
+                        fdc_writeprotect();
+                        continue;
+                }
+                if (mfm->in_write && mfm->write_protected) {
+                        mfm->in_write = 0;
+                        fdc_writeprotect();
+                        continue;
+                }
+
+                if (mfm->rw_write) {
+//                        if (!mfm->writedatapoll)
+//                                fatal("rw_write but not writedatapoll\n");
+                        if (mfm->pollbitsleft == 16) {
+                                uint8_t write_data;
+
+                                if (mfm->pollbytesleft <= 2) {
+                                        write_data = (mfm->pollbytesleft == 2) ? (mfm->crc >> 8) : (mfm->crc & 0xff);
+                                } else {
+                                        int c = fdc_getdata(mfm->pollbytesleft == 3);
+
+                                        write_data = c & 0xff;
+                                        calccrc(mfm, write_data);
+                                }
+
+                                if (mfm->density == 2)
+                                        mfm->buffer = (uint64_t)encode_mfm_1us(mfm, write_data) << 48;
+                                else if (mfm->density == 1)
+                                        mfm->buffer = (uint64_t)encode_mfm_2us(mfm, write_data) << 32;
+                                else
+                                        mfm->buffer = encode_fm_4us(write_data);
+//                                rpclog("MFM write %04i %02x %016llx   %06i  %04x\n", mfm->pollbytesleft, write_data, mfm->buffer, mfm->pos, mfm->crc);
+                        }
+
+                        for (c = 0; c < nr_bits; c++) {
+                                if (mfm->buffer & (1ull << 63))
+                                        mfm->track_data[mfm->side][(mfm->pos >> 3) & 0xFFFF] |= (1 << (7-(mfm->pos & 7)));
+                                else
+                                        mfm->track_data[mfm->side][(mfm->pos >> 3) & 0xFFFF] &= ~(1 << (7-(mfm->pos & 7)));
+                                mfm->buffer <<= 1;
+                                next_bit(mfm);
+                        }
+
+                        mfm->pollbitsleft--;
+                        if (!mfm->pollbitsleft) {
+                                mfm->pollbytesleft--;
+                                if (mfm->pollbytesleft) {
+                                        mfm->pollbitsleft = 16; /*Set up another word if we need it*/
+                                } else {
+//                                        rpclog("MFM finished write\n");
+                                        fdc_finishread();
+                                        mfm->writedatapoll = 0;
+                                        mfm->rw_write = 0;
+                                        mfm->in_write = 0;
+                                        mfm->writeback(mfm->drive);
+                                }
+                        }
+                } else {
+                        for (c = 0; c < nr_bits; c++) {
+                                tempi = mfm->track_data[mfm->side][(mfm->pos >> 3) & 0xFFFF] & (1 << (7-(mfm->pos & 7)));
+                                mfm->buffer <<= 1;
+                                mfm->buffer |= (tempi ? 1 : 0);
+                                next_bit(mfm);
+                        }
+                        if (mfm->density == 2)
+                                new_data = mfm->buffer & 0xffff;
+                        else if (mfm->density == 1)
+                                new_data = pack_2us(mfm->buffer);
+                        else
+                                new_data = pack_4us(mfm->buffer);
+
+                        if (!mfm->in_read && !mfm->in_readaddr && !mfm->in_write)
+                                continue;
+
+                        if (mfm->pollbitsleft)
+                                mfm->pollbitsleft--;
+                        if (!mfm->pollbitsleft && mfm->pollbytesleft) {
+                                mfm->pollbytesleft--;
+                                if (mfm->pollbytesleft)
+                                        mfm->pollbitsleft = 16; /*Set up another word if we need it*/
+                                if (mfm->readidpoll) {
+                                        mfm->sectordat[5 - mfm->pollbytesleft] = decodefm(new_data);
+                                        if (mfm->in_readaddr) {
+//                                                rpclog("inreadaddr - %02X\n", hfe_sectordat[5 - mfm->pollbytesleft]);
+                                                fdc_data(mfm->sectordat[5 - mfm->pollbytesleft]);
+                                        }
+                                        if (!mfm->pollbytesleft) {
+                                                if ((mfm->sectordat[0] == mfm->track && mfm->sectordat[2] == mfm->sector) || mfm->in_readaddr) {
+                                                        mfm->crc = (mfm->density) ? 0xcdb4 : 0xffff;
+                                                        calccrc(mfm, 0xFE);
+                                                        for (c = 0; c < 4; c++)
+                                                                calccrc(mfm, mfm->sectordat[c]);
+                                                        if ((mfm->crc >> 8) != mfm->sectordat[4] || (mfm->crc & 0xFF) != mfm->sectordat[5]) {
+//                                                        printf("Header CRC error : %02X %02X %02X %02X\n",crc>>8,crc&0xFF,hfesectordat[4],hfesectordat[5]);
+                                                                if (mfm->in_readaddr) {
+//                                                                rpclog("inreadaddr - %02X\n", mfm->sector);
+                                                                        fdc_sectorid(mfm->sectordat[0], mfm->sectordat[1], mfm->sectordat[2], mfm->sectordat[3]);
+                                                                }
+                                                                else
+                                                                        mfm->readidpoll = 0;
+                                                        } else if (mfm->sectordat[0] == mfm->track && mfm->sectordat[2] == mfm->sector && (mfm->in_read || mfm->in_write) && !mfm->in_readaddr) {
+                                                                mfm->nextsector = 1;
+                                                                mfm->readidpoll = 0;
+                                                                mfm->sectorsize = (1 << (mfm->sectordat[3] + 7)) + 2;
+                                                                mfm->fdc_sectorsize = mfm->sectordat[3];
+                                                        } else if (mfm->in_readaddr) {
+//                                                                rpclog("hfe_poll: ID %02x %02x %02x %02x %02x %02x\n", hfe_sectordat[0], hfe_sectordat[1], hfe_sectordat[2], hfe_sectordat[3], hfe_sectordat[4], hfe_sectordat[5]);
+                                                                fdc_sectorid(mfm->sectordat[0], mfm->sectordat[1], mfm->sectordat[2], mfm->sectordat[3]);
+                                                                mfm->in_readaddr = 0;
+                                                        }
+                                                }
+                                        }
+                                }
+                                if (mfm->readdatapoll) {
+//                                        rpclog("data %i %04x\n", mfm->pollbytesleft, new_data);
+                                        if (mfm->pollbytesleft > 1)
+                                                calccrc(mfm, decodefm(new_data));
+                                        else
+                                                mfm->sectorcrc[1 - mfm->pollbytesleft] = decodefm(new_data);
+                                        if (!mfm->pollbytesleft) {
+                                                mfm->in_read = 0;
+                                                if ((mfm->crc >> 8) != mfm->sectorcrc[0] || (mfm->crc & 0xFF) != mfm->sectorcrc[1]) {
+//                                                        rpclog("Data CRC error : %02X %02X %02X %02X\n",mfm->crc>>8,mfm->crc&0xFF,mfm->sectorcrc[0],mfm->sectorcrc[1]);
+                                                        fdc_data(decodefm(mfm->lastdat[1]));
+                                                        fdc_finishread();
+                                                        fdc_datacrcerror();
+                                                        mfm->readdatapoll = 0;
+                                                } else {
+//                                                        rpclog("End of hfe read %02X %02X %02X %02X\n",mfm->crc>>8,mfm->crc&0xFF,mfm->sectorcrc[0],mfm->sectorcrc[1]);
+                                                        fdc_data(decodefm(mfm->lastdat[1]));
+                                                        fdc_finishread();
+                                                }
+                                        }
+                                        else if (mfm->lastdat[1] != 0) {
+                                                fdc_data(decodefm(mfm->lastdat[1]));
+                           }
+                                        mfm->lastdat[1] = mfm->lastdat[0];
+                                        mfm->lastdat[0] = new_data;
+                                        if (!mfm->pollbytesleft)
+                                                mfm->readdatapoll = 0;
+                                }
+                        }
+
+                        if (mfm->density && !mfm->readdatapoll) {
+                                if (new_data == 0x4489) {
+                                        mfm->ddidbitsleft = 16;
+                                } else if (mfm->ddidbitsleft) {
+                                        mfm->ddidbitsleft--;
+                                        if (!mfm->ddidbitsleft) {
+//                                                rpclog("ID bits over %04X %02X %i\n",new_data,decodefm(new_data),mfm->pos);
+                                                if (decodefm(new_data) == 0xFE) {
+//                                                        rpclog("Sector header\n");
+                                                        mfm->pollbytesleft = 6;
+                                                        mfm->pollbitsleft  = 16;
+                                                        mfm->readidpoll    = 1;
+                                                } else if (decodefm(new_data) == 0xFB) {
+                                                        if (mfm->nextsector) {
+                                                                mfm->pollbytesleft  = mfm->sectorsize;
+                                                                mfm->pollbitsleft   = 16;
+                                                                mfm->readdatapoll   = mfm->in_read;
+                                                                mfm->writedatapoll  = mfm->in_write;
+                                                                mfm->rw_write = mfm->in_write;
+                                                                mfm->nextsector = 0;
+                                                                mfm->crc = 0xcdb4;
+                                                                if (new_data == 0xF56A) {
+                                                                        calccrc(mfm, 0xF8);
+                                                                        mfm->last_bit = 0;
+                                                                } else {
+                                                                        calccrc(mfm, 0xFB);
+                                                                        mfm->last_bit = 1;
+                                                                }
+                                                                mfm->lastdat[0] = mfm->lastdat[1] = 0;
+                                                        }
+                                                }
+                                        }
+                                }
+                        } else if (!mfm->readdatapoll) {
+                                if (new_data == 0xF57E) {
+//                                        rpclog("FM sector header %i\n", mfm->pos);
+                                        mfm->pollbytesleft = 6;
+                                        mfm->pollbitsleft  = 16;
+                                        mfm->readidpoll    = 1;
+                                } if (new_data == 0xF56F || new_data == 0xF56A) {
+//                                        rpclog("FM sector data %i  %i\n", mfm->pos, mfm->nextsector);
+                                        if (mfm->nextsector) {
+                                                mfm->pollbytesleft  = mfm->sectorsize;
+                                                mfm->pollbitsleft   = 16;
+                                                mfm->readdatapoll   = mfm->in_read;
+                                                mfm->writedatapoll  = mfm->in_write;
+                                                mfm->rw_write = mfm->in_write;
+                                                mfm->nextsector = 0;
+                                                mfm->crc = 0xffff;
+                                                if (new_data == 0xF56A)
+                                                        calccrc(mfm, 0xF8);
+                                                else
+                                                        calccrc(mfm, 0xFB);
+                                                mfm->lastdat[0] = mfm->lastdat[1] = 0;
+                                        }
+                                }
+                        }
+                }
+        }
+}
diff -r ca4be2ca9a9a -r 3c256b7d0551 src/disc_mfm_common.h
--- /dev/null    Thu Jan 01 00:00:00 1970 +0000
+++ b/src/disc_mfm_common.h    Sat Oct 09 17:47:01 2021 +0100
@@ -0,0 +1,34 @@
+typedef struct mfm_t
+{
+        uint8_t track_data[2][65536]; /*[side][byte]*/
+        int track_len[3];
+        int track_index[3];
+
+        int sector, track, side, drive, density;
+
+        int in_read, in_write, in_readaddr, in_format;
+        int sync_required;
+        uint64_t buffer;
+        int pos, revs;
+        int indextime_blank;
+        int pollbytesleft, pollbitsleft, ddidbitsleft;
+        int readidpoll, readdatapoll, writedatapoll;
+        int rw_write;
+        int nextsector;
+        uint8_t sectordat[1026];
+        uint16_t crc;
+        int lastdat[2], sectorcrc[2];
+        int sectorsize, fdc_sectorsize;
+        int last_bit;
+
+        int write_protected;
+        void (*writeback)(int drive);
+} mfm_t;
+
+extern void mfm_init(void);
+extern void mfm_common_poll(mfm_t *mfm);
+extern void mfm_readsector(mfm_t *mfm, int drive, int sector, int track, int side, int density);
+extern void mfm_writesector(mfm_t *mfm, int drive, int sector, int track, int side, int density);
+extern void mfm_readaddress(mfm_t *mfm, int drive, int track, int side, int density);
+extern void mfm_format(mfm_t *mfm, int drive, int track, int side, int density);
+extern void mfm_stop(mfm_t *mfm);
diff -r ca4be2ca9a9a -r 3c256b7d0551 src/fdc.c
--- a/src/fdc.c    Sat Oct 09 17:23:31 2021 +0100
+++ b/src/fdc.c    Sat Oct 09 17:47:01 2021 +0100
@@ -34,6 +34,7 @@
 #include "arm.h"
 #include "disc.h"
 #include "disc_adf.h"
+#include "disc_hfe.h"
 
 /* FDC commands */
 enum {
@@ -175,6 +176,7 @@
     const char *extension;
     long len;
     static const Format *format;
+    int is_hfe = 0;
 
     assert(drive == 0 || drive == 1); // Only support two drives
     assert(fn != NULL); // Must have filename
@@ -217,8 +219,10 @@
         } else {
             format = &formats[DISC_FORMAT_DOS_360K];
         }
+    }  else if (strcasecmp(extension, ".hfe") == 0) {
+        is_hfe = 1;
     } else {
-        error("Unknown disc image file extension '%s', must be .adf or .adl", extension);
+        error("Unknown disc image file extension '%s', must be .adf, .adl, .img or .hfe", extension);
         fclose(f);
         return;
     }
@@ -229,8 +233,11 @@
         drive_funcs[drive] = NULL;
     }
 
-    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,
+    rpclog("fdc_image_load: %s (%ld) loaded as '%s'\n", fn, len, format ? format->name : "HFE");
+    if (is_hfe)
+        hfe_load(drive, fn);
+    else
+        adf_load(drive, fn, format->sectors, format->sectorsize, format->sides, format->tracks == 40,
             format->density ? 1 : 2, format->sectorskew);
 }
 
diff -r ca4be2ca9a9a -r 3c256b7d0551 src/qt5/main_window.cpp
--- a/src/qt5/main_window.cpp    Sat Oct 09 17:23:31 2021 +0100
+++ b/src/qt5/main_window.cpp    Sat Oct 09 17:47:01 2021 +0100
@@ -661,7 +661,7 @@
     QString fileName = QFileDialog::getOpenFileName(this,
         tr("Open Disc Image"),
         "",
-        tr("All disc images (*.adf *.adl *.img);;ADFS D/E/F Disc Image (*.adf);;ADFS L Disc Image (*.adl);;DOS Disc Image (*.img)"));
+        tr("All disc images (*.adf *.adl *.hfe *.img);;ADFS D/E/F Disc Image (*.adf);;ADFS L Disc Image (*.adl);;DOS Disc Image (*.img);;HFE Disc Image (*.hfe)"));
 
     /* fileName is NULL if user hit cancel */
     if(fileName != NULL) {
@@ -675,7 +675,7 @@
     QString fileName = QFileDialog::getOpenFileName(this,
         tr("Open Disc Image"),
         "",
-        tr("All disc images (*.adf *.adl *.img);;ADFS D/E/F Disc Image (*.adf);;ADFS L Disc Image (*.adl);;DOS Disc Image (*.img)"));
+        tr("All disc images (*.adf *.adl *.hfe *.img);;ADFS D/E/F Disc Image (*.adf);;ADFS L Disc Image (*.adl);;DOS Disc Image (*.img);;HFE Disc Image (*.hfe)"));
 
     /* fileName is NULL if user hit cancel */
     if(fileName != NULL) {
diff -r ca4be2ca9a9a -r 3c256b7d0551 src/qt5/rpcemu.pro
--- a/src/qt5/rpcemu.pro    Sat Oct 09 17:23:31 2021 +0100
+++ b/src/qt5/rpcemu.pro    Sat Oct 09 17:47:01 2021 +0100
@@ -28,6 +28,8 @@
         ../arm.h \
         ../disc.h \
         ../disc_adf.h \
+        ../disc_hfe.h \
+        ../disc_mfm_common.h \
         main_window.h \
         configure_dialog.h \
         about_dialog.h \
@@ -57,6 +59,8 @@
         ../i8042.c \
         ../disc.c \
         ../disc_adf.c \
+        ../disc_hfe.c \
+        ../disc_mfm_common.c \
         settings.cpp \
         rpc-qt5.cpp \
         main_window.cpp \
diff -r ca4be2ca9a9a -r 3c256b7d0551 src/rpcemu.c
--- a/src/rpcemu.c    Sat Oct 09 17:23:31 2021 +0100
+++ b/src/rpcemu.c    Sat Oct 09 17:47:01 2021 +0100
@@ -53,6 +53,8 @@
 #include "fdc.h"
 #include "hostfs.h"
 #include "disc_adf.h"
+#include "disc_hfe.h"
+#include "disc_mfm_common.h"
 
 #ifdef RPCEMU_NETWORKING
 #include "network.h"
@@ -307,6 +309,8 @@
         cmos_init();
         fdc_init();
         adf_init();
+        hfe_init();
+        mfm_init();
         fdc_image_load("boot.adf", 0);
         fdc_image_load("notboot.adf", 1);
         initvideo();

_______________________________________________
RPCEmu mailing list
RPCEmu@riscos.info
http://www.riscos.info/cgi-bin/mailman/listinfo/rpcemu

No comments:

Post a Comment