The SM64 decompilation is a community effort to produce a byte-identical C rebuild of the original game. Pull requests are welcome — this page explains everything you need to know before opening one, from code formatting rules to how matching is verified and what kinds of contributions have the most impact.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/n64decomp/sm64/llms.txt
Use this file to discover all available pages before exploring further.
Join the community on Discord at discord.gg/DuYH3Fh to discuss changes, ask for help with matching, and coordinate before opening issues for large refactors.
Before you start
For major changes — restructuring the build system, altering type definitions that affect the ROM layout, or changing shared headers — open an issue first to discuss the approach. For smaller contributions (labeling symbols, fixing comments, matching a single function), a direct pull request is fine. The general rule from the README:Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
What the project goal means in practice
The decompilation’s primary goal is a bit-identical binary: the ROM produced by the build system must have the same SHA-1 hash as the original cartridge image for each supported version (JP, US, EU, SH, CN). This has two practical consequences:- Compiler: Bit-identical output for most files requires IDO 7.1 (the original SGI compiler). GCC produces functionally correct but differently optimized code.
- NON_MATCHING: When a correct C implementation exists but its assembly output does not match IDO’s output exactly, the function is wrapped in a
NON_MATCHINGguard:
NON_MATCHING=1 to compile a runnable PC port. The default build (NON_MATCHING=0) targets IDO and requires the full toolchain.
Code style
clang-format
All C source files must be formatted withclang-format before submitting. The configuration is in .clang-format at the repository root.
clang-tidy
.clang-tidy at the repository root provides lint rules. Running clang-tidy is not mandatory but is encouraged for new code. It will flag common issues such as implicit function declarations and sign/unsigned mismatches.
Style conventions
- 4-space indentation (changed from 3-space in Refresh 16, PR #1189).
snake_casefor functions and variables;UPPER_SNAKE_CASEfor macros and constants.- Struct field offsets are documented in comments:
/*0x00*/,/*0x04*/, etc. - Unknown fields are named
unkfollowed by their hex offset:unkF4,unk1AC. - Use the
UNUSEDattribute (frominclude/macros.h) for parameters that must exist for ABI compatibility but are not referenced.
Verifying a match
Two Python tools ship with the repository for comparing disassembly output.diff.py
diff.py is the primary matching tool. It disassembles a function from both the compiled object and the original ROM and displays a side-by-side diff.
first-diff.py
first-diff.py finds the first byte difference between the compiled ROM and the base ROM. It is useful for tracking down a mismatch that only appears after linking.
diff_settings.py
This file configures which built artifact and base ROMdiff.py compares. Edit it to match your toolchain prefix if you use a non-standard binutils installation.
config['source_directories'] if your cross-compiler is in a non-standard location so that diff.py can find source lines.
Contribution workflow
Fork and branch
Fork
n64decomp/sm64 on GitHub and create a feature branch. Use a descriptive name like match-bob-omb-behavior or label-camera-symbols.Implement the change
Write or match your code. If writing new C for an unmatched function, build with
NON_MATCHING=1 first to verify correctness, then iterate with diff.py to achieve a bit-identical match.Run clang-format
Format only the files you modified:Or use
format.sh to format everything, then check the diff to make sure you haven’t accidentally reformatted unrelated files.Verify the build
Build the default (matching) configuration to confirm A successful match prints
COMPARE=1 passes:OK for the ROM hash check.What makes a good contribution
Label unnamed symbols
The codebase still contains many functions and variables named
func_802XXXXX or D_802XXXXX. Giving them descriptive names based on their behavior is high-value work that helps everyone reading the code.Document behavior
Add comments that explain why code does something, not just what it does. Comments citing specific game mechanics (“this prevents the camera from entering the water before Mario” etc.) are especially useful.
Fix fake matches
A “fake match” is a function where the assembly output matches byte-for-byte but the C source uses incorrect types, logic, or undefined behavior to achieve it. Replacing fake matches with genuine decompilations is a priority.
Match non-matching functions
Functions guarded by
NON_MATCHING / GLOBAL_ASM need real C implementations that produce identical IDO output. Use diff.py iteratively to converge on a match.The CHANGES file
All significant contributions are recorded in theCHANGES file at the repository root, organized by “Refresh” release. It provides a historical record of every PR that has been merged, including the PR number. Browsing it is a good way to understand the project’s progress and find areas that still need work.
Useful macros for contributors
include/macros.h provides several attributes that are important for correctness in the decompilation context:
ALIGNED8 / ALIGNED16 on DMA buffers and audio data is required to match the original binary’s section layout.
Quick reference
| Task | Command |
|---|---|
| Build (US, compare ROM hash) | make VERSION=us COMPARE=1 -j$(nproc) |
| Build without matching (PC port) | make NON_MATCHING=1 VERSION=us -j$(nproc) |
| Build Japanese version | make VERSION=jp COMPARE=1 -j$(nproc) |
| Compare a function | ./diff.py -u function_name |
| Find first ROM difference | ./first-diff.py |
| Format modified file | clang-format -i path/to/file.c |
| Format all files | ./format.sh |