Skip to content

kiryk/chip8c

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

chip8c

As an alternative to an emulator, this tool translates CHIP-8 binaries into equivalent C code, which can be compiled on POSIX-compliant OSes with ncurses.

This is just a proof of concept, and the way it works could be still improved (see Details).

Usage

Compiling the tool:

make

Translating a CHIP-8 binary:

./chip8c breakout.ch8

Running the above will produce 3 files:

  1. mem.h - memory map of the binary
  2. breakout.ch8.c - translated C
  3. breakout.ch8.bin - runnable binary

CHIP-8 has its own keyboard layout. To interact with the binary, use mapped keys:

1 2 3 C --mapped as--> 1 2 3 4
4 5 6 D                Q W E R
7 8 9 E                A S D F
A 0 B F                Z X C V

Some CHIP-8 executables can be found on repos like this one. The ones that were tested and work well include pong, breakout and trip8 demo.

Details

What the tool was created for, is to check whether it's feasible to decompile machine code into a long switch-case, where the switched value is the program counter register, and the cases are instruction addresses coupled with code performing register and IO manipulation equivalent to that of a given instruction set.

Insides of the resulting switch-case look like the following example:

switch (pc) {
/* ... */
case 0x0200: reg[0] = reg[6];
case 0x0202: reg[1] = 0xFC;
case 0x0204: reg[0] &= reg[1];
case 0x0206: regi = 0x30C;
/* ... */
case 0x0242: reg[0] = 0xFE;
case 0x0244: reg[9] ^= reg[0];
case 0x0246: stack[sp++] = 0x0246 + 2; pc = 0x2A4; break;
case 0x0248: reg[5] += 0x01;
case 0x024A: stack[sp++] = 0x024A + 2; pc = 0x2A4; break;
case 0x024C: if (reg[5] != 0x60) { pc = 0x024C + 4; break; }
/* ... */
}

Worth noting, that breaking out from the switch-case is required only when jumps are performed, in all other cases it suffices to allow for the default linear flow.

There are a few disadvantages of the technique:

  1. Code gets separated from data, so whatever takes advantage of von Neumann architecture won't work.
  2. A hexdump of a translated binary must be included in the resulting C file, so it could access its static data.
  3. Jumps to unexpected addresses aren't handled (odd addresses, for instance).

This implementation uses ncurses for IO, which was chosen for its popularity and simplicity, but it's not a good fit for mimicking IO of CHIP-8. For instance, the instructions EX9E and EXA1 work best if the program maintains a map of keys that are currently pressed. It seems that ncurses doesn't detect key releases, so its hard to maintain such a map.

Also, it would be nice if Unicode block characters could be used for the output, then neighbouring pairs of pixels could be packed into one of: , , and to simulate nice looking square pixels.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published