Nicolas Allemand

Music, game dev and emulation.

Hello everyone, it has been a while since my last post, I hope to make up for it today with a substantial article about one of my latest works —a journey I followed to make a complete emulator.

After my adventures interpreting the CHIP-8, I was anxious to get my hands on some real systems. I didn't feel confident enough to start a NES emulator, so I looked up on emutalk.net to see if they had any ideas. I stumbled on what seemed to be a good in-between CHIP-8 and GameBoy, so I started... a Space Invaders emulator.

Space Invaders is a famous arcade video game developed by Taito in 1978. It is a simple system that features an Intel 8080 CPU (one of the ancestors of the x86 processor family) and a 256×224px monitor.

The video emulation is fairly straightforward, actually one only need to read the 256 * 224 / 8 = 7168 bytes in the video RAM, each bit representing a pixel (0 for off pixel, 1 for lit pixel). The colours, on the original machine, were simulated with a transparent overlay on the monitor.

As expected, most of the work was spent emulating the processor. First of all, I needed a structure to hold all the data the machine needs:

  • two 16-bit values: the program counter, which stores the adress of the next instruction to be executed; and the stack pointer, which represents the current adress in the stack
  • seven 8-bit registers, called A, B, C, D, E, H and L
  • five flags: the sign flag, zero flag, half-carry flag, parity flag and the carry flag
  • some memory to store the contents of the Space Invaders roms

This gives us something along those lines:

struct i8080 {
    uint8_t memory[0x10000];
    uint8_t A, B, C, D, E, H, L;
    bool S, Z, AC, P, CY;

    uint16_t pc;
    uint16_t sp;
};

Great, we now have our structure. At the beginning of the program, we need initialise all those variables —filling everything up with zeroes—, and load up the Space Invaders roms between 0x0000 and 0x1FFF in memory.
Then, we need to actually execute some processor instructions. This is made by "the loop", which is the heart of an emulator: it is a loop which basically executes an instruction and increment the program counter by one.
To know which instruction to execute, we read a byte in memory at the address pointed by the program counter; and execute the corresponding instruction: for example, the byte 0x87 is the opcode ("operation code") for the instruction ADD A.
Here is a pseudo-code of what it looks like:

i8080 machine;
i8080_init(&machine); // initialize structure + load rom in memory

while (1) {
    // retrieving the instruction to be executed
    uint8_t opcode = machine.memory[machine.pc];
    // incrementing the program counter
    machine.pc = machine.pc + 1;
    
    // executing the instruction
    if (opcode == 0x87) { // ADD A
        // do something
    }
    // ... other opcodes ...
}

After the base was set up, I needed to implement the whole 255 instructions of the Intel 8080 CPU. Most of them were easy to implement: add one to register A, substract register B to register A, execute a binary OR on register D...

Let me show you an example code of the implementation of the instruction ADD A:

if (opcode == 0x87) { // ADD A
    uint16_t result = machine.A + 1; // calculating `A + 1`
    machine.S = (result & 0x80) == 0x80;
    machine.Z = (result & 0xFF) == 0;
    machine.AC = (i8080.A & 0xF) > (result & 0xF);
    machine.P = parity(result);
    machine.CY = result > 0xFF || result < 0x00;
    machine.A = result & 0xFF; // setting register A to the result
}

You may notice that most of the work here is setting up the flags correctly, according to the result of the operation. Flags are usually used to check the result of a previous operation, and are used in some instructions: for example, the JNZ will jump to an address if flag Z == 0.

The instructions themselves are usually really simple: without flags, the previous intruction would just be machine.A = (machine.A + 1) & 0xFF; for example.

Of course, some of them are more complicated, and were pretty hard to code, let alone understand (I'm looking at you, DAA). With the help of the 8080 Assembly Language Programming Manual though, it was possible for me to implement these without much difficulty.

At this point, I finally finished emulating the CPU. I quickly wrote a video renderer in OpenGL —which basically reads from the video RAM between 0x2400 and 0x3FFF and displays a pixel whenever a bit in memory is equal to 1—, loaded up the Space Invaders roms, and...

si_no_interrupts-1 Ta-da~

After all these hours "blind-coding" something, it was nice to finally see something drawn on the screen. I waited for a couple of seconds... but nothing happened. The emulator was stuck.

I quickly realised that I forgot to implement the hardware interrupts, and that was the reason why the emulator stayed still like a picture. To explain it simply, interrupts are signals sent by the hardware to the processor to let it know something happened: for example, if the screen finished drawing, an interrupt might be sent.

It looked like Space Invaders generates two interrupts alternately every ~16666 cycles: to emulate this, I just had to execute a CALL instruction to a specific adress in memory when necessary. After implementing that, the menu finally displayed, but...

a glitched Space Invaders emulator Whoops.

What's happening? Where did I went wrong?

There had to be a problem somewhere in my CPU emulation. I tried to re-read my whole implementation to see if there was any obvious typos or semantic errors, without any success.

Then, I started to look up at other emulators. The first thing I tried is to boot up a working emulator, execute one instruction then retrieve the values of the registers / flags; and check if the values in my emulator matched. Of course, this method; which works perfectly well, turned out to be extremely time (and mind) consuming.

I noticed that most of the other projects had some tests roms; which basically are roms that test the well-being of the machine —or in that case, of the emulator—: it tries to execute a lot of instructions, and checks whether the machine holds the expected values.

I modified my program to run these test roms; and a couple of hours later —after debunking all the various typos and errors—, the tests finally passed, and I was greeted by a beautiful screen:

working Space Invaders screenshot Wooo

In retrospect, I should have started with test roms from the very beginning, that would have avoided me to waste hours...

After that, even if most the machine was done, a couple of bits were still missing (Space Invaders related). I won't go into great detail for these, as they aren't that interesting to talk about:

  • I/O ports emulation: some basic I/O ports that manage the player input —and some other little things—
  • emulation speed: in the Space Invaders machine, the Intel 8080 runs at 2MHz, meaning that I needed to run exactly 2000000 instruction cycles per second, so I needed to modify a bit my emulator in order to emulate the machine at the perfect speed

After all that, I ended up with a working emulator that executed the original Space Invaders code from 1978. You can grab the source code here (tested on macOS and Linux).

Overall, the experience was really entertaining and informative. Computer processors now look a little bit less like mysterious electronics filled with black magic. I would recommend emulating such a system to anyone interested in a fun way to learn how computers work.

See you soon with another emulation project...

Screenshot of BRIX The good ol' BRIX

Well, it's been a long time since I had this much fun programming something.

I've always been interested in emulation, but I never really took the time to see how it works; I simply felt that it was out of my league. After reading some good articles, I realized I could try emulating the simplest system of them all : the CHIP-8.

Technically speaking, the CHIP-8 is not a real machine, it's a interpreted programming language that anyone can implement. It contains 35 instructions, a couple of registers, and only one drawing method; making it really easy to emulate.

After a couple of nights trying to debug some bitwise operations, I managed to complete the emulator. I really encourage all of you to implement your own, as it makes you understand a little bit more how CPUs/computers work (and that makes for a good practice of bitwise operations). Almost anyone can do this with a little time! You can grab mine here.

So... What's next? GameBoy?