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);