Matching a function means writing C code that — when compiled with the project’s IDO compiler — produces MIPS assembly that is byte-for-byte identical to the original ROM. This is the primary contribution activity in the project. Each matched function brings the decompilation one step closer to a fully reconstructed source tree.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/pmret/papermario/llms.txt
Use this file to discover all available pages before exploring further.
Before you begin
You need a successful build (papermario.z64: OK) and the extra contributor dependencies installed:
Matching workflow
Snapshot the expected build
Once you have a passing build, copy it to the This copies
expected/ directory so diff.py has a reference to compare against:ver/us/build/ to ver/us/expected/ver/us/ (and equivalently for JP, PAL, and iQue). You only need to do this once per session, or after pulling upstream changes that affect the build.Pick a function to match
Unmatched functions live as
.s assembly files under ver/us/asm/nonmatchings/. Browse the subdirectories and choose one. Also locate the .c file that references your chosen function — it will contain an INCLUDE_ASM macro with the function name.Generate a context file with m2ctx.py
mips_to_c needs to know the project’s type definitions and function prototypes. Generate a context file from the relevant .c source file:ctx.c in the repository root, containing preprocessed declarations from all included headers.Convert assembly to C with mips_to_c
Pass the function’s Clone
.s file through mips_to_c to get an initial C scaffold.Local version (recommended once you’re used to it):mips_to_c into a sibling directory of papermario first and run with -h to see all options.Web version (easier to start with): paste the .s file contents into the top box at simonsoftware.se/other/mips_to_c.py and the ctx.c contents into the lower box.Replace INCLUDE_ASM with the C code
Open the
.c file and replace the INCLUDE_ASM line for your function with the output from mips_to_c. For example, for func_DEADBEEF in src/FOO.c:mips_to_c frequently emits void pointers and unusual syntax. You will need to correct the function signature and fix type errors before the file compiles.Compile with ninja
Rebuild the ROM:The build will either
FAIL (ROM doesn’t match the baserom) or fail to compile. Address compilation errors first — consult include/common_structs.h for struct definitions.Compare assembly with diff.py
Once the file compiles, compare your output against the original:
- The left column shows the original game’s assembly.
- The right column shows what your C code produces.
-mwtellsdiff.pyto watch the file and recompile on every save.-ocolourises the diff output.
-3 to add a third column showing the previous saved version, or -b to compare against the assembly from when diff.py was started.Iterate until the function matches
Edit your C code, save, and watch
diff.py update automatically (with -mw). Keep adjusting until both columns are identical — at that point the function is matched.If you get stuck, try:- Asking on Discord
- Running decomp-permuter to search for equivalent code that compiles to a match
- Wrapping your best attempt in
#ifdef NON_MATCHINGand moving on to a smaller function
Clean up matched ASM files
After matching, run:This removes the
.s files from nonmatchings/ that correspond to functions now implemented in C.Open a pull request
Push your branch and open a pull request on GitHub. By submitting, you agree to give the maintainers permission to use, alter, and distribute your contribution.
When you can’t fully match a function
Sometimes matching isn’t possible — the compiler produces different register allocation, or a code pattern has no clean C equivalent. Use the labels below to mark these cases. Always leave a comment above the function explaining the specific issue.NON_MATCHING
UseNON_MATCHING when your C code is logically equivalent to the original but doesn’t compile to identical assembly (for example, a register swap you can’t reproduce):
NON_MATCHING functions will be used in place of the included ASM.
NON_EQUIVALENT
UseNON_EQUIVALENT when you’re unable to figure out a section of the code, or when you’re confident the original logic can’t be replicated cleanly. Make a genuine best-effort attempt — a half-finished function is less useful to the next contributor:
