▒▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
▒▒▒▒▒▒ ▒▒▒▒ ▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒ ▒▒▒▒
▒▒▒▒▒▒ ▒▒▒ ▒▒▒ ▒▒▒▒ ▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒ ▒▒▒▒
▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒ ▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
▒▒▒▒▒▒ ▒▒▒ ▒▒▒ ▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒ ▒▒▒▒
▒▒▒▒▒▒ ▒▒▒▒ ▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒ ▒▒▒▒
▒▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
I wrote a Chip8 virtual machine. Chip8 was implemented by a number of computers in the 70s and HP calculators in the 80s. Instead of using actual microprocessor opcodes, it was always designed to be a virtual language and be interpreted at runtime.
(A high quality video version of the gif is found here.)
This project has no third-party dependencies and renders on the terminal.
To compile:
make
To run:
./play path/to/rom.ch8
Compile and run the sanity tests (mostly for CI):
make test
To clean all object and executable files:
make clean
The keys for each rom along with their description will be listed on the right panel. Read this section only if you want to edit them. Chip8's hex keypad has been mapped to the keyboard in the following way by default:
+---+---+---+---+ +---+---+---+---+
| 1 | 2 | 3 | C | | 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 |
+---+---+---+---+ +---+---+---+---+
You can edit the keys in keypad.hpp.
Each rom (.ch8
file in roms
directory) is accompanied by a .cfg
file.
This describes each control key and sets the frequency each rom will run at. It
was necessary to set the frequency because Chip8 games used to run on different
machines over the decades. More detailed description of .cfg
files can be
found at roms/README.md
.
- CPU and renderer.
- UI including controls and debugger view including pause, exit, and stepping key.
- .cfg file each ROM; lists the controls and sets the emulation frequency.
Found at
roms/*.cfg
. - Configurable keys.
- CI.
- Sound; probably never going to implement this.
<--- Main memory --->
Read Registers
<- only -> Stack 0 1 15
+-----------+-------+ +-----------+ +--+ +--+ +--+
| | | | | | | | | | | | . . . | |
| Instr/s | Fonts | +-----------+ +--+ +--+ +--+
| | | 0x18 ^ ^
+-----------+-------+ ^ | |
0xFFF ^ 0x200 0x0 | 2 bytes 1 byte
| ^ |
| | |
Program ------+ | Delay Sound
start | | timer time
+-----------------------|------+ +---+ +---+
Program | Stack | | | | | |
counter | pointer | Index register +---+ +---+
(PC) | (SP) | (I) 1 byte 1 byte
+----+ | +----+ | +----+
| |----+ | |------+ | |
+----+ +----+ +----+
2 bytes 2 bytes 2 bytes
Renderer
+----------------------+ ^
| | |
| | 32
| | |
+----------------------+ v
<-------- 64 ---------->
+-------+
| start |
+-------+
|
+------>---------------------+
| |
+------>--------+ |
| | |
| +~~~~~~~~~+ +~~~~~~~~~~+
+---------+ | Delay & | | Key |
| Set PC | | sound | | listener |
+---------+ | thread | | thread |
| +~~~~~~~~~+ +~~~~~~~~~~+
v | |
+-------------+ | |
| | +-->--+--<---+
+-------+ | |
| Fetch | | x
+-------+ | / \
| | / \
instruction | / \
v ^ x End x
+--------+ | \ loop/
| Decode | | \ ? /
+--------+ | \ /
| | x
opcode | | y
v | |
+---------+ | |
| Execute | | +---------+
+---------+ | | Join |
| | | threads |
+----->-------+ +---------+
| |
+-----<---------------+
|
v
+-----+
| End |
+-----+
The emulator uses 3 threads in total. More detailed comments on how the fetch-
decode-execute cycle works are found in the source file chip8.cpp
. Some
forbidden unoptomised programming was used to write the instruction table but
it's my hobby project so I make the rules. More comprehensive techninal
resources are found in the reference section.
I found that without applying
SCHIP1.1's quirks, several ROMs were
crashing. These involve instructions such as 8xy6
, which is implemented as
Vx = Vy >> 1
in the classic Chip8 and as Vx >>= 1
in the newer SCHIP.
- Get rid of excessive screen flicker (f27bd6d)