JAXE (Just Another XO-CHIP/CHIP-8 Emulator)
Brix | Space Invaders (In Debug Mode) |
---|---|
![]() |
![]() |
Black Rainbow | DVN8 |
---|---|
![]() |
![]() |
Super Neat Boy | Chicken Scratch |
---|---|
![]() |
![]() |
CHIP-8 was a virtual machine/programming language developed by Joseph Weisbecker for the COSMAC VIP in the 1970s. It was designed with 35 opcodes and resembles assembly language, but was made for the easier development of video games on the VIP.
Today, it is a popular target to be emulated because of its simplicity and charm.
Features
- Fully implemented instruction set (including S-CHIP and XO-CHIP)
- HI-RES (128x64) mode to support S-CHIP programs
- Dual display buffers to support XO-CHIP programs
- Accurate delay and sound timers
- Extended sound (though can sometimes be a bit noisy)
- Integrated graphical debugger allowing user to step forward and back through program execution
- Adjustable CPU/timer/refresh frequencies, display scale, colors, and program start address
- Toggle S-CHIP "quirks" for compatibility with a wide variety of ROMs
- Save and load memory dumps
- Unit tests for those writing a C emulator
- Emulator decoupled from any particular graphics/media library allowing for easy embedding into other C programs
Technical Info
The original CHIP-8 virtual machine was designed with the following specs:
- 35 opcodes
- 4kb RAM
- 16 8-bit general purpose registers
- 16-bit program counter, stack pointer, and index registers
- 8-bit delay and sound timer registers
- 64x32 monochrome display
- 16-key keypad (0-F)
- Program memory starting at address 0x200
Due to the way CHIP-8 was designed, the "flicker" that happens when sprites are drawn is normal. Games developed for it also rarely made any attempt to cap their frame rate due to the slow hardware of the time hence the need to artificially slow the CPU down on modern emulators.
In the early 90s, Andreas Gustafsson created a port for the HP48 calculator which was eventually superseded by S-CHIP 1.0/1.1 created by Erik Bryntse. The S-CHIP added several features as well as accidentally (or intentionally?) modifying the behavior of several original opcodes:
- 9 new opcodes
- 128x64 HI-RES display
- Persistent storage
- Modified Bnnn, Fx55, Fx65, Dxyn, 8xy6, and 8xyE instructions
With time it seems the S-CHIP became more popular and many programs were written to work with its various quirks. Thus, JAXE defaults to original S-CHIP design however many of its quirks can be toggled for improved compatibility using the flags in the Options section below.
However, recently John Earnest designed the XO-CHIP extension allowing CHIP-8 programs to take advantage of modern hardware to an extent. This extension adds several more instructions and features including:
- 7 new opcodes
- 16-bit addressing for a total of ~64kb RAM
- Second display buffer allowing for 4 colors instead of the typical 2
- Improved sound support
- Modified Fx75 and Fx85 instructions to allow for 16 user flags instead of typical 8
JAXE currently supports all of these extensions.
It should also be noted that JAXE stores its fonts in memory starting at address 0x0000 followed immediately by large fonts and finally immediately by the stack. Therefore the stack pointer initially points to address 0x00F0.
TODO
- Continue to improve sound
- Continue to immprove Windows support
- Improve build procedures
- Add more color themes
Requirements
- SDL2
- SDL2_ttf (for debug mode)
- CMake (for automatic build)
Build Procedures
Linux/Windows (MinGW)
mkdir build && cd build
cmake -B. --config Release --target jaxe ..
make jaxe
Windows (non-MinGW)
Unknown at this time. Currently the code uses the POSIX getopt() function to handle command-line arguments. To build without MinGW, remove #define ALLOW_GETOPTS
from the top of main.c which will unfortunately remove command-line arguments until I handle them in a portable way.
Unit Tests (Debug Must Be Set)
mkdir build && cd build
cmake -B. --config Debug --target test ..
make test
Run
Linux
./jaxe [options] <path-to-rom/dump-file>
./test
(for unit tests)
Windows
If built with MinGW, command line options are available:
jaxe.exe [options] <path-to-rom/dump-file>
Otherwise:
jaxe.exe <path-to-rom/dump-file>
test.exe
(for unit tests)
Options
-x
Enable compatibility mode (disables all S-CHIP quirks but keeps HI-RES and new instructions)
-d
Enable debug mode
-m
Load dump file instead of ROM
-p
Set program start address (in hex)
-c
Set CPU frequency (in Hz, value of 0 means uncapped)
-t
Set timer frequency (in Hz, value of 0 means uncapped)
-r
Set screen refresh frequency (in Hz, value of 0 means uncapped)
-s
Set display scale factor
-b
Set background color (in hex)
-f
Set plane1 color (in hex)
-k
Set plane2 color (in hex)
-n
Set overlap color (in hex)
Also includes flags for disabling specific S-CHIP "quirks" (which are all enabled by default):
-0
Disable uninitialized RAM
-1
Disable 8xy6/8xyE bug
-2
Disable Fx55/Fx65 bug
-3
Disable Bnnn bug
-4
Allow big sprites to be drawn in LO-RES mode
-5
Clear display when 00FE/00FF execute
-6
Allow sprite wrapping
-7
Disable collision enumeration
-8
Disable collision check with bottom of screen
Controls
Keyboard (This maps to the key layouts below)
1
2
3
4
Q
W
E
R
A
S
D
F
Z
X
C
V
COSMAC VIP Keypad
1
2
3
C
4
5
6
D
7
8
9
E
A
0
B
F
HP48 Keypad
7
8
9
/
4
5
6
*
1
2
3
-
0
.
_
+
Other Controls
Key | Action |
---|---|
SPACE |
Pause/Unpause |
UP |
Step Forward (DBG Mode Only) |
DOWN |
Step Back (DBG Mode Only) |
RIGHT |
Increase CPU Speed |
LEFT |
Decrease CPU Speed |
ENTER |
Save/Create Dump File |
BACKSPACE |
Cycle Color Themes |
ESC |
Reset Emulator |
Troubleshooting
- This emulator defaults to S-CHIP mode, which has become more popular since the 90s. Unfortunately, S-CHIP changed the behavior of several instructions and introduced some other quirks, making some programs developed for the original COSMAC VIP not backwards-compatible. If a ROM is not working correctly (especially one written before 1990), try enabling compatibility mode with the
-x
flag. - If running a program developed for Octo, you should also enable compatibility mode with the
-x
flag since Octo ignores all S-CHIP quirks. - This emulator defaults to 0x200 as the start address, however some programs assume other defaults (namely, those written for the ETI-660 which default to 0x600). Try to find out what default address the program assumes and set that with the
-p
option. - If a program is running very slowly, try increasing the CPU speed or even uncapping it (by setting the
-c
option to 0). Some ROMs are developed around an uncapped execution frequency and will run much more smoothly. - There are many CHIP-8 variants and this emulator does not support all of them. If a ROM still does not work correctly after trying the suggestions above, it may have been written for an unsupported variant and thus will simply not work.
Contributing
Anyone is welcome to contribute! I will try to review pull requests as quickly as possible.
License
JAXE is licensed under the MIT license so you are free to do almost whatever you please with this code (see LICENSE file).
ROMs
References
- Cowgod's Chip-8 Technical Reference v1.0
- Matthew Mikolay's Instruction Set
- HP48-Superchip Investigations
- CHIP-8 extensions and compatibility
- XO-CHIP Specification