From 5e10215269f105dc7dae4e941bd053f1d600ce81 Mon Sep 17 00:00:00 2001 From: Drew T <50529377+Druthulu@users.noreply.github.com> Date: Wed, 2 Sep 2026 19:23:25 -0600 Subject: [PATCH] =?UTF-8?q?feat(md):=20bank=20the=204=20-O0-stranded=20fun?= =?UTF-8?q?ctions=20=E2=80=94=20and=20the=20class=20is=20now=20essentially?= =?UTF-8?q?=20empty?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit md_MAIN_011:func_800CF28C · md_MAIN_003:func_800D0268/func_800D0740/func_800D0C50, all byte-verified from a clean rebuild and counted from the SOURCE: md_MAIN_011 is now FULLY MATCHED (0 open stubs), md_MAIN_003 is down to 1 (func_800CF3E8). THE PREMISE I HANDED THE AGENT WAS WRONG, AND IT SAID SO. md_MAIN_011 is already a whole-object -O0 module — no carve was needed. Its real blocker was tools/jtbl_rodata_pads._s_rodata_span ignoring a trailing `.align`, the SAME defect this session fixed for md_SC07_003 from the other direction: two agents converged on it independently. Adopted this agent's stricter form (only a TRULY trailing align rounds `hi`; an interior one is followed by data that sets `hi` higher anyway). Note WHY it stayed latent: `derive`'s zero_gap self-corrects a 1-3 byte undershoot whenever the next stream item is an anchor. A C jump table has NO anchor — so the bug can only fire the moment someone banks a switch function into such an object, and when it fires it accuses the CARVE ("island layout drift"), not itself. md_MAIN_003 needed one new -O0 object, and the boundary I proposed (0x1f74 -> 0x1e58) was both too narrow and off by 0x2B8. The carve made is `md_MAIN_003_o0e` at 0x1308 (vram 0x800D0100) running to the existing o0c boundary: everything in that span is a §265 verbatim __asm__ body or an INCLUDE_ASM stub — zero optimizable C — so the whole tail flips with one cut. Proved byte-identical with NOTHING banked first (§431 discipline), then the three drafts gated one at a time. TWO MORE GENERAL DEFECTS FIXED IN jr_isolate_all, both of which silently mis-place a boundary: * an item-less CLOSING region emitted a duplicate `- [off, c, …]` line and the validator refused; the empty-region skip covered only region 0, and `_partition`'s empty `footer` made the closing region look non-empty. * A §265 VERBATIM __asm__ BODY IS PREAMBLE, AND PREAMBLE IS ASSUMED BYTE-NEUTRAL. It is not — it emits bytes. `parse_overlay_c` has four addressed-anchor forms and a verbatim body is none of them, so it attaches to the NEXT anchor: cutting at func_800D0268 would have moved 0x168 bytes of other functions into the new object while the yaml claimed the region starts higher. New `_region_emit_start()` derives the yaml offset from the region's CONTENT (item addresses + every .globl/.ent the text names that resolves inside the object) and takes min(cut, emit), so a boundary can only move DOWN. Where no verbatim asm is in play it equals the cut — every existing isolate is unchanged. BLAST RADIUS PROVEN, not argued: jtbl_rodata_pads is in the build path (`--derive` for md_*/main), so the agent rebuilt main + all 70 md_* from scratch (71/71) and then ran the full fleet: **make check-all 213/213 passed, 0 failed**, main 143dbb89 BYTE-IDENTICAL. CENSUS, denominator asserted (1057 live stubs, 0 without a .s): exactly ONE -O0-prologue stub remains stranded in an -O2 TU fleet-wide — main:func_8002C410 in src/800_b.c, 299 ins. Nothing more should be built for this class; the general tool already existed and what was missing was correctness, not coverage. --- config/splat.md_MAIN_003.yaml | 1 + src/md_MAIN_003/md_MAIN_003.c | 682 ---------------------- src/md_MAIN_003/md_MAIN_003_o0e.c | 917 ++++++++++++++++++++++++++++++ src/md_MAIN_011/md_MAIN_011.c | 185 +++++- tools/jr_isolate_all.py | 62 +- tools/jtbl_rodata_pads.py | 29 +- 6 files changed, 1176 insertions(+), 700 deletions(-) create mode 100644 src/md_MAIN_003/md_MAIN_003_o0e.c diff --git a/config/splat.md_MAIN_003.yaml b/config/splat.md_MAIN_003.yaml index 2f7a657dc9..f025b73af9 100644 --- a/config/splat.md_MAIN_003.yaml +++ b/config/splat.md_MAIN_003.yaml @@ -97,6 +97,7 @@ segments: # - [0x0, rodata, head] - [0x0, .rodata, md_MAIN_003_jr_800D1E18] # module-id header (+jtbl/ptr table) — §154-A; named for the TU holding ALL island emitters (D_800CEDF8 include, D_800CEE1C asm, MDEC literals, func_800D30D0 with its migrated strings): spimdisasm rodata-migration is same-subseg-only. Renamed _jr_800D12D0 -> _jr_800D1E18 by the S68 func_800D12D0 o0 carve (region0 became md_MAIN_003_o0d; the emitters live in the post region) - [0xd8, c, md_MAIN_003] + - [0x1308, c, md_MAIN_003_o0e] - [0x1f74, c, md_MAIN_003_o0c] - [0x24d8, c, md_MAIN_003_o0d] - [0x3020, c, md_MAIN_003_jr_800D1E18] diff --git a/src/md_MAIN_003/md_MAIN_003.c b/src/md_MAIN_003/md_MAIN_003.c index 24f52051fd..cc26835715 100644 --- a/src/md_MAIN_003/md_MAIN_003.c +++ b/src/md_MAIN_003/md_MAIN_003.c @@ -580,685 +580,3 @@ void func_800CFFEC(void) { D_800AF6DC = 0; D_800AF680 = 0; } - - -/* func_800D0100 - VERBATIM-ASM BANK (cookbook sec 265, file-scope form #1). - * -O0 body (addu $fp,$sp,$zero prologue, per-statement scheduling, every delay slot - * a nop) stranded inside md_MAIN_003's -O2 object (sec 261: 116 functions across the - * tree are this class; nothing under src/md_* globs -O0 yet). Same family as the - * already-banked func_800D0440/func_800D05B4/func_800D06BC/func_800D09A0 in this - * exact TU (same $s0 = D_800AF630 far-base idiom, same ra/fp/s0(/s1) save set). - * - * Recovered C semantics for the eventual real -O0-object decomp: - * - * void (*fn)(void) = D_800D363C[*(u16 *)((u8 *)D_800AF630 + 0xA3B4)]; - * fn(); - * - * S69 provenance: a prior real-C draft (`register u8 *p = D_800AF630; D_800D363C[*(u16*) - * (p+0xA3B4)]();`) reported MATCH under match_one's --auto-o0 (it force-compiles a - * standalone C draft at -O0 on seeing the target's frame-pointer prologue), but - * tools/recover_integration.py's real-cc1 probe against the actual TU (compiled -O2, - * per this object's Makefile globs) came back DIFF 15/29 mismatched -- exactly the - * §261 "shown an -O2 compile of its own C" failure mode: no C draft can bank this - * function inside md_MAIN_003.c's -O2 object. This file-scope verbatim body is - * opt-level-independent (cc1 passes the string through untouched per §265), so it - * reproduces the target bytes regardless of the TU's compile flags. No C externs - * shipped (link-time resolution). - */ -__asm__(".text\n.align 2\n.globl func_800D0100\n.ent\tfunc_800D0100\n" -"func_800D0100:\n.frame $sp,32,$31\n.mask 0xC0030000,-16\n.fmask 0,0\n" -".set\tnoreorder\n" -"addiu $sp, $sp, -32\n" -"sw $ra, 28($sp)\n" -"sw $fp, 24($sp)\n" -"sw $s1, 20($sp)\n" -"sw $s0, 16($sp)\n" -"addu $fp, $sp, $zero\n" -"lui $s0, %hi(D_800AF630)\n" -"addiu $s0, $s0, %lo(D_800AF630)\n" -"lui $at, 1\n" -"addu $at, $s0, $at\n" -"lhu $v0, -23628($at)\n" -"nop\n" -"addu $v1, $v0, $zero\n" -"sll $v0, $v1, 2\n" -"lui $v1, %hi(D_800D363C)\n" -"addiu $v1, $v1, %lo(D_800D363C)\n" -"addu $v0, $v0, $v1\n" -"lw $s1, 0($v0)\n" -"nop\n" -"jalr $s1\n" -"nop\n" -"addu $sp, $fp, $zero\n" -"lw $ra, 28($sp)\n" -"lw $fp, 24($sp)\n" -"lw $s1, 20($sp)\n" -"lw $s0, 16($sp)\n" -"addiu $sp, $sp, 32\n" -"jr $ra\n" -"nop\n" -".set\treorder\n.end\tfunc_800D0100\n"); - - -__asm__(".text\n.align 2\n.globl func_800D0174\n.ent\tfunc_800D0174\n" -"func_800D0174:\n.frame $sp,32,$31\n.mask 0xC0010000,-16\n.fmask 0,0\n" -".set\tnoreorder\n" -"addiu $sp, $sp, -32\n" -"sw $ra, 24($sp)\n" -"sw $fp, 20($sp)\n" -"sw $s0, 16($sp)\n" -"addu $fp, $sp, $zero\n" -"lui $s0, %hi(D_800AF630)\n" -"addiu $s0, $s0, %lo(D_800AF630)\n" -"addiu $v0, $zero, 1\n" -"lui $at, 1\n" -"addu $at, $s0, $at\n" -"sb $v0, -23583($at)\n" -"jal func_8001C044\n" -"nop\n" -"jal func_80015310\n" -"nop\n" -"jal func_8002D858\n" -"nop\n" -"lui $a0, %hi(D_800D93FC)\n" -"addiu $a0, $a0, %lo(D_800D93FC)\n" -"jal func_800183E0\n" -"nop\n" -"lui $at, %hi(D_800EC894)\n" -"sh $zero, %lo(D_800EC894)($at)\n" -"jal func_800D1E18\n" -"nop\n" -"lui $at, %hi(D_800EC8B0)\n" -"sw $v0, %lo(D_800EC8B0)($at)\n" -"jal func_800118AC\n" -"nop\n" -"addu $sp, $fp, $zero\n" -"lw $ra, 24($sp)\n" -"lw $fp, 20($sp)\n" -"lw $s0, 16($sp)\n" -"addiu $sp, $sp, 32\n" -"jr $ra\n" -"nop\n" -".set\treorder\n.end\tfunc_800D0174\n"); - - -__asm__(".text\n.align 2\n.globl func_800D0204\n.ent\tfunc_800D0204\n" -"func_800D0204:\n.frame $sp,24,$31\n.mask 0xC0000000,-8\n.fmask 0,0\n" -".set\tnoreorder\n" -"addiu $sp, $sp, -24\n" -"sw $ra, 20($sp)\n" -"sw $fp, 16($sp)\n" -"addu $fp, $sp, $zero\n" -"lui $v0, %hi(D_800EC8B0)\n" -"lw $v0, %lo(D_800EC8B0)($v0)\n" -"nop\n" -"beqz $v0, .L800D0248\n" -"nop\n" -"jal func_800D1E58\n" -"nop\n" -"jal func_800D0D6C\n" -"nop\n" -"jal func_800118AC\n" -"nop\n" -"j .L800D0250\n" -"nop\n" -".L800D0248:\n" -"jal func_800118AC\n" -"nop\n" -".L800D0250:\n" -"addu $sp, $fp, $zero\n" -"lw $ra, 20($sp)\n" -"lw $fp, 16($sp)\n" -"addiu $sp, $sp, 24\n" -"jr $ra\n" -"nop\n" -".set\treorder\n.end\tfunc_800D0204\n"); - - -INCLUDE_ASM("asm/md_MAIN_003/nonmatchings/md_MAIN_003", func_800D0268); - -__asm__(".text\n.align 2\n.globl func_800D0440\n.ent\tfunc_800D0440\n" -"func_800D0440:\n.frame $sp,40,$31\n.mask 0xC0010000,-16\n.fmask 0,0\n" -".set\tnoreorder\n" -"addiu $sp, $sp, -40\n" -"sw $ra, 32($sp)\n" -"sw $fp, 28($sp)\n" -"sw $s0, 24($sp)\n" -"addu $fp, $sp, $zero\n" -"lui $s0, %hi(D_800AF630)\n" -"addiu $s0, $s0, %lo(D_800AF630)\n" -"addiu $a0, $zero, 4\n" -"jal func_800167F0\n" -"nop\n" -"andi $v1, $v0, 65535\n" -"beqz $v1, .L800D0590\n" -"nop\n" -"lui $v0, %hi(D_800EC894)\n" -"lh $v0, %lo(D_800EC894)($v0)\n" -"addiu $v1, $zero, 1\n" -"beq $v0, $v1, .L800D04EC\n" -"nop\n" -"slti $v1, $v0, 2\n" -"beqz $v1, .L800D04A4\n" -"nop\n" -"beqz $v0, .L800D04C4\n" -"nop\n" -"j .L800D0560\n" -"nop\n" -".L800D04A4:\n" -"addiu $v1, $zero, 2\n" -"beq $v0, $v1, .L800D0510\n" -"nop\n" -"addiu $v1, $zero, 4\n" -"beq $v0, $v1, .L800D0538\n" -"nop\n" -"j .L800D0560\n" -"nop\n" -".L800D04C4:\n" -"addiu $v0, $zero, 1\n" -"lui $at, 1\n" -"addu $at, $s0, $at\n" -"sh $v0, -23626($at)\n" -"addiu $v0, $zero, 2\n" -"lui $at, 1\n" -"addu $at, $s0, $at\n" -"sh $v0, -23624($at)\n" -"j .L800D0560\n" -"nop\n" -".L800D04EC:\n" -"addiu $v0, $zero, 1\n" -"lui $at, 1\n" -"addu $at, $s0, $at\n" -"sh $v0, -23626($at)\n" -"lui $at, 1\n" -"addu $at, $s0, $at\n" -"sh $zero, -23624($at)\n" -"j .L800D0560\n" -"nop\n" -".L800D0510:\n" -"addiu $v0, $zero, 1\n" -"lui $at, 1\n" -"addu $at, $s0, $at\n" -"sh $v0, -23626($at)\n" -"addiu $v0, $zero, 1\n" -"lui $at, 1\n" -"addu $at, $s0, $at\n" -"sh $v0, -23624($at)\n" -"j .L800D0560\n" -"nop\n" -".L800D0538:\n" -"addiu $v0, $zero, 1\n" -"lui $at, 1\n" -"addu $at, $s0, $at\n" -"sh $v0, -23626($at)\n" -"addiu $v0, $zero, 4\n" -"lui $at, 1\n" -"addu $at, $s0, $at\n" -"sh $v0, -23624($at)\n" -"j .L800D0560\n" -"nop\n" -".L800D0560:\n" -"sh $zero, 16($fp)\n" -"sh $zero, 18($fp)\n" -"addiu $v0, $zero, 320\n" -"sh $v0, 20($fp)\n" -"addiu $v0, $zero, 480\n" -"sh $v0, 22($fp)\n" -"addiu $a0, $fp, 16\n" -"addu $a1, $zero, $zero\n" -"addu $a2, $zero, $zero\n" -"addu $a3, $zero, $zero\n" -"jal func_80059888\n" -"nop\n" -".L800D0590:\n" -"jal func_800D0D6C\n" -"nop\n" -"addu $sp, $fp, $zero\n" -"lw $ra, 32($sp)\n" -"lw $fp, 28($sp)\n" -"lw $s0, 24($sp)\n" -"addiu $sp, $sp, 40\n" -"jr $ra\n" -"nop\n" -".set\treorder\n.end\tfunc_800D0440\n"); - - -/* func_800D05B4 - VERBATIM-ASM BANK (cookbook sec 265, file-scope form #1). - * -O0 body (addu $fp,$sp,$zero prologue) stranded inside md_MAIN_003's -O2 object - * (sec 261/6 -- nothing under src/md_ globs -O0 yet). Recovered C semantics for the - * eventual real decomp (register u8 *s0 = D_800AF630): - * - * func_8001C044(); - * func_80015310(); - * s0[0xA3E1] = 0; - * D_800EC890 = 0; - * D_800EC8A0 = 1; - * func_800183E0((s32)&D_800D4E6C); - * func_800183E0((s32)&D_800D52BC); - * D_800EC894 = 0; - * D_800EC88C = -1; - * *(u16 *)(s0 + 0xA3B8) = 0; - * func_800118AC(); - * - * Siblings func_800D0440/func_800D06BC/func_800D09A0 (same TU) are the same shape - * banked the same way; frame/mask (48/0xC0010000,-16) matches the ra/fp/s0 save set - * used throughout this file's verbatim-asm blocks. No C externs shipped (link-time - * resolution). - */ -__asm__(".text\n.align 2\n.globl func_800D05B4\n.ent\tfunc_800D05B4\n" -"func_800D05B4:\n.frame $sp,48,$31\n.mask 0xC0010000,-16\n.fmask 0,0\n" -".set\tnoreorder\n" -"addiu $sp, $sp, -48\n" -"sw $ra, 40($sp)\n" -"sw $fp, 36($sp)\n" -"sw $s0, 32($sp)\n" -"addu $fp, $sp, $zero\n" -"lui $s0, %hi(D_800AF630)\n" -"addiu $s0, $s0, %lo(D_800AF630)\n" -"jal func_8001C044\n" -"nop\n" -"jal func_80015310\n" -"nop\n" -"lui $at, 1\n" -"addu $at, $s0, $at\n" -"sb $zero, -23583($at)\n" -"lui $at, %hi(D_800EC890)\n" -"sw $zero, %lo(D_800EC890)($at)\n" -"addiu $v0, $zero, 1\n" -"lui $at, %hi(D_800EC8A0)\n" -"sw $v0, %lo(D_800EC8A0)($at)\n" -"lui $a0, %hi(D_800D4E6C)\n" -"addiu $a0, $a0, %lo(D_800D4E6C)\n" -"jal func_800183E0\n" -"nop\n" -"lui $a0, %hi(D_800D52BC)\n" -"addiu $a0, $a0, %lo(D_800D52BC)\n" -"jal func_800183E0\n" -"nop\n" -"lui $at, %hi(D_800EC894)\n" -"sh $zero, %lo(D_800EC894)($at)\n" -"addiu $v0, $zero, -1\n" -"lui $at, %hi(D_800EC88C)\n" -"sw $v0, %lo(D_800EC88C)($at)\n" -"lui $at, 1\n" -"addu $at, $s0, $at\n" -"sh $zero, -23624($at)\n" -"jal func_800118AC\n" -"nop\n" -"addu $sp, $fp, $zero\n" -"lw $ra, 40($sp)\n" -"lw $fp, 36($sp)\n" -"lw $s0, 32($sp)\n" -"addiu $sp, $sp, 48\n" -"jr $ra\n" -"nop\n" -".set\treorder\n.end\tfunc_800D05B4\n"); - - -/* func_800D0664 - VERBATIM-ASM BANK (cookbook sec 265, file-scope form #1). - * -O0 body (addu $fp,$sp,$zero prologue, nop in every delay slot) stranded inside - * md_MAIN_003's -O2 object (sec 261/6 -- this subseg has no -O0 glob; the _o0c/_o0d - * objects start at 0x1f74, past this function's 0x186c). No -O2 C can ever emit this - * prologue, so C drafting cannot converge here -- a prior attempt scored match_one - * MATCH only because the oracle auto-detected -O0, which the real object never uses. - * This body sidesteps that entirely: cc1 passes the string through untouched, so it is - * opt-level-independent -- VERIFIED, not assumed: match_one scores MATCH 22/22 both at - * -O0 (auto) AND under --no-auto-o0 (forced -O2, the level this object really uses). - * match_one still prints its 'CANNOT BANK until the function lives in an -O0 object' - * NOTE here, but that heuristic keys only on (target has -O0 prologue) + (subseg builds - * -O2) and is blind to the draft's FORM; it describes the C lane, not this one. The - * gated-green counterexamples are in this very file: func_800D0440, func_800D05B4 and - * func_800D06BC are all -O0 bodies banked verbatim inside this -O2 subseg. - * Recovered C semantics for the eventual real decomp: - * - * register u8 *s0 = D_800AF630; // hoisted base, never read (sec 6 idiom) - * func_80015310(); - * func_800183E0((s32)&D_800D93FC); - * func_800118AC(); - * - * Immediate siblings func_800D05B4 (above) and func_800D06BC (below) are the same - * shape banked the same way; frame/mask (40/0xC0010000,-16) derived the same way they - * were -- frame 0x28=40, lowest saved reg $s0 at 0x18=24, 24-40 = -16; save set - * ra/fp/s0 = 0xC0010000. All immediates decimal (maspsx rejects hex in __asm__ - * strings). No C externs shipped (link-time resolution, sec 265 / sec 236-1). - */ -__asm__(".text\n.align 2\n.globl func_800D0664\n.ent\tfunc_800D0664\n" -"func_800D0664:\n.frame $sp,40,$31\n.mask 0xC0010000,-16\n.fmask 0,0\n" -".set\tnoreorder\n" -"addiu $sp, $sp, -40\n" -"sw $ra, 32($sp)\n" -"sw $fp, 28($sp)\n" -"sw $s0, 24($sp)\n" -"addu $fp, $sp, $zero\n" -"lui $s0, %hi(D_800AF630)\n" -"addiu $s0, $s0, %lo(D_800AF630)\n" -"jal func_80015310\n" -"nop\n" -"lui $a0, %hi(D_800D93FC)\n" -"addiu $a0, $a0, %lo(D_800D93FC)\n" -"jal func_800183E0\n" -"nop\n" -"jal func_800118AC\n" -"nop\n" -"addu $sp, $fp, $zero\n" -"lw $ra, 32($sp)\n" -"lw $fp, 28($sp)\n" -"lw $s0, 24($sp)\n" -"addiu $sp, $sp, 40\n" -"jr $ra\n" -"nop\n" -".set\treorder\n.end\tfunc_800D0664\n"); - - -/* func_800D06BC - VERBATIM-ASM BANK (cookbook sec 265, file-scope form #1). - * -O0 body (addu $fp,$sp,$zero prologue) stranded inside md_MAIN_003's -O2 object - * (sec 261/6 -- nothing under src/md_ globs -O0 yet). Recovered C semantics for the - * eventual real decomp: - * - * D_800EC890 += 4; - * if (D_800EC890 >= 128) { - * D_800EC890 = 128; - * func_800118AC(); - * } - * - * Sibling func_800D09A0 (same TU, few lines below) is the same shape banked the same - * way; frame/mask (32/0xC0010000,-16) copied from it. All immediates decimal - * (maspsx rejects hex in __asm__ strings). No C externs shipped (link-time resolution). - */ -__asm__(".text\n.align 2\n.globl func_800D06BC\n.ent\tfunc_800D06BC\n" -"func_800D06BC:\n.frame $sp,32,$31\n.mask 0xC0010000,-16\n.fmask 0,0\n" -".set\tnoreorder\n" -"addiu $sp, $sp, -32\n" -"sw $ra, 24($sp)\n" -"sw $fp, 20($sp)\n" -"sw $s0, 16($sp)\n" -"addu $fp, $sp, $zero\n" -"lui $s0, %hi(D_800AF630)\n" -"addiu $s0, $s0, %lo(D_800AF630)\n" -"jal func_800D12D0\n" -"nop\n" -"lui $v0, %hi(D_800EC890)\n" -"lw $v0, %lo(D_800EC890)($v0)\n" -"nop\n" -"addiu $v1, $v0, 4\n" -"lui $at, %hi(D_800EC890)\n" -"sw $v1, %lo(D_800EC890)($at)\n" -"lui $v0, %hi(D_800EC890)\n" -"lw $v0, %lo(D_800EC890)($v0)\n" -"nop\n" -"slti $v1, $v0, 128\n" -"bnez $v1, .L800D0724\n" -"nop\n" -"addiu $v0, $zero, 128\n" -"lui $at, %hi(D_800EC890)\n" -"sw $v0, %lo(D_800EC890)($at)\n" -"jal func_800118AC\n" -"nop\n" -".L800D0724:\n" -"addu $sp, $fp, $zero\n" -"lw $ra, 24($sp)\n" -"lw $fp, 20($sp)\n" -"lw $s0, 16($sp)\n" -"addiu $sp, $sp, 32\n" -"jr $ra\n" -"nop\n" -".set\treorder\n.end\tfunc_800D06BC\n"); - - -INCLUDE_ASM("asm/md_MAIN_003/nonmatchings/md_MAIN_003", func_800D0740); - -__asm__(".text\n.align 2\n.globl func_800D09A0\n.ent\tfunc_800D09A0\n" -"func_800D09A0:\n.frame $sp,32,$31\n.mask 0xC0010000,-16\n.fmask 0,0\n" -".set\tnoreorder\n" -"addiu $sp, $sp, -32\n" -"sw $ra, 24($sp)\n" -"sw $fp, 20($sp)\n" -"sw $s0, 16($sp)\n" -"addu $fp, $sp, $zero\n" -"lui $s0, %hi(D_800AF630)\n" -"addiu $s0, $s0, %lo(D_800AF630)\n" -"jal func_800D12D0\n" -"nop\n" -"lui $v0, %hi(D_800EC898)\n" -"lhu $v0, %lo(D_800EC898)($v0)\n" -"nop\n" -"addiu $v1, $v0, 1\n" -"addu $v0, $v1, $zero\n" -"lui $at, %hi(D_800EC898)\n" -"sh $v0, %lo(D_800EC898)($at)\n" -"lui $v0, %hi(D_800EC898)\n" -"lhu $v0, %lo(D_800EC898)($v0)\n" -"nop\n" -"andi $v1, $v0, 4\n" -"sll $a0, $v1, 16\n" -"sra $v0, $a0, 16\n" -"beqz $v0, .L800D0A24\n" -"nop\n" -"lui $v0, %hi(D_800EC894)\n" -"lh $v0, %lo(D_800EC894)($v0)\n" -"nop\n" -"addu $a0, $v0, $zero\n" -"addiu $a1, $zero, 1\n" -"jal func_800D1D14\n" -"nop\n" -"j .L800D0A40\n" -"nop\n" -".L800D0A24:\n" -"lui $v0, %hi(D_800EC894)\n" -"lh $v0, %lo(D_800EC894)($v0)\n" -"nop\n" -"addu $a0, $v0, $zero\n" -"addu $a1, $zero, $zero\n" -"jal func_800D1D14\n" -"nop\n" -".L800D0A40:\n" -"lui $v0, %hi(D_800EC898)\n" -"lh $v0, %lo(D_800EC898)($v0)\n" -"nop\n" -"slti $v1, $v0, 33\n" -"bnez $v1, .L800D0A60\n" -"nop\n" -"jal func_800118AC\n" -"nop\n" -".L800D0A60:\n" -"addu $sp, $fp, $zero\n" -"lw $ra, 24($sp)\n" -"lw $fp, 20($sp)\n" -"lw $s0, 16($sp)\n" -"addiu $sp, $sp, 32\n" -"jr $ra\n" -"nop\n" -".set\treorder\n.end\tfunc_800D09A0\n"); - - -/* func_800D0A7C - VERBATIM-ASM BANK (cookbook sec 265, file-scope form #1). - * -O0 body (addu $fp,$sp,$zero prologue) stranded inside md_MAIN_003's -O2 object - * (sec 261/6 -- nothing under src/md_ globs -O0 yet). Recovered C semantics for the - * eventual real decomp: - * - * D_800EC890 -= 4; - * if (D_800EC890 < 0) { - * D_800EC890 = 0; - * func_800146B0(1); - * *(s32 *)((u8 *)D_800AF630 + 0xA3E8) = 2; - * func_800118AC(); - * } else { - * func_800D12D0(); - * } - * - * Siblings func_800D06BC / func_800D09A0 (same TU) are the same shape banked the same - * way; frame/mask (32/0xC0010000,-16) copied from them. All immediates decimal - * (maspsx rejects hex in __asm__ strings). No C externs shipped (link-time resolution). - */ -__asm__(".text\n.align 2\n.globl func_800D0A7C\n.ent\tfunc_800D0A7C\n" -"func_800D0A7C:\n.frame $sp,32,$31\n.mask 0xC0010000,-16\n.fmask 0,0\n" -".set\tnoreorder\n" -"addiu $sp, $sp, -32\n" -"sw $ra, 24($sp)\n" -"sw $fp, 20($sp)\n" -"sw $s0, 16($sp)\n" -"addu $fp, $sp, $zero\n" -"lui $s0, %hi(D_800AF630)\n" -"addiu $s0, $s0, %lo(D_800AF630)\n" -"lui $v0, %hi(D_800EC890)\n" -"lw $v0, %lo(D_800EC890)($v0)\n" -"nop\n" -"addiu $v1, $v0, -4\n" -"lui $at, %hi(D_800EC890)\n" -"sw $v1, %lo(D_800EC890)($at)\n" -"lui $v0, %hi(D_800EC890)\n" -"lw $v0, %lo(D_800EC890)($v0)\n" -"nop\n" -"bgez $v0, .L800D0AF8\n" -"nop\n" -"lui $at, %hi(D_800EC890)\n" -"sw $zero, %lo(D_800EC890)($at)\n" -"addiu $a0, $zero, 1\n" -"jal func_800146B0\n" -"nop\n" -"addiu $v0, $zero, 2\n" -"lui $at, 1\n" -"addu $at, $s0, $at\n" -"sw $v0, -23576($at)\n" -"jal func_800118AC\n" -"nop\n" -"j .L800D0B00\n" -"nop\n" -".L800D0AF8:\n" -"jal func_800D12D0\n" -"nop\n" -".L800D0B00:\n" -"addu $sp, $fp, $zero\n" -"lw $ra, 24($sp)\n" -"lw $fp, 20($sp)\n" -"lw $s0, 16($sp)\n" -"addiu $sp, $sp, 32\n" -"jr $ra\n" -"nop\n" -".set\treorder\n.end\tfunc_800D0A7C\n"); - - -/* func_800D0B1C - VERBATIM-ASM BANK (cookbook sec 265, file-scope form #1). - * -O0 body (addu $fp,$sp,$zero prologue / 21F0A003, a nop in every delay slot, - * per-statement li) stranded inside md_MAIN_003's -O2 object (sec 261: nothing - * under src/md_* globs -O0 yet). Sec 261a addendum (d) names this TU explicitly: - * the fleet's TERMINAL state for an -O0 function stranded in an -O2 TU is the - * sec 265 verbatim-asm block IN THIS TU, not (yet) the sec 18/sec 261 _o0 carve. - * Same family and same save set (ra/fp/s0, frame 32, mask 0xC0010000,-16) as the - * already-banked func_800D0174 / func_800D0204 / func_800D0440 / func_800D06BC / - * func_800D09A0 / func_800D0A7C in this exact file. - * - * Three prior wave agents each reported match_one MATCH 77/77 for the real C body - * below (match_one force-compiles -O0 on seeing the frame-pointer prologue) and - * each was rejected by the whole-binary gate: tools/recover_integration.py's - * real-cc1 probe DIFFs 49/77 because the object's own CC1FLAGS are -O2. That is - * exactly sec 261's "shown an -O2 compile of its own C" failure mode - no C source - * can bank this function while md_MAIN_003.c compiles -O2. A raw __asm__ body is - * opt-level-independent (cc1 passes the string through untouched), so it emits the - * target bytes regardless of the TU's compile flags. - * - * Recovered C semantics for the eventual real -O0-object decomp: - * - * register u8 *s0 = D_800AF630; // sec 127 far-base hi/lo pair - * func_800183E0((s32)&D_800D4E6C); - * switch (D_800EC894) { // extern s16 D_800EC894 (lh) - * case 0: *(u16 *)(s0 + 0xA3B6) = 1; *(u16 *)(s0 + 0xA3B8) = 2; break; - * case 1: *(u16 *)(s0 + 0xA3B6) = 1; *(u16 *)(s0 + 0xA3B8) = 0; break; - * case 2: *(u16 *)(s0 + 0xA3B6) = 1; *(u16 *)(s0 + 0xA3B8) = 1; break; - * case 4: *(u16 *)(s0 + 0xA3B6) = 1; *(u16 *)(s0 + 0xA3B8) = 4; break; - * } - * - * All immediates decimal (maspsx rejects hex inside __asm__ strings); -0x5C4A = - * -23626, -0x5C48 = -23624, lui $at,(0x10000>>16) = lui $at,1. No C externs - * shipped (link-time resolution, per sec 265 / sec 236-1). - */ -__asm__(".text\n.align 2\n.globl func_800D0B1C\n.ent\tfunc_800D0B1C\n" -"func_800D0B1C:\n.frame $sp,32,$31\n.mask 0xC0010000,-16\n.fmask 0,0\n" -".set\tnoreorder\n" -"addiu $sp, $sp, -32\n" -"sw $ra, 24($sp)\n" -"sw $fp, 20($sp)\n" -"sw $s0, 16($sp)\n" -"addu $fp, $sp, $zero\n" -"lui $s0, %hi(D_800AF630)\n" -"addiu $s0, $s0, %lo(D_800AF630)\n" -"lui $a0, %hi(D_800D4E6C)\n" -"addiu $a0, $a0, %lo(D_800D4E6C)\n" -"jal func_800183E0\n" -"nop\n" -"lui $v0, %hi(D_800EC894)\n" -"lh $v0, %lo(D_800EC894)($v0)\n" -"addiu $v1, $zero, 1\n" -"beq $v0, $v1, .L800D0BC0\n" -"nop\n" -"slti $v1, $v0, 2\n" -"beqz $v1, .L800D0B78\n" -"nop\n" -"beqz $v0, .L800D0B98\n" -"nop\n" -"j .L800D0C34\n" -"nop\n" -".L800D0B78:\n" -"addiu $v1, $zero, 2\n" -"beq $v0, $v1, .L800D0BE4\n" -"nop\n" -"addiu $v1, $zero, 4\n" -"beq $v0, $v1, .L800D0C0C\n" -"nop\n" -"j .L800D0C34\n" -"nop\n" -".L800D0B98:\n" -"addiu $v0, $zero, 1\n" -"lui $at, 1\n" -"addu $at, $s0, $at\n" -"sh $v0, -23626($at)\n" -"addiu $v0, $zero, 2\n" -"lui $at, 1\n" -"addu $at, $s0, $at\n" -"sh $v0, -23624($at)\n" -"j .L800D0C34\n" -"nop\n" -".L800D0BC0:\n" -"addiu $v0, $zero, 1\n" -"lui $at, 1\n" -"addu $at, $s0, $at\n" -"sh $v0, -23626($at)\n" -"lui $at, 1\n" -"addu $at, $s0, $at\n" -"sh $zero, -23624($at)\n" -"j .L800D0C34\n" -"nop\n" -".L800D0BE4:\n" -"addiu $v0, $zero, 1\n" -"lui $at, 1\n" -"addu $at, $s0, $at\n" -"sh $v0, -23626($at)\n" -"addiu $v0, $zero, 1\n" -"lui $at, 1\n" -"addu $at, $s0, $at\n" -"sh $v0, -23624($at)\n" -"j .L800D0C34\n" -"nop\n" -".L800D0C0C:\n" -"addiu $v0, $zero, 1\n" -"lui $at, 1\n" -"addu $at, $s0, $at\n" -"sh $v0, -23626($at)\n" -"addiu $v0, $zero, 4\n" -"lui $at, 1\n" -"addu $at, $s0, $at\n" -"sh $v0, -23624($at)\n" -"j .L800D0C34\n" -"nop\n" -".L800D0C34:\n" -"addu $sp, $fp, $zero\n" -"lw $ra, 24($sp)\n" -"lw $fp, 20($sp)\n" -"lw $s0, 16($sp)\n" -"addiu $sp, $sp, 32\n" -"jr $ra\n" -"nop\n" -".set\treorder\n.end\tfunc_800D0B1C\n"); - - -INCLUDE_ASM("asm/md_MAIN_003/nonmatchings/md_MAIN_003", func_800D0C50); diff --git a/src/md_MAIN_003/md_MAIN_003_o0e.c b/src/md_MAIN_003/md_MAIN_003_o0e.c new file mode 100644 index 0000000000..4ac83410b7 --- /dev/null +++ b/src/md_MAIN_003/md_MAIN_003_o0e.c @@ -0,0 +1,917 @@ +#include "common.h" + +/* ==== Phase-26 §8b carried decl layer (jr_isolate_all.py) =================== + * The file-scope decl environment from earlier code regions of this object — + * file-local types, col-0 decls, DEFINE_func macro externs, and each earlier + * definition's implied prototype (types first, then decls in original order). + * Decls emit no code => byte-neutral. See cookbook §8c. */ +extern void (*D_800D3598[])(void); +extern void func_800CEED0(void); +extern u8 D_800B9A11; +extern s32 D_800EC694; +extern s32 D_800EC68C; +extern s16 D_800EC678; +extern s32 D_800EC67C; +extern s32 D_800EC680; +extern s32 D_800EC690; +extern s32 D_800EC698; +extern s32 D_800EC688; +extern s32 D_800EC684; +extern u8 D_800DA48C[]; +extern void func_8001C044(void); +extern void func_80015310(void); +extern void func_8002D858(void); +extern s32 func_800D1E18(void); +extern void func_800CFB3C(); +extern void func_800118AC(void); +extern void func_800CEF04(void); +extern void func_8001A9F8(s32 a0); +extern s32 CdReadRequest(s32 *a0, void *a1, s32 a2, s32 a3); +extern s32 D_800AE858; +extern void func_800CEFBC(void); +extern s32 D_800B9A18; +extern s32 D_800EC6A0; +extern s32 D_800EC6A4; +extern unsigned char D_800DA48C[]; +extern void func_800D1E58(void); +extern void func_800CFFEC(void); +extern void func_800CF010(void); +extern void func_800CF3E8(void); +extern s32 func_800CFC1C(); +extern void func_800CF078(void); +extern s32 func_800149E0(s32); +extern s32 func_80014B10(s32); +extern void func_8002D4C8(s32, s32); +extern void func_800CFE00(void); +extern void func_800CF104(void); +extern void func_80059888(void *a0, s32 a1, s32 a2, s32 a3); +extern void func_800CF300(void); +extern void func_800146B0(s32); +extern void func_800118AC(); +extern void func_800CF370(void); +extern s8 D_800D52BC[]; +extern u16 D_800B99E6; +extern u16 D_800B99E8; +extern void func_800183E0(s32 a0); +extern void func_800CF3A4(void); +extern s32 D_800EC69C; +extern void func_800599B8(); +extern void func_800CFB3C(u16 *arg0); +extern s32 func_800CFC1C(u16 *param_1); +extern void func_800599B8(u16 *, u16 *); +extern s32 func_800CFEB4(u16 *arg0); +extern u16 D_800AF7BC; +extern u16 D_800AF7BE; +extern u16 D_800AF7C0; +extern void GsInitGraph2(s32 w, s32 h, s32 mode, s32 a3, s32 st); +extern void func_80053EEC(s32 a0, s32 a1, s32 a2, s32 a3); +extern void func_80059234(s32 a0); +extern void func_80053218(void); +extern void func_800147B8(void); +extern u8 D_800AF6DC; +extern u8 D_800AF680; +/* ==== end §8b carried decl layer ==== */ + + +/* func_800D0100 - VERBATIM-ASM BANK (cookbook sec 265, file-scope form #1). + * -O0 body (addu $fp,$sp,$zero prologue, per-statement scheduling, every delay slot + * a nop) stranded inside md_MAIN_003's -O2 object (sec 261: 116 functions across the + * tree are this class; nothing under src/md_* globs -O0 yet). Same family as the + * already-banked func_800D0440/func_800D05B4/func_800D06BC/func_800D09A0 in this + * exact TU (same $s0 = D_800AF630 far-base idiom, same ra/fp/s0(/s1) save set). + * + * Recovered C semantics for the eventual real -O0-object decomp: + * + * void (*fn)(void) = D_800D363C[*(u16 *)((u8 *)D_800AF630 + 0xA3B4)]; + * fn(); + * + * S69 provenance: a prior real-C draft (`register u8 *p = D_800AF630; D_800D363C[*(u16*) + * (p+0xA3B4)]();`) reported MATCH under match_one's --auto-o0 (it force-compiles a + * standalone C draft at -O0 on seeing the target's frame-pointer prologue), but + * tools/recover_integration.py's real-cc1 probe against the actual TU (compiled -O2, + * per this object's Makefile globs) came back DIFF 15/29 mismatched -- exactly the + * §261 "shown an -O2 compile of its own C" failure mode: no C draft can bank this + * function inside md_MAIN_003.c's -O2 object. This file-scope verbatim body is + * opt-level-independent (cc1 passes the string through untouched per §265), so it + * reproduces the target bytes regardless of the TU's compile flags. No C externs + * shipped (link-time resolution). + */ +__asm__(".text\n.align 2\n.globl func_800D0100\n.ent\tfunc_800D0100\n" +"func_800D0100:\n.frame $sp,32,$31\n.mask 0xC0030000,-16\n.fmask 0,0\n" +".set\tnoreorder\n" +"addiu $sp, $sp, -32\n" +"sw $ra, 28($sp)\n" +"sw $fp, 24($sp)\n" +"sw $s1, 20($sp)\n" +"sw $s0, 16($sp)\n" +"addu $fp, $sp, $zero\n" +"lui $s0, %hi(D_800AF630)\n" +"addiu $s0, $s0, %lo(D_800AF630)\n" +"lui $at, 1\n" +"addu $at, $s0, $at\n" +"lhu $v0, -23628($at)\n" +"nop\n" +"addu $v1, $v0, $zero\n" +"sll $v0, $v1, 2\n" +"lui $v1, %hi(D_800D363C)\n" +"addiu $v1, $v1, %lo(D_800D363C)\n" +"addu $v0, $v0, $v1\n" +"lw $s1, 0($v0)\n" +"nop\n" +"jalr $s1\n" +"nop\n" +"addu $sp, $fp, $zero\n" +"lw $ra, 28($sp)\n" +"lw $fp, 24($sp)\n" +"lw $s1, 20($sp)\n" +"lw $s0, 16($sp)\n" +"addiu $sp, $sp, 32\n" +"jr $ra\n" +"nop\n" +".set\treorder\n.end\tfunc_800D0100\n"); + + +__asm__(".text\n.align 2\n.globl func_800D0174\n.ent\tfunc_800D0174\n" +"func_800D0174:\n.frame $sp,32,$31\n.mask 0xC0010000,-16\n.fmask 0,0\n" +".set\tnoreorder\n" +"addiu $sp, $sp, -32\n" +"sw $ra, 24($sp)\n" +"sw $fp, 20($sp)\n" +"sw $s0, 16($sp)\n" +"addu $fp, $sp, $zero\n" +"lui $s0, %hi(D_800AF630)\n" +"addiu $s0, $s0, %lo(D_800AF630)\n" +"addiu $v0, $zero, 1\n" +"lui $at, 1\n" +"addu $at, $s0, $at\n" +"sb $v0, -23583($at)\n" +"jal func_8001C044\n" +"nop\n" +"jal func_80015310\n" +"nop\n" +"jal func_8002D858\n" +"nop\n" +"lui $a0, %hi(D_800D93FC)\n" +"addiu $a0, $a0, %lo(D_800D93FC)\n" +"jal func_800183E0\n" +"nop\n" +"lui $at, %hi(D_800EC894)\n" +"sh $zero, %lo(D_800EC894)($at)\n" +"jal func_800D1E18\n" +"nop\n" +"lui $at, %hi(D_800EC8B0)\n" +"sw $v0, %lo(D_800EC8B0)($at)\n" +"jal func_800118AC\n" +"nop\n" +"addu $sp, $fp, $zero\n" +"lw $ra, 24($sp)\n" +"lw $fp, 20($sp)\n" +"lw $s0, 16($sp)\n" +"addiu $sp, $sp, 32\n" +"jr $ra\n" +"nop\n" +".set\treorder\n.end\tfunc_800D0174\n"); + + +__asm__(".text\n.align 2\n.globl func_800D0204\n.ent\tfunc_800D0204\n" +"func_800D0204:\n.frame $sp,24,$31\n.mask 0xC0000000,-8\n.fmask 0,0\n" +".set\tnoreorder\n" +"addiu $sp, $sp, -24\n" +"sw $ra, 20($sp)\n" +"sw $fp, 16($sp)\n" +"addu $fp, $sp, $zero\n" +"lui $v0, %hi(D_800EC8B0)\n" +"lw $v0, %lo(D_800EC8B0)($v0)\n" +"nop\n" +"beqz $v0, .L800D0248\n" +"nop\n" +"jal func_800D1E58\n" +"nop\n" +"jal func_800D0D6C\n" +"nop\n" +"jal func_800118AC\n" +"nop\n" +"j .L800D0250\n" +"nop\n" +".L800D0248:\n" +"jal func_800118AC\n" +"nop\n" +".L800D0250:\n" +"addu $sp, $fp, $zero\n" +"lw $ra, 20($sp)\n" +"lw $fp, 16($sp)\n" +"addiu $sp, $sp, 24\n" +"jr $ra\n" +"nop\n" +".set\treorder\n.end\tfunc_800D0204\n"); + + +extern s32 func_800149E0(s32 arg0); +extern u8 D_800AF630[]; +extern void func_8002D4C8(s32 arg0, s32 arg1); +extern s16 D_800EC894; +extern void func_800167B8(s32 arg0); +extern void func_800118AC(void); +extern void func_800D0D6C(void); + +void func_800D0268(void) { + u16 sp10; + register u8 *p = D_800AF630; + + sp10 = func_800149E0(0); + if (sp10 & 0x4000) { + func_8002D4C8(0x9C1, 0); + D_800EC894++; + if (D_800EC894 >= 3) { + D_800EC894 = 0; + } + } else if (sp10 & 0x1000) { + func_8002D4C8(0x9C1, 0); + D_800EC894--; + if (D_800EC894 < 0) { + D_800EC894 = 2; + } + } + switch (D_800EC894) { + case 0: + if (sp10 & 0x800) { + func_8002D4C8(0x9C0, 0); + func_800167B8(4); + func_800118AC(); + } + break; + case 1: + case 2: + if (sp10 & 0x800) { + func_8002D4C8(0x9C0, 0); + func_800167B8(4); + func_800118AC(); + } + break; + } + func_800D0D6C(); +} + + +__asm__(".text\n.align 2\n.globl func_800D0440\n.ent\tfunc_800D0440\n" +"func_800D0440:\n.frame $sp,40,$31\n.mask 0xC0010000,-16\n.fmask 0,0\n" +".set\tnoreorder\n" +"addiu $sp, $sp, -40\n" +"sw $ra, 32($sp)\n" +"sw $fp, 28($sp)\n" +"sw $s0, 24($sp)\n" +"addu $fp, $sp, $zero\n" +"lui $s0, %hi(D_800AF630)\n" +"addiu $s0, $s0, %lo(D_800AF630)\n" +"addiu $a0, $zero, 4\n" +"jal func_800167F0\n" +"nop\n" +"andi $v1, $v0, 65535\n" +"beqz $v1, .L800D0590\n" +"nop\n" +"lui $v0, %hi(D_800EC894)\n" +"lh $v0, %lo(D_800EC894)($v0)\n" +"addiu $v1, $zero, 1\n" +"beq $v0, $v1, .L800D04EC\n" +"nop\n" +"slti $v1, $v0, 2\n" +"beqz $v1, .L800D04A4\n" +"nop\n" +"beqz $v0, .L800D04C4\n" +"nop\n" +"j .L800D0560\n" +"nop\n" +".L800D04A4:\n" +"addiu $v1, $zero, 2\n" +"beq $v0, $v1, .L800D0510\n" +"nop\n" +"addiu $v1, $zero, 4\n" +"beq $v0, $v1, .L800D0538\n" +"nop\n" +"j .L800D0560\n" +"nop\n" +".L800D04C4:\n" +"addiu $v0, $zero, 1\n" +"lui $at, 1\n" +"addu $at, $s0, $at\n" +"sh $v0, -23626($at)\n" +"addiu $v0, $zero, 2\n" +"lui $at, 1\n" +"addu $at, $s0, $at\n" +"sh $v0, -23624($at)\n" +"j .L800D0560\n" +"nop\n" +".L800D04EC:\n" +"addiu $v0, $zero, 1\n" +"lui $at, 1\n" +"addu $at, $s0, $at\n" +"sh $v0, -23626($at)\n" +"lui $at, 1\n" +"addu $at, $s0, $at\n" +"sh $zero, -23624($at)\n" +"j .L800D0560\n" +"nop\n" +".L800D0510:\n" +"addiu $v0, $zero, 1\n" +"lui $at, 1\n" +"addu $at, $s0, $at\n" +"sh $v0, -23626($at)\n" +"addiu $v0, $zero, 1\n" +"lui $at, 1\n" +"addu $at, $s0, $at\n" +"sh $v0, -23624($at)\n" +"j .L800D0560\n" +"nop\n" +".L800D0538:\n" +"addiu $v0, $zero, 1\n" +"lui $at, 1\n" +"addu $at, $s0, $at\n" +"sh $v0, -23626($at)\n" +"addiu $v0, $zero, 4\n" +"lui $at, 1\n" +"addu $at, $s0, $at\n" +"sh $v0, -23624($at)\n" +"j .L800D0560\n" +"nop\n" +".L800D0560:\n" +"sh $zero, 16($fp)\n" +"sh $zero, 18($fp)\n" +"addiu $v0, $zero, 320\n" +"sh $v0, 20($fp)\n" +"addiu $v0, $zero, 480\n" +"sh $v0, 22($fp)\n" +"addiu $a0, $fp, 16\n" +"addu $a1, $zero, $zero\n" +"addu $a2, $zero, $zero\n" +"addu $a3, $zero, $zero\n" +"jal func_80059888\n" +"nop\n" +".L800D0590:\n" +"jal func_800D0D6C\n" +"nop\n" +"addu $sp, $fp, $zero\n" +"lw $ra, 32($sp)\n" +"lw $fp, 28($sp)\n" +"lw $s0, 24($sp)\n" +"addiu $sp, $sp, 40\n" +"jr $ra\n" +"nop\n" +".set\treorder\n.end\tfunc_800D0440\n"); + + +/* func_800D05B4 - VERBATIM-ASM BANK (cookbook sec 265, file-scope form #1). + * -O0 body (addu $fp,$sp,$zero prologue) stranded inside md_MAIN_003's -O2 object + * (sec 261/6 -- nothing under src/md_ globs -O0 yet). Recovered C semantics for the + * eventual real decomp (register u8 *s0 = D_800AF630): + * + * func_8001C044(); + * func_80015310(); + * s0[0xA3E1] = 0; + * D_800EC890 = 0; + * D_800EC8A0 = 1; + * func_800183E0((s32)&D_800D4E6C); + * func_800183E0((s32)&D_800D52BC); + * D_800EC894 = 0; + * D_800EC88C = -1; + * *(u16 *)(s0 + 0xA3B8) = 0; + * func_800118AC(); + * + * Siblings func_800D0440/func_800D06BC/func_800D09A0 (same TU) are the same shape + * banked the same way; frame/mask (48/0xC0010000,-16) matches the ra/fp/s0 save set + * used throughout this file's verbatim-asm blocks. No C externs shipped (link-time + * resolution). + */ +__asm__(".text\n.align 2\n.globl func_800D05B4\n.ent\tfunc_800D05B4\n" +"func_800D05B4:\n.frame $sp,48,$31\n.mask 0xC0010000,-16\n.fmask 0,0\n" +".set\tnoreorder\n" +"addiu $sp, $sp, -48\n" +"sw $ra, 40($sp)\n" +"sw $fp, 36($sp)\n" +"sw $s0, 32($sp)\n" +"addu $fp, $sp, $zero\n" +"lui $s0, %hi(D_800AF630)\n" +"addiu $s0, $s0, %lo(D_800AF630)\n" +"jal func_8001C044\n" +"nop\n" +"jal func_80015310\n" +"nop\n" +"lui $at, 1\n" +"addu $at, $s0, $at\n" +"sb $zero, -23583($at)\n" +"lui $at, %hi(D_800EC890)\n" +"sw $zero, %lo(D_800EC890)($at)\n" +"addiu $v0, $zero, 1\n" +"lui $at, %hi(D_800EC8A0)\n" +"sw $v0, %lo(D_800EC8A0)($at)\n" +"lui $a0, %hi(D_800D4E6C)\n" +"addiu $a0, $a0, %lo(D_800D4E6C)\n" +"jal func_800183E0\n" +"nop\n" +"lui $a0, %hi(D_800D52BC)\n" +"addiu $a0, $a0, %lo(D_800D52BC)\n" +"jal func_800183E0\n" +"nop\n" +"lui $at, %hi(D_800EC894)\n" +"sh $zero, %lo(D_800EC894)($at)\n" +"addiu $v0, $zero, -1\n" +"lui $at, %hi(D_800EC88C)\n" +"sw $v0, %lo(D_800EC88C)($at)\n" +"lui $at, 1\n" +"addu $at, $s0, $at\n" +"sh $zero, -23624($at)\n" +"jal func_800118AC\n" +"nop\n" +"addu $sp, $fp, $zero\n" +"lw $ra, 40($sp)\n" +"lw $fp, 36($sp)\n" +"lw $s0, 32($sp)\n" +"addiu $sp, $sp, 48\n" +"jr $ra\n" +"nop\n" +".set\treorder\n.end\tfunc_800D05B4\n"); + + +/* func_800D0664 - VERBATIM-ASM BANK (cookbook sec 265, file-scope form #1). + * -O0 body (addu $fp,$sp,$zero prologue, nop in every delay slot) stranded inside + * md_MAIN_003's -O2 object (sec 261/6 -- this subseg has no -O0 glob; the _o0c/_o0d + * objects start at 0x1f74, past this function's 0x186c). No -O2 C can ever emit this + * prologue, so C drafting cannot converge here -- a prior attempt scored match_one + * MATCH only because the oracle auto-detected -O0, which the real object never uses. + * This body sidesteps that entirely: cc1 passes the string through untouched, so it is + * opt-level-independent -- VERIFIED, not assumed: match_one scores MATCH 22/22 both at + * -O0 (auto) AND under --no-auto-o0 (forced -O2, the level this object really uses). + * match_one still prints its 'CANNOT BANK until the function lives in an -O0 object' + * NOTE here, but that heuristic keys only on (target has -O0 prologue) + (subseg builds + * -O2) and is blind to the draft's FORM; it describes the C lane, not this one. The + * gated-green counterexamples are in this very file: func_800D0440, func_800D05B4 and + * func_800D06BC are all -O0 bodies banked verbatim inside this -O2 subseg. + * Recovered C semantics for the eventual real decomp: + * + * register u8 *s0 = D_800AF630; // hoisted base, never read (sec 6 idiom) + * func_80015310(); + * func_800183E0((s32)&D_800D93FC); + * func_800118AC(); + * + * Immediate siblings func_800D05B4 (above) and func_800D06BC (below) are the same + * shape banked the same way; frame/mask (40/0xC0010000,-16) derived the same way they + * were -- frame 0x28=40, lowest saved reg $s0 at 0x18=24, 24-40 = -16; save set + * ra/fp/s0 = 0xC0010000. All immediates decimal (maspsx rejects hex in __asm__ + * strings). No C externs shipped (link-time resolution, sec 265 / sec 236-1). + */ +__asm__(".text\n.align 2\n.globl func_800D0664\n.ent\tfunc_800D0664\n" +"func_800D0664:\n.frame $sp,40,$31\n.mask 0xC0010000,-16\n.fmask 0,0\n" +".set\tnoreorder\n" +"addiu $sp, $sp, -40\n" +"sw $ra, 32($sp)\n" +"sw $fp, 28($sp)\n" +"sw $s0, 24($sp)\n" +"addu $fp, $sp, $zero\n" +"lui $s0, %hi(D_800AF630)\n" +"addiu $s0, $s0, %lo(D_800AF630)\n" +"jal func_80015310\n" +"nop\n" +"lui $a0, %hi(D_800D93FC)\n" +"addiu $a0, $a0, %lo(D_800D93FC)\n" +"jal func_800183E0\n" +"nop\n" +"jal func_800118AC\n" +"nop\n" +"addu $sp, $fp, $zero\n" +"lw $ra, 32($sp)\n" +"lw $fp, 28($sp)\n" +"lw $s0, 24($sp)\n" +"addiu $sp, $sp, 40\n" +"jr $ra\n" +"nop\n" +".set\treorder\n.end\tfunc_800D0664\n"); + + +/* func_800D06BC - VERBATIM-ASM BANK (cookbook sec 265, file-scope form #1). + * -O0 body (addu $fp,$sp,$zero prologue) stranded inside md_MAIN_003's -O2 object + * (sec 261/6 -- nothing under src/md_ globs -O0 yet). Recovered C semantics for the + * eventual real decomp: + * + * D_800EC890 += 4; + * if (D_800EC890 >= 128) { + * D_800EC890 = 128; + * func_800118AC(); + * } + * + * Sibling func_800D09A0 (same TU, few lines below) is the same shape banked the same + * way; frame/mask (32/0xC0010000,-16) copied from it. All immediates decimal + * (maspsx rejects hex in __asm__ strings). No C externs shipped (link-time resolution). + */ +__asm__(".text\n.align 2\n.globl func_800D06BC\n.ent\tfunc_800D06BC\n" +"func_800D06BC:\n.frame $sp,32,$31\n.mask 0xC0010000,-16\n.fmask 0,0\n" +".set\tnoreorder\n" +"addiu $sp, $sp, -32\n" +"sw $ra, 24($sp)\n" +"sw $fp, 20($sp)\n" +"sw $s0, 16($sp)\n" +"addu $fp, $sp, $zero\n" +"lui $s0, %hi(D_800AF630)\n" +"addiu $s0, $s0, %lo(D_800AF630)\n" +"jal func_800D12D0\n" +"nop\n" +"lui $v0, %hi(D_800EC890)\n" +"lw $v0, %lo(D_800EC890)($v0)\n" +"nop\n" +"addiu $v1, $v0, 4\n" +"lui $at, %hi(D_800EC890)\n" +"sw $v1, %lo(D_800EC890)($at)\n" +"lui $v0, %hi(D_800EC890)\n" +"lw $v0, %lo(D_800EC890)($v0)\n" +"nop\n" +"slti $v1, $v0, 128\n" +"bnez $v1, .L800D0724\n" +"nop\n" +"addiu $v0, $zero, 128\n" +"lui $at, %hi(D_800EC890)\n" +"sw $v0, %lo(D_800EC890)($at)\n" +"jal func_800118AC\n" +"nop\n" +".L800D0724:\n" +"addu $sp, $fp, $zero\n" +"lw $ra, 24($sp)\n" +"lw $fp, 20($sp)\n" +"lw $s0, 16($sp)\n" +"addiu $sp, $sp, 32\n" +"jr $ra\n" +"nop\n" +".set\treorder\n.end\tfunc_800D06BC\n"); + + +/* func_800D0740 - the pad-driven 3-way menu cursor tick. + * + * -O0 BODY (§261a). match_one force-compiles -O0 on seeing the frame-pointer + * prologue (sw $fp / addu $fp,$sp,$zero) and reports MATCH 152/152. It CANNOT + * bank while md_MAIN_003.c compiles -O2 -- it needs an -O0 object of its own + * (tools/o0_subsplit.py / rollout_o0.py), exactly like the siblings + * func_800D06BC / func_800D09A0 that are banked as §265 verbatim __asm__. + * Its true home is a md_MAIN_003_o0*.c, whose house spellings are copied below. + * + * The three -O0 laws this body rests on: + * - `register u8 *base = D_800AF630;` is the §6 / §127 far-base idiom: never + * read, but it emits the lui/addiu %hi/%lo pair. Here it crosses calls, so + * -O0 gives it a CALLEE-saved reg ($s0) -- unlike the o0c/o0d instances that + * land in $v0 for want of a call. + * - `D_800EC894++` / `--D_800EC88C` AS A STATEMENT routes through + * expand_increment -> expand_assignment(want_value=1) -> store_expr's + * copy_to_reg, which is what emits the extra `addu $v0,$v1,$zero` / + * `addu $v1,$v0,$zero` copy before the store. `x = x + 1;` does NOT emit it. + * The same law lets `if (--D_800EC88C == 0)` test the COPY with no reload. + * - expand_binop's no_extend=1 for add/sub/and makes the s16 global load `lhu` + * when it feeds arithmetic but `lh` (+ signed `slti`, not `sltiu`) when it + * feeds a comparison. A prior draft read that `lhu` as proof of u16 and got + * `sltiu` -- that single mistype cost it 109 instructions. + * - the beqz / bltz / slti 3 / beqz / j ladder is emit_case_nodes on a real + * `switch` whose `case 1:` and `case 2:` share one body (two separate `if`s + * cannot produce the bltz + slti pair). + * + * Verified past match_one's masking (law 1c / §195-D): all 56 relocations are + * symbol-for-symbol identical to the .s, and all 15 edges -- including the four + * internal `j` targets that masked_diff.mask_for zeroes -- were compared + * unmasked against the objdump of the kept object. + */ + +extern u16 D_800EC888; +extern s16 D_800EC894; +extern s16 D_800EC898; +extern s32 D_800EC88C; +extern u8 D_800AF630[]; + +extern void func_800D12D0(void); +extern s32 func_800149E0(s32); +extern void func_8002D4C8(s32, s32); +extern void func_800167B8(s32); +extern void func_800118AC(); + +void func_800D0740(void) { + register u8 *base = D_800AF630; + s32 sp10; + + func_800D12D0(); + D_800EC888 = func_800149E0(0); + sp10 = 0; + if (D_800EC888 & 0x4000) { + func_8002D4C8(0x9C1, 0); + sp10 = 1; + D_800EC894++; + if (D_800EC894 >= 3) { + D_800EC894 = 0; + } + } else if (D_800EC888 & 0x1000) { + func_8002D4C8(0x9C1, 0); + sp10 = 1; + D_800EC894--; + if (D_800EC894 < 0) { + D_800EC894 = 2; + } + } + D_800EC898 = 0; + switch (D_800EC894) { + case 0: + if (D_800EC888 & 0x800) { + func_8002D4C8(0x9C0, 0); + func_800167B8(4); + func_800118AC(); + } + break; + case 1: + case 2: + if (D_800EC888 & 0x800) { + func_8002D4C8(0x9C0, 0); + func_800167B8(4); + func_800118AC(); + } + break; + } + if (D_800EC88C > 0) { + if (--D_800EC88C == 0) { + func_800167B8(4); + D_800EC894 = 4; + func_800118AC(); + } + } +} + + +__asm__(".text\n.align 2\n.globl func_800D09A0\n.ent\tfunc_800D09A0\n" +"func_800D09A0:\n.frame $sp,32,$31\n.mask 0xC0010000,-16\n.fmask 0,0\n" +".set\tnoreorder\n" +"addiu $sp, $sp, -32\n" +"sw $ra, 24($sp)\n" +"sw $fp, 20($sp)\n" +"sw $s0, 16($sp)\n" +"addu $fp, $sp, $zero\n" +"lui $s0, %hi(D_800AF630)\n" +"addiu $s0, $s0, %lo(D_800AF630)\n" +"jal func_800D12D0\n" +"nop\n" +"lui $v0, %hi(D_800EC898)\n" +"lhu $v0, %lo(D_800EC898)($v0)\n" +"nop\n" +"addiu $v1, $v0, 1\n" +"addu $v0, $v1, $zero\n" +"lui $at, %hi(D_800EC898)\n" +"sh $v0, %lo(D_800EC898)($at)\n" +"lui $v0, %hi(D_800EC898)\n" +"lhu $v0, %lo(D_800EC898)($v0)\n" +"nop\n" +"andi $v1, $v0, 4\n" +"sll $a0, $v1, 16\n" +"sra $v0, $a0, 16\n" +"beqz $v0, .L800D0A24\n" +"nop\n" +"lui $v0, %hi(D_800EC894)\n" +"lh $v0, %lo(D_800EC894)($v0)\n" +"nop\n" +"addu $a0, $v0, $zero\n" +"addiu $a1, $zero, 1\n" +"jal func_800D1D14\n" +"nop\n" +"j .L800D0A40\n" +"nop\n" +".L800D0A24:\n" +"lui $v0, %hi(D_800EC894)\n" +"lh $v0, %lo(D_800EC894)($v0)\n" +"nop\n" +"addu $a0, $v0, $zero\n" +"addu $a1, $zero, $zero\n" +"jal func_800D1D14\n" +"nop\n" +".L800D0A40:\n" +"lui $v0, %hi(D_800EC898)\n" +"lh $v0, %lo(D_800EC898)($v0)\n" +"nop\n" +"slti $v1, $v0, 33\n" +"bnez $v1, .L800D0A60\n" +"nop\n" +"jal func_800118AC\n" +"nop\n" +".L800D0A60:\n" +"addu $sp, $fp, $zero\n" +"lw $ra, 24($sp)\n" +"lw $fp, 20($sp)\n" +"lw $s0, 16($sp)\n" +"addiu $sp, $sp, 32\n" +"jr $ra\n" +"nop\n" +".set\treorder\n.end\tfunc_800D09A0\n"); + + +/* func_800D0A7C - VERBATIM-ASM BANK (cookbook sec 265, file-scope form #1). + * -O0 body (addu $fp,$sp,$zero prologue) stranded inside md_MAIN_003's -O2 object + * (sec 261/6 -- nothing under src/md_ globs -O0 yet). Recovered C semantics for the + * eventual real decomp: + * + * D_800EC890 -= 4; + * if (D_800EC890 < 0) { + * D_800EC890 = 0; + * func_800146B0(1); + * *(s32 *)((u8 *)D_800AF630 + 0xA3E8) = 2; + * func_800118AC(); + * } else { + * func_800D12D0(); + * } + * + * Siblings func_800D06BC / func_800D09A0 (same TU) are the same shape banked the same + * way; frame/mask (32/0xC0010000,-16) copied from them. All immediates decimal + * (maspsx rejects hex in __asm__ strings). No C externs shipped (link-time resolution). + */ +__asm__(".text\n.align 2\n.globl func_800D0A7C\n.ent\tfunc_800D0A7C\n" +"func_800D0A7C:\n.frame $sp,32,$31\n.mask 0xC0010000,-16\n.fmask 0,0\n" +".set\tnoreorder\n" +"addiu $sp, $sp, -32\n" +"sw $ra, 24($sp)\n" +"sw $fp, 20($sp)\n" +"sw $s0, 16($sp)\n" +"addu $fp, $sp, $zero\n" +"lui $s0, %hi(D_800AF630)\n" +"addiu $s0, $s0, %lo(D_800AF630)\n" +"lui $v0, %hi(D_800EC890)\n" +"lw $v0, %lo(D_800EC890)($v0)\n" +"nop\n" +"addiu $v1, $v0, -4\n" +"lui $at, %hi(D_800EC890)\n" +"sw $v1, %lo(D_800EC890)($at)\n" +"lui $v0, %hi(D_800EC890)\n" +"lw $v0, %lo(D_800EC890)($v0)\n" +"nop\n" +"bgez $v0, .L800D0AF8\n" +"nop\n" +"lui $at, %hi(D_800EC890)\n" +"sw $zero, %lo(D_800EC890)($at)\n" +"addiu $a0, $zero, 1\n" +"jal func_800146B0\n" +"nop\n" +"addiu $v0, $zero, 2\n" +"lui $at, 1\n" +"addu $at, $s0, $at\n" +"sw $v0, -23576($at)\n" +"jal func_800118AC\n" +"nop\n" +"j .L800D0B00\n" +"nop\n" +".L800D0AF8:\n" +"jal func_800D12D0\n" +"nop\n" +".L800D0B00:\n" +"addu $sp, $fp, $zero\n" +"lw $ra, 24($sp)\n" +"lw $fp, 20($sp)\n" +"lw $s0, 16($sp)\n" +"addiu $sp, $sp, 32\n" +"jr $ra\n" +"nop\n" +".set\treorder\n.end\tfunc_800D0A7C\n"); + + +/* func_800D0B1C - VERBATIM-ASM BANK (cookbook sec 265, file-scope form #1). + * -O0 body (addu $fp,$sp,$zero prologue / 21F0A003, a nop in every delay slot, + * per-statement li) stranded inside md_MAIN_003's -O2 object (sec 261: nothing + * under src/md_* globs -O0 yet). Sec 261a addendum (d) names this TU explicitly: + * the fleet's TERMINAL state for an -O0 function stranded in an -O2 TU is the + * sec 265 verbatim-asm block IN THIS TU, not (yet) the sec 18/sec 261 _o0 carve. + * Same family and same save set (ra/fp/s0, frame 32, mask 0xC0010000,-16) as the + * already-banked func_800D0174 / func_800D0204 / func_800D0440 / func_800D06BC / + * func_800D09A0 / func_800D0A7C in this exact file. + * + * Three prior wave agents each reported match_one MATCH 77/77 for the real C body + * below (match_one force-compiles -O0 on seeing the frame-pointer prologue) and + * each was rejected by the whole-binary gate: tools/recover_integration.py's + * real-cc1 probe DIFFs 49/77 because the object's own CC1FLAGS are -O2. That is + * exactly sec 261's "shown an -O2 compile of its own C" failure mode - no C source + * can bank this function while md_MAIN_003.c compiles -O2. A raw __asm__ body is + * opt-level-independent (cc1 passes the string through untouched), so it emits the + * target bytes regardless of the TU's compile flags. + * + * Recovered C semantics for the eventual real -O0-object decomp: + * + * register u8 *s0 = D_800AF630; // sec 127 far-base hi/lo pair + * func_800183E0((s32)&D_800D4E6C); + * switch (D_800EC894) { // extern s16 D_800EC894 (lh) + * case 0: *(u16 *)(s0 + 0xA3B6) = 1; *(u16 *)(s0 + 0xA3B8) = 2; break; + * case 1: *(u16 *)(s0 + 0xA3B6) = 1; *(u16 *)(s0 + 0xA3B8) = 0; break; + * case 2: *(u16 *)(s0 + 0xA3B6) = 1; *(u16 *)(s0 + 0xA3B8) = 1; break; + * case 4: *(u16 *)(s0 + 0xA3B6) = 1; *(u16 *)(s0 + 0xA3B8) = 4; break; + * } + * + * All immediates decimal (maspsx rejects hex inside __asm__ strings); -0x5C4A = + * -23626, -0x5C48 = -23624, lui $at,(0x10000>>16) = lui $at,1. No C externs + * shipped (link-time resolution, per sec 265 / sec 236-1). + */ +__asm__(".text\n.align 2\n.globl func_800D0B1C\n.ent\tfunc_800D0B1C\n" +"func_800D0B1C:\n.frame $sp,32,$31\n.mask 0xC0010000,-16\n.fmask 0,0\n" +".set\tnoreorder\n" +"addiu $sp, $sp, -32\n" +"sw $ra, 24($sp)\n" +"sw $fp, 20($sp)\n" +"sw $s0, 16($sp)\n" +"addu $fp, $sp, $zero\n" +"lui $s0, %hi(D_800AF630)\n" +"addiu $s0, $s0, %lo(D_800AF630)\n" +"lui $a0, %hi(D_800D4E6C)\n" +"addiu $a0, $a0, %lo(D_800D4E6C)\n" +"jal func_800183E0\n" +"nop\n" +"lui $v0, %hi(D_800EC894)\n" +"lh $v0, %lo(D_800EC894)($v0)\n" +"addiu $v1, $zero, 1\n" +"beq $v0, $v1, .L800D0BC0\n" +"nop\n" +"slti $v1, $v0, 2\n" +"beqz $v1, .L800D0B78\n" +"nop\n" +"beqz $v0, .L800D0B98\n" +"nop\n" +"j .L800D0C34\n" +"nop\n" +".L800D0B78:\n" +"addiu $v1, $zero, 2\n" +"beq $v0, $v1, .L800D0BE4\n" +"nop\n" +"addiu $v1, $zero, 4\n" +"beq $v0, $v1, .L800D0C0C\n" +"nop\n" +"j .L800D0C34\n" +"nop\n" +".L800D0B98:\n" +"addiu $v0, $zero, 1\n" +"lui $at, 1\n" +"addu $at, $s0, $at\n" +"sh $v0, -23626($at)\n" +"addiu $v0, $zero, 2\n" +"lui $at, 1\n" +"addu $at, $s0, $at\n" +"sh $v0, -23624($at)\n" +"j .L800D0C34\n" +"nop\n" +".L800D0BC0:\n" +"addiu $v0, $zero, 1\n" +"lui $at, 1\n" +"addu $at, $s0, $at\n" +"sh $v0, -23626($at)\n" +"lui $at, 1\n" +"addu $at, $s0, $at\n" +"sh $zero, -23624($at)\n" +"j .L800D0C34\n" +"nop\n" +".L800D0BE4:\n" +"addiu $v0, $zero, 1\n" +"lui $at, 1\n" +"addu $at, $s0, $at\n" +"sh $v0, -23626($at)\n" +"addiu $v0, $zero, 1\n" +"lui $at, 1\n" +"addu $at, $s0, $at\n" +"sh $v0, -23624($at)\n" +"j .L800D0C34\n" +"nop\n" +".L800D0C0C:\n" +"addiu $v0, $zero, 1\n" +"lui $at, 1\n" +"addu $at, $s0, $at\n" +"sh $v0, -23626($at)\n" +"addiu $v0, $zero, 4\n" +"lui $at, 1\n" +"addu $at, $s0, $at\n" +"sh $v0, -23624($at)\n" +"j .L800D0C34\n" +"nop\n" +".L800D0C34:\n" +"addu $sp, $fp, $zero\n" +"lw $ra, 24($sp)\n" +"lw $fp, 20($sp)\n" +"lw $s0, 16($sp)\n" +"addiu $sp, $sp, 32\n" +"jr $ra\n" +"nop\n" +".set\treorder\n.end\tfunc_800D0B1C\n"); + + +extern s16 D_800EC894; +extern void func_800599B8(u16 *, u16 *); +extern void func_80011928(s32); + +void func_800D0C50(void) { + s16 sp10[8]; + u16 *addr2; + u16 *addr1; + + addr1 = (u16 *)(D_800EC894 * 307744 + 0x80114014); + addr2 = (u16 *)(D_800EC894 * 307744 + 0x80114220); + sp10[0] = 0; + sp10[1] = 0x1E0; + sp10[2] = 0x100; + sp10[3] = 1; + sp10[4] = 0x280; + sp10[5] = 0x10; + sp10[6] = 0x140; + sp10[7] = 0x1E0; + func_800599B8(sp10, addr1); + func_800599B8(&sp10[4], addr2); + func_80011928(3); +} + + diff --git a/src/md_MAIN_011/md_MAIN_011.c b/src/md_MAIN_011/md_MAIN_011.c index 406436464d..2feb63421f 100644 --- a/src/md_MAIN_011/md_MAIN_011.c +++ b/src/md_MAIN_011/md_MAIN_011.c @@ -85,7 +85,190 @@ void func_800CEF00(void) { INCLUDE_RODATA("asm/md_MAIN_011/nonmatchings/md_MAIN_011", D_800CEDF8); -INCLUDE_ASM("asm/md_MAIN_011/nonmatchings/md_MAIN_011", func_800CF28C); +void func_800CF28C(void) { + extern u8 D_800AF630[]; + extern u8 D_80078E78[]; + extern u8 D_800D31F8[]; + extern u8 D_800D3334[]; + typedef struct { s16 unk00; s16 unk02; s16 unk04; } S6; + typedef struct { u8 pad00[0x1A]; u16 f1A; } SP18; + extern S6 D_800D4A5C[]; + extern s16 D_800D4C80; + extern u16 D_800D4C9C; + extern s32 D_800D4C90; + extern s32 D_800D4C94; + extern s32 D_800D3344; + extern s16 D_800D3348; + extern s16 D_800D334A; + extern void func_800D0858(void); + extern void func_8001534C(int, void *, int, int, int, int); + extern void func_80011928(s32); + extern void func_800167B8(s32); + extern void func_80029514(s32); + extern s32 func_80029178(s32); + extern void func_80029124(s32, s32); + extern void func_800D04F4(void); + extern void func_800CFBF0(void); + extern void func_800CFB88(void); + + register u8 *v0 = D_800AF630; + SP18 *sp18 = (SP18 *)D_80078E78; + s32 sp1C; + + v0[0xA3E1] = 0; + func_800D0858(); + if ((u16)(D_800D4C9C & 0x4000)) { + D_800D4C80++; + if (D_800D4C80 >= 13) { + D_800D4C80 = 0; + } + } else if ((u16)(D_800D4C9C & 0x1000)) { + D_800D4C80--; + if (D_800D4C80 < 0) { + D_800D4C80 = 12; + } + } + func_8001534C(1, D_800D31F8, 0x34, (s16)D_800D3334[D_800D4C80], 0, 0); + switch (D_800D4C80) { + case 0: + if ((u16)(D_800D4C9C & 0x820)) { + func_80011928(4); + } + break; + case 1: + case 2: + case 3: + case 5: + if ((u16)(D_800D4C9C & 0x820)) { + func_80011928(2); + func_800167B8(4); + } + break; + case 4: + if ((u16)(D_800D4C9C & 0x8000)) { + D_800D4C90--; + if (D_800D4C90 < 0) { + D_800D4C90 = 6; + } + } + if ((u16)(D_800D4C9C & 0x2000)) { + D_800D4C90++; + if (D_800D4C90++ >= 7) { + D_800D4C90 = 0; + } + } + break; + case 6: + if ((u16)(D_800D4C9C & 0x8000)) { + D_800D4C94--; + if (D_800D4C94 < 0) { + D_800D4C94 = 7; + } + } + if ((u16)(D_800D4C9C & 0x2000)) { + D_800D4C94++; + if (D_800D4C94 >= 8) { + D_800D4C94 = 0; + } + } + break; + case 7: + if ((u16)(D_800D4C9C & 0x8000)) { + if ((D_800D3344 = D_800D3344 - 10) < 0) { + D_800D3344 = 0; + } + } + if ((u16)(D_800D4C9C & 0x2000)) { + if ((D_800D3344 = D_800D3344 + 10) >= 0x6A5) { + D_800D3344 = 0x6A4; + } + } + if ((u16)(D_800D4C9C & 0x20)) { + if ((D_800D3344 = D_800D3344 + 1) >= 0x6A5) { + D_800D3344 = 0x6A4; + } + } + if ((u16)(D_800D4C9C & 0x40)) { + if ((D_800D3344 = D_800D3344 - 1) < 0) { + D_800D3344 = 0; + } + } + if ((u16)(D_800D4C9C & 0x10)) { + if ((D_800D3344 = D_800D3344 + 100) >= 0x6A5) { + D_800D3344 = 0x6A4; + } + } + if ((u16)(D_800D4C9C & 0x80)) { + if ((D_800D3344 = D_800D3344 - 100) < 0) { + D_800D3344 = 0; + } + } + func_80029514(D_800D3344); + break; + case 8: + if ((u16)(D_800D4C9C & 0x8000)) { + if ((D_800D3348 = D_800D3348 - 1) < 0) { + D_800D3348 = 0x2B; + } + } + if ((u16)(D_800D4C9C & 0x2000)) { + if ((D_800D3348 = D_800D3348 + 1) >= 0x2C) { + D_800D3348 = 0; + } + } + if ((u16)(D_800D4C9C & 0x20)) { + sp1C = D_800D4A5C[D_800D3348].unk04; + func_80029124(sp1C, (u8)func_80029178(sp1C) == 0); + } + break; + case 9: + if ((u16)(D_800D4C9C & 0x2000)) { + D_800D334A += 0x3C; + } + if ((u16)(D_800D4C9C & 0x8000)) { + D_800D334A -= 0x3C; + } + if ((u16)(D_800D4C9C & 0xA0)) { + D_800D334A += 0xF; + } + if ((u16)(D_800D4C9C & 0x40)) { + D_800D334A -= 0xF; + } + if (D_800D334A < 0) { + D_800D334A = 0x59F; + } + if (D_800D334A >= 0x5A0) { + D_800D334A = 0; + } + sp18->f1A = D_800D334A; + break; + case 10: + if ((u16)(D_800D4C9C & 0x2000)) { + func_80029124(0, (u8)func_80029178(0) == 0); + } + break; + case 11: + if ((u16)(D_800D4C9C & 0x2000)) { + func_80029124(1, (u8)func_80029178(1) == 0); + } + break; + case 12: + if ((u16)(D_800D4C9C & 0x2000)) { + func_80029124(2, (u8)func_80029178(2) == 0); + } + break; + } + if (D_800D4C80 >= 6) { + if ((u16)(D_800D4C9C & 0x800)) { + D_800D4C80 = 0; + func_80011928(4); + } + } + sp18->f1A = D_800D334A; + func_800D04F4(); + func_800CFBF0(); + func_800CFB88(); +} void func_800CFB88(void) { extern s32 D_800D4C90; diff --git a/tools/jr_isolate_all.py b/tools/jr_isolate_all.py index 11fc484d75..568d0d2b2a 100644 --- a/tools/jr_isolate_all.py +++ b/tools/jr_isolate_all.py @@ -272,6 +272,38 @@ def carve_owners(ov, banked, base, carve_offs): return owners +# .globl / .ent inside a §265 verbatim `__asm__` body — the separator can be a literal two-char +# escape (`\t`, `\n`) or a quote boundary, since the directives live inside C string literals. +_EMIT_SYM_RE = re.compile(r'\.(?:globl|ent)(?:\s|\\[nt]|")+([A-Za-z_]\w*)') + + +def _region_emit_start(items, syms, obj_lo, obj_hi): + """The lowest vram a region's TEXT actually EMITS — which is not always its cut vram. + + P31 S74. `overlay_src_split.parse_overlay_c` recognises four ADDRESSED ANCHOR forms; a §265 + verbatim `__asm__(".text\n.globl func_X\n…")` body is none of them, so it lands in the + PREAMBLE of the next anchor. Preamble is assumed byte-neutral (comments + decls) — and for a + verbatim asm body that assumption is false: it emits its bytes. Cutting md_MAIN_003 at + func_800D0268 therefore carried the verbatim bodies of func_800D0100/0174/0204 into the new + region while the yaml said the region starts at 0x800D0268 — a config 0x168 bytes above where + the object's bytes actually begin. (Only the TRAILING case was handled, in `_partition`.) + + So derive the boundary from the CONTENT: the min of the region's item addresses and of every + `.globl`/`.ent` symbol its text names that resolves INSIDE this object. Returns None when + nothing resolves. Where no verbatim asm is in play this equals the cut, so every existing + isolate is unchanged — the whole-binary byte-gate (G3/P9) remains the arbiter.""" + best = None + for it in items: + if it[0] is not None: + best = it[0] if best is None else min(best, it[0]) + for nm in _EMIT_SYM_RE.findall(it[3] or ''): + a = oss.addr_of(nm, syms) + if a is None or a < obj_lo or (obj_hi is not None and a >= obj_hi): + continue + best = a if best is None else min(best, a) + return best + + def build_new_config(ov, p): """Return (new_cfg_lines, new_files:{path:content}, carve_renames:{old_sub:new_sub}).""" base = p["base"] @@ -318,10 +350,21 @@ def build_new_config(ov, p): # ov_SC01_000_jr_801734BC — the leader 0x801734BC is a cut too, per the banked-jr rule). # Emitting it would duplicate region 1's line exactly (same offset, and subseg_name(lo) # == nm when the object is already named _jr_) → splat "segments out of order". - if lo is None and not items: + # ...and an EMPTY CUT region likewise (P31 S74): a region with no items emits no + # bytes, so its config line is a zero-length subseg AT the next boundary's offset — + # `- [0x1f74, c, md_MAIN_003_o0e]` immediately above the existing + # `- [0x1f74, c, md_MAIN_003_o0c]`, which the ascending/unique validator rejects as + # "out of order". o0_subsplit closes every run with a cut at the next anchor (or --hi); + # when that lands exactly on an existing subseg boundary the closing region is empty by + # construction and must simply not be emitted. + if not items: continue sub = nm if lo is None else subseg_name(ov, lo) - off = (s if lo is None else lo) - base + if lo is None: + off = s - base + else: + _emit = _region_emit_start(items, syms, s, e) + off = (lo if _emit is None else min(lo, _emit)) - base cfg_block.append(f"{ind}- [{hex(off)}, c, {sub}]") body = _render_region(header, items, old_sub=nm, new_sub=sub, ambient=ambient, syms=syms, obj_start=s) @@ -434,9 +477,18 @@ def _partition(srcpath, cuts, syms): if (lo is None or it[0] >= lo) and (hi is None or it[0] < hi)), key=lambda it: it[0]) regions.append((lo, hi, sel)) - if tail or footer: # tail = guarded last-region content (see above); - lo, hi, sel = regions[-1] # footer = comment/blank-only trailing chunk - regions[-1] = (lo, hi, sel + tail + footer) + if tail: # tail = guarded last-region content (see above): it HAS + lo, hi, sel = regions[-1] # addresses, validated at/after the last cut, so it belongs + regions[-1] = (lo, hi, sel + tail) + if footer: + # footer = comment/blank-only trailing chunk: it emits NOTHING, so it must not be what + # makes an otherwise-empty last region look non-empty (P31 S74 — that is what kept + # build_new_config's empty-region skip from firing on md_MAIN_003, whose closing cut at + # 0x800D0D6C lands exactly on the existing md_MAIN_003_o0c boundary). Attach it to the last + # region that actually has content, so the text is preserved and no empty subseg is emitted. + idx = max((i for i, (_l, _h, sel) in enumerate(regions) if sel), default=len(regions) - 1) + lo, hi, sel = regions[idx] + regions[idx] = (lo, hi, sel + footer) # Place each file-local `static` definition with the ONE region that references it. for it in local_defs: name = it[1] diff --git a/tools/jtbl_rodata_pads.py b/tools/jtbl_rodata_pads.py index 4a639e9561..2ac4e34fbd 100644 --- a/tools/jtbl_rodata_pads.py +++ b/tools/jtbl_rodata_pads.py @@ -157,8 +157,17 @@ def _module_target(binary): return vram, open(tgt, "rb").read() def _s_rodata_span(path): - """[lo, hi) vaddr span of everything the included .s emits into .rodata (comments carry vaddr).""" + """[lo, hi) vaddr span of everything the included .s emits into .rodata (comments carry vaddr). + + P31 S74: a TRAILING `.align N` counts. spimdisasm closes a sized symbol with the `.align` that + produced the original's padding (`.asciz "7"` + `.align 2` = 4 emitted bytes, not 2), and `as` + emits that pad — so the walk position after the include is the ROUNDED end. The under-report was + invisible while the next item was an anchor (`derive`'s zero_gap self-corrects an undershoot of + 1-3 zero bytes) and fatal the moment the next item was a C jump table, which has no anchor: + md_MAIN_011's banked func_800CF28C refused with "C table entry 0 at 0x800CEDFA ... not a code + address" — the walk was 2 bytes short of the island, not the island adrift.""" lo, hi, in_ro = None, None, False + pend_align = 0 # `.align N` seen with no sized item after it for ln in open(path, errors="replace"): st = ln.strip() if st.startswith(".section"): @@ -166,6 +175,10 @@ def _s_rodata_span(path): continue if not in_ro: continue + if st.startswith(".align"): + tok = st.split() + pend_align = (1 << int(tok[1])) if len(tok) > 1 and tok[1].isdigit() else 0 + continue m = re.match(r"/\*\s*[0-9A-Fa-f]+\s+([0-9A-Fa-f]{8})(?:\s+([0-9A-Fa-f]+))?\s*\*/\s*(\S+)\s*(.*)$", st) if m: a = int(m.group(1), 16) @@ -182,17 +195,9 @@ def _s_rodata_span(path): else: continue lo = a if lo is None else min(lo, a); hi = a + n if hi is None else max(hi, a + n) - elif st.startswith(".align") and hi is not None: - # A TRAILING `.align` IS PART OF THE SPAN (P31 S74). The assembler emits the padding - # to satisfy it, so a `.s` ending in `.asciz "r"` + `.align 2` occupies 4 bytes, not 2. - # Measuring only the emitted DATA left `hi` short, the island walk then landed - # mid-object, and `--derive` aborted with `C table entry 0 at 0x801A00DA ... island - # layout drift` — a true statement about a span that was never the real one. Found by a - # drafting agent that ran its own gate reject to ground instead of respelling the body: - # the reject was this, not its C. Byte-neutral control: the unmodified TU's object is - # identical with and without this branch. - al = 1 << int(st.split()[1]) - hi = (hi + al - 1) // al * al + pend_align = 0 + if hi is not None and pend_align > 1: + hi = (hi + pend_align - 1) // pend_align * pend_align return lo, hi _DIRSIZE = {".word": 4, ".long": 4, ".half": 2, ".short": 2, ".byte": 1, ".float": 4, ".double": 8}