mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-26 13:33:34 -04:00
5f937bdda5
- splat.us.exe.yaml: text subseg asm->c (INCLUDE_ASM scaffold); include/common.h (committed prelude); Makefile c-rule cpp->cc1->maspsx->as + -Map - PIN (G8): gcc-2.7.2-psx -O2 -G0 -mips1 -mcpu=3000 -mgas -msoft-float -fgnu-linker + maspsx --aspsx-version=2.56 --expand-div; byte-exact on func_80018F20 + instruction-identical across 3 idiom classes; --expand-div REQUIRED for div/rem (SETUP.md §5.4 PINNED, Makefile MASPSX_FLAGS) - harness: diff_settings.py (asm-differ mipsel object mode), tools/decompile.py (m2c wrapper), tools/permuter/ (decomp-permuter harness + objdump shim), expected/ - 14 real functions matched (asm-differ score 0): func_80018F20 + 13 accessors; +14 splat-auto empty no-ops; make check BYTE-IDENTICAL throughout - 2 instruction-identical near-misses guarded NON_MATCHING (func_80015A74 scheduling, func_80016714 phantom frame) -> decomp-permuter candidates - flywheel: docs/matching-cookbook.md, memory + CLAUDE.md step 5 (consult+evolve), R16 - requirements-python.txt: venv freeze (pycparser<3.0 pinned — permuter needs plyparser) - LZSS spike: needs jump-table-in-rodata workflow (102 tables, mixed blob) -> Phase 7 - venv: asm-differ + permuter deps installed - bumps project version 1.5.0 -> 1.6.0
60 lines
2.4 KiB
Python
60 lines
2.4 KiB
Python
#!/usr/bin/env python3
|
|
"""decompile.py — m2c scaffold helper for the BFM matching loop (Phase 6+).
|
|
|
|
Given a function's splat label (e.g. func_80015A74, main, GameModeDispatch), locate
|
|
its disassembly under asm/nonmatchings/ and run m2c (target mipsel-gcc-c) to emit a C
|
|
scaffold to stdout. The scaffold is a STARTING POINT only — refine it by hand against
|
|
asm-differ until the diff score is 0 (G3), then paste the matched body into src/ in
|
|
place of the INCLUDE_ASM stub.
|
|
|
|
Usage:
|
|
tools/decompile.py <function> # m2c scaffold -> stdout
|
|
tools/decompile.py <function> --context src/800.c # seed m2c with existing C types
|
|
tools/decompile.py <function> --stack-structs # also emit stack-struct templates
|
|
|
|
Notes:
|
|
- m2c parses splat's annotated .s natively (no preprocessing needed).
|
|
- For complex functions, Ghidra's decompiler (via MCP get_code) is often a richer
|
|
starting point than m2c; use whichever is closer, then converge with asm-differ.
|
|
"""
|
|
import argparse
|
|
import glob
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
M2C = os.path.join(REPO, "tools", "m2c", "m2c.py")
|
|
|
|
|
|
def find_asm(fn):
|
|
return glob.glob(os.path.join(REPO, "asm", "nonmatchings", "**", fn + ".s"), recursive=True)
|
|
|
|
|
|
def main():
|
|
ap = argparse.ArgumentParser(description="m2c scaffold helper for the BFM matching loop")
|
|
ap.add_argument("function", help="splat function label, e.g. func_80015A74")
|
|
ap.add_argument("--context", help="preprocessed C file to seed m2c types/structs (e.g. src/800.c)")
|
|
ap.add_argument("--target", default="mipsel-gcc-c", help="m2c target (default: mipsel-gcc-c)")
|
|
ap.add_argument("--stack-structs", action="store_true", help="emit stack-struct templates")
|
|
args = ap.parse_args()
|
|
|
|
hits = find_asm(args.function)
|
|
if not hits:
|
|
sys.exit(f"decompile.py: no asm/nonmatchings/**/{args.function}.s "
|
|
f"(is {args.function} still an INCLUDE_ASM stub in src/?)")
|
|
if len(hits) > 1:
|
|
sys.stderr.write(f"decompile.py: {len(hits)} matches, using {hits[0]}\n")
|
|
|
|
cmd = [sys.executable, M2C, "-t", args.target, "-f", args.function]
|
|
if args.context:
|
|
cmd += ["--context", args.context]
|
|
if args.stack_structs:
|
|
cmd.append("--stack-structs")
|
|
cmd.append(hits[0])
|
|
sys.exit(subprocess.run(cmd).returncode)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|