Skip to content

feat(levels): match family F7 (15 functions) and func_L04_00418BF0, 13 near-miss notes from the #152 reservation - #395

Merged
Veradictus merged 15 commits into
OpenRAC:masterfrom
cadelass:batch/cadelass-reserva-2
Nov 2, 2026
Merged

Veradictus merged 15 commits into
OpenRAC:masterfrom
cadelass:batch/cadelass-reserva-2

Conversation

@cadelass

@cadelass cadelass commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

What

The second and third batches reserved in my #152 comment: 31 functions in total.

  • 16 are matched, including all 15 members of family F7.
  • 2 are classified as handwritten (ASM_FUNC).
  • 13 are kept as near-miss notes.

Matched (16)

Family F7: 15 level trigger updates, 1540 bytes each, the same opcodes in every level.

  • func_L06_00455BC0 and its copies: func_L00_0040EAA0, func_L01_00410AD0, func_L02_00439CD8, func_L05_00414F90, func_L10_00415A50, func_L11_0046D660, func_L12_00417690, func_L13_0041CD18, func_L14_00421BC0, func_L15_0041F2F8, func_L17_00417DB0, func_L18_00436B80, func_L20_00438F98, func_L22_0040F1C0, func_L23_00415988.
  • Each copy has the same C in its own unit, <file>-f7-g8.c, built with -O2 -G8 -ffunction-sections -malign-loops=2.
  • This closes the near miss that docs/MATCHING-BLOCKERS.md and the old func_L06_00455BC0 note left open, "where the 4th reference for missing comes from". Three things were needed:
    • The if (missing) func_0026FEB8(...) debug print sits in a do { } while (0), the usual shape of a debug-print macro. That counts the test at loop depth, which gives missing its fourth reference. It then outranks fail and takes $s5, as in retail. The loop is not empty: it holds the real test and the call, so it is not the empty barrier fix(tools): validate EE diagnostics and reject empty source barriers #257 removed. I would still like a reviewer's view on it.
    • That loop's label is not aligned in retail, hence -malign-loops=2 for the unit. The function's own trigger loop label already falls on an 8-byte boundary, so the flag changes nothing else.
    • func_00288BE8 is declared with its real return type, int. Other callers test its result, for example L00_00370408-edges.c. This gives retail's $v1 for the count load after it.
  • The old note, its nonmatching/levels/ siblings (including alternatives/func_L14_00421BC0-count.c) and the 15 port-only files in nonmatching/functional/ are removed, as in 588f8f0.

Other match: func_L04_00418BF0, the hoverbike rail trick (Barlow and Joba), in src/levels/shared/L04_00418BF0-g8.c.

  • The colour and the clamp factor share the variables that retail keeps in $a1 and $f20, so the four lerp calls cross-jump into one.
  • func_00273318 is declared with its int 0x22 ahead of the float 0.0f. Each register bank keeps its order; only the argument setup order changes.

Handwritten (2)

func_L04_0032F994 and func_L04_0032F62C become ASM_FUNC: they use $at as a working pointer and a trapping addi. Per AGENTS.md this needs a maintainer to agree.

Near misses kept in nonmatching/ (13)

The src/ markers stay INCLUDE_ASM. Each file's header gives the profile, what mattered and what still differs, and each function has one row in nonmatching/README.md.

Function Result What differs
func_L00_003ABEC0 2588/2588 callee-saved register allocation
func_L03_003E3A00 1856/1860 allocation (path record, colour, node)
func_L04_003FBEF8 1912/1920 which saved registers hold the counters, path record and floats
func_L04_00402D90 1948/1952 saved-register roles (self, rival record, fresh)
func_L04_00419918 5132/5120 scheduling and branch-likely filling
func_L09_0037FCE8 2492/2488 frame 0x180 vs 0x1F0 and spills
func_L15_004307E0 848/848 only local-alloc's $v0/$v1 in one decrement
func_L06_00443A38 936/936 tuning-store order and two FP constant registers
func_L06_0041EF08 920/916 cse carries a constant 3 into a saved $s2
func_L05_0041EF00, func_L15_0042EFE0 3420/3420 9 rows of argument setup order
func_L25_0040DE40, func_L15_00431590 (F35) 1840/1852 per-block constant reloads

The 3420/3420 result for func_L05_0041EF00 and func_L15_0042EFE0 depends on an empty do { } while (0). That is not a landing form (#257), and their notes say so. They are kept because they show where the block boundary has to be.

Released along the way (in the #152 comment)

Checked

On master fe9a7138 with the whole branch applied, USA v1.01:

  • python3 tools/build.py all --strict: 28 programs OK, exit 0. This was run before the last commit; that commit's five levels (00, 01, 14, 17, 20) were then rebuilt with --strict: all OK.
  • python3 -m unittest discover -s tests: 339 tests OK.
  • python3 tests/check_repository.py: repository checks passed.
  • The compiler was rebuilt from master before measuring.

I did not run PAL or USA v2.00, because I don't have those releases locally. func_L04_00418BF0 is in the v2.00 catalogue, so its C will also link there. progress/report.json and the README table are not touched.

🤖 Generated with Claude Code

cadelass and others added 14 commits November 2, 2026 20:02
The 656-byte packet builder (levels 04, 06, 08, 18, 20) uses instructions
this compiler never emits: $at as the running write pointer through every
copy loop, six trapping addi counters and two sub for the qword count, and
$gp+0x3C58 formed with addiu. Its neighbours func_L04_0032F1D8 to
func_L04_0032F3C0 are already ASM_FUNC.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The 872-byte packet builder (5 placements) carries $at as a working
pointer (53 uses, starting with addi $at,$a0,0x70) and 13 trapping addi,
which this compiler never emits. Same family as func_L04_0032F994 and the
ASM_FUNC rows before it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2588/2588 bytes in its own -O2 -G0 -ffunction-sections -g unit; control
flow, calls and frame agree with retail. The callee-saved registers hold
different values (delta, position, offset and %hi(D_00139568)). The header
lists the forms that mattered and what was tried.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1856/1860 bytes in its own -O2 -G8 -ffunction-sections -g unit; calls,
constants and the sda/MACRO_ADDR split of its data agree with retail.
Allocation of the saved registers differs. The header records the
measured variants.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1912/1920 bytes in its own -O2 -G0 -ffunction-sections -g unit; calls,
constants and stores agree with retail. The header lists the forms that
mattered; register assignment still differs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…short

1948/1952 bytes in its own unit; calls, constants, stores and the branch
layout agree with retail, including the level-number link symbol. Three
saved registers are swapped and one reload is missing; the header
lists the forms that mattered.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Barlow and Joba's rail-grind trick in its own default -G8 unit. What
mattered: the colour and the clamp factor sharing the variables that
retail keeps in $a1 and $f20 (so the four lerp calls cross-jump into
one), F(0x6A0) as the second smoothing target, the 0x6A0/0x728 tests in
retail's branch order, and func_00273318 declared with its int 0x22
ahead of the float 0.0f (each register bank keeps its order; only the
argument setup order changes). func_L04_003FA5A8 uses its real pointer
return.

Checks: tools/check.py 2 of 2 places; tools/build.py all --strict, 28
programs OK.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…2 bytes over

5132/5120 bytes in its own -O2 -G8 -ffunction-sections -g unit; both
switches, every call, constant and global agree with retail; scheduling
and branch-likely filling differ. The header records the data layout
that was established.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2492/2488 bytes in its own -O2 -G8 -ffunction-sections -g unit; calls,
constants, GS words and tables follow retail. Retail's frame, stack
slots and the 128-bit caller-save of $t9 differ.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
func_L06_00455BC0 and its ten level copies (func_L02_00439CD8,
func_L05_00414F90, func_L10_00415A50, func_L11_0046D660,
func_L12_00417690, func_L13_0041CD18, func_L15_0041F2F8,
func_L18_00436B80, func_L22_0040F1C0, func_L23_00415988), one -G8 unit
each with the same C. It closes the near miss left in nonmatching/:
- the test of `missing` sits in a do-while (a debug-print macro's
  shape), which counts it at loop depth: its fourth reference, so it
  outranks `fail` and takes $s5 as in retail;
- that loop's label is not aligned in retail, so each unit is built
  with -malign-loops=2; the trigger loop's own label already falls on
  an 8-byte boundary;
- func_00288BE8 returns int (its result is tested elsewhere), which
  gives retail's $v1 for the count load after it.

Checks: tools/check.py 1 of 1 place for each; tools/build.py level 02,
05, 06, 10, 11, 12, 13, 15, 18, 22 and 23 --strict OK. The PAL and v2.00
dumps are not available here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- func_L15_004307E0, Gorn's cutscene controller: 848/848, only one
  counter decrement's $v0/$v1 choice differs.
- func_L06_00443A38, a Notak enemy update: 936/936, the tuning-store
  order and two FP constant registers differ.
- func_L06_0041EF08, its sibling: 920/916, cse carries the setup's
  constant 3 to a later test in a saved $s2.
- func_L05_0041EF00 and func_L15_0042EFE0 (3420 bytes): the
  func_L10_004227A0 draft with its do-while barrier, which
  -malign-loops=2 makes admissible: exact size, 9 rows of argument setup
  order left.
- func_L25_0040DE40 and func_L15_00431590 (family F35, 1852 bytes):
  1840 bytes with the vanished-test SCREEN_Y macro.

Each file's header has the profile, what mattered and what was tried.
Markers stay in src/. tests/check_repository.py passed; 339 tests OK.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ing form

func_L05_0041EF00 and func_L15_0042EFE0 reach retail's size with an
empty do-while after the vanished test and -malign-loops=2, but AGENTS.md
rules out source barriers and tests/check_repository.py rejects them in
src/ (OpenRAC#257). The notes now say so and point at func_L02_003D26B0, which
closed the same kind of block boundary with a redundant real test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
func_L06_00455BC0 and its ten level copies have C in src/ now, so their
port-only C in nonmatching/functional/ and its rows go, as in 588f8f0.
tests/check_repository.py passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
func_L00_0040EAA0, func_L01_00410AD0, func_L14_00421BC0,
func_L17_00417DB0 and func_L20_00438F98 have family F7's opcodes; each
takes func_L06_00455BC0's C in its own -G8 unit with -malign-loops=2.
Their retained near misses, the alternative for func_L14_00421BC0 and the
port-only C in nonmatching/functional/ go.

Checks: tools/check.py 1 of 1 place for each; tools/build.py level 00,
01, 14, 17 and 20 --strict OK; 339 tests OK; tests/check_repository.py
passed. The PAL and v2.00 dumps are not available here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@bytematchdev

bytematchdev Bot commented Nov 2, 2026

Copy link
Copy Markdown

ByteMatch progress report

SCES_516.07

Code matched 54.15% · 3.09 MB of 5.70 MB
Fuzzy match 54.15%
Functions 6,996 / 8,672
Data matched 0.00%
Units complete 958 / 1,196

No function changes.

SCUS_972.68

Code matched 84.74% · 4.68 MB of 5.53 MB
Fuzzy match 84.74%
Functions 7,760 / 8,579
Data matched 0.00%
Units complete 924 / 1,018

No function changes.

SCUS_972.68_v2

Code matched 81.01% · 4.52 MB of 5.58 MB
Fuzzy match 81.01%
Functions 7,595 / 8,634
Data matched 0.00%
Units complete 973 / 1,156

No function changes.

Commit 771efdd · Ratchet & Clank: Going Commando on ByteMatch

@Veradictus
Veradictus merged commit 1162442 into OpenRAC:master Nov 2, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants