Support the C-first campaign: globalasm now detects whether each GLOBAL_ASM is behind a NON_MATCHING guard; ps-status --c-coverage reports guarded vs bare counts (the "bare -> 0" metric) with --list/--json; ps-fdiff --file summarizes every function in a source object, ranked closest-first. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| crates | ||
| Cargo.lock | ||
| Cargo.toml | ||
| README.md | ||
Pokémon Stadium matching tools (Rust)
A cargo workspace with the tooling for the byte-for-byte matching effort. It has
no Python dependencies; MIPS disassembly uses the rabbitizer crate — the same
disassembler the Python scripts use — for output parity.
Crates
| Crate | Binary | Python equivalent (maintained) |
|---|---|---|
ps-core |
(library) | shared parsers / models |
ps-status |
ps-status |
progress.py |
ps-firstdiff |
ps-firstdiff |
tools/first_diff.py |
ps-fdiff |
ps-fdiff |
./diff.py -mwo <func> |
The Python scripts are kept alongside the Rust tools, not replaced — the two are validated to parity (see below) so either can be used.
Two extra modes support the "C-first" campaign (writing C for every function
before matching; see docs/c-first-plan.md):
ps-status --c-coverage [--list] [--json]— how manyGLOBAL_ASMfunctions are guarded (have a#ifdef NON_MATCHINGC body) vs bare (asm only). Campaign metric: bare → 0.--listprints the bare worklist with addresses.ps-fdiff --file <src.c>— summarize every function in a source file's object, ranked closest-first (fewest differing words), flagging any that already match.
ps-core contains the reusable pieces:
globalasm— scansrc/**/*.cfor#pragma GLOBAL_ASM(...)(build-free list of pending functions), tracking whether each is behind aNON_MATCHINGguard.symbols— parselinker_scripts/<v>/symbol_addrs*.txt.mapfile— minimal GNUld.mapparser:.textsymbols with sizes, plus vram/vrom lookups (vrom derived from each section'sload address).rom— big-endian.z64reader + md5 verification.disasm—rabbitizerwrapper; resolvesjaltargets to symbol names.
Build & test
cargo build --release # binaries in target/release/
cargo test # unit tests
cargo clippy --all-targets
Modes that need build artifacts
ps-status (default), works with only the committed repo. Everything else needs
artifacts produced by make:
ps-status --build-awareneedsbuild/pokestadium-<v>.map.ps-firstdiffneedsbuild/…z64+.mapandexpected/build/…(make diff-init).ps-fdiffneedsbuild/…z64+.mapandbaseroms/<v>/baserom.z64.
Parity-validation status
The Python scripts are kept in place. Validated so far:
-
ps-statusbuild-free — validated: total (190) and per-file counts matchgrep -rho 'GLOBAL_ASM("[^"]*")' src/ | wc -landgrep -rln GLOBAL_ASM src/. -
ps-status --build-awarevsprogress.py— validated to exact parity on a real matching build: identical total (1975096 / 2204464 = 89.5953%) and every per-folder decomp/total byte count. The.textsymbol table produced byps-core's map parser matchesmapfile_parsersymbol-for-symbol (8240 symbols, 2204464 bytes). Reaching this required replicating twomapfile_parserbehaviours: skippingvram == 0(unallocated archive members) and synthesizing a$_static_symbol_...for the leading gap before a contribution's first named symbol (static functions / symbol-less headers). -
ps-firstdiffvstools/first_diff.py— validated with an injected regression (one instruction word patched in the built ROM). Both report the identical first difference: same ROM offset, containing function + inner offset, differing bytes, and decoded instructions — including resolving the patchedjaltarget to its symbol via the map. -
ps-fdiffvs./diff.py— validated on the same regression: both flag the same differing instruction at the same offset (marked|). Presentation differs by design —ps-fdiffresolvesjaltargets to symbol names and stops at the function boundary, while asm-differ shows raw addresses over a wider window with its own scoring — but the located difference matches. Exit codes:0match,1differ,2error.
All three matching tools now have confirmed parity against their Python counterparts. Reproduce the diff checks in a full build environment with:
# build-aware vs progress.py (compare bytes / percentages)
make && make diff-init
python3 progress.py
./tools/rust/target/release/ps-status --build-aware
# first-diff vs first_diff.py (introduce a deliberate regression first)
python3 tools/first_diff.py
./tools/rust/target/release/ps-firstdiff
# per-function diff vs diff.py
./diff.py -mwo <func>
./tools/rust/target/release/ps-fdiff <func>
Note: ps-fdiff v1 is non-interactive (word-by-word alignment); diff.py's
interactive TUI, scoring and insert/delete alignment are not reimplemented.