I accidentally wrote a 6502 emulator
Hobby projects are a strange thing, you never know where they’re going to lead you. When developing software professionally you’re constrained by many factors and this affects your decision-making process and the path you follow to, hopefully, complete the project.
For hobby projects, most of these restrictions go flying out of the window. There are no deadlines to meet unless you enforce them yourself. Feel like refactoring that crufty looking piece of code instead of polishing the UI? Sure why not! Just had an awesome idea for a feature that’s not in the original specification? Hell yeah, drop what you’re doing and start researching it. Nobody’s there to point the finger when you don’t finish it. As long as you have fun and learn something in the process, right?
That means it’s totally normal to start the weekend learning 6502 assembly to write a demo/game for that C64 lurking in the attic and end up working on a cycle-accurate MOS 6502 CPU emulator in C on Sunday evening. That doesn’t only happen to me, right? Right?!
All joking aside, one of my hobbies is messing about with old computers and game consoles. Cleaning, fixing, modding the hardware, collecting software. Being a software developer by trade, I thought it would be fun to write a small game for each retro-system I own. I decided to start with the first system I bought that could be considered retro at the time I bought it: the venerable Commodore 64.
Why start with the Commodore 64?
A good question, with a potentially long answer. Emotionally, it makes sense because it’s the first computer I came in contact with. Sometime in the late eighties, early nineties. I never owned one back in the day, but it was the first retro computer I purchased a few years ago. And much to my shame, I must admit I haven’t really spent much time with it. Time to change that.
It’s also one of the most popular 8-bit systems around. This means there’s no shortage of available resources covering every aspect of the system. From compilers and debuggers to programming tutorials and emulators.
Technically, it also makes sense because the MOS 6510 CPU used in the C64 is a modified form of the very successful 6502 CPU. The 6502 was used in many other systems of the time, including the Apple II2, the BBC Micro, Atari 2600, and in modified form in the Nintendo Entertainment System. As such, I hope it can act as a proverbial gateway drug to these systems.
Learning 6502 assembly
There are 2 major languages when programming on the Commodore 64: BASIC or 6502 assembly. I’m afraid being subjected to Visual Basic and VBScript as a budding computer science student has ruined my appetite for BASIC (probably unfairly) so 6502 assembly it is.
I must admit, I had more trouble getting comfortable with 6502 assembly than I anticipated. Being familiar with x86 assembly, back in the 486/Pentium days, I hoped that experience would translate better than it ended up doing.
I never worked on an 8-bit system before. The implications of that architectural limitation were bigger than I anticipated. Adding two numbers quickly becomes a big deal when the largest value you can store in a register is 256. Those 32-bit processors really spoiled me. Kids these days!
Additionally (no pun intended), the multiple addressing modes available for most instructions confused me very much. Handling the IRQ lines, reading and writing to the I/O ports of the VIC and CIA-chips, lead to a lot of head-scratching and brow furrowing.
I tried following multiple, excellent, tutorials but it never really clicked for me. Writing a 6502-emulator seems like some sort of rite of passage for a software developer. So I thought: “Is there a better way to learn about something?”. Let’s do this!
Writing the emulator
I chose C to develop the core of the emulator, basically just because I felt like it. A more hip choice would probably be to use Rust or something but I didn’t want the added complexity of learning a new programming language as well.
I started by reading the MOS Technology MCS6500 Microcomputer Family Hardware Manual and its companion, the Programming Manual. I haven’t written anything more complicated than a simple virtual machine. So I didn’t know what I was doing … good times!
For this project, I wanted to stay as true to real hardware as possible. I wanted to be able to observe the effects of changing the address bus or writing to the data bus on the rest of the system. The goal is not to write the fastest or most elegant 6502 emulator. It’s to learn about the 6502 architecture.
So I took the hardware and programming manuals and started translating what it described, to C-code that manipulates the state of the virtual CPU-registers. At first, it was a single instruction (LDA) and some unit tests. I added instruction by instruction, refactoring along the way, until I ended up with a jumble of case-statements that implemented all 6502 assembly instructions and passed all the unit tests I could come up with on my own.
Contact with the enemy
At this point, I’d had several “Aha”-moments and presumably a better understanding of the 6502. But all I really had were a few C functions that react to data on the input-pins and produce what is, hopefully, the expected 6502 behavior on the output-pins. And those unit tests? They’re just my interpretation of the 6502 programming manual. And what do I know, right?
High time to introduce some real code to my 6502 emulator, code-named Dromaius. But how? All we’ve got is a CPU. Ok, let’s whip up some simple ROM and RAM-modules and a very (very) basic UI, and we’re ready to rumble. First up was a simple program that loads the A-register and writes it to a fixed memory location. That seemed to run ok. Much joy was had! Let’s make the program a bit more interesting, while we’re on a roll, and increment a memory location. Didn’t work - depressed now. Just kidding. Found a bug that kept the RAM module enabled too long. A one-line fix later and we’re back to being happy!
I quickly realized this process would take too long to iron out all the bugs, assuming I’d be able to stumble upon them all myself. So I started looking around online and came across the excellent functional tests for 6502/65C02 type processors by Klaus Dorman (GitHub repo). I found a few more bugs and more importantly some areas where I misinterpreted the 6502 Programming Manual. Soon, my little emulator was passing all the tests. Except for the decimal mode arithmetic … that required some more head-scratching and brow-furrowing but eventually I hammered it into submission.
I feel like I accomplished the goals I set for myself. I learned quite a bit about the 6502 and, as a side effect, I ended up with a cycle-accurate emulation of the 6502. I’m not entirely satisfied with the structure of the implementation. Or more accurately, the lack of decent structure in the mess of nested switch-statements. I have ideas to tackle that and implement it in a much nicer and, potentially, more efficient manner. But it’s working now and there are a lot of other interesting this to add to it.
There’s only one chip really driving the databus in the emulator right now. The ROM- and RAM-modules are basically just a bit of combinatorial logic. I want to try emulating a full computer (probably a Commodore PET) first because I fear the synchronization between more clock-based chips might pose some problems. Implementing one of the other chips used in the PET will be the next big job. But that will be for another blog post.
If you stuck around and reached this point of the post, you have my sincerest respect. It took me multiple sessions to get to this point :-)
Thank you, and until the next!