A cross-platform installer for the ModRetro Chromatic that programs both the MCU (ESP32) firmware and the FPGA (Gowin GW5A) bitstream in one step — the same job the official updater does, built from the open-source release artifacts.
It ships as a single-file, self-contained executable per OS (the whole .NET runtime and Avalonia UI are bundled inside; only the native flash library and the firmware payload sit next to it):
| OS | Artifact |
|---|---|
| macOS | Chromatic Installer.app (arm64 & x64) |
| Windows | ChromaticInstaller.exe (x64) |
| Linux | ChromaticInstaller (x64) |
Note: This is not official Chromatic software; this is a hobby expansion of it.
For more information about the official ModRetro Chromatic hardware, please visit ModRetro.com. To revert back to official Chromatic firmware, use the official Chromatic updater.
Highlights: Super Game Boy with basic SFX support and Overclocking are here!
- Easy Setup: Added the new Chromatic Installer for a streamlined, user-friendly installation process.
- Super Game Boy (SGB) Support:
- Added SGB Palettes.
- Added Basic SGB SFX, including Pauline's cry in Donkey Kong '94 and sound effects for Kirby's Dream Land 2.
- Note: Your MCU must be updated to support SGB SFX.
- Overclocking: Introduced 2x and 4x speed modes. Note: Overclocking is defined here as reducing game slowdown. It does not do fast-forward or increase the overall speed of the game, as we are limited by the read speed of the cartridge.
The FPGA chip has reached 97% utilisation and is now routing and logic bound. This hardware limitation means adding new features is no longer feasible, and this sgb_sound branch/project is final. It has all the features intended for this expansion.
Please read carefully before using the new overclocking features.
- General Instability: Consider Overclock mode to be inherently unstable at all times, especially when running at 4x speed.
- Menu Boot Failures: Do NOT use 4x mode while in the EverDrive menu, or your games will fail to boot. It is strongly advised to only enable 4x mode after you are actively running a game.
- SD Card Corruption Risk: Changing the overclock speed during a card read or write may cause severe system instability. Timing issues with EverDrive carts during these states can result in SD card corruption.
- Manual Precautions: Although the system logic automatically checks for cartridge activity, you should manually ensure no speed changes are made during read/write operations as an extra precaution.
(Note: No liability is accepted for potential data loss or SD card corruption).
The installer always flashes the MCU before the FPGA. This order is deliberate: once a custom FPGA bitstream is programmed, the FPGA can block USB flashing of the ESP32 until the device is returned to stock (see NPisor/chromatic_fpga_accessibility). Updating the MCU while the previous FPGA is still in place is therefore the safe sequence. Both steps are idempotent, so re-running the installer is always a valid recovery path.
- MCU flash — The C# app P/Invokes a small native helper library
(
chromaticflash) that wraps Espressif's officialesp-serial-flasherC library (included as a git submodule). The ESP32 ROM/stub flash protocol is handled entirely by that library; this repo only adds a thin C ABI plus the macOS/Linux and Windows serial-port layers. The MCU is flashed over the Chromatic's USB serial port at 921600 baud, then hard-reset. - FPGA flash — The app invokes
openFPGALoader(--write-flash --cable gwu2x --reset <bitstream>) as a subprocess. It looks for a bundled copy, thenPATH, and on macOS can install it via Homebrew.
The two release payloads are copied into payload/ by update_payload.sh:
| File | Offset | Source |
|---|---|---|
bootloader.bin |
0x1000 |
chromatic_mcu/release |
partition-table.bin |
0x8000 |
chromatic_mcu/release |
mcu_fw.bin |
0x10000 |
chromatic_mcu/release |
sgb_sfx_bank.bin |
0x110000 |
chromatic_mcu/release |
evt1_x2.fs |
— | chromatic_fpga_sgb_oc/release |
chromatic_installer/
├── update_payload.sh # copy release artifacts into payload/
├── payload/ # MCU binaries + FPGA bitstream (committed)
├── native/
│ ├── esp-serial-flasher/ # git submodule (Espressif C flash library)
│ ├── src/ # chromatic_flash wrapper + posix/windows ports
│ ├── CMakeLists.txt
│ ├── build_native.sh # build the native lib for all OS targets
│ └── runtimes/<rid>/native/ # staged native libraries (build output)
└── app/
├── ChromaticInstaller.slnx
├── ChromaticInstaller/ # Avalonia GUI + CLI (C#)
├── publish.sh # publish + bundle for every OS
└── dist/ # per-target publish/ + zip/ (build output)
This repo is meant to sit next to the two firmware repos:
Desktop/
├── chromatic_fpga_sgb_oc/
├── chromatic_mcu/
└── chromatic_installer/
- .NET SDK 10 (
brew install dotnetor https://dotnet.microsoft.com) - CMake and a C compiler (for the native library)
- Cross toolchains (only if building those targets):
- Windows from macOS:
brew install mingw-w64 - Linux from macOS:
brew install zig
- Windows from macOS:
- zstd (for bundling openFPGALoader on Windows:
brew install zstd) - openFPGALoader at runtime for the FPGA step:
- macOS:
brew install openfpgaloader(the app can do this for you) - Windows: bundled with the installer (run
native/fetch_openfpgaloader.shto stage it at build time) - Linux: see Platform notes
- macOS:
./update_payload.shCopies the MCU binaries and FPGA bitstream from the sibling release folders
into payload/ and writes payload/VERSIONS.txt. Override the sources with
MCU_RELEASE_DIR=... FPGA_RELEASE_DIR=... if they live elsewhere.
cd native
./build_native.sh # all targets whose toolchain is present
./build_native.sh osx-arm64 # or just oneStages libchromaticflash.dylib / .so / chromaticflash.dll under
native/runtimes/<rid>/native/ so the C# project picks them up.
cd app
dotnet run --project ChromaticInstaller # GUI
dotnet run --project ChromaticInstaller -- --cli --dry-run # headless testcd app
./publish.sh # osx-arm64, osx-x64, win-x64, linux-x64
./publish.sh osx-arm64 # or a single targetOutputs land in app/dist/, one folder per target with the ready-to-run
publish folder and its distributable zip side by side:
app/dist/
├── publish/
│ ├── macos-arm64/ Chromatic Installer (osx-arm64).app (ad-hoc signed)
│ ├── macos-x64/ Chromatic Installer (osx-x64).app (ad-hoc signed)
│ ├── windows-x64/ ChromaticInstaller.exe + dll + payload/
│ └── linux-x64/ ChromaticInstaller + so + payload/
└── zip/
├── macos-arm64/ ChromaticInstaller-macos-arm64.zip
├── macos-x64/ ChromaticInstaller-macos-x64.zip
├── windows-x64/ ChromaticInstaller-windows-x64.zip
└── linux-x64/ ChromaticInstaller-linux-x64.zip
Publishes are single-file: the .NET runtime, Avalonia and all managed
dependencies are embedded in the executable itself, so each artifact contains
just the executable, the native chromaticflash library and the payload/
folder. The native library is deliberately kept outside the bundle (the host
extracts bundled files to a per-user cache path that cannot be dlopen'd
reliably), and the payload stays loose on disk because the flashing tools read
it by file path — this also lets users swap in a newer payload without
rebuilding. The app is not trimmed: Avalonia relies heavily on reflection and
trimmed builds break at runtime.
Make sure the Chromatic is powered ON and connected over USB.
Launch the app, pick the detected serial port (or press Rescan), then press Install. Progress and logs stream into the window. Options:
- Skip MCU / Skip FPGA — run only one step.
- Dry run — simulate without touching the device.
ChromaticInstaller --cli [--port PORT] [--only mcu|fpga|all] [--dry-run]If no display is available, the GUI automatically falls back to this CLI.
The app is ad-hoc signed. If Gatekeeper blocks it, right-click → Open, or:
xattr -dr com.apple.quarantine "Chromatic Installer (osx-arm64).app"Launch the .app bundle from app/dist/publish/macos-arm64/
(double-click it, or open "Chromatic Installer (osx-arm64).app").
If you instead double-click the bare ChromaticInstaller executable in Finder,
macOS wraps any executable in a Terminal window — that console is not required
by the app and never appears when launching the bundle. (Windows builds use
WinExe, so no console window there either.)
openFPGALoader.exe and its DLL dependencies are bundled with the installer —
no separate download is needed. The only manual step is a one-time driver
replacement: use Zadig to switch the GWU2X device
from its default driver to WinUSB (Options → List All Devices → select
"GWU2X" → WinUSB → Replace Driver). This must be done once per USB port
you plug the Chromatic into.
You may need permission to talk to USB. Either run as root, or add a udev rule:
# /etc/udev/rules.d/99-chromatic.rules
SUBSYSTEM=="usb", ATTRS{idVendor}=="33aa", ATTRS{idProduct}=="0120", MODE="0666"
(Adjust the VID/PID if your device enumerates differently.) Serial access may
also require membership in the dialout group.
- No serial port detected — Confirm the Chromatic is powered ON and the USB
cable carries data. Try another port/cable, or pass
--portexplicitly. - Could not connect to the ESP32 bootloader — Same as above; also make sure nothing else is holding the serial port open.
- openFPGALoader not found — Install it (macOS:
brew install openfpgaloader), or place the binary next to the app. - FPGA step fails after a successful MCU step — Re-run with Skip MCU.
- GUI won't start / no display — The app falls back to the CLI
automatically, or run
--clidirectly.