CHIP-8 emulator in C

note by author @Jia Hao: This was an attempt to dig into low-level programming and to work towards creating a NES/Gameboy Advance emulator as it is my first time writing code in a low-level programming language like C (the code can be found here!). I hope you enjoy reading this as much as I did working on this!

another note by author @Jia Hao: I intend to make this into a blog series (and maybe video series). These are just the rough notes that I had taken and the process I took to implement chirp!


specifications

we have to start somewhere

CHIP-8 has the following components, which have to all be implemented in this chirp:

bits & bobs

understanding how the various components of CHIP-8 works (based on the specifications)

rendering

memory

stack

keypad

timers

instructions

emulator loop

ROM file format

process

implementing the actual emulator in C

core

  1. implement memory
    1. implemented as a uint8_t mem[4096] array
    2. indexed via hexadecimal to directly reference the notes above, e.g. starting instruction at 0x200
    3. visualized memory using string joins
  2. implement stack
    1. implemented as a regular stack with push/ pop/ peek/ is_empty/ is_full operations
    2. using a fixed size of 64 since the originally recommended minimum size is 16
  3. implement registers
    1. same exact logic as the memory, it could in-fact be a shared struct that is used across for both
  4. implement core struct for emulator state
    1. relatively simple since it’s just a single struct with the previously implemented components
    2. need to make sure that the state is properly initialized
    3. including some boolean states for whether the emulator is running since instructions will modify the emulator state directly (such as telling it to stop running)
  5. read ROM file contents
    1. when loading the rom, we use the following C pattern:
      1. fseek to the end of the file using SEEK_END
      2. fetch the size of the file using ftell
      3. rewind the file to the beginning
      4. allocate a buffer of the size of the file using malloc
      5. read the contents of the file using fread into the buffer
      6. for every section of the file, load into the emulator state
      7. close the file
      8. free the allocated buffer
  6. load fonts into memory
    1. storing the fonts as a hard-coding constant
    2. load them into the intended memory buffer area
  7. implement game loop
    1. largely similar to the emulator loop described with two problems:
      1. care for timers (must be separate from the core game loop)
      2. the native machine’s clock speed might be way faster than the CHIP-8 original clock speed
      3. algorithm to solve these described below
  8. implement CPU + timer ticks
    1. see clocks for information about algorithm, but essentially we map a duration of the system clock to the number of actual ticks to occur
    2. interleaved with instruction processing to avoid bulk processing instructions then timers
  9. parse instructions
  10. execute instructions
  11. render contents
    1. using SDL
  12. play audio through the sound timer

clocks

understanding how to build clocks in emulators and games to understand frame rate and clock speeds

not this, but sure

not this, but sure

grokking SDL

learning how SDL works (probably the most technical part of the project since I have no clue what SDL is or does)