Build and install GameQ on Q
macOS prerequisites
Section titled “macOS prerequisites”Install Git, command-line developer tools (xcode-select --install if needed),
and Docker Desktop or a working Docker-compatible local engine. Start Docker.
The build downloads a Debian-based toolchain once and caches it locally. It
contains ARM GCC 12.2, newlib, Python signing dependencies, and RGBDS 1.0.3.
RGBDS is built from a checksum-verified source archive. No Homebrew installs or
global Python package changes happen during a build.
git clone --recursive --branch main git@github.com:tcashel/GameQ.gitcd GameQmake pokeredmake firmwaremake sd SD=/Volumes/GAMEQmain contains the tested 0.1.7GQ baseline. The operator confirmed walking,
CAPS fast-forward and save/reload on the Q. See hardware-test.md
for the installed artifact and remaining checks.
A normal non-recursive clone also works: the scripts initialize the pinned dependencies they actually need. This avoids downloading the unrelated ESP32, Pico, and other MCU SDKs in the full recursive dependency tree.
Outputs
Section titled “Outputs”build/roms/pokemon-red.gb: 1,048,576 bytes; canonical SHA-1ea9bcae617fdf159b045185467ae58b2e4a48b9a.build/roms/gameq-hub.gb: the walkable library, built withmake hubfrom the pinned Red source plus the GameQ hub overlays. The full 1 MiB ROM is compressed losslessly into firmware; the room does not need an SD copy.build/roms/gameq-hub.build.json: hashes tying the room ROM and symbols to their source inputs. Firmware builds rebuild the room; SD staging verifies this manifest before changing the card.build/firmware/gameq-q1.dfu: the file to install.build/firmware/builtin-hub.json: hashes and sizes binding the compressed flash asset to the complete hub ROM and its source manifest.build/firmware/gameq-q1.bin: signed application payload.build/firmware/gameq-q1.elfand.map: symbols and memory accounting.build/firmware/memory-budget.json: linked heap/core sizes; builds require at least 256 KiB of MicroPython heap before runtime allocations.build/firmware/verification.json: DFU structure and signature result.build/firmware/source-info.json: commit, source pins, and input hashes.build/firmware/gameq-stack-usage.txt: ARM GCC stack estimates for the native module.build/firmware/SHA256SUMS: exported binary hashes.
make sd builds Red and the hub, stages Red, then copies an already-built
gameq-q1.dfu to the card root. It preserves existing saves. Firmware builds
embed the room; staging does not copy it to SD. Legacy gameq-hub.gb files on
the card are ignored by the library, as are hidden macOS metadata files.
Eject the card after staging. Use the Q’s slot A for bring-up and recovery.
Build guarantees and limits
Section titled “Build guarantees and limits”The build uses a source snapshot in Docker BuildKit and exports artifacts.
It does not need USB, privileged containers, or access to a physical Q.
The upstream checkouts remain available for inspection; build-time overlays
are applied inside the snapshot. make prepare is an optional inspection helper
that applies those overlays to the local Coldcard checkout.
The DFU contains one application element at 0x08020000, targets Q only, and
uses Coinkite’s published developer key 0. The immutable bootloader is not
part of the image. Header length, flash budget, reset vector, DFU CRC, and ECDSA
signature are checked. The high-water/downgrade-protection flag is not set.
The build also checks that the native module and frozen boot shell were linked.
The resident hub is part of that signed application, not a separate internal
filesystem install. Build checks round-trip the compressed asset back to the
exact ROM. The lean frozen runtime removes unused wallet menus and retains
hardware support plus the authenticated GameQ recovery updater.
The signing timestamp defaults to the GameQ commit timestamp via
SOURCE_DATE_EPOCH. Signing uses deterministic ECDSA. To deliberately select a
newer build timestamp, set SOURCE_DATE_EPOCH to a Unix timestamp and keep that
value with the build record. Generated firmware/ROMs are ignored by Git.
Use GAMEQ_NO_CACHE=1 make firmware to force a fresh build execution when
comparing two checkouts. Identical source, toolchain, and timestamp should
produce identical DFU bytes; this does not claim bit-identical output from
arbitrarily different system packages or compiler versions.
The generic MicroPython build message about installing mboot is inapplicable
to the stock Q: use the packaged GameQ DFU through its existing update UI.
Do not install MicroPython’s intermediate unsigned firmware.dfu.
First installation
Section titled “First installation”- Build and stage the files above on a FAT32 MicroSD card.
- On the currently installed stock Q firmware, select Advanced/Tools →
Upgrade Firmware → From MicroSD, and choose
gameq-q1.dfu. - Keep power connected throughout the update. Accept the immutable developer/custom-firmware warning and its forced delay.
- Follow the hardware checks in hardware-test.md.
The menu path follows Coinkite’s firmware-update instructions.
Updating an installed GameQ
Section titled “Updating an installed GameQ”The marker must name the version currently installed on the Q. For a Q
running 0.1.6GQ and updating to 0.1.7GQ, place this text in GameQ/system/recovery on the card:
for-version:0.1.6GQ- Eject the card, insert it in slot A, and reboot with USB power connected.
- In GameQ recovery, use Left/Right to choose
gameq-q1.dfu, then Enter to load and verify it. - Enter the existing main PIN if requested, then confirm Install this new firmware?. Keep power connected through the developer warning and update.
- After installing 0.1.7GQ, the older marker no longer matches and the resident room opens automatically. Follow hardware-test.md.
The updater retains main-PIN authentication when a PIN is configured and
bootloader signature verification. The operator successfully installed
0.1.7GQ through this updater; its Cancel return still needs explicit
physical acceptance. For a later update from 0.1.7GQ, use
for-version:0.1.7GQ.
If the installed version is 0.1.4GQ or earlier, use its version in the marker. Those versions enter stock startup: enter the existing PIN and select Advanced/Tools → Upgrade Firmware → From MicroSD.
Recovery from an application fault
Section titled “Recovery from an application fault”Create an empty /GameQ/system/recovery file on the card and reboot. This marker
is checked before importing the emulator and requests recovery on every
version until removed. Through 0.1.4GQ it opens stock startup; from 0.1.5GQ it
opens GameQ’s dedicated updater. Canceling the new updater opens the resident
room; remove the empty marker to boot directly into the room next time.
From 0.1.2GQ, a for-version: marker selects recovery only while its named
version is installed. Older GameQ builds treat any marker as recovery, so use
for-version:0.1.1GQ when updating 0.1.1GQ.
This is experimental application firmware: an SD/LCD/PSRAM fault can leave it unresponsive. A correctly signed application that crashes does not automatically trigger the bootloader’s corrupt-image recovery. The marker helps when startup reaches the SD check; an earlier failure may still require hardware recovery. The immutable bootloader is preserved, but do not assume every application fault is recoverable from its normal SD screen.
Local checks
Section titled “Local checks”make test # shell tests and host C adapter; real ROM if builtmake firmware # ARM build, linked-module and signature checksmake clean removes exported firmware and ROM files. It preserves source edits
and does not run git reset --hard or clean the upstream repositories.
The host adapter runs the actual canonical ROM with AddressSanitizer and UndefinedBehaviorSanitizer. It reaches the title and accepts input into the new-game introduction. This checks emulator behavior, not the Q’s physical SPI, keyboard, PSRAM timing, or SD power-loss behavior.
Make a starter package for testers
Section titled “Make a starter package for testers”The package copies an existing verified firmware build; it does not rebuild or flash the Q. It includes the canonical Red ROM, an offline illustrated guide, checksums, source notices and update markers. It never includes saves or diagnostic files and does not put a recovery marker in the ready-to-copy GameQ folder.
After building firmware and the documentation screenshots:
python3 -m venv build/package-envbuild/package-env/bin/python -m pip install ecdsa==0.19.1build/package-env/bin/python scripts/package-release.py \ --upgrade-from 0.1.5GQ --upgrade-from 0.1.6GQOutputs are build/release-packages/GameQ-0.1.7GQ-starter.zip and its .sha256
file when packaging 0.1.7GQ. --firmware-dir, --rom and --output-dir can
point to preserved release artifacts. The script verifies the developer
signature, clean-source build record and canonical ROM before packaging. It
refuses a version-scoped marker matching the packaged version, which would
keep opening recovery after a same-version install. The separate
unknown-version marker is blank; its guide explicitly requires removing it
after updating.
Review README-FIRST.html, check package hashes and extract into a temporary
folder before publishing. The same inputs produce the same ZIP bytes. Starter
packages are distributed through the private repository’s release assets;
generated ROMs, DFUs and ZIPs stay outside Git history.