There’s the correct way, then there’s the right way.

25 Jun

I’ve been tinkering with my Chip-8 emulator in my spare time, and I kept circling around a bug that annoyed me but I couldn’t seem to track down.

In a few ROMs the emulator behaved strangely, it’s hard to put in more precise terms than that, which is in a large part what made it tricky to track down. Check out this image of the TicTacToe game for example.chip8_bug_tictactoe

Clearly something is going on in that top left corner. You can actually play in that square (and a few others) as many times as you like, the game won’t stop you from playing over your opponent. To further complicate matters you can’t play in the top center square, or a few others, at all.

Ok, maybe the ROM itself is broke? Well, check out Connect-4. It has a similar issue, you can play on top of your opponent here as well. Which messes up the graphics. Notice that square piece? That doesn’t belong there. That’s a square peg in a round hole.

chip8_bug_connect4

At first I thought this was probably a bug in my Chip8 graphics routine (opcode DXYN). Since Chip-8 systems used XOR drawing and set a “collision” flag if two pixels are drawn on top of one another it seemed reasonable to think that maybe I wasn’t setting that flag correcting?

After check and rechecking it a couple of times I felt certain that wasn’t the problem. Plus it was still bothering me that part of the bug didn’t seem to depend on graphics at all – like when we couldn’t play in the top center square of the TicTacToe game.

I was certain one of my opcodes were behaving incorrectly, but which one?

I decided to check them one by one against the spec to make certain I was doing exactly what the spec called for.

I pulled up Cowgod’s Chip-8 Technical Reference and set about checking each of my opcodes.

I had gotten through 33 of the 35 opcodes and hadn’t found anything wrong. But then, on the very last two opcodes I noticed something…

Fx55 - LD [I], Vx
Store registers V0 through Vx in memory starting at location I.

The interpreter copies the values of registers V0 through Vx into memory, starting at the address in I.

My code looked like this

unsigned char X = GetX(opcode);
for (unsigned char r = 0; r <= X; r++) {
  memory[I+r] = V[r];
}
I = I + X + 1;
pc += 2;

Odd, why am I modifying the I register? Well, it turns out the original CHIP-8 interrupter FX55 and FX66 modified I is the manor. However, on current implementations I is left unchanged. I had written my Chip8 emulator to the original spec, but these ROMs are expecting to be run on the more current implementations that don’t modify I.

Easy enough, I want my emulator to match what most every ROM these days expects which means I just need to delete that line in FX55 and FX66. As to why most implementations are not inline with the spec? I’m not sure, if I had to guess I would say CHIP-8 emulators took off with this bug in them, people built ROMs expecting them to work that way and when it was noticed that this deviated from the spec it was too late, but that’s just supposition.

Just because the spec says do it one way, doesn’t make it the right way to do it.

With that said, if you we’re shipping a real product you should probably take a different approach. Like maybe exposing an option to simulate using the CHIP-8 spec or the newer style. Or better yet, how about checking a bunch of commons ROMs, seeing which ones are affected by this bug (maybe by checking their use of the affected opcodes) and then saving their checksums. Then you could auto detect them and use the correct style without the user ever having to worry about it (at least for most cases).

Here’s the commit on GitHub with the changes, if your interested.