feat(phase-32): T3 (3) — resident: func_800D06E8 (344 ins) BANKED byte-identical 8e17e02f — THE RESIDENT IS 100% C (145/145)

- 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
This commit is contained in:
Drew T
2026-09-05 01:03:07 -06:00
parent ceeb1a1eb2
commit 5ff842dfd3
3 changed files with 231 additions and 5 deletions
+2 -2
View File
@@ -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
+1 -2
View File
@@ -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
+228 -1
View File
@@ -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);