Progress on my CHIP8 “Emulator”

in #programming20 hours ago

WIP Building a CHIP8 Interpreter in C

Ever wondered how emulators work?

I have been programming a CHIP8 interpreter, because while I have used a lot of other people's interpreter and emulation code, I have never really built one myself.

CHIP8 is generally considered a great introduction to writing emulators, it's the "Hello World" of this kind of thing.

We could expand to be a true emulator if you wanted that additional challenge - CHIP8 was originally used on the COSMAC VIP and Telmac 1800, which were 8-bit computers from the mid-1970s.

Really, though, the idea of CHIP8 was mostly to make creating and porting games easier for these systems.

If you want to follow my progress, you can find the public repo for my CHIP8 emulator solution written in C over at Github.

I am coding my interpreter using the following useful reference docs:

For CHIP8 programs I am using https://johnearnest.github.io/Octo/ , though I might make my own assembler which would be another interesting challenge.

Loading a program involves reading each byte into the emulated computer's 4kb of RAM in the correct place.

Each CHIP-8 instruction is exactly 2 bytes long, and programs should be loaded into memory starting at address 0x200, so after loading that is where we need to set our Program Counter (PC) to start.

The main loop keeps reading the next instruction from "RAM", combining two bytes into a sixteen-bit value.

CHIP-8 has 35 opcodes, which are all two bytes long and stored big-endian.

Our instructions being "Big-Endian" means the first byte takes up the left 8 bits, then the second byte is put into the right-hand bits. We do this by shifting the first byte left:

combined_instruction = (current_byte << 8 | next_byte);

We have a big switch statement to parse instructions. Some start with the same number, so we have to further filter using individual nibbles.

In fact a lot of my debugging has come down to which parts of the instruction we are using at any given time, so I made these variables:

opcode = instruction & 0xF000;

rNibble = instruction & 0x000F;

reg = (instruction & 0x0F00) >> 8;

reg2 = (instruction & 0x00F0) >> 4;

data = instruction & 0x0FFF;

low_byte = instruction & 0x00FF;

For any instruction we do not yet handle, I output the details:

PC:2 Unhandled Instruction: Op:9000 Reg:0 rNibble:90 Data:90

Results so far:

Programs from the chip8 test suite and tests assembled in Octo running on my interpreter

I'm quite happy that a lot of CHIP8 test suite programs actually run on my little interpreter, but I would like to get it to the point where 64×32 games with the original set of opcodes run (no extensions).

Not sure if I will bother with sound, though!

Sort:  

This is all so far over my head! I fully support your efforts though! Keep on rocking!

It's a super, super niche thing, but because I do so much with other people's emulators it is important for me to understand how they work :)

Plus it's a neat achievement when/if it works :P

Thanks for your contribution to the STEMsocial community. Feel free to join us on discord to get to know the rest of us!

Please consider delegating to the @stemsocial account (85% of the curation rewards are returned).

Consider setting @stemsocial as a beneficiary of this post's rewards if you would like to support the community and contribute to its mission of promoting science and education on Hive.