Match 600+ P2 functions & VU0/splice foundations#263
Conversation
scripts/decomp_lhf_draft.workflow.js fans out parallel read-only agents that draft matching C for batches of tiny leaf functions. scripts/decomp_apply_drafts.py verifies each draft in isolation (instructions + relocations vs the asm), rejects ones that grow non-.text sections (rodata-layout ripple) or whose raw FUN_ symbol has asm callers, then applies the byte-exact matches and renames FUN_ symbols. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
AddWaterExternalAccelerations dispatches through the SO vtable (offset 0x128) via STRUCT_OFFSET; FUN_001ef830 clears zpd.cploThrow. Annotate the remaining INCLUDE_ASM stubs with why they're deferred (VU0 SIMD, or permuter-class codegen for PostWaterLoad/HandleWaterMessage). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Small getters/setters and helpers on ALO/SO/SW: interact/look-at/throb/ack accessors, FInflictSoZap, UpdateSoPosWorldPrev, and SW list/world helpers. Base-struct fields past the truncated structs are reached via STRUCT_OFFSET. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Small wrappers/getters/setters across act, chkpnt, cplcy, difficulty, dmas, path, po, puffer, pzo, rog, sb, sensor, stepguard, and xform, drafted by the batch workflow and verified byte-exact (instructions + relocations). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
VU_VECTOR was a 2-byte stub { ushort data; }, so passing it by value compiled
to lhu instead of lq. It is a 128-bit VU quadword passed in a single 128-bit GP
register, so define it as { qword data; } (TImode, 16 bytes, 16-aligned). Kept
as a struct named VU_VECTOR to preserve the 9VU_VECTOR by-value mangling.
This resolves the long-standing 89.47% "single load mismatch" in
ClipVismapSphereOneHop, now matched as plain C. VU_VECTOR is only used by value
in signatures (never embedded), so the size change ripples nothing.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
VU_FLOAT was a 2-byte stub { uint16_t data; }; like VU_VECTOR it is a 128-bit
VU scalar (the VU_FLOAT(float) ctor stores it with sq, and it is passed by value
in a single 128-bit GP register). Define it as { qword data; }. Used only by
value in signatures, so the size change ripples nothing; full checksum OK.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
VU_VECTOR was a 2-byte stub { ushort data; }, so passing it by value compiled
to lhu instead of lq. It is a 128-bit VU quadword passed in a single 128-bit GP
register, so define it as { qword data; } (TImode, 16 bytes, 16-aligned). Kept
as a struct named VU_VECTOR to preserve the 9VU_VECTOR by-value mangling.
This resolves the long-standing 89.47% "single load mismatch" in
ClipVismapSphereOneHop, now matched as plain C. VU_VECTOR is only used by value
in signatures (never embedded), so the size change ripples nothing.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
VU_FLOAT was a 2-byte stub { uint16_t data; }; like VU_VECTOR it is a 128-bit
VU scalar (the VU_FLOAT(float) ctor stores it with sq, and it is passed by value
in a single 128-bit GP register). Define it as { qword data; }. Used only by
value in signatures, so the size change ripples nothing; full checksum OK.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Establish the inline-asm VU0 idiom on the small vector/scalar primitives, building on the VU_VECTOR/VU_FLOAT 128-bit type fixes: - VU_VECTOR(const VECTOR&) and VECTOR::operator=(VU_VECTOR): lq/sq quadword copies (plain C through the qword member). - operator*(VU_FLOAT, VU_VECTOR): qmtc2.ni / vmulx.xyzw / qmfc2.ni via inline asm, with VU types passed by value in single 128-bit GP registers ($4/$5/$2, no extra moves). Adds the ctor/operator declarations to vec.h. VU_FLOAT(float) stays INCLUDE_ASM for now (one scheduling instruction off). Full checksum OK. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
First water VU0 function matched: the vadd.xyzw combining the warp result is emitted via inline asm (lqc2/lqc2/vadd.xyzw/sqc2) over VU_VECTOR stack locals; the surrounding ConvertAloVec/CalculateAloTransformAdjust/WarpWrTransform calls and the *pv/*pw quadword copies are plain C. Adds WATER::vecCurrent at 0x570 and references the shared D_00248D30 rodata constant. Full checksum OK. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The sphere-bounds length (dot product + vsqrt) and the AABB vsub/vadd are emitted as one VU0 inline-asm block over the GetWrBounds result and the SO bounds fields (sRadiusBounds/unk_0x3d4/vecBoundsMin/vecBoundsMax). vsqrt has no assembler mnemonic so it's a .word, like the original .s. Full checksum OK. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
LSG's apos/anormal are 16-byte VU vectors; widen them to VECTOR4 and 16-align the struct so sizeof(LSG) is the real 0x70 (au at 0x40/0x44, apos[1] at 0x10). This is the key fix for water's clip-using functions: a typed LSG[16] clip workspace now lands at frame 0x20 (after the edge vectors) instead of the base, matching the original frame layout. No ripple — full checksum OK. With that, UGetWaterSubmerged is written (VU0 vmulax/vmaddx transform, g_pjt height logic, ClsgClipEdgeToBsp into LSG[16], float return) and ~95% matched; kept under SKIP_ASM (asm still used by the real build) pending permuter work on a few g_pjt-branch scheduling instructions. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Byte-exact, checksum-green (out/SCUS_971.98: OK): - PtnfnFromTn (tn): null-check ternary returning &D_00275980 or ptn+0x2F0 - FUN_0014c820 (crusher): indexed pointer into 0xB0-stride array - extern "C" leaf accessors called by other asm via unmangled names: InitCplcy, FActiveCplcy, SetCpmanCpmt, FUN_001e4880, FUN_00145DD8, FUN_001c9a48 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Byte-exact, checksum-green: - RetractLasen/ExtendLasen (sensor): +-1.0f/dt stored at 0xB08 - GetActvalScale (act): 3x qword copy ACTVAL+0x90 -> MATRIX3 rows - SetLookerSgvr (shdanim): store 3 LOOKER field addrs into SGVR - InvalidateSwXpForObject (bbmark): flags &= ~grfpva on pso->sw - FUN_0014c838 (crusher): indexed append into 0x14-stride array Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
These showed t==c "DIFFER" in the dual-build only because their jal targets a still-INCLUDE_ASM sibling (reloc-name artifact); the full link is byte-identical (out/SCUS_971.98: OK): - ImpactClue -> ImpactSo - func_0015F658 -> func_0015F618 - AddStepCustomXps -> AddStepCustomXpsBase Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two tail-call wrappers whose raw C-linkage siblings needed forward declarations (extern "C"). checksum-green (out/SCUS_971.98: OK): - call_search_level_by_id -> search_level_by_id - FUN_001d34e0 -> FUN_001bc4d8 (renamed FUN_001d34e0 -> mangled in symbol_addrs; it has no asm callers) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
UMaxCrv/SMaxCrv (crv): mpicvu/mpicvs[ccv-1]. TouchFlake/TouchBublet/ OnTrailRemove (rip): thin guarded/forwarding wrappers. All showed "DIFFER" only via dual-build artifacts (trailing unsymboled JUNK macros, and jal-to-external-sibling reloc names); full link is byte-identical (out/SCUS_971.98: OK). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
checksum-green (out/SCUS_971.98: OK): - GetActrefScale (act): explicit qword copy of MATRIX3 via loaded ptr (MATRIX3 is float[3][3], align-4; a plain *pmat=*p went unaligned) - AddFrzgObject (frzg): cache coid in a local so it isn't reloaded - FUN_001a93c8 (rwm, extern "C", has asm callers) + FUN_001a86f8 (renamed to mangled; no asm callers) - FUN_001cf138 (stephide, extern "C"): add 1000.0f loaded from D_00274E3C rather than materialized as an immediate Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two leaf functions; checksum-green (out/SCUS_971.98: OK): - GetSuvCpdefi: tail-call forwarding to GetSoCpdefi - SetAsegaSpeed: chained float multiply stored at 0x18 (match.sh's per-symbol check falsely reported DIFFER on both due to flaky configure.py asm regeneration / trailing-junk artifacts; the full-link checksum is the ground truth.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…CrvcCache/DuGetCrvSearchIncrement/MeasureCrvl) checksum-green (out/SCUS_971.98: OK). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
checksum-green (out/SCUS_971.98: OK): UpdateSuvInternalXps, OidFromSmIsms, PostFlyingEmit (+SgnCmpHp), InitDysh (wrapper to InitAlo), FUN_0014f900. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…harness checksum-green (out/SCUS_971.98: OK). Accessors, wrappers and vtable-dispatch leaves across 6 units; size/content-mismatched drafts auto-rejected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…F harness checksum-green (out/SCUS_971.98: OK). Accessors, vtable-dispatch and forwarding wrappers; size/content/data-growth mismatches auto-rejected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
checksum-green (out/SCUS_971.98: OK): PushCplookLookk, FUN_0014a8d0, VacateCredit, SetLightHighlightColor, BreakClue, SetShadowFrustrumUp. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tail wrapper FUN_001aea70(1, 0xFFFF); extern "C" fwd-decl of the raw sibling; renamed FUN_001aec90 -> mangled (no asm callers). checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
grfrob bit tests on g_plsCur; '(x & 2) > 0' steers GCC to andi+sltu (matching the ROM) instead of the shift-fold. Removed stale 80%% scratch. checksum-green (out/SCUS_971.98: OK). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…and, dartgun/screen) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…coin/game/jt/blip/chkpnt) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…obj/jlo cross-unit) game.h: reload_post_death is a raw symbol (extern C). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…turret/vifs/wr etc.) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… dartgun, sky/tv/ub etc.) game.h: tally_world_completion is a raw symbol (extern C). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The previous commit (5a38764 "wip: more function matching") did not build and, once made to build, produced a binary ~64% different from the ROM: it "finished" 37 functions (deleted INCLUDE_ASM) of which most did not actually match, plus left several compile/link breakages. HEAD~1 (wave-9) builds byte-perfect, so the damage was isolated to that one commit. This restores out/SCUS_971.98: OK by: - Reverting all 37 finished functions to in-progress form (INCLUDE_ASM + #ifdef SKIP_ASM-wrapped C), preserving the C drafts as diff targets. The dual-build flagged 14 as matching, but 7 of those were false matches (size-shifters: ProjectActPose, UpdateBarrier, MatchCnvoScrollerToBeltSpeed, check_anticrack_antigrab, AddSwProxySource, InitTn, DrawWipe) and the rest caused residual rodata/assembler-state side effects, so all were reverted. - Reverting two game.c switch functions (UnlockIntroCutsceneFromWid, DefeatBossFromWid) whose ROM jump tables dangle when built from C. - Reverting header perturbations no longer needed (sw.h PFNFILTER, act.c clock.h include, difficulty.h extern "C") now that their callers are asm. - Keeping harmless build-enabling decls (mpeg CMpegAudio::Update, shadow memset include) so the wrapped drafts still dual-build. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…dding) Brings the two changes from decomp/p2-leaf-matches that fable did not already have (its water.c STRUCT_OFFSET refactor and TODO cleanup were already present and superseded). Both verified byte-identical to the prior green build. - Name FUN_001c0c50/68 as GetAMRegister/UpdateAMRegister and drop extern "C" (the functions are already decompiled; rename only, mangled symbols, no asm callers depend on the raw names). - Pad SO to its real 0x550 size (STRUCT_PADDING(160)) instead of carrying the 0x2d0..0x550 base gap in each subclass: WATER drops its leading 160-pad and JT's pad goes 1090 -> 930, both keeping their fields at the same absolute offsets. This is the root-cause fix requested in the PR TheOnlyZac#257 review. - Drop the verbose truncated-base / STRUCT_OFFSET explanatory comments in water.c per the same review (the STRUCT_OFFSET calls are self-documenting). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Remove the extern "C" shortcut from matched C++ functions by renaming their
symbol_addrs.txt entries to the GCC2-mangled form, so a plain C++ decl/def
emits the exact target symbol (manglings read from nm, not hand-computed).
Symbol renames are checksum-neutral (stripped ELF); splat regenerates asm
callers and linker scripts. 38 extern "C" removed, 0 added.
- Data globals + __asm__ aliases: just drop extern "C" (C++ doesn't mangle
namespace-scope variable names; the asm alias already forces the symbol).
- Real-named free functions (OnRwmRemove, InitCplcy/FActiveCplcy/SetCpmanCpmt/
InitCplook, SetCmLookAt/ResetCmLookAtSmooth, HandleJtGrfjtsc,
SfxhMusicUnknown1/2, MvgkUnknown3/4, UnlockEndgameCutscenesFromFgs):
pre-mangle + convert owning-header/caller decls to plain C++.
- UpdateAloXfWorld: fix alo.h (it declared the literal mangled identifier),
drop the so.c _UpdateAloXfWorld __asm__ alias, call it directly.
SetAMRegister and OnDifficultyPlayerDeath keep extern "C" -- both are
load-bearing: they pass match.sh per-symbol but fail the full checksum when
converted (caller-side uchar narrowing / a GCC 2.95 register-allocation flip).
Also trim decomp/tooling-explanation, AI-process, and TODO/blocker comments
this branch added; condense the load-bearing "kept wrapped (unwrapping breaks
the checksum)" notes to one line each. Struct-field annotations and Doxygen
kept.
Verified: out/SCUS_971.98: OK.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
These were local agent/tooling artifacts that don't belong in the repo. The ignore patterns (CLAUDE.md, .claude/, docs/DECOMP_PROMPT.md, report_*.json) move to .git/info/exclude so they stay ignored locally without being tracked; .gitignore returns to its upstream form. CLAUDE.md stays on disk, untracked. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
origin/main's content is fully contained in fable (every main commit has a patch-equivalent here), so this records the integration without changing the tree. Verified: out/SCUS_971.98: OK. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PchzFriendlyFromWid is an UpperCamelCase C++ function (its real symbol is mangled), so its extern "C" in game.h was only a still-asm shortcut, not a genuine requirement. Pre-mangle the symbol to PchzFriendlyFromWid__Fi (update symbol_addrs.txt + the INCLUDE_ASM label) and declare it plain C++; it has no C callers, so this is byte-neutral. The remaining extern "C" in game.h (tally_world_completion, reload_post_death, clr_8_bytes_1) are genuinely C-linkage exports of the level/save subsystem -- siblings of get_level_completion_by_id / LsFromWid, which are bound to their literal C symbols via __asm__(). Their real symbol IS the unmangled name, so extern "C" is the correct permanent declaration, not a wart. Verified: out/SCUS_971.98: OK. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Remove inline offset trailers, "// ..." placeholders, commented-out fields, and the padding/mangling/node-list rationale notes. Doxygen API blocks kept. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
match.sh, structoff.sh, decomp_apply_drafts.py and decomp_lhf_draft.workflow.js are local agent/decomp tooling, not part of the game build (they were committed to main by an earlier session). Remove from tracking; they stay on disk via .git/info/exclude. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Wow that's a lot of code! it might a while to review this. The first and main thing I've noticed is that many functions are declared extern "C" in the P2 sources, but I think the P2 sources are all CPP (the only place I've seen C functions are the statically linked libraries).
|
I'm actually getting build errors after configuring the project with the |
The codebase compiles as C++, so functions whose binary symbol is unmangled needed an extern "C" wrapper. Many FUN_xxxx/func_xxxx placeholders, however, are already decompiled (real C body, no INCLUDE_ASM) and only kept the wrapper to emit the unmangled symbol_addrs label. Convert ~77 of them to plain C++: pre-mangle their config/symbol_addrs.txt entries to the GCC2-mangled form and drop extern "C". This is checksum-neutral (symbols are stripped from the final ELF; the compiled bytes are unchanged) — splat regenerates the asm callers, .s filenames, and auto linker scripts on the next configure. Also fix two latent SKIP_ASM build errors surfaced by the cleanup: - OnDifficultyPlayerDeath: header declared it plain C++ while the definition used extern "C"; drop the wrapper so both agree. - ub.c: declare PostGomerLoad in its owning header (gomer.h). Left as-is: functions still in assembly (INCLUDE_ASM / asm forward-decls), where extern "C" is correct scaffolding until they are reversed; plus FUN_001c9a48 (conflicting signatures across files) and the rwm/font mixed extern "C" blocks. Verified: out/SCUS_971.98: OK. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
@TheOnlyZac I fixed the build errors and a bunch of |
Resolve conflicts in 13 files between our extern "C" cleanup / leaf matches and upstream's newer decomp work. Per translation unit either branch's matched version is byte-identical to the target, so each conflicted unit was resolved to one coherent side: - ours (we matched; upstream still INCLUDE_ASM): water.c, dmas.c, gifs.c, sound.c, alo.c, so.c, and our FUN_ symbol pre-manglings (alo/sw) in symbol_addrs.txt. - theirs (upstream advanced further): murray.c, font.c, the real CFontBrx layout in font.h, so.h comments, and FUN_001c9a48 unified to (STEPGUARD*,int) in stepguard.c (resolving the prior cross-file signature conflict). - combined declarations: stepguard.h, font.h. Integration fixups so the merged tree links: - rename VTACT globals D_00219560/D_0021A790/D_002195D8 -> g_vtact/g_vtactla/ g_vtactadj in act.c and alo.c (upstream renamed them in symbol_addrs). - game.h: reload_post_death is now plain C++ (reload_post_death__Fv), drop its extern "C". Verified: out/SCUS_971.98: OK. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
tally_world_completion has no C++ callers — it's only referenced asm-to-asm, so the declaration in game.h is inert and the extern "C" served no purpose (it only matters when C++ code emits a reference to an unmangled label). Our 459b0b1 added it defensively; revert to the plain declaration, matching upstream/base. A sweep of every extern "C" declaration (inline + brace-blocks) confirmed this was the only caller-less one; all others have real C++ callers. Verified: out/SCUS_971.98: OK. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Awesome, thanks. I will start making review comments, but it will take me some time to finish. |
|
@lindskogen It seems that the model has littered the code with |
I will check it out |
| INCLUDE_ASM("asm/nonmatchings/P2/dialog", PostDialogLoad__FP6DIALOG); | ||
| void PostDialogLoad(DIALOG *pdialog) | ||
| { | ||
| extern int *PfLookupDialog(LS *pls, OID oid); |
There was a problem hiding this comment.
Move function prototypes elsewhere.
| INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpSetMusicRegister__FiP4CRefP6CFrame); | ||
| CRef RefOpSetMusicRegister(int carg, CRef *aref, CFrame *pframe) | ||
| { | ||
| SetAMRegister__FiUc(aref[0].m_tag.m_n, aref[1].m_tag.m_n); |
There was a problem hiding this comment.
Now it's conclusive. The body @ 0x1c0c08 doesn't mask its 2nd param either — move a2,a1 then uses it as a full word throughout (beq a2,v0 / sw a2 / passes a2). So nowhere — not the callers, not the body — does the original narrow the 2nd argument to 8 bits.
Answer: no, no natural combination can unmangle it
The original SetAMRegister__FiUc symbol is essentially a misnomer — it's named as taking unsigned char but is compiled as taking a full int everywhere. That makes a true unmangle impossible:
Parameters aren't free — __FiUc decodes to exactly (int, unsigned char), and unsigned char is the only type that mangles to Uc (typedef/const don't change that). So any naturally-mangled declaration must declare the 2nd param uchar.
A uchar param must narrow somewhere — GCC 2.95 will emit an andi …,0xff at a call site (or the callee). But the original has no narrowing instruction anywhere. Any insertion is a byte the original doesn't have → broken match. (That's the andi that killed the bif caller.)
Arguments can't rescue it either — to avoid the narrow you'd need the source value to already be a byte, but the original loads it as a word (lw a1,12(a2)). A uchar-typed field would compile that load as lbu instead → now you break the load rather than the call.
I don't really understand why, but the function cannot be unmangled
Per PR review (example: P2/cm.c): forward-declarations of functions defined elsewhere were scattered inline directly above the functions referencing them. Move each to its owning unit's header so declarations live in one logical place. - same-unit decls to that unit's header: cm.h, binoc.h, crusher.h, frm.h, mpeg.h, puffer.h, rwm.h (deduped a double-decl), screen.h - cross-unit to the owning unit's header: PreloadVag1 to sound.h, FUN_001d4c98 to stepzap.h, strcpy1 to text.h - new headers for units that lacked one: jp.h (func_001781E0), sce/libs.h (func_00202120/58, memmove) - drop frm.c's duplicate SignalSema decl (already in eekernel.h) - game.h: the relocated search_level_by_id replaces its stale commented-out line Declaration-only change. out/SCUS_971.98: OK. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Three "Match wave-N" commits removed previously-matched functions while adding new ones (bad rebase/merge artifacts): c436f8a (wave-4), e02bf9b (wave-8), 459b0b1 (wave-9). The functions still exist upstream. Restore them -- all are #ifdef SKIP_ASM bodies, so the binary is unchanged: - 989snd.c: snd_GotReturns - util.c: CSolveQuadratic - light.c: CloneLight - sensor.c: SetSensorSensors, FUN_001afaf8 - game.c: UnlockIntroCutsceneFromWid out/SCUS_971.98: OK. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Brings the P2 decomp from 2567 → 1890 remaining INCLUDE_ASM stubs (~677 functions newly matched) across 118 source files / 23 headers, plus the supporting struct, SIMD, and tooling work to make those matches possible. Every change is verified against the ground-truth checksum (out/SCUS_971.98: OK).
Highlights
Symbol & comment cleanup (final commit)
Notes for reviewers
Verification
./scripts/build.sh → out/SCUS_971.98: OK.