Emu - X65 Emulator

-

RP2350B chips are still not available on the free market, so I cannot work on the real hardware - thus, I diverted all my focus to working on the X65 machine emulator: Emu.

Modern development for any retro machine requires proper tooling:

For IDE and assembler, I’ve chosen VSCode and the cc65 toolchain, which allows me to easily write simple C apps and proper 65C816 assembly. See the X65 examples repository for information on how that works.

Then, there was the case for the emulator. I needed to write one.

Fortunately, I was aware of a wonderful chip-emulators toolbox, created exactly for the purpose of building complex system emulators with ease.

I started with a C64 emulator codebase as the foundation, hard-forked it to Emu, and began the long process of adapting it into the X65 Emu.

C64 is a similar system to X65 (figures… 🤔) - consisting of a 6502 CPU emulator, VIC-II video chip, SID sound chip, and a few I/O chips.

The chip-emulators toolbox is a very loose set of components. Let me quote the documentation:

The USP of the chip emulators is that they communicate with the outside world through a ‘pin bit mask’: A ‘tick’ function takes an uint64_t as input where the bits represent the chip’s in/out pins, the tick function inspects the pin bits, computes one tick, and returns a (potentially modified) pin bit mask.

A complete emulated computer then more or less just wires those chip emulators together just like on a breadboard.

So, my task is to replace the C64 chips with X65 ones (implementing them on the go) and wire them together on the “breadboard” of the main app code.

Implementing new chips went smoothly. There are so many chips in the toolbox that can be used as references.

The CGIA chip was implemented based on mc6847.h, which is the simplest video chip included. My implementation is a bit of a hack, not following the clean single-header-file design of the original. I wanted Emu to be as close as possible to the real hardware. Since the CGIA firmware for RP2350 is implemented in C with ASM parts, I just included the C parts in the Emu codebase (as a Git submodule) and compiled it, wrapping it in the chip emulator. The ASM parts were rewritten in C.

This idea proved a double win: Emu is as close to the hardware implementation as possible, and I found some bugs in the RP2350 firmware during Emu development.

Sound chip emulation is another story. X65 uses the Yamaha SD-1 as the FM synthesis chip. This chip is another step in the OPL line, very similar to OPL3. Unfortunately, it is not popular in the mainstream, so there are no software emulators available. We will need to implement our own.

As a stopgap, I’ve decided to include an OPL3 chip emulator in Emu to both aid SD-1 emulation development and facilitate translating OPL3 software to use SD-1 instead.

There is a well-known software emulator of OPL3: Nuked-OPL3, which has very high accuracy. So naturally, I wrapped it in ymf262.h. It turned out that it didn’t work for me - all I got were buzzing noises instead of the expected waveforms.

After a bit of trial and error, and some research, I found the ESFMu library, which is a hard fork of Nuked-OPL3 modified to emulate the ESS ESFM chip - a clone of the OPL3 chip with some extensions. After plugging ESFMu in place of Nuked-OPL3, the sound played as expected. So… we’re good to go.

The Emu emulator is starting to look like a proper X65 machine.

The chip-emulators toolbox and the sokol library used to render the emulator’s user interface natively support WASM builds for the browser. So, I created a web page with a preview of the emulator, showcasing all the available examples at: https://x65.zone/emu/

Have fun toying around. 😄