CHIP-8 is an interpreted programming language, developed by Joseph Weisbecker and initially used on the COSMAC VIP and Telmac 1800 8-bit microcomputers in the mid-1970s. CHIP-8 programs are run on a CHIP-8 virtual machine.
This project consists of an emulator for the original CHIP-8 interpreted language. It implements some of the fundamental concepts of Computer Architecture, such as dealing with the CPU structure, instruction cycle, I/O and system frequency.
This emulator is coded using the Rust programming language.
The SDL2 library is used to handle user input, audio, and graphics.
CHIP-8 has 34 opcodes (35 actually, but one of them is ignored by modern interpreters), which are all two bytes long.
To make sure that all opcodes and the entire CPU structure work as intended, all the links at the References section can - and should - be used. They have enough information to understand how the emulator should work from start to finish.
Overall, the most important thing to understand at the beginning is probably how the fetch-decode-execute cycle works. The emulator runs in an infinite loop. In each loop, the emulator:
- Fetchs the instruction from memory at the current program counter (PC);
- Because each instruction is two bytes long, 2 should be added to the program counter so it points to the next instruction address in memory.
- Decodes the instruction to find out what it has to do;
- Executes the instruction and do what it tells the emulator to do.
In emulation projects, testing can be quite the challenge. To make sure everything worked fine, test ROMs were used while the instructions were implemented, as well as unit tests for the CPU methods and each individual instruction.
Test ROMs can be found at the test_roms/ folder in this repository, and can be run normally by the emulator just like any other CHIP-8 ROM.
The IBM logo ROM was the program that initially guided the implementation of the CPU instructions. All it does is display the IBM logo, and it only uses six instructions:
00E0 (clear screen)
1NNN (jump)
6XNN (set register `VX`)
7XNN (add value to register `VX`)
ANNN (set index register I)
DXYN (display/draw)
It allows us to quickly implement the required instructions and also test the instruction DXYN
, the most difficult instruction to implement. Making sure this instruction works properly will allow us to use SDL2 to display the results on screen, which is required by the other test ROMs.
Unit tests were created for all CHIP-8 instructions and some CPU methods, in a total of 40 unit tests available at cpu_test.rs. To run the tests, use
cargo test
All of them should pass accordingly.
To handle graphics, user input and audio, the files display_driver.rs
, keypad_driver.rs
and audio_driver.rs
were created and can be found at drivers/ in this repository. These are the only files that use SDL2 code in the project.
Even though they could be directly implemented in the main.rs
file, dividing them into their own appropriate drivers makes it so they encapsulate the third-party code from the rest of the project.
Therefore, changing these files (for example, using a library other than SDL2) shouldn't affect the project at all.
-
Clone and move to the repository by using the
git clone
andcd
commands:- If you want to clone the entire repository (all branches), you should clone it and move to the current branch by using
git clone --branch sdl2-development [email protected]:leleosilva/CHIP-8-Emulator.git cd CHIP-8-Emulator
- If you want to clone only the current branch (that uses SDL2), use
git clone --branch sdl2-development --single-branch [email protected]:leleosilva/CHIP-8-Emulator.git cd CHIP-8-Emulator
- If you want to clone the entire repository (all branches), you should clone it and move to the current branch by using
-
Build the project by entering the following command which uses Cargo, Rust’s build system and package manager:
cargo build --release
By default, it will create a binary file in ./target/release
.
This binary is completely self-contained, so it can be movd or copied to somewhere else on your computer.
From the CHIP-8-Emulator/
directory, you can run the emulator with
# Mac/Linux
./target/release/chip-8 <PATH TO ROM>
# Windows
.\target\release\chip-8 <PATH TO ROM>
If you moved or copied the binary file elsewhere in your computer, go to the directory that contains the binary and run the emulator with
# Mac/Linux
./chip-8 <PATH TO ROM>
# Windows
.\chip-8 <PATH TO ROM>
CHIP-8 uses a 16-key hexadecimal keypad labeled 0
through F
, arranged in a 4x4 grid, with the following layout:
CHIP-8 keypad | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
It’s customary to map the original keypad layout using the left side of the QWERTY keyboard. In this project, the keys used by the user have the following layout:
User keyboard | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
- Test compatibility with Windows systems;
- Add support to WebAssembly;
- Substitute SDL2 for
egui
; - Create a proper debugger with:
- A disassembler;
- An option to pause/resume the emulator;
- An option to choose new ROM files;
- An option to reload the same game;
- An option to change background and sprite colors.
Leonardo Cavalcante da Silva (@leleosilva)