I’m writing an NES emulator in Swift!
The NES uses a 6502 processor, which has 3 normal registers (a
, x
, and y
) and defines its own instruction set of 56 instructions. That makes for a lot of little tiny implementations! Addition (ADC
) and subtraction (SBC
) are probably the most complex ones, with the latter taking me some two hours to figure out simply because it’s the first time since 2004(?) that I’ve had to think about binary math and two’s complements. Luckily (or annoyingly depending on your point of view) many of the instructions are nearly identical, especially the six “transfer” instructions, which just copy values between different registers.
While the obvious thing might have been to implement each instruction as a small function on my CPU
class, I wanted to break each out into its own file to avoid making it a multi-thousand-line mess. Having each instruction implemented as its own struct also gives me the flexibility to turn each into a little state machine if I decide to make my emulator clock-accurate in the future. For the time being, each instruction fully executes on its first clock tick, and then the CPU just spins for the correct number of ticks before executing the next instruction. So my current implementation is duration-accurate, but not clock-accurate.
The Instruction
protocol that each instruction conforms to just defines an execute
method that takes the CPU as an argument. Since the instruction naturally needs to be able to fully access the CPU, one downside of this arrangement is that none of the CPU’s state can be declared private. The NES
class is the only other code with a reference to the CPU, but it does expose it as public so that I can create some debugging UI with access to its registers. Maybe I can mitigate that with some module boundaries. We’ll see.
Because I have no idea what I’m doing (and because I hope the source can be a bit of a portfolio piece to show to potential employers), I wrote unit tests for each instruction and addressing mode.
One mistake I made is forgetting that of course some instructions write to memory! Since most of the instructions just read values and store results in registers, I had the CPU’s tick
function use the current addressing mode to fetch the appropriate value and make it available to the instruction via a property on CPU
before calling the instruction’s execute
method. When I got to read-modify-write instructions like ASL
, I let the instruction return a value from execute
and then the tick function would use the addressing mode to write it back to where it came from.
But wait! There’s another complication! JMP
actually needs to read two bytes from memory. (Addresses are 2 bytes long, but memory reads and writes only operate on a byte at a time.) This means I need to store the address from the addressing mode so that the instruction can read the extra byte from the following address.
I think sometime down the road instead of having the CPU’s tick
method try to be smart and do these things, I’ll just pass the addressing mode into the instruction’s execute
method and let it read and write exactly what it needs. Whoops!
I finally finished implementing all of the instructions and I’m on to the PPU, starting with its memory-mapped registers that are exposed on the CPU’s bus. Reading and writing these registers cause side effects within the PPU! More interesting times ahead! Stay tuned for more.
If you’re interested in following along you can find the code on Github.