Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 46 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,16 @@ brew install \

## Diffing a Function

This repo uses [asm-differ](https://github.com/simonlindholm/asm-differ) (`tools/asm-differ`, a submodule) to compare your current C output against the target assembly for a function.
Both diffing tools below compare your current build's object files against a known-good baseline (`expected/build`), so the general workflow is:

1. `make setup` - only needed once, or after pulling changes that touch `splat.yaml`/the base ROM. Regenerates `asm/`, `bin/`, and `assets/` from `dmpj.d64`.
2. `make` - rebuilds the ROM from current source. If it succeeds, `md5sum -c checksum.md5` prints `build/dmpj.d64: OK`, confirming a bit-exact match against the original ROM regardless of which functions are matched yet (unmatched functions still compile to identical bytes via their `GLOBAL_ASM` stubs).
3. `cp -r build expected/build` - snapshot that known-good build as the baseline. Only needs to be redone after step 1/2 change what "known-good" looks like (e.g. after `make setup`, or after pulling other people's matches).
4. Diff a specific function with `asm-differ` or `objdiff` (below) to see if your in-progress C matches.

### Using asm-differ

[asm-differ](https://github.com/simonlindholm/asm-differ) (`tools/asm-differ`, a submodule), is a tool used by default on decomp.me, to compare your current C output against the target assembly for a function.

Before diffing for the first time, snapshot a known-good build as the baseline to diff against:

Expand All @@ -117,6 +126,42 @@ python3 tools/asm-differ/diff.py -mo func_80007D64

Run `python3 tools/asm-differ/diff.py --help` for the full list of options.

### Using objdiff

[objdiff](https://github.com/encounter/objdiff) is an alternative diffing tool also used on decomp.me with a GUI, live rebuild-on-save, and a function/object browser - also the same diffing engine decomp.me uses under the hood, so a scratch that matches in the browser will match here too. The project's `objdiff.json` (repo root) is already configured with one unit per `c`-type source file.

Install it (either works):

```sh
# prebuilt binary - see https://github.com/encounter/objdiff/releases
# or, with Rust installed:
cargo install --locked --git https://github.com/encounter/objdiff.git objdiff-gui objdiff-cli
```

Like `asm-differ`, it needs a known-good baseline to diff against:

```sh
make
cp -r build expected/build
```

Then launch the GUI, pointing it at the repo root (it won't auto-detect the current directory):

```sh
objdiff -p /path/to/PaintStudioDecomp
```

- The sidebar lists every unit from `objdiff.json` (one per `c`-type source file, e.g. `src/gameboot.c`).
- Click a unit to open its diff view: target assembly on the left, your current build on the right, function by function. Matching lines are unhighlighted; mismatches are highlighted, similar to `asm-differ`'s output.
- Each unit also shows a match percentage in the sidebar so you can see progress at a glance.
- With the window focused, save the source file you're working on and objdiff rebuilds and re-diffs automatically (via `watch_patterns` in `objdiff.json`) - no need to switch back to a terminal.

To check overall progress without the GUI, use the CLI instead:

```sh
objdiff-cli report generate
```

## Using decomp.me

Functions can also be matched entirely in the browser using [decomp.me](https://decomp.me/), which doesn't require a local build environment. This is useful for getting help from others, or for working without a full local setup.
Expand Down
89 changes: 89 additions & 0 deletions objdiff.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
{
"custom_make": "make",
"build_base": true,
"build_target": false,
"watch_patterns": [
"*.c",
"*.h",
"*.s",
"Makefile",
"splat.yaml"
],
"ignore_patterns": [
"build/**/*"
],
"units": [
{
"name": "src/gameboot.c",
"target_path": "expected/build/src/gameboot.c.o",
"base_path": "build/src/gameboot.c.o",
"metadata": {
"source_path": "src/gameboot.c"
}
},
{
"name": "src/main/787C8.c",
"target_path": "expected/build/src/main/787C8.c.o",
"base_path": "build/src/main/787C8.c.o",
"metadata": {
"source_path": "src/main/787C8.c"
}
},
{
"name": "src/capture/11C2D8.c",
"target_path": "expected/build/src/capture/11C2D8.c.o",
"base_path": "build/src/capture/11C2D8.c.o",
"metadata": {
"source_path": "src/capture/11C2D8.c"
}
},
{
"name": "src/leo/lib/leotestunit.c",
"target_path": "expected/build/src/leo/lib/leotestunit.c.o",
"base_path": "build/src/leo/lib/leotestunit.c.o",
"metadata": {
"source_path": "src/leo/lib/leotestunit.c"
}
},
{
"name": "src/libultra/io/piacs.c",
"target_path": "expected/build/src/libultra/io/piacs.c.o",
"base_path": "build/src/libultra/io/piacs.c.o",
"metadata": {
"source_path": "src/libultra/io/piacs.c"
}
},
{
"name": "src/libultra/io/vitbl.c",
"target_path": "expected/build/src/libultra/io/vitbl.c.o",
"base_path": "build/src/libultra/io/vitbl.c.o",
"metadata": {
"source_path": "src/libultra/io/vitbl.c"
}
},
{
"name": "src/libultra/gu/scale.c",
"target_path": "expected/build/src/libultra/gu/scale.c.o",
"base_path": "build/src/libultra/gu/scale.c.o",
"metadata": {
"source_path": "src/libultra/gu/scale.c"
}
},
{
"name": "src/overlays/camera/27BA20.c",
"target_path": "expected/build/src/overlays/camera/27BA20.c.o",
"base_path": "build/src/overlays/camera/27BA20.c.o",
"metadata": {
"source_path": "src/overlays/camera/27BA20.c"
}
},
{
"name": "src/overlays/saveload/saveload.c",
"target_path": "expected/build/src/overlays/saveload/saveload.c.o",
"base_path": "build/src/overlays/saveload/saveload.c.o",
"metadata": {
"source_path": "src/overlays/saveload/saveload.c"
}
}
]
}