Posted February 08, 2025 by howprice
At long last I am proud to present Aira Force 0.9.0. This is a big release for me, because it features a working Amiga 500 emulator. It is available to download now for Windows (64 and 32 bit), Mac, Linux (64-bit), and Raspberry Pi. Download links at end of this post.
I hope it will be useful for disassembling software live. I often code while on a breakpoint, because the debugger provides so much more context to help improve the code. The same should be true for disassembling.
The emulation works, but compatibility is not very good at this point. It plays a good set of the games that I've tried. See the list at the end of this post.
The emulator is working but certainly not finished.
See the games lists later in this post to see how this affects compatibility.
The CPU emulator was born when I wanted to implement dynamic analysis of the disassembly, which required an 68000 instruction interpreter. Learning from my mistakes on a previous unfinished emulator project (buggy Sega SG-1000 / MSX) I hunted out some excellent SingleStepTests (1 and 2) and made sure my CPU passed them all.
The best advice I had for implementing and Amiga emulator was from r/EmuDev/ where someone said "You should be aiming to execute the system ROM". This gave me a clear purpose. Armed with a 1.3 system ROM binary and an extremely helpful 1.2 Exec disassembly (they're quite similar) from back in the day I set about it. I was surprised how much hardware the system ROM requires - almost all of it: CPU (obviously), CIA, blitter, DMA, copper and eventually the disk controller. This eventually lead to the Strap module, which does two things: 1. draws the Kickstart hand and disk image 2. Loads the bootblock from the inserted disk.
I have a very comprehensive Kickstart1.3.cnf that I would love to include in the package, but I have not yet managed to get permission.
The CIA chips were well documented and straightforward to emulate and write comprehensive tests for to ensure they don't break.
The Blitter was quite a big job, but it was well documented and understood. The Strap module uses blitter line filll and transfer (copy) mode to draw the image. Surprisingly, the trackdisk module uses the blitter to decode MFM buffers. It does not use blitter fill mode - this is why it is still not implemented! I had a lot of fun writing the blitter, but I suspect there may be a bug because there is corruption in some games. The blitter was testable, but more difficult.
The copper was quite fun to implement. It has quite a lot of undocumented behaviour. Lots of thanks to the guys on EAB for helping me out with this. In fact, the 1.3 ROM relies on undocumented blitter stop behaviour when it tries to write to an invalid register. This is a bug in the ROM copperlist, but it worked!
The Denise video out I have found tough. The Amiga's timing is quite complex, with Agnus and Denise loosely coupled, and lots of pipelining and cycle delays to confuse matters. Also, the famous DMA Time Slot Allocation diagram in the Hardware Reference Manual is incorrect! The cycle numbers have been biased to aid comprehensibility - fine for Amiga programmers, but not for emulator writers. Again, many thanks to Toni Willen and Ross of WinUAE fame for explaining this stuff. Denise is fed bitplane and sprite data by DMA and processes it. I've been fixing this until the last minute of this release, and it is still not quite right. In my implementation, performance is poor for this part. It needs work.
The DMA manager is the beating heart of the Amiga. Every cycle, it chooses which single device (sprite, disk, bitplane, audio, blitter, copper, CPU) is allowed access to the chip bus, which is usually to read or write from Chip RAM. This is reasonably straightforward, but there are some little quirks like the blitter needing the bus to be free to tick, even if it doesn't actually need the bus, and there are some strange edge effects I have not even tried to emulate. I think I have some copper timing problems here because both Shadow of the Beast and Lionheart (see image above) copper writes do not line up with the bitplane output. I had some great help and advice from the EmuDev Discord when it came to implementing busses: the bus implements the address map! I have added a WinUAE like DMA debugging overlay to the Video window to help me to debug the emulator, but it should also be handy for debugging software.
Emulating a mechanical floppy drive was great fun. First job was to convert ADF images into Amiga Trackdisk format (which uses MFM encoding), then emulate the motor, heads and signals to and from the CIA chips. I would like to add IPF/SPS support in the future. This part of the emulation is embarassingly slow because mechanical components are stepped at electronic frequencies so not to miss sampling bitcells on the spinning disk. This is more simulation than emulation. This could be simplifed a lot, and will be. This is why only 1 drive is supported for now!
After I got the ROM working I had to get Workbench loading, then games playing.
Some unplanned features that went in to improve compatibility included:
This workflow will be improved in a future release, but is possible with a little effort.
You will need an image on disk of the binary data you want to disassemble. This can be saved from Aira by breakpointing and saving memory. For example to disassemble a bootblock, set the "Break when PC in RAM" option (or breakpoint at 5C4C for stock A500!) and save 1024 bytes from 5C40.
When the binary is saved for disk, File > New Project, to configure the disassembly. This will open the interactive ira disassembly view. Now you should be able to use the disassembler and debugger in tandem to step and interactively add comments, labels etc.
This workflow is not well tested sorry, but should work well for single-load games and has been tested on Wicked.
Many thanks to everyonewho has helped me with this release, especially PHX for ira support, Toni and Ross on EAB for demystifying this wonderful machine, and everyone who has tested pre-releases and provided valuable feedback to improve the tool.
Games marked with "no blit waits" in the below list have been written without code to make the CPU wait for the blitter to finish before starting another blit. On a fixed machine like the A500, coders could get away with this because they knew the CPU code would take long enough to run to avoid overlaps.
The Aira emulator uses a hardware "catch-up" model: the CPU executes an instruction, which takes say 4 cycles and then the hardware steps forward by the number of cycles it took to catch back up. The CPU timing model I had in place was very simple: 4 cycles per memory access, and hardware did not block the CPU from the Chip bus. This meant that the CPU was running far too fast and this caused lots of blits to overlap - a serious cause of incompatibility.A
I added some code to catch blits that were kicked off while a previous blit was still in flight and was shocked by how many games it fired on! So, I spent a few hours adding more accurate cycle counts for every emulated instruction's cycle count using the fantastic cbmeeks/Yacht.txt 68000 timing document. Then I updated the hardware emulation "catch-up" to add CPU wait states on bus cycles used by hardware DMA. This made a huge difference to compatibility - suddenly many games started working.
I've tested some of my favourite games, and added some notes on which hardware features were required to run them.
I suspect many of these titles fail due to inaccurate timing or missing hardware features - see the nostes. If you figure out why any games are not working please let me know.