The v3.0 Japanese (SCPH-5500, 09/09/96) and US (SCPH-5501, 11/18/96)
retail BIOS images join SCPH-1001, SCPH-101 and SCPH-5552, so every v3.0
region (J, A, E) has a profile.
Both images match SCPH-1001 v2.2 byte for byte in the kernel,
ROM [0x80, 0x18000). SCPH-5501's reset vector is identical too; SCPH-5500's
differs in 24 bytes. The shell differs in both. So each profile is
SCPH1001.toml with its own identity (name, id, rom, sha256 pin, stem): the
copy windows and install slots are kernel properties and carry over
unchanged. The shell runs through the dirty-RAM interpreter, as for
SCPH5552.
Each image gets its own seed list, derived by the same rule as
phase2_ghidra_seeds_SCPH5552.json: the SCPH-1001 corpus filtered to seeds
whose 64-byte ROM window is identical in both images (534 kept, 569
dropped), plus the two architectural vectors and 6 A0/B0/C0 kernel-table
targets. The files carry only addresses, labels and rationales, plus the
SHA-256 of both ROMs.
- psx_bios_known_images.h: CRC-32 FF3EEB8C (SCPH-5500) and 8D8CB7E4
(SCPH-5501), both 512 KiB. A build that does not link these backends
builds one from the player's own dump as a loadable module, like
SCPH-5552, and the netplay lobby can name the image.
- main_cli.cpp: map SCPH5500 / SCPH5501 dumps to their profiles.
- build_cli.py: package both profiles with the CLI framework.
- docs/BIOS_SELECTION.md: list them among the module-built images.
Preserve current segmented dispatch, active-plan mod hooks and software scale limits. Extend function filters through the active plan, retain the last-store pointer with overlay ABI 25, and keep default config fingerprints stable. Refresh BIOS emitter stamps after byte-identical regeneration and reconcile regression fixtures.
Retro Studio's bulk tab bumps the title's psxrecomp pin first so the script
it runs is the one the title will pin; the clean-tree gate must not refuse
that. Submodule-internal changes are still refused at bump time.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
One pass per title: bump psxrecomp/recomp-ui to a ref that carries
docs/ci/templates/game-release.yml and the committed BIOS backends (refused
otherwise), un-ignore generated/, ensure [runtime] overlay_cache = true, emit
scripts/package_release.sh (retiring package_setup_release.sh) and
release.yml from the pinned template, rebuild emitters + regenerate the game
C from the title's disc, refresh framework_pins.txt, run check_boot_exe and
check_generated, commit; --push optional, --dry-run writes nothing.
The operation lives in project_studio/migrate_bundled.py; the tools/ script,
`git migrate-bundled` and `git bulk-migrate-bundled` (map_repos, per-repo
streaming) are its faces. Exercised end to end on a scratch copy of
Bomberman Party Edition (48 generated files committed, zip prefix kept,
generate_ci --check current).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The windows-2022 release job accepted the committed backends in the step
shell (Git Bash) and refused them at configure: runtime.cmake ran the bash
fingerprint through whichever bash find_program() located, and that
environment hashed a byte-identical tree differently. The fingerprint is now
tools/bios_emitter_fingerprint.cmake, run with the configuring cmake itself
on every platform; the shell script is a thin wrapper around it. Same digest
shape as before, so existing stamps stay valid (verified on an LF tree and
an autocrlf clone).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The Windows release job reports the committed backends as stale while
Linux and macOS accept the same tree; the configure error names no input.
check_bios_stamps.sh compares each stem's stamp with the local fingerprint
and, on mismatch, prints every hashed input's digest and the tool versions,
so the next run attributes the difference to a file.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Git for Windows checks text files out with CRLF, so the windows-2022 release
job hashed a byte-identical tree to a different value and BIOS_STALE_FATAL
refused the committed backends there while Linux and macOS passed. Stripping
CR before hashing makes the fingerprint line-ending independent (verified:
an LF tree and a CRLF copy of it now agree). Stamps rewritten to the new
canonical value; the generated C is unchanged.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
--check only looked for template steps the installed file lacked, so a copy
that still ran the removed OpenBIOS emission (or the setup-host wipe) read as
current and failed on the runner.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Decision (Alex, 2026-09-30): the recompiled BIOS carries the same risk as
the recompiled game, which titles already commit, so the retail backend is
compiled in rather than built on the player's machine. The retail image is
still never shipped: the runtime needs its data at run time and accepts only
the exact image the backend was built from, so the player supplies their
own dump as before.
- generated/{OpenBIOS,SCPH1001}_{full,dispatch}.c and their .emitter.sha
stamps are tracked (.gitignore un-ignores exactly those); regenerated with
the current emitter.
- bios_emitter_fingerprint.sh no longer hashes the ROM image: the profile's
SHA-256 pin stands for it and the emitter refuses any other image, and CI
has no dump, so hashing it made every CI configure read "stale".
- runtime.cmake: the staleness check covers every LINKED stem and
-DPSXRECOMP_BIOS_STALE_FATAL=ON makes a stale stamp fail configure.
- game-release.yml: no CI-side OpenBIOS emission (generate_openbios.sh is
gone); configure with BIOS_STALE_FATAL and assert both backends linked.
check_generated.sh asserts the submodule carries both backends tracked
and no dump is tracked anywhere.
- The player-side module build stays for a known image a build does not
link (SCPH-5552).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A buildable dump used to verify as usable and then block at Play behind a
modal while the module compiled. Now:
- ae_bios_verify reports a buildable, not-yet-cached dump as needs_regen,
and the runtime wires recomp-ui's new bios_prepare_with_progress job
(ae_bios_prepare) whenever the toolchain is present and no Generate host
is: the launcher runs the build as a progress job from the wizard's
"Prepare BIOS" button or the Play prompt, re-verifies, and resumes the
wizard. Generate & rebuild is never offered for a BIOS in a bundled build.
- psx_bios_module.c gains a progress sink fed from the builder's output
lines (dump / emit / compile / self-check / published map to stage
percentages with readable messages); run_command streams lines on both
platforms.
- The launch-time build stays as the fallback for --bios / --no-launcher.
Requires recomp-ui 9f86c49 (GameInfo.bios_prepare_with_progress).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Bundled releases link OpenBIOS only; retail-BIOS-derived C never ships.
"Bring your own BIOS" now works without it: when a dump matching a shipped
profile (psx_bios_known_images.h) is selected, the runtime builds that
backend on the player's machine with the overlay toolchain the release
already carries, caches it, and loads it as one more registered backend.
- runtime/include/psx_bios_module.h: the module contract. An overlay-style
self-contained shared library (no imports from the executable) exporting
psx_bios_module_{abi,codegen_hash,init,backend}; reaches the runtime only
through OverlayCallbacks plus a new PsxBiosModuleCallbacks table (traps,
dirty-RAM/kernel-bless probes, fntrace, log_probe) and pointer aliases of
the globals the generated dispatcher touches. Its #defines rewrite the
emitter's own extern lines, so the generated C compiles unchanged.
- runtime/include/psx_bios_module_glue.c.inc: module-side forwarders and the
four exports, compiled after overlay_dispatch_preamble.c.inc.
- runtime/src/psx_bios_module.c: host side. Cache path
<exe>/cache/bios/<os-arch>/bm<abi>_<codegen hash>_f<flavor>/<STEM>_<crc>,
ABI + codegen-hash gated load, callback fill, and a blocking build via
overlay_toolchain/bios_module_build.py (gcc via compiler.txt or PATH,
else tcc), then psx_bios_register().
- psx_bios_backend.c: the registry is now a mutable table seeded from the
CMake-generated psx_bios_builtin_registry by a constructor, with
psx_bios_register(); every existing walker keeps working.
- main.cpp: validate_bios_for_launch acquires a module (announcing a first
build) before declaring a mismatch; discovery accepts a buildable dump;
the launcher verify reports it usable ("ready" / "compiled on first
launch") with no Generate & rebuild; the BIOS row shows whenever the
toolchain is present; bundled_only respects module support.
- emitter: the CPS-marker constructor is not emitted in a module build.
- overlay_api.h: OverlayCallbacks gains a struct tag;
overlay_loader_callbacks() exposes the host table before loader init.
- tools/bios_module_build.py (ships in the toolchain): identity + profile
SHA-256 gate, staged emitter tree, emit, three-TU compile, ctypes
self-check, atomic publish. release_stage.py stages psxrecomp-bios, every
bios/*.toml, the seeds and the builder into overlay_toolchain/.
- Tests: runtime/tests/test_bios_module_host.c against three fake modules
(good / wrong ABI / wrong hash) on real dlopen; recompiler/tests/
test_bios_module_build.py builds the bundled OpenBIOS end to end and reads
the descriptor back; guards extended.
Verified on Twisted Metal 4 (bundled build + staged toolchain, headless):
first launch with --bios SCPH1001.BIN builds and loads the module and boots
on image=SCPH-1001; the second launch loads it from cache.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A shipped bundled build links OpenBIOS only and carries no CLI, sources
or toolchain, yet the codegen host forced the BIOS row on and a retail
pick answered with needs_regen ("Generate & rebuild to switch"), a step
that cannot run there.
- The BIOS row is shown only when a choice can mean something: a retail
backend is linked, nothing is linked yet (setup host), or the codegen
host actually wired Generate (prepare_with_progress). main.cpp decides
after host_apply instead of the host forcing has_bios.
- ae_bios_verify short-circuits a bundled-only build with a plain
"runs its bundled OpenBIOS only" message before the identity checks,
whose "this build expects SCPH-1001" wording names the pinned stem,
not a linked backend, and sets needs_regen only when Generate exists.
- test_bios_selection_guards pins both.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The icon copy iterated a literal path nullglob does not cover and died on
the first real title (runtime.cmake stages the icon at assets/psxrecomp.png,
not beside the exe). And the dump gate rejected overlay_toolchain/bios/
SCPH1001.toml, a profile the toolchain needs; only image files are
forbidden.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A stale psxrecomp/recompiler/build/psxrecomp-game from August shadowed the
build-recompiler tree built from the pinned submodule, so generate emitted
a dispatch calling psx_ram_canon_code_addr, which the pinned runtime had
removed; the bundled release failed at link on every platform. The
project's emitter tree is what CI and the scaffold build, so it wins, and
the resolved paths are logged.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
check_test_registration.cmake fails configure for an unregistered test
file, which broke every title's emitter build at the new pin.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Retire the setup-host release model (CI wiped generated/ and shipped
emitters + sources + a wizard so every player regenerated and rebuilt the
title). Titles now commit generated/ and CI ships the compiled game.
- docs/ci/templates/game-release.yml replaces setup-release.yml: gate on
committed game C (tools/ci/check_generated.sh), emit the OpenBIOS backend
in CI (tools/ci/generate_openbios.sh), configure with
PSXRECOMP_REQUIRE_GAME_C=ON and assert the full path was taken, package
with tools/package_game_release.sh, verify the zip is a game not a kit.
- tools/package_game_release.sh: exe, assets, bundled OpenBIOS, configs, mod
catalog + overlay toolchain via release_stage.py, notices; refuses sources,
emitters, generated C, BIOS dumps. clear_generated.sh removed;
package_setup_host.sh marked retired.
- Scaffold: gitignore templates track generated/, package_release.sh.in
wrapper, setup_project.{sh,ps1} commit generated/ after Generate.
- Project Studio: audit flags ignored/untracked generated/, retail BIOS C
and setup-host workflows; merge_gitignore un-ignores generated/; ops emit
the bundled packager + workflow; generate_ci uses the new template.
- Docs: docs/ci/BUNDLED_RELEASES.md replaces HOST_ONLY_RELEASES.md.
- Tests: tools/tests/test_bundled_release_layout.py; fix pre-existing
false positives in the packager-surface and overlay-static tests.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>