From 5ff842dfd3c2b1977f1509661d9f28df3b1e4cbd Mon Sep 17 00:00:00 2001 From: Drew T <50529377+Druthulu@users.noreply.github.com> Date: Sat, 5 Sep 2026 01:03:07 -0600 Subject: [PATCH] =?UTF-8?q?feat(phase-32):=20T3=20(3)=20=E2=80=94=20reside?= =?UTF-8?q?nt:=20func=5F800D06E8=20(344=20ins)=20BANKED=20byte-identical?= =?UTF-8?q?=208e17e02f=20=E2=80=94=20THE=20RESIDENT=20IS=20100%=20C=20(145?= =?UTF-8?q?/145)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - the Opus drafter recovered the closeness-0 body the journals (attempts 1-3) pointed at (.run/S71b_1/fable/) — the pack's inline 292-draft was the wrong one — and found the real blocker: the TU defines Struct80078E78 AFTER the slot with a layout lacking bytes 0x36/0x37; only a BLOCK-scoped typedef under a distinct tag (Blk80078E78) + a block-scoped extern compiles (decl-hoisting resolver variants recreate the S7x 'conflicting types'). Idioms: §162k1 QImode (u8)(c-3)<2; explicit flag temp t=(u32)(r-0x64)<0x1E, s1=t^1; switch decision trees for both currentLocationId dispatches. reloc_identity AGREE 50/50; rtu_match MATCH 344/344 (verified by the coordinator) - jtbl_carve --func: jtbl_80113FA4 (5 words, the old tail2) joins the resident_jr_800D00E4 .rodata piece (0x450e0..0x451c0, JTBL_PADS 0,0,0,0, tables +0x0/+0x3c/+0xb4/+0xcc); carve set 5 -> 4 pieces, --pre kept - make extract + make build BINARY=resident -j8 rc 0; sha 8e17e02ff8954d07c979449198f7e1645046b353 == check; pads_audit ok/ok; interleave_check ALIGNED n=4 --- config/overlays.mk | 4 +- config/splat.resident.yaml | 3 +- src/resident/resident_jr_800D00E4.c | 229 +++++++++++++++++++++++++++- 3 files changed, 231 insertions(+), 5 deletions(-) diff --git a/config/overlays.mk b/config/overlays.mk index f453b65b6..90ad56d10 100644 --- a/config/overlays.mk +++ b/config/overlays.mk @@ -5126,6 +5126,6 @@ ov_SC03_107_UNDEF_FUNCS := build/ov_SC03_107/undefined_funcs_auto.txt # --- resident (engine blob) — §8e jtbl pad spec for the 0x450e0..0x451ac .rodata carve --- # --- resident (engine blob) — §8f leading-rodata sandwich: rodata(hdr) -> text -> data -> rodata(carve) -> data --- -resident_JTBL_INTERLEAVE := --pre hdr.rodata.o --order tail.data.o,resident_jr_800D00E4.o,tail2.data.o,resident_jr_800D128C.o,tail3.data.o # Phase-26 §8 jtbl-rodata carve -build/src/resident/resident_jr_800D00E4.o: JTBL_PADS := 0,0,0 # §8e pads (jtbl_carve.py) tables=+0x0,+0x3c,+0xb4 +resident_JTBL_INTERLEAVE := --pre hdr.rodata.o --order tail.data.o,resident_jr_800D00E4.o,resident_jr_800D128C.o,tail2.data.o # Phase-26 §8 jtbl-rodata carve +build/src/resident/resident_jr_800D00E4.o: JTBL_PADS := 0,0,0,0 # §8e pads (jtbl_carve.py) tables=+0x0,+0x3c,+0xb4,+0xcc build/src/resident/resident_jr_800D128C.o: JTBL_PADS := 0,4 # §8e pads (jtbl_carve.py) tables=+0x0,+0x1e0 diff --git a/config/splat.resident.yaml b/config/splat.resident.yaml index a286fc2f5..99e0d0afc 100644 --- a/config/splat.resident.yaml +++ b/config/splat.resident.yaml @@ -88,7 +88,6 @@ segments: - [0x2494, c, resident_jr_800D128C] - [0x4610, data, tail] - [0x450e0, .rodata, resident_jr_800D00E4] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x451ac, data, tail2] - [0x451c0, .rodata, resident_jr_800D128C] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x453c4, data, tail3] + - [0x453c4, data, tail2] - [0x5935C] # EOF (365,404 B) -> end vram 0x80128154 diff --git a/src/resident/resident_jr_800D00E4.c b/src/resident/resident_jr_800D00E4.c index 347b6a3bc..69688ddff 100644 --- a/src/resident/resident_jr_800D00E4.c +++ b/src/resident/resident_jr_800D00E4.c @@ -503,7 +503,234 @@ void func_800D06CC(void) { D_80127500 = 3; } -INCLUDE_ASM("asm/resident/nonmatchings/resident_jr_800D00E4", func_800D06E8); +/* func_800D06E8 -- two independent state machines driven by currentLocationId (344 ins). + * + * SHAPE: both currentLocationId dispatches are gcc-2.7.2 expand_case DECISION TREES + * (switch; adjacent case values merge into range nodes, balance_case_nodes roots both + * on [0x1077,0x1078] -> `slti 0x1079` first). The D_80127500 dispatch is a 3-value + * tree; the D_801151F8 dispatch has 5 consecutive cases -> `sltiu 5` + jtbl_80113FA4. + * The s0 and D_800A2B70 arms are switches (if-chains cost ~10 ins); if/else arms (not + * assign-then-test) keep `s1=` out of the two jal delay slots. + * + * §162k1 (QImode): mips.h has WORD_REGISTER_OPERATIONS + LOAD_EXTEND_OP=ZERO_EXTEND but + * NO PROMOTE_MODE, so `u8 c` is a genuine QImode pseudo. `c == 1` is a QImode compare -> + * no cmpqi -> convert_to_mode(SImode) = the `andi $v1,$a0,0xFF`, and combine cannot fold + * it into the lbu (the pseudo has a second use). The second use must NOT re-widen: + * `(u32)(c-3)` is SImode arithmetic (a second andi, cse-tied to the first); `(u8)(c - 3)` + * is QImode -> expand_binop has no subqi3 -> widen_operand(no_extend=1) hands it a + * PARADOXICAL SUBREG (optabs.c:299) = `addiu $v0,$a0,-3` on the RAW register, and + * combine.c:9246's "A - C1 vs C2" rule drops the QI truncation before the sltiu. + * + * Expand-time subtarget reuse: in `s1 = (cmp) ^ 1` the XOR passes s1's pseudo down as the + * subtarget and do_store_flag expands `r - 0x64` straight INTO it (addiu $s1 / sltiu $v0,$s1). + * An explicit flag temp makes the subtraction and the flag share the temp's pseudo -> + * the target's `addiu $v0,$v1,-0x64 ; sltiu $v0,$v0,0x1E ; xori $s1,$v0,1`. + * + * D_80078E78: this TU file-scope-defines `Struct80078E78` as {u8 pad[0x34]; s16} for + * func_800D10EC, but AFTER this function's address slot -- so that name is neither visible + * here nor redefinable (gcc-2.7.2 rejects even a byte-identical typedef redefinition). + * A BLOCK-SCOPED typedef under a different tag + a block-scoped `extern` for the object is + * only a pedwarn ("type mismatch with previous external decl") and compiles the real TU clean. + * The local pointer `p = &D_80078E78` is what pins the address in the callee-saved $s2. + */ + +extern s16 currentLocationId; +extern s32 func_80029504(void); +extern void func_8002D4C8(s32 arg0, s32 arg1); +extern s32 func_8001AAA0(s32 arg0); +extern s32 D_800A2B70; +extern s32 D_800BA0FC; +extern s32 D_8011529C; +extern s32 D_80114EA0; +extern s32 D_801151F8; +extern s32 D_801201F0; +extern s32 D_80126AE8; +extern s32 D_80127050; +extern s32 D_80127500; +extern s32 resLoad_lastId; + +void func_800D06E8(void) { + typedef struct { + u8 pad00[0x36]; + u8 field_0x36; + u8 field_0x37; + } Blk80078E78; + extern Blk80078E78 D_80078E78; + Blk80078E78 *p = &D_80078E78; + s32 s0; + s32 s1; + s32 r; + s32 t; + u8 c; + + switch (D_80127500) { + case 0: + switch (currentLocationId) { + case 0x1010: + case 0x1011: + case 0x1077: + case 0x1078: + case 0x1094: + case 0x1095: + r = func_80029504(); + if ((u32)(r - 0x460) < 0x32) { + s1 = 0; + } else { + t = (u32)(r - 0x64) < 0x1E; + s1 = t ^ 1; + } + if (s1 == 0) { + D_800A2B70 = 0; + } + c = p->field_0x37; + s0 = 0; + if (c == 1) { + s0 = 1; + } else if ((u8)(c - 3) < 2) { + s0 = 2; + } + if (D_800A2B70 != 0) { + D_80127500 += 1; + break; + } + if (s1 == 0) { + break; + } + if (s0 == D_8011529C) { + break; + } + D_8011529C = s0; + if (D_80127050 != 0) { + D_80127050 = 0; + break; + } + switch (s0) { + case 1: + func_8002D4C8(0x518, 0); + break; + case 2: + func_8002D4C8(0x517, 0); + break; + default: + goto sw1_end; + } + D_800A2B70 = s0; + D_800BA0FC = 0; + D_80127500 += 1; + break; + case 0x3014: + case 0x301C: + if (p->field_0x37 != D_8011529C) { + D_8011529C = p->field_0x37; + if (p->field_0x37 == 4) { + func_8002D4C8(0x683, 0); + } else if (p->field_0x37 == 0) { + func_8002D4C8(0xD, 0x683); + } + } + break; + } + break; + case 1: + D_800BA0FC += 1; + if ((u32)D_800BA0FC >= 0x97) { + switch (D_800A2B70) { + case 1: + func_8002D4C8(0xD, 0x518); + break; + case 2: + func_8002D4C8(0xD, 0x517); + break; + } + D_800A2B70 = 0; + D_80127500 = 0; + } + break; + case 2: + D_801201F0 -= 1; + if (D_801201F0 == 0) { + func_8002D4C8(0xD, 0x683); + D_80127500 = 0; + } + break; + } + +sw1_end: + switch (D_801151F8) { + case 0: + switch (currentLocationId) { + case 0x1010: + case 0x1011: + case 0x1077: + case 0x1078: + case 0x1094: + case 0x1095: + r = func_80029504(); + if ((u32)(r - 0x460) < 0x32) { + s1 = 0x89; + } else if ((u32)(r - 0x384) < 0x6E) { + s1 = 0x65; + } else if ((u32)(r - 0x64) < 0x1E) { + s1 = 0x28; + } else { + s1 = 0x10; + if (p->field_0x36 == 1) { + s1 = 0xF; + } + } + break; + case 0x1052: + case 0x1053: + s1 = 0x27; + break; + case 0x3014: + case 0x301C: + case 0x301E: + case 0x3023: + s1 = 0xA; + if (p->field_0x37 == 4) { + s1 = 0x3C; + } + break; + } + if (s1 != resLoad_lastId) { + D_80114EA0 = s1; + D_80126AE8 = 0x3C; + resLoad_lastId = 0; + D_801151F8 += 1; + func_8002D4C8(1, 2); + } + break; + case 1: + D_80126AE8 -= 1; + if (D_80126AE8 == 0) { + D_801151F8 += 1; + } + break; + case 2: + switch (D_80114EA0) { + case 0xA: + func_8002D4C8(0x10C, 0); + break; + case 0xF: + func_8001AAA0(0xF); + break; + case 0x10: + func_8001AAA0(0x10); + break; + case 0x3C: + func_8002D4C8(0x13B, 0); + break; + } + D_801151F8 = 0; + resLoad_lastId = D_80114EA0; + break; + case 3: + case 4: + break; + } +} + extern s32 resLoad_lastId; extern void func_8002D4C8(s32 arg0, s32 arg1);