Home

Awesome

Cadmium

A CHIP-8 emulation environment written in C++ with a raylib backend.

License: MIT Supported Platforms CMake Build Matrix Latest Release Tag

<!-- TOC --> <!-- TOC -->

Introduction

CHIP-8 is maybe the first breed of what is today called a "fantasy console". The first opcode interpreter was written by Joseph Weisbecker for the "COSMAC" CDP1802 cpu that he developed at RCA and was used in machines like e.g. the COSMAC VIP and the Telmac 1800.

CHIP-8 is today seen as the "Hello world" of emulators, so the first suggestion if someone wants to get into emulator coding is to write a CHIP-8 the get the feeling for it. I already had done some work on emulators and wrote my own implementation of a Commodore 64 emulator in C++, so one could say that I had no reason to actually make a CHIP-8 one, but on a longer weekend off, I stumbled across the topic, I knew the system from my trusty old HP-48GX, during my study times in the 1990s, so I felt it would be fun to try to cobble an implementation together in a few hours. It worked quite well, and as I was using raylib for some tools and took part in a raylib game jam, I saw this as a good fit.

Cadmium debug view

I had so much fun with this project that I added emulation of the original COSMAC VIP and the DREAM6800 to the project, to allow using those to run the historical CHIP-8 interpreters from the past and also to allow execution of hybrid CHIP-8 programs that contain a mix of CHIP-8 and assembly subroutines using the rarely supported 0nnn opcode. So this project explores the corners of historic CHIP-8 as well and sometimes goes a bit beyond it.

Online Version

Emscripten builds are available here for testing:

Simply drag rom files (.ch8, .hc8, .ch10, .c8h, .c8e, .c8x, .sc8, .mc8, .xo8) or Octo sources (.8o), or Octo cartridges (.gif), or even COSMAC VIP programs (.bin or .ram) onto the window to load them.

Features

The emulation behavior used in Cadmium is based on opcode information documented in the opcode table, various VIPER magazine issues, the CHIP-8 extensions and compatibility pages and tests on various emulators and the HP-48SX/HP-48GX calculator implementations as well as analyzing the historic interpreters' code and running them on COSMAC VIP and DREAM6800 (but both emulated, as I sadly don't have access to real hardware of those yet).

Supported CHIP-8 variants

The emulation is based on different emulation cores and, depending on the core, on a set of "quirks" named options that go along with the core. To lessen the burden to remember the combinations, Cadmium uses "Behavior Presets" to combine a core, some settings and set of quirks to easily switch between CHIP-8 variants. The naming conventions adapted are based on the list put together by Tobias V. Langhoff at https://chip-8.github.io/extensions/ and for the classic COSMAC VIP based variants it is mainly based on the VIPER magazine where those interpreter variants where published.

The Supported presets are:

Whith CHIP-8-STRICT Cadmium might be the first high-level emulator that has a core that can execute CHIP-8 with the behavior and timing of the initial VIP CHIP-8 interpreter without actually emulating the actual COSMAC VIP. While this core, like other HLE emulators, can not execute machine subroutines, it emulates the exact timing behavior of every instruction and the overall frame timing to reach cycle exact accuracy compared to the real machine. The main difference to the VIP-CHIP-8 preset is, that this one needs quite less host CPU resources, but as said, can't run hybrid programs.

The SUPER-CHIP COMP or SCHIPC is a more generic variant that is similar to Chromatophores SCHPC/GCHPC variants of SCHIP1.1 to allow more modern games (often developed on Octo) that target SuperCHIP to run without tweeking some quirks that, while correct for the original SCHIP1.1, are not common in modern programs.

The MODERN-SUPER-CHIP is more or less Octo's interpretation of SUSER-CHIP and what Timendus test suite v4.1 checks for as modern SCHIP.

The VIP-CHIP-8 variant presets activate a core that is emulating a COSMAC VIP driven by a CDP1802 CPU with 4k RAM, to execute original CHIP-8 interpreter variants to allow more accurate emulation of classic CHIP-8 and even allow hybrid roms (.hc8) that contain CDP1802 parts to execute on Cadmium. The currently available behaviors are classic CHIP-8, CHIP-8 Two Page Display (TPD), HI-RES-CHIP-8 (four page display, FPD), and CHIP-8X with the VP-590 Color Board and the VP-595 Simple Sound Board attached, as well as a TDP and a HI-RES version of 8X using that hardware.

The CHIP-8-DREAM preset activates a core that is emulating a DREAM6800 driven by an M6800 CPU with 4k RAM, to execute the original CHIP-8 CHIPOS kernel and run an accurate emulation of DREAM6800 CHIP-8. This core also allows hybrid roms that use machine code parts.

There now also is the possibility to select a COSMAC VIP without any CHIP-8 interpreter. Cadmium then falls back into a raw 1802 COSMAC VIP emulation that allows to load and run games and programs made for the VIP that don't use CHIP-8.

Multi Architecture Debugging

Cadmium allows for those presets, that emulate actual hardware, to debug seamlessly on the CHIP-8 opcode level or the backend CPU assembly level:

Cadmium emulating DREAM6800 Cadmium emulating DREAM6800

Breakpoints and single stepping works in both views, the selected instruction tab defines the logical entity the debug buttons work on, the register view shows the registers of that entity. Breakpoints of the hidden entity still work and the tab switches to the entity that hit the breakpoint.

Note: Be aware, that in COSMAC VIP 1802 mode, while breakpoints and single stepping works fine, there is no step-over/step-out support as there is no defined way of the 1802 CPU to enter subroutines and return, and no stack in the sense most other CPUs have it. The M6800 debugging of the DREAM6800 side has those features enabled, as have all CHIP-8 modes, even the VIP one.

Quirks

Emulation uses a number of configurable "quirks" or options, to allow a wide range of roms to work with it. Contrary to some other sources, Cadmium sees the initial original VIP behavior as the reference, so disabling all following options gives a basic VIP CHIP-8:

Keyboard Shortcuts

FunctionWindows/LinuxmacOS
New<kbd>Ctrl</kbd> + <kbd>O</kbd><kbd>Cmd</kbd> + <kbd>O</kbd>
Open File<kbd>Ctrl</kbd> + <kbd>O</kbd><kbd>Cmd</kbd> + <kbd>O</kbd>
Save File<kbd>Ctrl</kbd> + <kbd>S</kbd><kbd>Cmd</kbd> + <kbd>S</kbd>
Key Map<kbd>Ctrl</kbd> + <kbd>K</kbd><kbd>Cmd</kbd> + <kbd>K</kbd>
Quit<kbd>Ctrl</kbd> + <kbd>Q</kbd><kbd>Cmd</kbd> + <kbd>Q</kbd>
Execution
Run/Play<kbd>F5</kbd><kbd>F5</kbd>
Stop/Pause<kbd>Shift</kbd> + <kbd>F5</kbd><kbd>Shift</kbd> + <kbd>F5</kbd>
Step Over<kbd>F8</kbd><kbd>F8</kbd>
Step Into<kbd>F7</kbd><kbd>F7</kbd>
Step Out<kbd>Shift</kbd> + <kbd>F7</kbd><kbd>Shift</kbd> + <kbd>F7</kbd>
Editor
Find<kbd>Ctrl</kbd> + <kbd>F</kbd><kbd>Cmd</kbd> + <kbd>F</kbd>
Replace<kbd>Ctrl</kbd> + <kbd>R</kbd><kbd>Cmd</kbd> + <kbd>R</kbd>
Copy<kbd>Ctrl</kbd> + <kbd>C</kbd><kbd>Cmd</kbd> + <kbd>C</kbd>
Cut<kbd>Ctrl</kbd> + <kbd>X</kbd><kbd>Cmd</kbd> + <kbd>X</kbd>
Paste<kbd>Ctrl</kbd> + <kbd>X</kbd><kbd>Cmd</kbd> + <kbd>X</kbd>

Command-line

Cadmium allows to select the CHIP-8 variant on startup via the preset parameter and quirk options. For that to work you need to give the preset first and then each quirk option can either implicitly flip the quirk to the negated one of the preset, or you can use them with an optional true, on, yes for activating the quirk or false, off or no to disable it. For example cadmium -p chip8 --instant-dxyn will start with a classic CHIP-8 that does not wait for vertical blank on sprite draws.

USAGE: bin/cadmium.app/Contents/MacOS/cadmium [options] ...
OPTIONS:

General Options:
  --draw-dump
    Dump screen after every draw when in trace mode.

  --opcode-json
    Dump opcode information as JSON to stdout

  --random-gen <arg>
    Select a predictable random generator used for trace log mode (rand-lgc or counting)

  --random-seed <arg>
    Select a random seed for use in combination with --random-gen, default: 12345

  --screen-dump
    When in trace mode, dump the final screen content to the console

  --test-suite-menu <arg>
    Sets 0x1ff to the given value before starting emulation in trace mode, useful for test suite runs.

  --trace-log
    If true, enable trace logging into log-view

  -b <arg>, --benchmark <arg>
    Run given number of cycles as benchmark

  -c, --compare
    Run and compare with reference engine, trace until diff

  -h, --help
    Show this help text

  -p <arg>, --preset <arg>
    Select CHIP-8 preset to use: chip-8, chip-10, chip-48, schip1.0, schip1.1, megachip8, xo-chip of vip-chip-8

  -r, --run
    if a ROM is given (positional) start it

  -s <arg>, --exec-speed <arg>
    Set execution speed in instructions per frame (0-500000, 0: unlimited)

  -t <arg>, --trace <arg>
    Run headless and dump given number of trace lines

Quirks:
  --allow-color
    If true, support for multi-plane drawing is enabled

  --allow-hires
    If true, support for hires (128x64) is enabled

  --cyclic-stack
    If true, stack operations wrap around, overwriting used slots

  --dont-reset-vf
    If true, Vf will not be reset by 8xy1/8xy2/8xy3

  --extended-display-wait
    If true, Dxyn might even wait 2 screens depending on size and position

  --half-pixel-scroll
    If true, use SCHIP1.1 lores half pixel scrolling

  --has-16bit-addr
    If true, address space is 16bit (64k ram)

  --instant-dxyn
    If true, Dxyn don't wait for vsync

  --jump0-bxnn
    If true, use Vx as offset for Bxnn

  --just-shift-vx
    If true, 8xy6/8xyE will just shift Vx and ignore Vy

  --load-store-dont-inc-i
    If true, Fx55/Fx65 don't change I

  --load-store-inc-i-by-x
    If true, Fx55/Fx65 increment I by x

  --lores-dxy0-width-16
    If true, draw Dxy0 sprites have width 16

  --lores-dxy0-width-8
    If true, draw Dxy0 sprites have width 8

  --mode-change-clear
    If true, clear screen on lores/hires changes

  --only-hires
    If true, emulation has hires mode only

  --sc11-collision
    If true, use SCHIP1.1 collision logic

  --wrap-sprites
    If true, Dxyn wrap sprites around border

  --xo-chip-sound
    If true, use XO-CHIP sound instead of buzzer

...
    ROM file or source to load (`.ch8`, `.hc8`, `.ch10`, `.c8h`, `.c8e`, `.c8x`, `.sc8`, `.mc8`, `.xo8`, `.gif`, `.bin`, `.ram`, or `.8o`)

Versioning

Cadmium uses version numbers to communicate the difference between releases and work-in-progress builds. Only even patch versions will be used for releases and odd patch version will only be used for commits while working on the next version. So a version like v1.0.1 can vary in features and behavior as it is the changing main branch head between v1.0.0 and v1.0.2.

Compiling from Source

Cadmium is written in C++17 and uses CMake as a build solution. To build it, checkout or download the source.

Linux / macOS

The Linux build of Cadmium has the same prerequisites that raylib has and as thus the following packages are expected to be installed:

Additionally, if building for Wayland, one needs wayland-devel libxkbcommon-devel wayland-protocols-devel and add the -DUSE_WAYLAND=ON option to the initial CMake call.

For macOS, only the Xcode commandline tools and CMake are needed.

Open a terminal, enter the directory where the code was extracted and run:

cmake -S . -B build

to configure the project, and

cmake --build build

to compile it.

Windows

Currently, Cadmium is not being able to compile with MSVC++ so the recommended toolchain is W64devkit. I might try to make it compile on MSVC++, but I am not working on that in the near future. That being said, I would not per-se reject PRs helping with this.

export PATH="$PATH;C:/Program Files/CMake/bin"
cmake -G"Unix Makefiles" -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DGRAPHICS=GRAPHICS_API_OPENGL_21 -S . -B build-w64dev

Build for Web

This has only been tried on macOS yet, you need emsdk and cmake installed, and I expect it to work on Linux the same way.

cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=<path-to-emsdk>/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake
cmake --build build

Used Resources

Information

Other Emulators used for Verification

Libraries

Special Credits

Cadmium started as a "Well I guess I should at least implement CHIP-8 once" project, after I already privately had fun writing emulators But the combined early reactions from the raylib Discord and the Emulation Development Discord gave me so much fun that I started to dig more into the subject. So first of all a big thank you to all those who pushed me with their nice comments and inspirational remarks, I can't name you all, but it really did kick off this project.

I still want to give out some explicit thanks to:

FAQ

Why the name Cadmium?

The first time I got into contact with CHIP-8 was with Super-Chip on an HP-48 calculator during my CS studies. The base of that was the CHIP-48 variant, named after the calculator. I think the reliving of CHIP-8 on these calculators was one of the things that helped CHIP-8 survive the time from the seventies until today. Cadmium is an element with the atomic number of 48 in the periodic table of elements, so that made me chose it as the name reference for this project.

Why the pixel look?

Cadmium is about emulating and developing for CHIP-8 and its variants, a platform that has a resolution of traditionally 64x32 pixel, the "hires" mode has 128x64 pixels and even MegaChip8 only 256x192 pixels, so if you hate seeing pixels, this might not be the platform for you. :wink: Jokes aside, I wanted Cadmium to have an original and recognizable look. Many emulators use the absolutely great Dear ImGui for the UI, and the fact that a ready-to-use memory editor exists for it helps a lot, getting something professionally looking done fast. While there is nothing wrong with that, and Dorito another CHIP-8 IDE that I only came to know after I already had editor and assembler working, is a really great example of what can be done that way, I still think there is not much individually recognizable between the look of these emulators. One can argue that standardization is a good thing, and I can see that, I just didn't feel like adding one to the list. So I guess Cadmium is for people that can appreciate this individuality and raygui, the raylib extension that is behind many widgets of Cadmium is the way to get this pixel look.

Which font is that?

Cadmium's UI uses a handmade font heavily inspired by the 5x8 pixel font integrated in the Thomson EF936x video chip that was used in an extension card of the NDR-Klein-Computer, a DIY computer that could be build following a german educational tv program in the eighties. The font is build in an ASCII file in the tools folder through a commandline tool and the generated array is embedded into the src/cadmium.cpp source file. The chip originally only has 95 characters and I created the basic set and filled up the latin-1 codepage characters and some additional unicode code points. I think its historic source and its look add to the unique look and feel of the Cadmium UI, but I can agree that it is a matter of taste. :wink: