It’s been a (long) while since I blogged. I thought I’d break the silence by talking about a fun little project I started.
I was working on a 2d physics based game and was getting frustrated by my own lack of maths knowledge. One night I watched One Lone Coder’s video series on building a NES emulator and it triggered a something of a nostalgia vibe in me.
Growing up, we never had a game console - instead my folks bought a ZX Spectrum +3. Although I was about 8 at the time, having a strange typewriter hooked up to the TV was fascinating to me. I eventually learned Sinclair BASIC and my programming life was kicked off.
The OLC NES emulator videos sparked off a very silly little idea - “I’m going to write a spectrum emulator!”.
Not a Speccy
I needed a name for my new git repository - “Not a Speccy”, thus “neccy” was born.
I’m coding neccy in C++ and am using the olcPixelGameEngine for the basic framework. I picked it as it seemed to be a nice little single header library and it alls all the tedious “new project” guff out of the way. I’ve not felt the need to move from it yet, so I will likely stick with it until something changes. Thanks to David (javidx9) for this little library, it has been very helpful.
Writing a Spectrum emulator naturally involves emulating the CPU, a Zilog Z80 processor. For an 8-bit processor there are actually quite a few instructions - especially if you try and emulate all the undocumented ones.
My emulation of the Z80 has been re-written 3 times so far on this project. I first tried to code-generate it from C#, which ended up in a bit of a disaster. The second variant I threw away as I was making too many assumptions and tried to over-generalise the ALU logic. This current version is “ok”, but needs some cleanup.
My emulation is very crude at present. I’m not simulating the various T & M states in the CPU, instead choosing to do all the fetch, decode and operation code at once and doing nothing for the rest of the cycles. In future this may change, but it’ll do for now.
Emulation is tough
If I’d realised how tough it was to write an emulator, I probably wouldn’t have started the project. However now I have, I’m pretty hooked on it.
For starters, you have to learn a lot about the machine you’re emulating. You have to understand the guts of the CPU, the memory maps used, how the screen is rendered, the various IO port mappings to handle peripherals; then there’s all the timings and everything else to get stuff working.
When I started the project, I realised I’d need to visualise what was going on. So the very first thing I ended up writing was actually a memory viewer and disassembler.
From here, I can see the state of the CPU and look at the program that is being executed. I started out writing my own little test assembler routines, but realised very quickly I needed something “real”. From here, I started to try and run the 48k Spectrum ROM.
I picked the 48k ROM as it’d be simpler than the later 128k models of the Spectrum, which had memory paging and better sound - if I ever get this thing “working” I’d probably try and progress to the 128k model Spectrum - but let’s not run before we can walk.
Running the ROM
I ended up deciding to implement the parts of the emulator as I went; adding the instructions as I needed them in order to run the ROM.
The this point I realised that I had to start actually understanding the programs I was running, which meant actually being able to read the disassembly of the ROM itself. Thankfully Skoolkit has a great 48K ROM disassembly, which has helped immensely.
When got to the point of the ROM that was clearing the screen, I decided to figure out how the Spectrum video memory worked.
Eventually, I was able to load a scr format file of my favourite game, Uridium.
This was a very exciting milestone in the journey and the first time that I felt I was doing something right.
After this I had the next milestone in sight - I wanted to see the iconic copyright message text.
It turns out this was actually a while off; mostly due to lots and lots of little bugs and glitches in my Z80 emulation. Little things catch you out here - not setting the flags correctly, not treating 16 bit numbers with the correct endianness (which caused a stack stomp) forgetting that jump relative instructions need a signed operand and the one that took me far to long to figure out, a bug where I was treating
LD BC,(NN) like
LD BC,NN. Essentially operating on a pointer value instead of following the indirection.
Finally after lots of swearing and frustration I got to the milestone I set.
I’m currently implementing the Keyboard IO with the aim that I can try and use Sinclair BASIC for the first time.
As you can see though, there’s a few glitches…
One thing about writing an emulator is that it’s a case of fixing issue after issue, glitch after glitch… It’s frustrating at times (ok most of the time), but very satisfying when stuff starts to work.
My next milestone is to get Sinclair BASIC working. After that, who knows - I’ll probably try and go for sound and then onto trying to run a game.
It’s a long journey ahead.