Sunday, 31 October 2021

[Rpcemu] RPCEmu 0.9.4

In article
<CANc9Z=xbXjOyziiND38ooP9+Pipi+dZZJyWNaaR5q98rKXi5YA@mail.gmail.com>,
Peter Howkins <rpcemu.howkins@marutan.net> wrote:
> A new version of RPCEmu is available, 0.9.4
> http://www.marutan.net/rpcemu/

[Snip]

Excellent news as usual. Thanks folks :-)

Small problem and I wonder what it means...

RPCEmu 0.9.4 ROD 5.28

"Filing system HostFS: Must be given a name 640" presents during the boot
sequence, and after I click it away the boot sequence continues... but
some of the configs are missing.

To make sure, I have done the CLI
*configure filesystem hostfs
*configure boot

But that doesn't resolve it.

Any thoughts please?

Thanks

Dave

1) This does not happen with another new RPCEmu 0.9.4 and RISC OS 6.20
which boots and run without any problems.

2) I used to know a command that would show the boot list after the
emulator was run, but damned if I can remember it, anyone help with that
also?

Thanks Dave

--

Dave Triffid

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

Saturday, 30 October 2021

[Rpcemu] RPCEmu with RISC OS 4.00 auUUP00-00 and Ursula0020 issues

Hi all,

I have been trying out the the Pace Internal RISC OS 4 roms with RPCEmu 0.9.3 and 0.9.4 and I have a couple of questions/comments:

1. Both Ursula0020 and auUUP00-00 only seem to work with the Interpreter version of RPCEmu, when trying the Dynamic Recompiler version on 0.9.3 it immediately crashes with the error "Bad PC 030b8000 030b8000". With 0.9.4, both roms cause RPCemu to displace a black window. I freshly compiled both versions of RPCEmu on KDE Neon 5.23 (Linux). Is this a known problem?

2. Does anyone know if any of the "stock" !Boot sequences available online will work with both of these versions?

Any help would be appreciated :)

Cheers,

Dan

[Rpcemu] RPCEmu 0.9.4

A new version of RPCEmu is available, 0.9.4    http://www.marutan.net/rpcemu/      ARM  	Performance gains on x86 and x64 dynamic recompiler.    	Many of the instructions that were not accelerated on the x64          architecture but were on x86 have now been implemented on x64.    	Refactoring of Dynamic Recompiler code.  	  	Many bugfixes.    	Accessing CP15 should only be permitted in privileged modes.    Network Address Translation  	You can now configure ports to be forwarded between your host          network and RPCEmu. This allows you to host servers under RPCEmu          that can be accessed by other machines on your network.  	(Note, this still does not enable the use of ShareFS)    Floppy Disc          Support HFE format floppy disc images. HFE disc images are          lower-level than ADF discs as they can also store the information          required for various copy protection systems. Contributed by          Sarah Walker.    VIDC          If you are not using VRAM you can now use up to 4MB of RAM for          video modes.    Other  	Fix the crash on shutdown or reset of RISC OS 5. Based on a          suggestion from Rob Sprowson.    GCC          Compiling with GCC 10 no longer needs a workaround for the common          symbols errors.        Matthew Howkins  Peter Howkins

Friday, 22 October 2021

[Rpcemu] RPCEmu at the RISC OS London Show, 30-10-2021

At the RISC OS Show, next weekend, in Feltham London, RPCEmu will be having
a stand.

It will be a great chance to catch up with people after a couple of years
and see all the latest projects.

On the RPCEmu stand we will be showing the latest features and also have
demonstrations of two work-in-progress advanced items that are due for
release in the future. [1]

Hope to see you there

Peter

[1] Don't worry too much if you can't make it, I'll post a summary here
afterwards :-)

Monday, 18 October 2021

[Rpcemu] Mercurial down?

Hi,

I tried (as I do regularly, i.e. once in 6 months...) to visit RPCEmu's
Mercurial repo, but the link failed:
http://www.home.marutan.net/hg/rpcemu
leads to a classic 404.

CLI hg also fails with 404.

Steffen aka hubersn

--
Steffen Huber LambdaComm System – Welcome to Trollinger Country
steffen@huber-net.de
Private homepage http://www.huber-net.de/
RISC OS Blog http://riscosblog.huber-net.de/

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

Saturday, 16 October 2021

Re: [gccsdk] VFP vs FPA in library builds

In article <0FCB5232-FB88-479B-B2F4-4F722A086C78@bigblue.net.au>,
Alan Williams <ajw@bigblue.net.au> wrote:
> Rhett,
> I have found my work on that and I would be very happy if it saves you some time.
> There is a file where I was keeping track of what I had done and what I wanted to get done.
> I just zipped up the whole dir and bunged it here:
> http://riscix.info/nettle12.tgz
> There is a conflict in that you can't us this and the default build interchangeable as mine extends the book marks file format to hold the key name and the original version doesn't like this. I think I only extended the English template file correctly. That is any other languages will have English names for the extra fields.
> I believe it was building and running on RISC OS 4.39 when I looked at it last about 2015, but I know it spat it when I tried it on a pi. Normally I just telnet a linux box and ssh from there so I just worked around the issue and never got back to it.

> I also did some other work to make it more putty/iTerm2 like in that selected text is put on the clip board and adjust I think pastes.

After building your version using the GCCSDK autobuilder logging in using a
key worked OK on a RPi 4.


_______________________________________________
GCCSDK mailing list gcc@gccsdk.riscos.info
Bugzilla: http://www.riscos.info/bugzilla/index.cgi
List Info: http://www.riscos.info/mailman/listinfo/gcc
Main Page: http://www.riscos.info/index.php/GCCSDK

Re: [gccsdk] VFP vs FPA in library builds

In article <alpine.DEB.2.22.394.2110151354320.3902245@thelappy>,
Rhett Aultman <rhett@rhettaultman.com> wrote:


> On Fri, 15 Oct 2021, David Pitt wrote:

> > Nettle has just built here on the autobuilder but libsssh2 had to be built
> > first.

> Ah! I wasn't aware that it build through the autobuilder. I've noticed
> that the autobuilder tends to download checkpointed sources and clean up
> after itself following building, so I'm curious if there are ways to use
> it as an environment more friendly to active development and iteration?

> Apologies if these are basic questions to ask; I really did try to educate
> myself through the wiki first.

Adding the '-D' option to the build command will leave the folder in place
after building, Any dependencies should also get built automatically.


../autobuilder/build -v nettle -D

Assuming there's a build-setvars file with similar to below in the folder
the build command is run from.

GCCSDK_INSTALL_CROSSBIN=<path to autobuilder>/cross/bin
GCCSDK_INSTALL_ENV=<path to autobuilder>/env
RO_SHAREDLIBS=no
AB_ELFBUILD=yes


Then build with,

<path to autobuilder>/env/ro-make -f GNUmakefile


_______________________________________________
GCCSDK mailing list gcc@gccsdk.riscos.info
Bugzilla: http://www.riscos.info/bugzilla/index.cgi
List Info: http://www.riscos.info/mailman/listinfo/gcc
Main Page: http://www.riscos.info/index.php/GCCSDK

Re: [gccsdk] VFP vs FPA in library builds

Rhett,
I have found my work on that and I would be very happy if it saves you some time.
There is a file where I was keeping track of what I had done and what I wanted to get done.
I just zipped up the whole dir and bunged it here:
http://riscix.info/nettle12.tgz
There is a conflict in that you can't us this and the default build interchangeable as mine extends the book marks file format to hold the key name and the original version doesn't like this. I think I only extended the English template file correctly. That is any other languages will have English names for the extra fields.
I believe it was building and running on RISC OS 4.39 when I looked at it last about 2015, but I know it spat it when I tried it on a pi. Normally I just telnet a linux box and ssh from there so I just worked around the issue and never got back to it.

I also did some other work to make it more putty/iTerm2 like in that selected text is put on the clip board and adjust I think pastes.

Alan

On 16/10/21, 5:00 am, "Rhett Aultman" <rhett@rhettaultman.com> wrote:



On Fri, 15 Oct 2021, Alan Williams wrote:

> I can't answer your actual question but I am interested in what you plan
> with nettle as a while ago I did some work on it which I am happy to
> share if its of interest. Particularly I improved its capacity to use
> keys rather than passwords for ssh. Unfortunately it got abandoned as
> it wasn't building compatible with the PI and I just haven't got back to
> it for a long time. Alan

Actually, support for keys is precisely what I'm after, so if there's
extant work I could carry on from, that'd be great! I'm also curious to
know what was keeping it from building for the Pi, since I'm using a Pi 2
as my RISC OS hardware at the moment. I'm fairly experienced with
low-level systems, but RISC OS and the gccsdk are very new subjects to me.

Best,
Rhett

_______________________________________________
GCCSDK mailing list gcc@gccsdk.riscos.info
Bugzilla: http://www.riscos.info/bugzilla/index.cgi
List Info: http://www.riscos.info/mailman/listinfo/gcc
Main Page: http://www.riscos.info/index.php/GCCSDK

Friday, 15 October 2021

Re: [gccsdk] VFP vs FPA in library builds

Rhett Aultman, on 15 Oct, wrote:

[snip]

> I've noticed that the autobuilder tends to download checkpointed sources
> and clean up after itself following building, so I'm curious if there are
> ways to use it as an environment more friendly to active development and
> iteration?

A couple of links that may help.

http://www.riscos.info/index.php/Cross-compiling_software_with_GCCSDK

https://www.stevefryatt.org.uk/risc-os/build-tools/environment

HTH.

--
David Pitt

_______________________________________________
GCCSDK mailing list gcc@gccsdk.riscos.info
Bugzilla: http://www.riscos.info/bugzilla/index.cgi
List Info: http://www.riscos.info/mailman/listinfo/gcc
Main Page: http://www.riscos.info/index.php/GCCSDK

Re: [gccsdk] VFP vs FPA in library builds

On Fri, 15 Oct 2021, Alan Williams wrote:

> I can't answer your actual question but I am interested in what you plan
> with nettle as a while ago I did some work on it which I am happy to
> share if its of interest. Particularly I improved its capacity to use
> keys rather than passwords for ssh. Unfortunately it got abandoned as
> it wasn't building compatible with the PI and I just haven't got back to
> it for a long time. Alan

Actually, support for keys is precisely what I'm after, so if there's
extant work I could carry on from, that'd be great! I'm also curious to
know what was keeping it from building for the Pi, since I'm using a Pi 2
as my RISC OS hardware at the moment. I'm fairly experienced with
low-level systems, but RISC OS and the gccsdk are very new subjects to me.

Best,
Rhett

Re: [gccsdk] VFP vs FPA in library builds

On Fri, 15 Oct 2021, Chris Gransden wrote:

> In the setvars file for libssl1.1.1 look for the line which has e.g.,
> AB_ROARCHV=v3
>
> If it's different to the above change it match. This ensures it is built
> for FPA.
> The default was v6zk until a couple of days ago.

Ah! I'd started to get the hang of playing around with some of the
variables (autobuilder reminds me a bit of the yocto builder), but missed
that one. Much obliged.

Best,
Rhett

_______________________________________________
GCCSDK mailing list gcc@gccsdk.riscos.info
Bugzilla: http://www.riscos.info/bugzilla/index.cgi
List Info: http://www.riscos.info/mailman/listinfo/gcc
Main Page: http://www.riscos.info/index.php/GCCSDK

Re: [gccsdk] VFP vs FPA in library builds

On Fri, 15 Oct 2021, David Pitt wrote:

> Nettle has just built here on the autobuilder but libsssh2 had to be built
> first.

Ah! I wasn't aware that it build through the autobuilder. I've noticed
that the autobuilder tends to download checkpointed sources and clean up
after itself following building, so I'm curious if there are ways to use
it as an environment more friendly to active development and iteration?

Apologies if these are basic questions to ask; I really did try to educate
myself through the wiki first.

Best,
Rhett

_______________________________________________
GCCSDK mailing list gcc@gccsdk.riscos.info
Bugzilla: http://www.riscos.info/bugzilla/index.cgi
List Info: http://www.riscos.info/mailman/listinfo/gcc
Main Page: http://www.riscos.info/index.php/GCCSDK

Re: [gccsdk] VFP vs FPA in library builds

In article <alpine.DEB.2.22.394.2110141753370.3825109@thelappy>,
Rhett Aultman <rhett@rhettaultman.com> wrote:
> Hi, all,

> I've recently become interested in RISC OS because of its support for more
> minimal hardware specs while supporting a number of features critical for
> modern computing (e.g. SSL/TLS).

> I'm trying to get Nettle building from source, and it appears to require a
> gccsdk setup, which I've done, and also a number of libraries from gccsdk
> which I could get through the build-libs script. One tricky thing,
> though, is that it appears that some of the libraries, like openssl 1.1.1,
> build with VFP enabled, while others, like zlib, build with FPA instead.
> This brings up a linkage problem when it comes time to link Nettle.

> I temporarily resolved this through going into the build scripts and
> forcing VFP everywhere through CFLAGS manipulation, but it's not entirely
> an ideal process, and really I'd prefer the more widely accepted FPA just
> because VFP shouldn't be all that important for doing SSH.

> Is there a way to control the floating point support that I'm building for
> that I missed? Any particular reason why the openssl is building in VFP
> but other libraries aren't?

In the setvars file for libssl1.1.1 look for the line which has e.g.,
AB_ROARCHV=v3

If it's different to the above change it match. This ensures it is built
for FPA.
The default was v6zk until a couple of days ago.


_______________________________________________
GCCSDK mailing list gcc@gccsdk.riscos.info
Bugzilla: http://www.riscos.info/bugzilla/index.cgi
List Info: http://www.riscos.info/mailman/listinfo/gcc
Main Page: http://www.riscos.info/index.php/GCCSDK

Re: [gccsdk] VFP vs FPA in library builds

Rhett Aultman, on 14 Oct, wrote:

[snip]
>
> I'm trying to get Nettle building from source, and it appears to require a

> gccsdk setup, which I've done, and also a number of libraries from gccsdk
> which I could get through the build-libs script.

[snip]

Nettle has just built here on the autobuilder but libsssh2 had to be built
first.

--
David Pitt

_______________________________________________
GCCSDK mailing list gcc@gccsdk.riscos.info
Bugzilla: http://www.riscos.info/bugzilla/index.cgi
List Info: http://www.riscos.info/mailman/listinfo/gcc
Main Page: http://www.riscos.info/index.php/GCCSDK

Thursday, 14 October 2021

Re: [gccsdk] VFP vs FPA in library builds

Rhett,
I can't answer your actual question but I am interested in what you plan with nettle as a while ago I did some work on it which I am happy to share if its of interest. Particularly I improved its capacity to use keys rather than passwords for ssh. Unfortunately it got abandoned as it wasn't building compatible with the PI and I just haven't got back to it for a long time.
Alan

On 15/10/21, 10:21 am, "Rhett Aultman" <gcc-bounces@gccsdk.riscos.info on behalf of rhett@rhettaultman.com> wrote:

Hi, all,

I've recently become interested in RISC OS because of its support for more
minimal hardware specs while supporting a number of features critical for
modern computing (e.g. SSL/TLS).

I'm trying to get Nettle building from source, and it appears to require a
gccsdk setup, which I've done, and also a number of libraries from gccsdk
which I could get through the build-libs script. One tricky thing,
though, is that it appears that some of the libraries, like openssl 1.1.1,
build with VFP enabled, while others, like zlib, build with FPA instead.
This brings up a linkage problem when it comes time to link Nettle.

I temporarily resolved this through going into the build scripts and
forcing VFP everywhere through CFLAGS manipulation, but it's not entirely
an ideal process, and really I'd prefer the more widely accepted FPA just
because VFP shouldn't be all that important for doing SSH.

Is there a way to control the floating point support that I'm building for
that I missed? Any particular reason why the openssl is building in VFP
but other libraries aren't?

Best,
Rhett

_______________________________________________
GCCSDK mailing list gcc@gccsdk.riscos.info
Bugzilla: http://www.riscos.info/bugzilla/index.cgi
List Info: http://www.riscos.info/mailman/listinfo/gcc
Main Page: http://www.riscos.info/index.php/GCCSDK

_______________________________________________
GCCSDK mailing list gcc@gccsdk.riscos.info
Bugzilla: http://www.riscos.info/bugzilla/index.cgi
List Info: http://www.riscos.info/mailman/listinfo/gcc
Main Page: http://www.riscos.info/index.php/GCCSDK

[gccsdk] VFP vs FPA in library builds

Hi, all,

I've recently become interested in RISC OS because of its support for more
minimal hardware specs while supporting a number of features critical for
modern computing (e.g. SSL/TLS).

I'm trying to get Nettle building from source, and it appears to require a
gccsdk setup, which I've done, and also a number of libraries from gccsdk
which I could get through the build-libs script. One tricky thing,
though, is that it appears that some of the libraries, like openssl 1.1.1,
build with VFP enabled, while others, like zlib, build with FPA instead.
This brings up a linkage problem when it comes time to link Nettle.

I temporarily resolved this through going into the build scripts and
forcing VFP everywhere through CFLAGS manipulation, but it's not entirely
an ideal process, and really I'd prefer the more widely accepted FPA just
because VFP shouldn't be all that important for doing SSH.

Is there a way to control the floating point support that I'm building for
that I missed? Any particular reason why the openssl is building in VFP
but other libraries aren't?

Best,
Rhett

_______________________________________________
GCCSDK mailing list gcc@gccsdk.riscos.info
Bugzilla: http://www.riscos.info/bugzilla/index.cgi
List Info: http://www.riscos.info/mailman/listinfo/gcc
Main Page: http://www.riscos.info/index.php/GCCSDK

Re: [gccsdk] OpenSSL 1.1.1

In article <961CC205-3958-4323-B5D3-E4D00D4EC7FD@lessthan3.org.uk>,
Chris Johns <chris@lessthan3.org.uk> wrote:
> Hello

> I'm porting python 3.10.0 to risc os, and while it now builds along with most of the extensions, it looks like python now requires libssl 1.1.1.

> Does anyone know the state of that for RISC OS? Is it not done because there's been no real news or is there something more significant?

libssl1.1 should appear in PackMan tomorrow. There is also an updated
libssl (1.0.2) so they can both be installed at the same time.

Update current libssl (1.0.2) before installing libssl1.1.


_______________________________________________
GCCSDK mailing list gcc@gccsdk.riscos.info
Bugzilla: http://www.riscos.info/bugzilla/index.cgi
List Info: http://www.riscos.info/mailman/listinfo/gcc
Main Page: http://www.riscos.info/index.php/GCCSDK

Wednesday, 13 October 2021

[gccsdk] OpenSSL 1.1.1

Hello

I'm porting python 3.10.0 to risc os, and while it now builds along with most of the extensions, it looks like python now requires libssl 1.1.1.

Does anyone know the state of that for RISC OS? Is it not done because there's been no real news or is there something more significant?

Cheers

Chris

_______________________________________________
GCCSDK mailing list gcc@gccsdk.riscos.info
Bugzilla: http://www.riscos.info/bugzilla/index.cgi
List Info: http://www.riscos.info/mailman/listinfo/gcc
Main Page: http://www.riscos.info/index.php/GCCSDK

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