From 35307803f73ff7ea41012972ecf6a002a3b2371e Mon Sep 17 00:00:00 2001 From: Drew T <50529377+Druthulu@users.noreply.github.com> Date: Wed, 2 Sep 2026 16:22:10 -0600 Subject: [PATCH] feat(main): 6 more banked byte-identical from wave S73m_1 Six of the nine drafts, one clean rebuild, 10.5s. Verified from the SOURCE (the INCLUDE_ASM stub is gone), not from the tool's own report. --- src/800_b.c | 1092 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/800_c.c | 494 ++++++++++++++++++++++- 2 files changed, 1580 insertions(+), 6 deletions(-) diff --git a/src/800_b.c b/src/800_b.c index 2cf4d957a..4bd4855ad 100644 --- a/src/800_b.c +++ b/src/800_b.c @@ -1236,7 +1236,134 @@ void func_8002D904(s32 arg0) { } -INCLUDE_ASM("asm/nonmatchings/800_b", func_8002DC68); +/* func_8002DC68 -- the 0x400+ message dispatcher: takes the D_8006451C record for + * (param_1 & 0xFFFF), optionally follows one level of indirection (kind 6), raises the + * D_800A4F17 reentrancy lock, and switches on the record's low-6-bit kind (1..18). + * + * Case 12's `(param_2 << 25) >> 25` is NOT decoration -- it is the byte lever (cookbook + * candidate: "defeat CSE with a shift pair combine folds back into the mask"). The target + * computes `andi $s2,0x7F` TWICE: once into $v1 for the `sltu` and again into $v0, which + * reorg then steals for the `beqz`'s delay slot. Written as `param_2 & 0x7F` on both sides, + * cse merges the two `(and:SI ...)` into one pseudo, the store reuses $v1 and the delay slot + * goes empty -- exactly the 2-instruction residual this function sat at (idx 156 nop vs + * `andi $v0,$s2,0x7F`, idx 158 `sb $v1` vs `sb $v0`). cse sees the shift pair as an unrelated + * expression, and combine's simplify_shift_const turns it back into `andi ...,0x7F` afterwards, + * so the second mask survives to fill the slot. Byte-verified both ways round (the shift pair + * on the compare side matches identically). + * + * NOTE for the gate (§378): src/800_b.c already carries four `extern void func_8002DC68(s32, s32);` + * decls (lines 851, 928, 1249, 2007) plus call sites at 868, 905, 936 (already self-cast) and + * inside func_8002F248. This definition returns s32, so the §376/§378 chain + * (fix_arity_callers --any-proto -> cast_self_callers) has to run before the whole-binary gate. */ +extern s16 D_800A4EFC; +extern u8 D_8006451C[]; +extern u8 D_800A4F1B; +extern s8 D_800A4F17; +extern u8 D_8006A980; +extern s16 D_8006A982; +extern u8 D_8006A984; +extern u8 D_8006A988[]; + +extern s32 func_8002F4E4(u8 *); +extern void func_8002F248(s32, s32); +extern void func_8002F714(s32, s32); +extern s32 func_80032048(u32, u8 *, u32); +extern s32 func_800322A8(u32, u8 *, u32); +extern s32 func_800324A4(u32, u8 *, u32, s32); +extern s32 func_80032774(u32, u8 *, u32); +extern s32 func_80034314(u32, u8 *, u32); + +s32 func_8002DC68(u32 param_1, u32 param_2) { + u8 *p; + u8 *lk; + s32 ret; + s8 old; + u16 val; + u32 m7; + + if (D_800A4EFC != 0) { + return 0; + } + p = &D_8006451C[(param_1 & 0xFFFF) * 4]; + if (D_800A4F1B == 0 && (*p & 0x80) == 0) { + return 0; + } + if ((*p & 0x3F) == 6) { + s32 id = func_8002F4E4(p) & 0xFFFF; + if (id == 0) { + return 0; + } + p = &D_8006451C[id * 4]; + } + lk = (u8 *)&D_800A4F17; + old = *lk; + *lk = 1; + ret = 0; + switch (*p & 0x3F) { + case 1: + ret = func_80032048(param_1, p, param_2 & 0xFFFF); + break; + case 9: + ret = func_800324A4(param_1, p, param_2 & 0xFFFF, 0); + break; + case 7: + ret = func_800324A4(param_1, p, param_2 & 0xFFFF, 1); + break; + case 10: + func_800322A8(param_1, p, param_2 & 0xFFFF); + /* fallthrough */ + case 8: + ret = func_80032774(param_1, p, param_2 & 0xFFFF); + break; + case 5: + ret = func_80034314(param_1, p, param_2 & 0xFFFF); + break; + case 2: + func_8002F248((s32)p, param_2 & 0xFFFF); + break; + case 11: + if ((D_8006A980 & 4) != 0) { + val = D_8006A982 + D_8006A988[param_2 & 7] - 2; + } else { + D_8006A980 |= 4; + val = D_8006A988[param_2 & 7]; + } + D_8006A982 = val; + m7 = param_2 & 7; + if (m7 == 6) { + D_8006A980 |= 1; + } else if (m7 == 2) { + D_8006A980 |= 2; + } + break; + case 12: + D_8006A980 |= 8; + if (D_8006A984 < (param_2 & 0x7F)) { + D_8006A984 = (u8)((param_2 << 25) >> 25); + } + break; + case 13: + ret = func_80032048((param_1 & 0xFFFF) | 0x08F40000, p, 0xFFFF); + break; + case 14: + ret = func_80032048((param_1 & 0xFFFF) | 0x0A8A0000, p, 0xFFFF); + break; + case 15: + ret = func_80032048((param_1 & 0xFFFF) | 0x08960000, p, 0xFFFF); + break; + case 17: + func_8002F714(p[3], param_2 & 0xFFFF); + break; + case 16: + ret = func_80032048((param_1 & 0xFFFF) | 0x0B7D0000, p, 0xFFFF); + break; + case 18: + ret = func_80032048((param_1 & 0xFFFF) | 0x04F30000, p, 0xFFFF); + break; + } + D_800A4F17 = old; + return ret; +} extern u8 D_8006A980; @@ -1316,7 +1443,224 @@ void func_8002DF80(void) { } } -INCLUDE_ASM("asm/nonmatchings/800_b", func_8002E138); +extern s16 D_8006A982; +extern u8 D_8006A96E; +extern u8 D_8006A980; +extern u8 D_8006A984; +extern s16 D_8006A990; +extern u8 D_8006A994[]; +extern s16 D_800A4E86; +extern u16 D_800A4E8C; +extern u16 D_800A4E8E; +extern u16 D_800A4EE0; +extern u8 D_800A4EE6; +extern s16 D_800A4EF6; +extern s16 D_800A4EF8; +extern s16 D_800A4EFA; +extern s16 D_800A4EFC; +extern u8 D_800A4F16; +extern u8 D_800A4F19; +extern u8 D_800A4F1B; +extern u8 D_800A4F1C; +extern u8 D_800A4F1E; +extern u16 D_800A4F20; + +extern void func_8002D904(s32); +extern void func_8002E5BC(void); +extern void func_8002E5F8(void); +extern void func_8002E638(s32 a0); +extern void func_8002E700(s32 a0); +extern void func_8002E79C(s32 a0); +extern void func_8002E818(s32 a0); +extern void func_8002E8DC(s32 a0); +extern void func_8002E94C(s32 a0); +extern void func_8002EB10(void); +extern void func_8002EBAC(void); +extern void func_8002EC10(void); +extern void func_8002EDE4(void); +extern void func_8002EE90(void); +extern void func_8002EEB8(void); +extern void func_8002EED8(s32 a0); +extern void func_8002EFD0(void); +extern void func_8002F0D0(void); +extern void func_80031CC8(void); +extern void func_80031DEC(void); +extern void func_80031E94(void); +extern void func_80031F14(void); +extern void func_80031FC8(void); +extern void func_8003491C(s32 arg0); +extern void func_80038668(s32 a0, s32 a1); + +void func_8002E138(s32 a0, s32 a1, s32 a2) { + if ((u16)a0 == 0x7F) { + return; + } + + switch ((u16)a0 - 1) { + case 0: + func_8002E638(a1 & 0xFFFF); + break; + case 7: + func_8002E700(a1 & 0xFFFF); + break; + case 1: + func_8002F0D0(); + func_8002EDE4(); + D_800A4F1B = 1; + D_800A4EE0 = 0x4000; + D_800A4F1C = 0; + D_8006A96E = 0; + D_8006A980 = 0; + D_8006A982 = 0; + D_8006A984 = 0; + D_800A4EE6 = 0; + D_800A4EFC = 0x1E; + D_800A4F1E = 0; + break; + case 2: + func_8002F0D0(); + func_80031CC8(); + D_800A4EFC = 0; + break; + case 3: + func_8002EED8((a1 & 0xFFFF) | (a2 << 16)); + break; + case 4: + func_8002EE90(); + break; + case 5: + case 15: + case 30: + D_800A4EF6 = 2; + break; + case 6: + case 16: + case 31: + D_800A4EF6 = 1; + break; + case 10: + if (D_800A4F19 != 0) { + func_8002E5BC(); + } + break; + case 11: + if (D_800A4F19 == 0) { + func_8002E5F8(); + } + break; + case 12: + func_8003491C((a1 & 0xFFFF) | (a2 << 16)); + break; + case 13: + func_8002EB10(); + break; + case 14: + func_8002EBAC(); + break; + case 17: + func_8002E79C(a1 & 0xFFFF); + break; + case 18: + func_8002E8DC(a1 & 0xFFFF); + break; + case 19: + func_80031F14(); + func_8002E818(0); + break; + case 20: + func_80031FC8(); + func_8002E94C(0); + break; + case 21: + func_8002EEB8(); + break; + case 22: + func_8002EC10(); + break; + case 23: + case 25: + func_80031DEC(); + break; + case 24: + case 26: + func_80031E94(); + break; + case 27: + func_8002EFD0(); + break; + case 28: + D_800A4F1B = 0; + break; + case 29: + D_800A4F1B = 1; + break; + case 32: { + s16 t = D_8006A994[a1 & 7]; + D_800A4F16 = 1; + D_800A4EF8 = t; + break; + } + case 33: + D_800A4EFA = D_8006A994[a1 & 7]; + break; + case 34: + { + u8 *p = &D_800A4F1C; + *p |= 1; + if (D_800A4E8C + 0x100 == 0x134) { + func_80038668(D_800A4E86, 3); + } + } + break; + case 35: + { + u8 *p = &D_800A4F1C; + *p |= 2; + if (D_800A4E8C + 0x100 == 0x134) { + func_80038668(D_800A4E86, 4); + } + } + break; + case 36: + { + u8 *p = &D_800A4F1C; + *p |= 4; + if (D_800A4E8C + 0x100 == 0x134) { + func_80038668(D_800A4E86, 5); + func_80038668(D_800A4E86, 6); + func_80038668(D_800A4E86, 7); + } + } + break; + case 37: + { + u8 *p = &D_800A4F1C; + *p |= 8; + if (D_800A4E8C + 0x100 == 0x134) { + func_80038668(D_800A4E86, 8); + } + } + break; + case 38: + if ((D_800A4E8E & 1) != 0) { + D_8006A990 = 0; + D_800A4F20 = a1; + } else { + func_8002D904(a1 & 0xFFFF); + } + break; + case 41: + D_800A4F1C = 0; + break; + case 39: + D_800A4F1E = 1; + break; + case 40: + D_800A4F1E = 0; + func_80031CC8(); + break; + } +} extern u8 D_800A4F19; extern void CdMix(u8 *); @@ -3466,7 +3810,128 @@ void func_800314DC(Obj *p) { } } -INCLUDE_ASM("asm/nonmatchings/800_b", func_800316F8); +void func_800316F8(s32 arg0) +{ + s32 base; + u16 *ptr; + u16 speed; + u16 delta; + s32 tmp; + s32 tmp1; + + base = arg0; + delta = 0; + ptr = *(u16 **)(base + 0x14); + speed = 0; + *(u8 *)(base + 0x37) = 0; + *(u32 *)(base + 0x18) = 0; + *(u32 *)(base + 0x20) = *(u32 *)(base + 0x24); + if (ptr == NULL) { + return; + } + switch (*ptr) { + case 1: + speed = ptr[1]; + delta = ptr[2]; + *(u16 *)(base + 0x30) = 0; + *(u8 *)(base + 0x38) = 1; + *(u16 *)(base + 0x3A) = ptr[3]; + *(u16 *)(base + 0x3C) = ptr[4]; + *(u16 *)(base + 0x12) = ptr[7]; + break; + case 9: + speed = ptr[1]; + tmp1 = ptr[2]; + *(u16 *)(base + 0x30) = 0; + *(u8 *)(base + 0x38) = 1; + *(u16 *)(base + 0x3A) = ptr[3]; + *(u16 *)(base + 0x3C) = ptr[4] + *(u32 *)(base + 0x20); + delta = tmp1 + *(u32 *)(base + 0x20); + *(u16 *)(base + 0x12) = ptr[7]; + break; + case 6: + speed = ptr[2]; + delta = ptr[3]; + *(u16 *)(base + 0x30) = 0; + *(u8 *)(base + 0x38) = 1; + *(u16 *)(base + 0x3A) = ptr[4]; + *(u16 *)(base + 0x3C) = ptr[5]; + *(u16 *)(base + 0x12) = ptr[8]; + goto L188c; + case 10: + speed = ptr[2]; + tmp = ptr[3]; + *(u16 *)(base + 0x30) = 0; + *(u8 *)(base + 0x38) = 1; + *(u16 *)(base + 0x3A) = ptr[4]; + *(u16 *)(base + 0x3C) = ptr[5] + *(u32 *)(base + 0x20); + *(u16 *)(base + 0x12) = ptr[8]; + goto L18ac; + case 0: + *(u8 *)(base + 0x38) = 0; + speed = ptr[1]; + delta = ptr[2]; + *(u16 *)(base + 0x12) = ptr[5]; + *(u16 *)(base + 0x30) = 0; + break; + case 7: + *(u8 *)(base + 0x38) = 0; + speed = ptr[1]; + delta = ptr[2] + *(u32 *)(base + 0x20); + *(u16 *)(base + 0x12) = ptr[5]; + *(u16 *)(base + 0x30) = 0; + break; + case 5: + *(u8 *)(base + 0x38) = 0; + speed = ptr[2]; + delta = ptr[3]; + *(u16 *)(base + 0x12) = ptr[6]; + L188c: + *(u16 *)(base + 0x30) = ptr[1]; + break; + case 8: + *(u8 *)(base + 0x38) = 0; + speed = ptr[2]; + tmp = ptr[3]; + *(u16 *)(base + 0x12) = ptr[6]; + L18ac: + delta = tmp + *(u32 *)(base + 0x20); + *(u16 *)(base + 0x30) = ptr[1]; + break; + case 2: + *(u8 *)(base + 0x38) = 0; + goto L18f4; + case 3: + *(u8 *)(base + 0x37) |= 2; + *(u32 *)(base + 0x1C) = (s32)(s16)ptr[2] << 8; + *(u16 *)(base + 0x32) = ptr[3]; + *(u8 *)(base + 0x38) = 0; + L18f4: + *(u16 *)(base + 0x12) = ptr[1]; + *(u16 *)(base + 0x30) = 0; + return; + case 4: + *(u8 *)(base + 0x37) |= 2; + *(u32 *)(base + 0x1C) = (s32)(s16)ptr[1] << 8; + *(u16 *)(base + 0x32) = ptr[2]; + *(u8 *)(base + 0x38) = 0; + *(u16 *)(base + 0x30) = 0; + return; + } + if (speed == 0) { + return; + } + if (*(s32 *)(base + 0x24) == delta) { + return; + } + *(u32 *)(base + 0x28) = delta; + *(u8 *)(base + 0x37) |= 1; + if (delta < *(s32 *)(base + 0x24)) { + *(u32 *)(base + 0x2C) = -speed; + } else { + *(u32 *)(base + 0x2C) = speed; + } +} void func_80031988(Ent30D80 *arg0) { @@ -4879,7 +5344,626 @@ void func_800336A8(Req336A8 *arg) } } -INCLUDE_ASM("asm/nonmatchings/800_b", func_8003388C); +/* func_8003388C -- MATCH (663 ins). Sequencer tick: ramps -> command-stream + * interpreter (switch 0x80..0x87 through jtbl_80073120) -> voice/channel setup. + * + * §405-A CHECKED: the .rodata jump table my compile emits is byte-identical to the + * target's (entries 0x27c/0x304/0x370/0x380/0x434/0x3c8/0x460/0x484) -- note the SOURCE + * case order must be 0x80,0x81,0x82,0x83,**0x85,0x84**,0x86,0x87: gcc emits case BODIES + * in source order while entry i points at case i, and the target's 0x84 body sits AFTER + * its 0x85 body. §409 law 1 CHECKED: all 46 jal/HI16/LO16 relocations verified in order + * against the .s with objdump -r (match_one masks them). + * + * THE LEVERS (each byte-load-bearing, measured 437 -> 0): + * 1. BLOCKS AT THE END ARE REAL `goto` TARGETS. pend83 / pend85 / set36 / advance are + * placed after the last statement, exactly where the target's 0x8003427C / 0x8003428C / + * 0x800342A0 / 0x800342AC blocks are; gcc-2.7.2 has no block reordering, so an inline + * `if (...) { ...; return; }` inside the switch would emit them in place instead. + * 2. CASE 0x80's BYTE SPLIT NEEDS FOUR PSEUDOS OFF A SELF-UPDATING ACCUMULATOR. + * `c0 = op; op >>= 8; c1 = op; ...` -- writing `c1 = c0 >> 8; c2 = c1 >> 8;` lets cse + * fold the chain to `sra op,16` (no chain, no copies); writing the stores between the + * shifts lets copy-prop delete the copies. c2's copy must come AFTER c0's two stores + * (that is what lets $v0 be reused), and c0/c1/c2/c3 are pinned $2/$3/$2/$4 because + * global.c has no coalescing and picks the mirror assignment otherwise. + * 3. ONE SIGNED `op`, ONE UNSIGNED SWITCH SUBJECT. `op` is s32 (case 0x80/0x81 `op >> 16` + * and case 0x84 `op >> 8` are `sra`); the dispatch is `(u32)op >> 24` to get `srl`. + * 4. §429-style SINGLE-SET LOCALS: `t` (ramp `h` widened) and `t18` (the 0x18 field) must + * be DIFFERENT locals -- sharing one costs the $v1/$a1 pair in the ramp loop. Same for + * `n86`/`x86` in case 0x86 and `pr1`/`pr2` for the two D_8007319E/D_800731A0 products. + * 5. THE $s3 COPY (`addu $s3,$v0,$zero` for cmd->unk09) is not expressible in plain C -- + * cse propagates any `lvl = tmp`. A zero-byte `__asm__ __volatile__("" : "=r"(t):"0"(t))` + * makes the temp opaque, so the load keeps its own pseudo and the copy survives. + * That one instruction was worth ~80 diff rows of index shift. + * 6. THE FINAL FENCE. `__asm__ __volatile__("")` after `vo->unk04 = 0x6009F;` is a sched1 + * barrier: it keeps the `lui/lh %hi/%lo(D_800A4EF6)` pair BELOW the three stores while + * the flipped comparison `D_800A4EF6 > cmd->unk0C` makes gcc expand that operand first + * (do_compare_and_jump expands TREE_OPERAND 0 first). Flip without fence = +3, fence + * without flip = +3, both = 0. + * 7. `m` pinned $3 / `v` pinned $2 / `sum` pinned $3 / `base`,`q` pinned $2 (the last two + * are func_800314DC's own lerp pins, cookbook: same idiom, same registers). + * 8. `t24 = cmd->unk06 + e->unk52;` hoisted above the ch->unk40 stores gives the two loads + * the lower LUID that wins sched1's priority tie, and `ch->unk12` before `ch->unk4F/48` + * is the store order the target actually has. + * 9. `amt = amt * 112; amt = amt >> 7;` as TWO statements (the product needs to land in + * amt's own register); the D_8007319E/D_800731A0 products stay ONE expression. + * 10. The `res`/`e->unk50 < amt` shapes: `if (A < B) x = B - A; else x = 0;` is what reorg + * collapses into `sltu/bnez/subu(delay)/addu zero` -- the "x = B-A; if (...) x = 0;" + * form cannot put the subu in the delay slot (it feeds the sltu). + */ + + + +typedef struct { + /* 0x00 */ u16 cur; + /* 0x02 */ u16 step; + /* 0x04 */ u16 tgt; + /* 0x06 */ u8 act; + /* 0x07 */ u8 pad07; +} Ramp388C; /* 0x08 */ + +typedef struct { + /* 0x00 */ u16 unk00; + /* 0x02 */ u16 unk02; + /* 0x04 */ u16 unk04; + /* 0x06 */ u16 unk06; + /* 0x08 */ u8 unk08; + /* 0x09 */ u8 unk09; + /* 0x0A */ u8 unk0A; + /* 0x0B */ u8 unk0B; + /* 0x0C */ u8 unk0C; + /* 0x0D */ u8 unk0D; + /* 0x0E */ u8 pad0E[2]; + /* 0x10 */ s32 unk10; +} Cmd388C; /* 0x14 */ + +typedef struct { + /* 0x00 */ s16 unk00; + /* 0x02 */ u8 pad02[6]; + /* 0x08 */ u16 unk08; + /* 0x0A */ u8 pad0A[2]; + /* 0x0C */ u32 *unk0C; + /* 0x10 */ u8 *unk10; + /* 0x14 */ u16 unk14; + /* 0x16 */ u8 unk16; + /* 0x17 */ u8 unk17; + /* 0x18 */ u16 unk18; + /* 0x1A */ u16 unk1A; + /* 0x1C */ Ramp388C unk1C[3]; + /* 0x34 */ u16 unk34; + /* 0x36 */ u8 unk36; + /* 0x37 */ u8 pad37[1]; + /* 0x38 */ u8 unk38; + /* 0x39 */ u8 unk39; + /* 0x3A */ u8 unk3A[8]; + /* 0x42 */ u8 pad42[2]; + /* 0x44 */ u32 *unk44; + /* 0x48 */ u8 unk48; + /* 0x49 */ u8 pad49[1]; + /* 0x4A */ u16 unk4A; + /* 0x4C */ u8 unk4C; + /* 0x4D */ u8 unk4D; + /* 0x4E */ u8 unk4E; + /* 0x4F */ u8 unk4F; + /* 0x50 */ u16 unk50; + /* 0x52 */ s16 unk52; +} Ent388C; + +typedef struct { + /* 0x00 */ s32 unk00; + /* 0x04 */ s32 unk04; + /* 0x08 */ u16 unk08; + /* 0x0A */ u16 unk0A; + /* 0x0C */ u16 unk0C; + /* 0x0E */ u16 unk0E; + /* 0x10 */ u16 unk10; + /* 0x12 */ u16 unk12; + /* 0x14 */ s32 unk14; + /* 0x18 */ u8 pad18[0x0C]; + /* 0x24 */ s32 unk24; + /* 0x28 */ u8 pad28[0x0C]; + /* 0x34 */ u8 unk34; + /* 0x35 */ u8 unk35; + /* 0x36 */ u8 unk36; + /* 0x37 */ u8 pad37[9]; + /* 0x40 */ void (*unk40)(u8 *, s32); + /* 0x44 */ s32 unk44; + /* 0x48 */ u16 unk48; + /* 0x4A */ u16 unk4A; + /* 0x4C */ u8 unk4C; + /* 0x4D */ u8 unk4D; + /* 0x4E */ u8 unk4E; + /* 0x4F */ u8 unk4F; + /* 0x50 */ u8 pad50[2]; + /* 0x52 */ u8 unk52; + /* 0x53 */ u8 unk53; +} Chan388C; /* 0x54 */ + +typedef struct { + /* 0x00 */ s32 unk00; + /* 0x04 */ s32 unk04; + /* 0x08 */ s16 unk08; + /* 0x0A */ s16 unk0A; + /* 0x0C */ s16 unk0C; + /* 0x0E */ s16 unk0E; + /* 0x10 */ u8 pad10[4]; + /* 0x14 */ s16 unk14; + /* 0x16 */ u8 pad16[2]; + /* 0x18 */ u16 unk18; + /* 0x1A */ u8 pad1A[2]; + /* 0x1C */ s32 unk1C; + /* 0x20 */ u8 pad20[0x1A]; + /* 0x3A */ s16 unk3A; + /* 0x3C */ s16 unk3C; + /* 0x3E */ u8 pad3E[2]; + /* 0x40 */ s32 unk40; + /* 0x44 */ u8 unk44; + /* 0x45 */ u8 unk45; + /* 0x46 */ u8 pad46[2]; +} Voice388C; /* 0x48 */ + +extern s16 D_800A4EF0; +extern s16 D_800C5328[]; +extern s16 D_800A46A2; +extern u8 D_800A4988[]; +extern B12 *D_8006A970[]; +extern s32 D_80073140[]; +extern u16 D_8006AB30[]; +extern u16 D_8006AB32[]; +extern u8 D_800A4F1E; +extern u16 D_8006AA30[]; +extern s16 D_800A4EFA; +extern u8 D_800A4F19; +extern const u16 D_8007319E[]; +extern const u16 D_800731A0[]; +extern u16 D_8007321E; +extern s16 D_800A4EF6; + +extern void func_80034650(u8 *, s32); +extern void func_800336A8(); +extern s32 func_80030CA4(u16); +extern s16 func_8003F144(s32, s32, s32, C24 *); +extern s32 func_8003F380(s32, s32); +extern void func_800316F8(s32); +extern void func_8002F064(s32, s32); +extern void func_8002EFF8(s32, s32); +extern void func_800342E8(u8 *, s32); + +void func_8003388C(Ent388C *arg, s32 arg1) +{ + Cmd388C rec; + C24 sp28; + s32 pad[4]; + Ent388C *e; + Cmd388C *cmd; + Chan388C *ch; + Voice388C *vo; + Ramp388C *r; + B12 *b; + u32 *p; + s32 op; + register s32 c0 __asm__("$2"); + register s32 c1 __asm__("$3"); + register s32 c2 __asm__("$2"); + register s32 c3 __asm__("$4"); + s32 mask; + s32 vi; + s32 bank; + s32 lvl; + register s32 res __asm__("$3"); + register s32 base __asm__("$2"); + register s32 sum __asm__("$3"); + s32 t24; + s32 tmp9; + u32 t, t18, d, amt, res2; + register u32 v __asm__("$2"); + register u32 m __asm__("$3"); + register u32 q __asm__("$2"); + u16 h; + u32 b04; + u16 h2; + s32 n84; + u32 n86; + register u32 x86 __asm__("$2"); + u8 flag; + s32 called; + s32 lv; + register u32 tv __asm__("$2"); + register u32 pr1 __asm__("$5"); + register u32 pr2 __asm__("$3"); + register u32 pr3 __asm__("$3"); + u32 i; + + e = arg; + if (e->unk34 != 0 && e->unk34 != D_800A4EF0) { + func_80034650((u8 *)e, 0); + return; + } + if (e->unk08 != 0) { + e->unk08 = e->unk08 - 1; + } + + r = e->unk1C; + flag = 0; + for (i = 0; i < 3; i++, r++) { + if (r->act != 0) { + flag = 1; + h = r->cur; + t = h; + if (t == r->tgt) { + r->act = 0; + } else if (t < r->tgt) { + r->cur = h + r->step; + if (r->cur >= 0x4000) { + r->cur = 0x3FFF; + } + if (r->tgt < r->cur) { + r->cur = r->tgt; + } + } else { + if (t >= r->step) { + r->cur = h - r->step; + } else { + r->cur = 0; + } + if (r->cur < r->tgt) { + r->cur = r->tgt; + } + } + } + } + + called = 0; + if (e->unk16 != 0) { + if (e->unk18 > e->unk1A) { + e->unk18 = e->unk18 - e->unk1A; + func_800336A8((void *)e); + called = 1; + } else { + func_80034650((u8 *)e, 1); + return; + } + } else if (flag != 0) { + func_800336A8((void *)e); + called = 1; + } + + if (e->unk39 != e->unk38) { + if (called == 0) { + func_800336A8((void *)e); + } + e->unk39 = e->unk38; + } + + if (e->unk36 != 0) { + for (i = 0; i < 8; i++) { + if (e->unk3A[i] != 0) { + return; + } + } + e->unk00 = 0; + return; + } + + e->unk14 = e->unk14 - 1; + if (e->unk14 != 0) { + return; + } + + if (e->unk48 != 0) { + p = e->unk0C; + for (;;) { + op = *p; + switch ((u32)op >> 24) { + case 0x80: + p++; + rec.unk06 = op; + rec.unk08 = op >> 16; + op = *p; + p++; + rec.unk02 = op; + rec.unk00 = op >> 16; + op = *p; + p++; + c0 = op; + op >>= 8; + c1 = op; + op >>= 8; + c3 = (u32)op >> 8; + rec.unk0C = c0; + e->unk4F = c0; + c2 = op; + rec.unk0B = c1; + e->unk4E = c1; + rec.unk0A = c2; + e->unk4D = c2; + rec.unk09 = c3; + e->unk4C = c3; + h2 = *(u16 *)p; + p++; + rec.unk04 = h2; + e->unk4A = h2; + op = *p; + p++; + rec.unk0D = 0; + rec.unk10 = op; + goto done; + case 0x81: + p++; + rec.unk06 = op; + rec.unk08 = op >> 16; + op = *p; + rec.unk02 = op; + rec.unk00 = op >> 16; + rec.unk0C = e->unk4F; + rec.unk0B = e->unk4E; + rec.unk0A = e->unk4D; + rec.unk09 = e->unk4C; + rec.unk04 = e->unk4A; + p++; + rec.unk10 = 0; + rec.unk0D = 0; + goto done; + case 0x82: + p++; + e->unk17 = op; + e->unk44 = p; + continue; + case 0x83: + if (e->unk17 != 0) { + e->unk17 = e->unk17 - 1; + if (e->unk17 == 0) { + p++; + continue; + } + } + if ((op & 0xFFFFFF) != 0) { + goto pend83; + } + p = e->unk44; + continue; + case 0x85: + if (e->unk17 != 0) { + e->unk17 = e->unk17 - 1; + if (e->unk17 == 0) { + p++; + e->unk50 = 0; + e->unk52 = 0; + continue; + } + } + e->unk52 = e->unk52 + (s8)op * 16; + e->unk50 = e->unk50 + (s8)(op >> 8); + mask = op & 0xFF0000; + if (mask != 0) { + goto pend85; + } + p = e->unk44; + continue; + case 0x84: + p++; + e->unk1C[0].act = 1; + e->unk1C[0].step = op >> 8; + n84 = op & 0x7F; + e->unk1C[0].tgt = (n84 * 16383) >> 7; + continue; + case 0x86: + n86 = op & 0x7F; + x86 = (n86 * 16383) >> 7; + p++; + e->unk1C[0].act = 0; + e->unk1C[0].tgt = x86; + e->unk1C[0].cur = x86; + continue; + case 0x87: + for (i = 0; i < 8; i++) { + if (e->unk3A[i] != 0) { + goto set36; + } + } + e->unk00 = 0; + return; + } + } + done: + e->unk0C = p; + cmd = &rec; + } else { + cmd = (Cmd388C *)e->unk0C; + } + + if (cmd->unk06 == 0) { + goto after; + } + vi = func_80030CA4(cmd->unk04); + if (vi == 0) { + goto after; + } + lvl = cmd->unk0A; + vi = vi - 1; + if ((lvl & 0x80) == 0) { + bank = D_800C5328[lvl * 2]; + } else { + bank = 4; + } + if (bank < 0) { + goto after; + } + ch = (Chan388C *)(D_800A4988 + vi * 0x54); + vo = (Voice388C *)(D_800A4988 + 0x2A0 + vi * 0x48); + if ((lvl & 0x80) == 0) { + b = &D_8006A970[bank][cmd->unk0B]; + vo->unk1C = b->unk00; + vo->unk18 = b->unk04; + vo->unk3A = b->unk06; + vo->unk3C = b->unk08; + } else { + if (func_8003F144(D_800A46A2, lvl & 0x7F, cmd->unk0B, &sp28) != 0) { + goto after; + } + res = func_8003F380(D_800A46A2, sp28.unk16); + if (res < 0) { + goto after; + } + b04 = sp28.unk04; + vo->unk1C = res; + vo->unk18 = b04 << 8; + vo->unk3A = sp28.unk10; + vo->unk3C = sp28.unk12; + } + + vo->unk44 = 1; + vo->unk40 = ch->unk0A; + vo->unk45 = 0; + ch->unk4C = 0; + ch->unk4A = 0x7FFF; + ch->unk4D = 0; + ch->unk00 = 0; + ch->unk04 = 0; + ch->unk08 = cmd->unk04; + ch->unk0C = cmd->unk0B; + ch->unk0E = lvl; + ch->unk36 = 0; + ch->unk10 = bank; + ch->unk14 = cmd->unk10; + tmp9 = cmd->unk09; + __asm__ __volatile__("" : "=r"(tmp9) : "0"(tmp9)); + lvl = tmp9; + ch->unk35 = lvl; + ch->unk52 = lvl; + if (e->unk38 != 0 && lvl != 0) { + sum = lvl + e->unk38; + if ((u8)sum < 0x42) { + lvl = 1; + } else { + lvl = sum - 0x40; + if ((u8)lvl >= 0x80) { + lvl = 0x7F; + } + } + } + + t24 = cmd->unk06 + e->unk52; + ch->unk40 = func_800342E8; + ch->unk44 = arg1; + ch->unk4E = 0x85; + ch->unk53 = 0; + ch->unk24 = t24; + ch->unk12 = cmd->unk02; + ch->unk4F = 0; + ch->unk48 = 0; + arg->unk3A[vi] = 1; + func_800316F8((s32)ch); + + vo->unk00 = D_80073140[ch->unk0A]; + t18 = vo->unk18; + base = (t18 & 0xFF00) + ((s8)t18 * 2); + base -= 0x3C00; + d = ch->unk24; + d -= base; + if (d >= 0x5300) { + res2 = 0x3FFF; + } else { + q = D_8006AB30[d >> 8]; + q = q * (0x100 - (d & 0xFF)); + pr3 = D_8006AB32[d >> 8] * (d & 0xFF); + res2 = (q + pr3) >> 8; + } + vo->unk14 = res2; + + amt = cmd->unk08; + if (e->unk50 < amt) { + amt = amt - e->unk50; + } else { + amt = 0; + } + if (D_800A4F1E != 0) { + amt = amt * 112; + amt = amt >> 7; + } + ch->unk34 = amt; + m = D_8006AA30[amt]; + m = m * D_800A4EFA; + m = m >> 7; + if (e->unk16 != 0) { + m = m * e->unk18; + m = m >> 15; + } + r = e->unk1C; + for (i = 0; i < 3; i++, r++) { + m = m * r->cur; + m = m >> 14; + } + lv = lvl & 0xFF; + if (lv != 0) { + if (D_800A4F19 != 0) { + tv = D_8007319E[lv]; + pr1 = m * tv; + v = pr1 >> 14; + vo->unk0A = v; + pr2 = m * D_800731A0[0x7F - lv]; + v = pr2 >> 14; + vo->unk08 = v; + } else { + v = (m * D_8007321E) >> 14; + vo->unk0A = v; + vo->unk08 = v; + } + } else { + v = m; + vo->unk08 = v; + vo->unk0A = v; + } + vo->unk0C = 0; + vo->unk0E = 0; + vo->unk04 = 0x6009F; + __asm__ __volatile__(""); + if (D_800A4EF6 > cmd->unk0C) { + func_8002F064(1, vo->unk00); + } else { + func_8002F064(0, vo->unk00); + } + func_8002EFF8(1, vo->unk00); + +after: + if (cmd->unk00 == 0) { + for (i = 0; i < 8; i++) { + if (e->unk3A[i] != 0) { + goto set36; + } + } + e->unk00 = 0; + return; + } + e->unk14 = cmd->unk00; + if (e->unk48 != 0) { + return; + } + if (cmd->unk0D == 0) { + goto advance; + } + if (e->unk17 != 0) { + e->unk17 = e->unk17 - 1; + if (e->unk17 == 0) { + goto advance; + } + } + e->unk0C = (u32 *)((u8 *)arg->unk10 + (cmd->unk0D * 20 - 20)); + return; +pend83: + e->unk14 = op; + e->unk0C = e->unk44; + return; +pend85: + e->unk14 = mask >> 16; + e->unk0C = e->unk44; + return; +set36: + e->unk36 = 1; + return; +advance: + cmd++; + e->unk0C = (u32 *)cmd; +} extern u16 D_800A46E8[]; diff --git a/src/800_c.c b/src/800_c.c index 6d5e6f54d..2bac7ab9b 100644 --- a/src/800_c.c +++ b/src/800_c.c @@ -5,9 +5,499 @@ * This TU owns .rodata span C (0x800732A0-0x8007344C); see config/splat.us.exe.yaml and cookbook §426. * Declarations shared with the sibling TUs live in src/800_shared.h. */ -INCLUDE_ASM("asm/nonmatchings/800_c", func_80035270); +/* func_80035270 — CD stream state machine (main, src/800_c.c, jtbl_800732A0 span C). + * + * Levers that made this byte-exact (all verified against asm/nonmatchings/800_c/func_80035270.s): + * - `+ zr` ($0 register variable, the src/800_c.c func_80036AF8 house idiom) forces the + * `addu $sN,$aN,$zero` copies that split `n`/`idx` and `drv`/`hi` into two pseudos. + * - HARD-REGISTER PINS, not declaration/statement order, fix gcc-2.7.2's global-alloc here: + * pinning ONLY `hi`->$s4 and `n`->$a0 rotates idx->$s2, h->$s3, drv->$a1 into place. + * (A full sweep of all 720 declaration orders and all 6 prologue statement orders moved + * nothing; the pins took the residual from 26 instructions to 6.) `sync` reuses $a0 for + * its two disjoint live ranges in cases 2 and 9; case 5 keeps its own `sync5` ($v1). + * - The shared tails are written as explicit `goto Lret0/Lret1/Lflush/Lsetflag` with the + * labels placed where the .s puts the merged blocks. gcc's cross_jump keeps the LAST + * duplicate; the target keeps the copy that sits with case 5's `f03 = 4; return 0`, so + * `default:` is co-located there (legal C89 — a case label may sit in a nested block). + * - `rec2 = ((s32)h << 6) + (s32)rec;` (fresh variable, h-first) puts the sum in the h64 + * register -> `addu $v0,$v0,$v1`; the self-assignment `rec = rec + ...` used by cases 4 + * and 6 reuses rec's register -> `addu $v1,$v1,$v0`. Both forms are load-bearing. + * - `func_8003EDE8(0, vol + zr, vol + zr)` is what emits `addu $a1,$s0,$zero` / + * `addu $a2,$a1,$zero`; a plain `(0, vol, vol)` emits `move $a2,$s0` (cse canonicalises + * the second copy back to the pseudo's own hard reg). + * - `if (++D_800760F8 < 10)` gives lhu/addiu/sh/sll16/sra16/slti; a plain post-increment + * then a reload would emit `lh`. `slti $v0,$v0,0x12D` is `<= 300`, not `< 300`. + * - Locals take sp offsets in DECLARATION order upward: result@0x10, param@0x18, loc@0x20. + * + * BANKING NOTE (§376): src/800_c.c:461 currently declares `extern void func_80035270(void);` + * (address-taken at `req.f08 = (s32)func_80035270;`). That conflicts with this definition; + * the decl must become `extern s32 func_80035270(s32);` (or the use be cast) before the TU + * will compile. + */ -INCLUDE_ASM("asm/nonmatchings/800_c", func_800359B0); +extern s32 D_8006A69C; +extern u8 D_8006A6A0; +extern s32 D_8006AEE8; +extern u8 D_8006AEEC; +extern s32 D_80078F10; +extern s16 D_800760F8; +extern s32 D_80076100; +extern u8 D_800760FC; +extern u8 D_800760FD; +extern s16 D_80076208; +extern u8 D_8007620C; +extern u8 D_80076210; +extern u8 D_80076214; +extern s32 D_800A4638; +extern s16 D_800A4688; +extern u8 D_800A4698; +extern s16 D_800A4EF6; +extern s16 D_800A4EFA; + +extern void func_800434BC(void); +extern s32 func_8004355C(s32 mode, u8 *result); +extern int func_800435CC(s32, void *, void *); +extern int func_80043830(int com, u8 *param, u8 *result); +extern int func_80043410(void); +extern int func_80043420(void); +extern s32 func_8003EDE8(s32, s32, s32); +extern void func_8003D650(int a0, int a1, int a2); + +s32 func_80035270(s32 arg0) { + register s32 zr __asm__("$0"); + u8 result[8]; + u8 param[8]; + CdlLOC loc; + s32 flags; + register s32 n __asm__("$4"); + s32 idx; + s32 lo; + s16 h; + s32 drv; + register s32 hi __asm__("$20"); + u8 *rec; + u8 *rec2; + u8 b; + s32 i; + s32 cnt; + s32 count; + s32 *p; + s32 *src; + s32 *dst; + s32 target; + s32 cmp; + u8 *q; + CdlLOC *lp; + register s32 sync __asm__("$4"); + s32 sync5; + s32 tmp; + s32 inc; + u8 ctr; + s32 st; + s32 t; + s32 val; + s32 vol; + + flags = *(s32 *)(arg0 + 0x10); + lo = flags >> 4; + h = lo & 0x1F; + n = flags & 0xF; + idx = n + zr; + drv = (flags >> 9) & 0x1F; + hi = drv + zr; + if (lo & 1) { + if (*(u8 *)((u8 *)&D_8006A6A0 + drv * 0x48) != 0) { + idx = n + 4; + } else { + idx = n + 8; + } + } + h = h >> 1; + + if (*(u8 *)(arg0 + 7) != 0) { + *(u8 *)(arg0 + 7) = 0; + *(u8 *)(arg0 + 3) = 0x11; + if (*(s32 *)(arg0 + 0xC) == 0) { + goto Lret1; + } + p = &D_80078F10; + target = *(s32 *)(arg0 + 0x2C) + 1; + if (target != p[0]) { + i = 1; + cmp = target + zr; + for (; i < 5; i++) { + if (p[i] == cmp) { + break; + } + } + if (i == 5) { + goto Lret1; + } + cnt = D_8006AEE8; + if (i < cnt) { + count = 0; + dst = &D_80078F10; + src = &D_80078F10 + i; + do { + *dst = *src; + src++; + i++; + count++; + dst++; + } while (i < cnt); + D_8006AEE8 = count; + } + } + *(s32 *)(arg0 + 0x14) = 0xF; + D_800760F8 = 0; + D_80076100 = func_80043420(); + } + + switch (*(u8 *)(arg0 + 3)) { + case 0x11: + q = &D_800760FC; + *q = 1; + D_800760FD = idx; + if (func_80043830(0xD, q, result) == 0) { + D_800760F8++; + goto Lcheck; + } + *(u8 *)(arg0 + 3) = 0x12; + func_8003EDE8(0, 0, 0); + D_800760F8 = 0; + /* fall through */ + case 0x12: + param[0] = 200; + if (func_80043830(0xE, param, result) == 0) { + D_800760F8++; + goto Lcheck; + } + if ((*(s32 *)(arg0 + 0x10) == 0x4486 || *(s32 *)(arg0 + 0x10) == 0x4364) && + D_800A4698 == 0 && D_800A4688 == 0x2B) { + goto Lvol; + } + rec = (u8 *)*(s32 *)((u8 *)&D_8006A69C + hi * 0x48); + rec2 = (u8 *)(((s32)h << 6) + (s32)rec); + b = *(u8 *)(rec2 + (idx << 2) + 1); + if ((b & 0x20) == 0) { + goto Lzero; + } + if ((b & 0x40) == 0) { + goto Lone; + } + Lvol: + if (D_800A4EF6 >= 2) { + func_8003D650(0, 1, 1); + } else { + func_8003D650(0, 1, 0); + } + goto Lcont; + Lone: + func_8003D650(0, 1, 1); + goto Lcont; + Lzero: + func_8003D650(0, 1, 0); + Lcont: + D_800760F8 = 0; + if (D_80076100 & 0x80) { + *(u8 *)(arg0 + 3) = 1; + goto Lcase1; + } + *(u8 *)(arg0 + 3) = 0; + /* fall through */ + case 0: + if (*(s32 *)(arg0 + 0x14) != 0) { + *(s32 *)(arg0 + 0x14) = *(s32 *)(arg0 + 0x14) - 1; + } + if (++D_800760F8 < 10) { + goto Lret0; + } + *(u8 *)(arg0 + 3) = 1; + D_800760F8 = 0; + /* fall through */ + case 1: + Lcase1: + if (*(s32 *)(arg0 + 0x14) != 0) { + *(s32 *)(arg0 + 0x14) = *(s32 *)(arg0 + 0x14) - 1; + } + lp = &loc; + CdIntToPos(*(s32 *)(arg0 + 0xC), lp); + D_800760F8++; + if (func_80043830(2, (u8 *)lp, 0) == 0) { + goto Lcheck; + } + if (func_800435CC(0x15, lp, 0) == 0) { + goto Lcheck; + } + D_800760F8 = 0; + *(u8 *)(arg0 + 3) = 2; + /* fall through */ + case 2: + if (*(s32 *)(arg0 + 0x14) != 0) { + *(s32 *)(arg0 + 0x14) = *(s32 *)(arg0 + 0x14) - 1; + } + sync = func_8004355C(1, result); + if (sync == 0) { + D_800760F8++; + goto Lcheck; + } + if (sync == 5) { + if (func_800435CC(1, param, result) != 0) { + *(u8 *)(arg0 + 3) = 1; + goto Lret0; + } + if (result[0] & 0x10) { + goto Lsetflag; + } + *(u8 *)(arg0 + 3) = 1; + goto Lret0; + } + D_80076208 = *(s32 *)(arg0 + 0x14); + *(u8 *)(arg0 + 3) = 3; + /* fall through */ + case 3: + if (*(s32 *)(arg0 + 0x14) != 0) { + *(s32 *)(arg0 + 0x14) = *(s32 *)(arg0 + 0x14) - 1; + goto Lret0; + } + D_800760F8 = 0; + *(u8 *)(arg0 + 3) = 4; + /* fall through */ + case 4: + CdIntToPos(*(s32 *)(arg0 + 0xC), &loc); + if (func_800435CC(0x1B, &loc, 0) == 0) { + D_800760F8++; + goto Lcheck; + } + rec = (u8 *)*(s32 *)((u8 *)&D_8006A69C + hi * 0x48); + rec = rec + ((s32)h << 6); + D_80076210 = 0; + D_800760F8 = 0; + vol = (*(u8 *)(rec + (idx << 2)) * D_800A4EFA >> 7) & 0x7F; + func_8003EDE8(0, vol + zr, vol + zr); + D_8006AEEC = vol; + *(u8 *)(arg0 + 3) = 5; + /* fall through */ + case 5: + sync5 = func_8004355C(1, result); + if (sync5 == 2) { + goto Lstate6; + } + if (sync5 == 5) { + if (result[0] & 0x10) { + goto Lflush; + } + func_800434BC(); + *(u8 *)(arg0 + 3) = 4; + default: + Lret0: + return 0; + } + D_800760F8++; + goto Lcheck; + Lstate6: + *(u8 *)(arg0 + 3) = 6; + /* fall through */ + case 6: + func_800435CC(1, 0, 0); + st = func_80043410(); + D_8007620C = st; + if ((st & 0x20) == 0) { + goto Lret0; + } + rec = (u8 *)*(s32 *)((u8 *)&D_8006A69C + hi * 0x48); + rec = rec + ((s32)h << 6); + t = D_800A4638; + *(s32 *)(arg0 + 0x18) = t; + val = *(s16 *)(rec + (idx << 2) + 2) + t; + *(s32 *)(arg0 + 0x14) = val; + if ((u32)val < (u32)t) { + *(u8 *)(arg0 + 6) = 1; + } else { + *(u8 *)(arg0 + 6) = 0; + } + *(u8 *)(arg0 + 3) = 7; + /* fall through */ + case 7: + ctr = D_80076210; + inc = ctr + 1; + tmp = ctr & 3; + D_80076210 = inc; + if (tmp == 0) { + func_800435CC(1, 0, 0); + st = func_80043410(); + D_8007620C = st; + if (st & 0x10) { + goto Lflush; + } + } + t = D_800A4638; + if ((u32)t < (u32)*(s32 *)(arg0 + 0x14)) { + goto Lret0; + } + if (*(u8 *)(arg0 + 6) != 0) { + if ((u32)t >= (u32)*(s32 *)(arg0 + 0x18)) { + goto Lret0; + } + } + *(u8 *)(arg0 + 3) = 8; + /* fall through */ + case 8: + func_8003EDE8(0, 0, 0); + if (func_800435CC(9, 0, 0) == 0) { + goto Lret0; + } + D_8007620C = 0; + *(u8 *)(arg0 + 3) = 9; + /* fall through */ + case 9: + sync = func_8004355C(1, result); + if (sync == 0) { + goto Lret0; + } + if (sync != 5) { + goto Lret1; + } + if ((result[0] & 0x10) == 0) { + goto Lret1; + } + goto Lsetflag; + } + +Lcheck: + if (D_800760F8 <= 300) { + goto Lret0; + } +Lflush: + func_800434BC(); +Lsetflag: + D_80076214 = 1; +Lret1: + return 1; +} + +/* func_800359B0 — CD/stream state pump (jtbl_800732F0, cases 0..0x12). + * + * Two cross-jump dials carry this function (§162 / §336 / §194-N): + * - case 0x10's `j .L80035B40` is BACKWARD into case 9's arm, so per §162 it is a + * source `goto`, not a compiler tail-merge (the survivor is always the LATER copy). + * - `do_flag:` sits INSIDE case 9's >=0x12D arm: that surviving CODE_LABEL is what + * stops find_cross_jump's backward walk from swallowing case 9's own block + * (jump.c:2404 `GET_CODE (i1) == CODE_LABEL` -> --minimum; break). + * - the zero-byte fence sits at the BOTTOM of case 0x10's twin, just before the shared + * `goto` (§336): without it the `minimum=1` path (jump.c:1978) matches case 0x10's + * `jal func_800434BC` against the one preceding `do_flag` and merges them backward, + * costing exactly the 2 instructions at 0x80035C1C. + */ +extern u8 D_8006AEEC; +extern s16 D_800A4EFA; +extern u8 D_8007620C; +extern u16 D_80076104; +extern u8 D_80076214; +extern void func_800434BC(void); +extern s32 func_8003EDE8(s32, s32, s32); +extern int func_800435CC(s32, void *, void *); +extern s32 func_8004355C(s32 mode, u8 *result); + +void func_800359B0(s32 arg0) { + u8 result[8]; + s32 sync; + + switch (*(u8 *)(arg0 + 3)) { + case 1: + case 2: + func_800434BC(); + *(u8 *)(arg0 + 2) = 0; + break; + case 4: + func_800434BC(); + *(u8 *)(arg0 + 2) = 1; + *(u8 *)(arg0 + 3) = 0x10; + break; + case 6: + case 7: + func_8003EDE8(0, (u32)((D_8006AEEC * D_800A4EFA) >> 7 & 0xFF) * 3 >> 2, + (u32)((D_8006AEEC * D_800A4EFA) >> 7 & 0xFF) * 3 >> 2); + *(u8 *)(arg0 + 2) = 1; + D_8007620C = 0; + *(u8 *)(arg0 + 3) = 0xB; + break; + case 5: + func_800434BC(); + *(u8 *)(arg0 + 3) = 8; + /* fall through */ + case 8: + func_8003EDE8(0, 0, 0); + if (func_800435CC(9, 0, 0) == 0) { + *(u8 *)(arg0 + 2) = 1; + *(u8 *)(arg0 + 3) = 0x10; + D_80076104 = 0; + return; + } + D_8007620C = 0; + D_80076104 = 0; + *(u8 *)(arg0 + 3) = 9; + /* fall through */ + case 9: + sync = func_8004355C(1, result); + if (sync == 0) { + D_80076104 = D_80076104 + 1; + if ((s16)D_80076104 >= 0x12D) { + func_800434BC(); + do_flag: + D_80076214 = 1; + *(u8 *)(arg0 + 2) = 0; + return; + } + *(u8 *)(arg0 + 2) = 1; + return; + } + if (sync == 5 && (result[0] & 0x10)) { + D_80076214 = 1; + } + *(u8 *)(arg0 + 2) = 0; + break; + case 11: + func_8003EDE8(0, D_8006AEEC >> 1, D_8006AEEC >> 1); + *(u8 *)(arg0 + 3) = 0xC; + break; + case 12: + func_8003EDE8(0, D_8006AEEC >> 2, D_8006AEEC >> 2); + *(u8 *)(arg0 + 3) = 0xD; + break; + case 13: + func_8003EDE8(0, 0, 0); + if (func_800435CC(9, 0, 0) != 0) { + *(u8 *)(arg0 + 3) = 9; + return; + } + *(u8 *)(arg0 + 3) = 0x10; + D_80076104 = 0; + break; + case 16: + if (func_800435CC(9, 0, 0) == 0) { + D_80076104 = D_80076104 + 1; + if ((s16)D_80076104 >= 0x12D) { + func_800434BC(); + __asm__ __volatile__(""); /* §336 cross-jump fence, zero bytes */ + goto do_flag; + } + break; + } + *(u8 *)(arg0 + 3) = 9; + break; + case 0: + case 3: + case 10: + case 14: + case 15: + case 17: + case 18: + default: + *(u8 *)(arg0 + 2) = 0; + break; + } +} INCLUDE_ASM("asm/nonmatchings/800_c", func_80035C4C);