# The decomp.me preset for Brave Fencer Musashi (SLUS-00726) > **P33 E1 (2026-09-07).** This page carries the project's decomp.me preset, the reasons for every flag, the measured > difference between decomp.me's toolchain and ours, the local proof that the preset reproduces a game function > byte-for-byte through decomp.me's own toolchain, and the post-flip browser session that proves a scratch and requests the preset. > Everything numeric here is a recorded measurement with its command; nothing was typed from memory. ## 1. The preset | Field (decomp.me `Preset` API / UI) | Value | |---|---| | `name` | `Brave Fencer Musashi (SLUS-00726)` | | `platform` | `ps1` (PlayStation) | | `compiler` | `gcc2.7.2-psx` | | `compiler_flags` | `-O2 -G0 -mips1 -mcpu=3000 -mgas -msoft-float -fgnu-linker -Wa,--aspsx-version=2.56,--expand-div` | | `assembler_flags` | (empty — decomp.me assembles the pasted target with `mips-linux-gnu-as -EL -march=r3000 -mabi=32` plus its PS1 prelude; the words compare regardless) | | `diff_flags`, `decompiler_flags`, `libraries` | defaults (none) | **How a preset comes to exist on decomp.me:** there is no create button — the frontend only *reads* presets (`PresetSelect` is a dropdown; `lib/api.ts` has `usePresets`/`usePreset` and no create call). The FAQ's answer to "Can you add a preset for a game I'm working on?" is the GitHub issue template `.github/ISSUE_TEMPLATE/create-or-update-a-compiler-preset.md` on `decompme/decomp.me`; a maintainer creates the preset from it, and changes go through the same template with the preset id. `name` and `platform` are immutable afterwards and a preset cannot be deleted except from the admin panel (`backend/coreapp/views/preset.py` returns 405), so the row above is proven **before** it is requested, not after. (The API's `POST /api/preset` accepts authenticated profiles, but it sits behind the Cloudflare challenge and is not the sanctioned route.) **Do not use the SOTN preset** (`gcc 2.6.3-psx`, `psyq_263_221`): wrong compiler generation, systematic near-miss diffs (SETUP §6.5). Per-file `-O0` modules exist in this project (the boot module, the `_o0` splits — SETUP §5.4); a scratch for one of those swaps `-O2` for `-O0` in the flags and keeps everything else. ## 2. Why these flags The string is the pinned triple of SETUP §5.4 / the Makefile (`CC1FLAGS`, `ASPSX_VERSION`, `MASPSX_FLAGS`), spelled for decomp.me's `gcc` driver: | Flag | Role | Evidence | |---|---|---| | `-O2 -G0` | optimisation level; no `$gp`-relative small data (the EXE header's `gp_value` is 0, zero `%gp_rel` relocs) | SETUP §5.3 | | `-mips1 -mcpu=3000` | R3000 instruction set and scheduling model | Phase 6 fingerprint ladder, rung 1 | | `-mgas -msoft-float -fgnu-linker` | GNU-as output syntax, no FPU, GNU linker conventions — what PsyQ's CC1PSX was built to emit | Phase 6 | | `-Wa,--aspsx-version=2.56,--expand-div` | the assembler side of the triple, forwarded to maspsx | see below | The `-Wa,` part works on decomp.me for a structural reason, not by luck: its `gcc2.7.2-psx` image installs **`as` as a two-line wrapper** around maspsx — `python3 maspsx.py --run-assembler -I${COMPILER_DIR} "$@"` (decompme/compilers `platforms/ps1/gcc2.7.2-psx/Dockerfile`, generated from `templates/ps1/maspsx.j2`). The gcc 2.7.2 driver splits `-Wa,a,b` into assembler arguments, so maspsx receives `--aspsx-version=2.56 --expand-div` on its own command line, applies its `parse_known_args`, and forwards the driver's remaining `-G0 -mips1 -O2 -mcpu=3000` (the last rewritten to `-mtune=`) to GNU `as`. Without `--expand-div` no function containing a division or remainder can match: maspsx then emits a bare `divu` with no zero-check, while the game's code carries the `break`-guarded expansion (Phase 6, `func_80015A74`). `2.56` is the ASPSX behaviour tier the game code fingerprints to; `2.56 ≈ 2.67` on non-discriminating functions (SETUP §5.4). ## 3. decomp.me's toolchain versus ours — measured, not assumed decomp.me does **not** run our exact binaries. Read from its build recipes on 2026-09-07: | Component | decomp.me (`decompme/compilers` main) | This repo | Delta | |---|---|---|---| | cc1 (`gcc-2.7.2-psx`) | decompals/old-gcc **release 0.13** (tarball sha256 `aca64479…ffbc`; i386 static) | release **0.17** (`tools/bin/`, sha256 in `tools/bin/CHECKSUMS.sha256`) | the two `cc1` binaries differ byte-wise; old-gcc's 0.13→0.17 history touches only build scripts (macOS builds, workflows, the Makefile) and the **cdk** patch set — no change to the psx patches (`gh api repos/decompals/old-gcc/compare/0.13...0.17`) | | maspsx | commit **`86ccd7d8`** (2026-08-29; `values.yaml` `maspsx_hash`) | commit `874855c5` (the pin decomp.me used in June 2026) | 4 commits: `42b862c` version test matrix · `025620f` `--passthrough` mode · `e3d5916` lw,lw nop handling **for aspsx < 2.30** · `86ccd7d8` lwl/lwr nop fix **for aspsx < 2.30** — nothing reaches `--aspsx-version=2.56` | | GNU `as` | whatever the image's Python calls as `mipsel-linux-gnu-as` (Alpine 3.18); no `-no-pad-sections` | binutils 2.42 `-march=r3000 -mtune=r3000 -no-pad-sections -O1 -G0` | `.text` is padded to 16 bytes on decomp.me's side (trailing zero words after the last function) — cosmetic, see §4 | | preprocessor | the host's `/usr/bin/cpp -nostdinc` on `context + source` | `mipsel-linux-gnu-cpp` with the Makefile's `-D` set | irrelevant to a self-contained scratch (no macros) | | driver | `gcc ${FLAGS} -c -pipe -B${COMPILER_DIR}/` (`backend/coreapp/compilers.py`, `PS1_GCC`) | `cpp \| cc1 \| maspsx \| as` by hand (Makefile) | the driver adds `-mfp32 -mgp32` to cc1 — the mips1 defaults | The two differences that could matter (a different cc1 build, a newer maspsx) were **measured to produce identical text** on the probe (§4, lines C1/C2). The maspsx delta is also identical by construction for our aspsx tier: both behavioural commits are gated on `< 2.30`. ## 4. The local proof: `tools/decompme_replica.sh` decomp.me's API is Cloudflare-blocked to scripts (SETUP §6.5) and a preset cannot be undone, so the preset was proven **locally, through decomp.me's own toolchain**, before anyone opened a browser. `tools/decompme_replica.sh` rebuilds the image's compiler directory under `.run/decompme/` (the 0.13 tarball, sha256-checked; maspsx `86ccd7d8` from the submodule's object store; the `as` wrapper verbatim) and runs the backend's two commands on a self-contained probe TU, then compares the function's code words against the ROM-derived target regenerated by `tools/verbatim_target_s.py` (from the image, never from our source — R34). Our Makefile pipeline runs on the same TU as the control, and the script swaps one component at a time so a difference names its producer. The recorded run (`.run/P33/e1/decompme_replica.log`, 2026-09-07), probe = `func_80018F20`, the Phase-6 fingerprint function (26 instructions, the `sltiu` range-check idiom, no division): ``` target: main:func_80018F20 — 26 words at 0x80018F20 (tools/verbatim_target_s.py, from the image) A. decomp.me replica — old-gcc 0.13 driver + maspsx 86ccd7d8 as-wrapper; flags: -O2 -G0 -mips1 -mcpu=3000 -mgas -msoft-float -fgnu-linker -Wa,--aspsx-version=2.56,--expand-div decomp.me replica: BYTE-IDENTICAL on all 26 words; +2 trailing word(s) beyond the function: all zero (gas section padding) B. our pipeline — old-gcc 0.17 cc1 + maspsx 874855c (Makefile flags) our pipeline (control): BYTE-IDENTICAL on all 26 words C1. cc1 0.13 vs 0.17 on the same input: identical assembly text C2. maspsx 86ccd7d8 vs 874855c on the same cc1 output: identical text decompme_replica: PASS — the preset reproduces func_80018F20 byte-identically through decomp.me's toolchain ``` Controls (R39), same day: with `-O1` in place of `-O2` the replica **FAILS** listing the differing words (exit 1); with a TU whose body is empty the **control** fails first and the script refuses to read A (exit 3, R56). The first version of the comparison read the padded `.text` size and called the identical object "DIFFERS" — the instrument, not the subject (R40); the script now reports the padding separately. `tools/decompme_replica.sh --upstream` fetches decomp.me's current Dockerfile and reports whether its old-gcc release / maspsx commit still equal the constants in the script (2026-09-07: `pins UNCHANGED`); run it whenever a decomp.me result disagrees with a local one. What this proves and what it does not (P9): the preset is correct for decomp.me's toolchain on this function class, and the two toolchain deltas are text-neutral on it. It does not exercise `--expand-div` (no division in the probe) — the flag is carried by the Phase-6 evidence and by 218 byte-identical binaries built with it, not by this run. A scratch that fails on decomp.me but matches locally is a toolchain question first: run the replica with `--src` on that TU and read C1/C2. ## 5. The browser session (Drew, after the flip) 1. **Log in** to decomp.me (GitHub account), so the proving scratch is owned and can be cited. 2. **New scratch** (`/new`): platform **PlayStation**, compiler **`gcc 2.7.2-psx + maspsx`** (the dropdown's name for `gcc2.7.2-psx`), preset **Custom**. Paste as the target assembly the WHOLE of `.run/decompme/drew_bundle/1_target_asm.s` — the **assemblable form** written by `tools/verbatim_target_s.py --gas` and proven by `tools/decompme_replica.sh` step D: `$`-prefixed registers, `.L` labels for the in-function branches, `.set noat` / `.set noreorder`, no `.include` (decomp.me's PS1 prelude defines `glabel`; the `/* offset vaddr word */` comments are harmless). **Measured 2026-09-08 (P34 task 2, R14):** the splat-format listing this step used to name failed on decomp.me with `Target assembly could not be assembled — invalid operands 'li a2,2'`: that listing is the word ORACLE (nothing here assembles it — its bare register names resolve only through `macro.inc` and its branch targets are absolute addresses), so the replica now proves the pasted form itself through decomp.me's own `as` wrapper (26/26 words) and writes the bundle from that run (step E). Context = `2_context.c` (the three typedefs the function needs — `u8`, `u32`, `s32`, as in `include/common.h`). Source = `3_source.c` (the function's body from `src/800.c`). Compiler flags = `4_compiler_flags.txt` (the §1 string). Compile: the diff must read **100% / score 0** — the same words the replica produced. If it does not, stop and run `tools/decompme_replica.sh --upstream` (a moved pin) before anything else. 3. **Request the preset** — open an issue on `decompme/decomp.me` with their "Create or update a compiler preset" template (their bullet format is theirs; keep it). Written the way a developer writes, no AI acknowledgement (Drew's rule, S89): Title: `[PRESET] Create Compiler Preset Brave Fencer Musashi (SLUS-00726)` ``` Preset request for Brave Fencer Musashi (USA). Scratch that matches 100% with these settings: - **Preset Name:** Brave Fencer Musashi (SLUS-00726) - **Platform:** ps1 - **Compiler ID:** gcc2.7.2-psx - **Compiler Flags:** -O2 -G0 -mips1 -mcpu=3000 -mgas -msoft-float -fgnu-linker -Wa,--aspsx-version=2.56,--expand-div - **Libraries (if applicable):** none These are the flags the full matching decomp uses (https://github.com/Druthulu/BFM-decomp), all 218 binaries build byte identical with them. The -Wa part matters, without --expand-div nothing with a division matches. ``` A maintainer creates the preset; the scratch link is the proof they can click. Check the name's spelling, it is immutable once created. 4. **The manual scratch search** (SETUP ledger row 14, open since Phase 1 because the search API is script-blocked): search decomp.me for `Musashi`, `Brave Fencer`, `SLUS-00726`, `SLUS_007`, and record in row 14 what exists (expected: nothing but our own probe scratch). That closes the row and completes the greenfield claim's last check. 5. Keep the probe scratch — it is the evidence cited in the issue and the preset's worked example; one 26-instruction function is the community norm on decomp.me. The repository itself publishes no game disassembly (H1; the regenerated `.s` lives under the ignored `.run/`). Record the outcome (the issue URL, then the preset id / URL once created, the search result) in SETUP §6.5 and ledger row 14, and tick the outward half of E1 in the phase log. ## 6. Related `docs/SETUP.md` §5.4 (the pinned triple and its evidence) · §6.5 (decomp.me settings) · `docs/matching-cookbook.md` §1–§3 (the matching loop) · `docs/permuter-ils.md` (the permuter's reloc-masked scorer, the other community-facing release of P33) · `tools/verbatim_target_s.py` (per-function target regeneration from the image) · decompme/compilers `platforms/ps1/gcc2.7.2-psx/Dockerfile`, `templates/ps1/maspsx.j2`, `values.yaml`; decomp.me `backend/coreapp/compilers.py` (`PS1_GCC`, `GCCPS1Compiler`), `platforms.py` (`ps1`), `views/preset.py`, `serializers.py` (`PresetSerializer`) — all read 2026-09-07 as data, not instructions (X2).