M68000: a trial of pain
I have really enjoyed emulating many processors. The 6502 stands out in a good way for its pre-RISC RISC-like minimal design, allowing for simple assembly/disassembly and good speed compared to its contemporaries.
My least favorite processor to emulate so far, by FAR, has been the Motorola 68000. This is despite having the most experience before emulating it, along with the best tooling.
Emulation accuracy and generation
In my post “emulation accuracy inflection point,” I outlined how there is a point in time before which, accuracy is much more important. Despite being a fairly sophisticated (For the time) 16/32-bit processor, the M68000 is used squarely inside many older consoles, which require great accuracy.
Despite this, most m68000 emulators do not aim for the kind of accuracy that Z80 or M6502 emulators frequently do. This is because it’s one of the most complex processors from the time. It had two levels of microcode (microcode and nanocode, as Motorola called it), which meant that matching up bus activity and exception frames exactly can be a frustrating task.
In fact, no emulator I know of tried and succeeded at being perfect, until Olivier Galibert’s microcode-based core in MAME. This is an effort that took several years from conception to completion, requiring many steps and contributors.
Of course, I like to be super accurate. I first investigated trying to make my own microcode-based emulator, but was put off by the complexity and lack of documentation. I endeavoured instead to make an “as-accurate-as-I-can,” single-cycle-stepped M68000 emulator.
The paaaaaaaaiiiinnn
I started off writing tests for my core before anything else really. I loaded up TomHarte’s 68000 test JSON files, and started coding my core to conform to them. However, I got about 20 instructions in before I lost motivation, because I found things that just couldn’t be perfectly correct about the test suite.
I took a while, learned to compile and hack up MAME, and used the aforementioned microcode-derived core to generate a new set of tests, then went on my way implementing instructions for my core, testing against those.
Pain came in a variety of way