2021-10-02
The DeMiSTify framework has now proved useful in porting a number of retro console and computer cores from the MiST board to the Turbo Chameleon 64, and others have found it useful in porting cores to the DECA board, which I mentioned in my previous post.
However, the jewel in the MiST crown has always been the Atari ST cores: it has two – the original MiST core which was developed side-by-side with the board sharing its name – and also the MiSTery core, an evolution of the project which features a cycle-exact implementation of the CPU and also most of the chipset.
With the cores ported so far, DeMiSTify manages to present a basic but usable menu structure using a bare minimum of resources. There’s no space to hold an internal copy of the config string, or of a complete menu structure – instead the menu is built on-the-fly, one page at a time, by reading the core’s config string anew every time the menu needs updating. It works surprisingly well, and allows, for example, the C16 core to deal with loading ROM images, tapes and d64 disk images with firmware, RAM and stack all fitting within 12k of RAM.
So it should be easy to apply the same principles in porting the Atari ST core, yes?
No – for one very simple reason: the Atari ST core doesn’t use config strings!
The reason for this is simply the heritage of the MiST firmware, which is a (very significant) evolution of the ARM controller firmware from the original Minimig. Originally the menu structure was hard-coded to suit the Amiga, then some extra hard-coded menu structure was added for the benefit of the Atari core, and ultimately the config string system was added for more generic cores. I was reluctant to even attempt bringing the hard-coded menu structures into DeMiSTify – a different approach was clearly needed.
I explored the menus of the MiSTery core on MiST and realised that even though the core doesn’t currently use a config string, there’s nothing about its menus that couldn’t be expressed that way. So I had two options: (a) add such a string to the core itself, or (b) embed one in the firmware, and modify how the menu code fetches it. I chose option b, so as to follow one of my guiding principles with DeMiSTify: “make as few modifications to the guest core as possible”.
A linker feature I’ve used a lot in the DeMiSTify project is weak linkage. This allows me to define a “default” version of a function, but override it with a core-specific version where necessary. Initially I restricted this to such things as input mapping (for example, the NES core swaps the two joystick buttons, due to their physical location on a real gamepad) or autobooting (just loading a particular filename). However, with the Atari ST core I’ve made much more heavy use of this overloading ability, and replaced the functions which previously fetched the config string, byte-by-byte from the FPGA, with functions which read them byte-by-byte from a string. The rest of the code neither knows nor cares where the menu definition is actually stored.
The next challenge was hard drive support. The Atari ST core handles hard drives in quite a different manner from other cores: it implements Atari’s ACSI system, complete with DMA, so that the Atari ST system software doesn’t have to sit around being spoon-fed with data. It’s quite elegant, and adapting the relevant code from the MiST firmware was easier than I’d anticipated.
One detail I did have to take care of was performance when reading from large hard files. On a FAT filesystem, random access seeking can take a significant time, since you need to follow cluster chains from the very start of the file. When that file is 3 gigabytes in size, that’s no joke. The traditional solution to this is to create an index – just a table which caches the clusters corresponding to key points within the file. Generally distributed at equal points throughout the file, the number of these index points is a tradeoff between desired performance and the amount of memory devoted to the index. As usual I’m erring very heavily on the side of frugality, so instead of building an index, I’m keeping around a small number of “bookmarks”. When I seek within a file, I first check the bookmarks to see if any of them is a better starting point than the beginning of the file for performing the seek. I also check the existing bookmarks to see whether any of them would be “useful” for returning to the old position. If not, I evict the current “least useful” bookmark and replace it with one to the current file position. (By ‘least useful’, I mean the bookmark which most closely follows either another bookmark or the beginning of the file.) This scheme seems to give adequate performance with only half a dozen bookmark entries.
The Atari ST was never a platform I’d had a particular reason or opportunity to explore. In tinkering with the core while porting it to TC64, I’ve realised that – as with most retro platforms – there’s a great deal to like about it!