C++ Chip8 Interpreter & hardware implementation – Part 1: How to debug an emulator

CHIP-8 is an interpreted programming language which was initially used in 8-bit microcomputers. Nowadays it serves as a great project in order to understand the architecture and inner workings of a computer. This post series will share the development of an interpreter for CHIP-8 written in C++ with SFML and Qt user interface. Furthermore, we will latter port this interpreter into real hardware so we can carry it outside in our pocket!

The source code can be found in the following GitHub repository:

https://github.com/scalableprototyping/chip8

The interpreter was based on the documentation provided by:

http://devernay.free.fr/hacks/chip8/C8TECH10.HTM#8xyE

The first stage of the project was to digest the information and to split the work. The system architecture can be divided in the following blocks:

We need to keep a modular approach in order to facilitate the replacement of a building block. For the desktop version of the interpreter, the SFML library was used to implement the keyboard input, speakers and display. Later we decided to provide a Qt interface to load roams and change different options. We ended up porting the screen to Qt too.

This modular approach is key in order to be able to replace the building blocks with a different implementation when we port our simulator to hardware. The idea is to replace the emulator display with a real OLED, as well as the keypad input and speaker with real buttons and a buzzer.

Once we had implemented the blocks and written test cases to ensure they were all working as intended, we implemented the instruction cycle and the different operational codes of the interpreter.

After many hours of development, we finally were able to press the play button. The result; a completely not working CHIP-8 interpreter!

Perfectly broken CHIP-8 interpreter

And here is where the fun begins. The most challenging part of implement an emulator is figuring out why it is not working!

If you try to implement your own version, you will most likely find your self in this situation.

The best approach to tackle this problems is to set test cases that isolate the different functionality. We first started with the simplest ROM we could find, a maze generator. We can use the xxd utility to display the binary content of the file as hexadecimal values

xxd -c 2 maze_rom.ch8
00000000: 6000  `.
00000002: 6100  a.
00000004: a222  ."
00000006: c201  ..
00000008: 3201  2.
0000000a: a21e  ..
0000000c: d014  ..
0000000e: 7004  p.
00000010: 3040  0@
00000012: 1204  ..
00000014: 6000  `.
00000016: 7104  q.
00000018: 3120  1 
0000001a: 1204  ..
0000001c: 121c  ..
0000001e: 8040  .@
00000020: 2010   .
00000022: 2040   @
00000024: 8010  ..
00000026: 0a    .

It’s a quite short program, but still, translating each opcode manually is quite a cumbersome task. The way to go is to develop a disassembler, luckily we found a very nice one which you can get from:

https://github.com/mwales/chip8

The results:

0x0200	mov v0, 0x00
0x0202	mov v1, 0x00
0x0204	mov I, 0x0222
0x0206	rand v2, 0x01
0x0208	skipnext_eq v2, 0x01
0x020a	mov I, 0x021e
0x020c	draw_spirte xreg=v0, yreg=v1, h=4
0x020e	add v0, 0x04
0x0210	skipnext_eq v0, 0x40
0x0212	jmp 0x0204
0x0214	mov v0, 0x00
0x0216	add v1, 0x04
0x0218	skipnext_eq v1, 0x20
0x021a	jmp 0x0204
0x021c	jmp 0x021c
0x021e	mov v0, v4
0x0220	call 0x0010
0x0222	call 0x0040
0x0224	mov v0, v1

Much easier to read. Finally we spot that the draw sprite instruction wasn’t correctly implemented. After fixing this issue we finally got our maze:

A CHIP-8 maze. Beauty

Time to test something a little bit more demanding. We tried to run the Space Invaders ROM, which can be found here:

https://github.com/dmatlack/chip8/tree/master/roms

The game was running perfectly fine, the title screen shown up and we could start the game. But… something funky happened. If you shoot the second enemy, the third one and forth one would disappear, and if you would shoot the first one… they would all revive!

How can we find what is wrong… We had to add additional debugging tools to our simulator, and so we added controls to our Qt interface to stop the interpreter and to step its execution while also providing information of the different registers.

This way, we translated the disassembly into more readable pseudo-code and figured out what the game was trying to do when the collision of the bullet was happening.

CHIP-8 Space Invaders

This way we were able to translate the logic of the game and figure out why the wrong enemies were being deleted when the bullet hit.

Excerpt of the disassembler analysis

We figured out that the problem was the shift instruction, which its definition in the documentation we were using was wrong. So we compared with other documentations and updated the code appropriately.

So far, the different ROMs that we have tested work perfectly fine! We observed some flicker of the pixels in most of the games. This might be due to the fact that pixels in old screens had a pixel response delay, so the flickering didn’t occur in those screens. In order to emulate the effect, we added a delay during which the pixel fades out to the off state instead of instantaneously switching off. The result was great, and so we finalized our first version of the emulator. Time to move into porting it to hardware so we can carry it around.

Leave a Reply