Above: Motorola 6809 CPU and Microsoft/Tandy Color Basic 1.0 ROM, both in ceramic packaging.
Daggorath, like many games of its era, is very sensitive to any changes to timing. Very slight changes in timing result in surprisingly different speed and movement of the enemy creatures. Not only does the existing PC port not match the timing of the original, but nor do most emulators (XRoar is the exception). Even running on a real Coco 3 does not perfectly match the Coco 1 or 2. PAL Cocos from Europe and Australia have very different video timing and surely do not run Daggorath the way the original developers intended. To meet my goals for this port the original CPU and video timing must be emulated exactly.
CPU emulation seems is mostly straightforward - implement a state machine to track the virtual CPU's internal state, execute each instruction according to the CPU specification and count the number of clock cycles each instruction takes. On some systems the interactions between multiple processors can be tricky to deal with but the Coco hardware and Daggorath's specific needs are very simple. The main challenges for this project are that even the 6809 has a lot of instruction variations to implement and it is important to validate each one. Bugs caused by errors in the CPU emulation often manifest in subtle ways that can be very difficult to debug.
CPU implementations create their numerous instruction variations by mixing common implementation elements together; for example several different arithmetic operations mixed with several different addressing modes. I took advantage of this in my implementation by using templates to combine inline functions. This not only reduced the amount of time needed to implement the full instruction set, it minimized the number of places I might make an implementation error. Performance is slightly worse than the more commonly used macro expansion technique but it has been completely worth it to have easier to debug code.
I also validated my CPU emulation in an existing emulator, comparing execution against the emulator's original CPU emulation. This involved quite a bit of work hacking up my emulation to match the emulator's, however it caught enough errors to be absolutely worth the effort. Knowing that the CPU was solid made implementing and debugging the rest of the Coco emulation much more enjoyable.