diff --git a/src/ov_SC01_077/ov_SC01_077_a.c b/src/ov_SC01_077/ov_SC01_077_a.c index c90238de7..5459d5d64 100644 --- a/src/ov_SC01_077/ov_SC01_077_a.c +++ b/src/ov_SC01_077/ov_SC01_077_a.c @@ -210,7 +210,56 @@ DEFINE_func_80128DB4() /* dedup: shared engine-core @0x80128DB4 (src/shared) */ DEFINE_func_80128EA8() /* dedup: shared engine-core @0x80128EA8 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_077/nonmatchings/ov_SC01_077_a", func_80128ED8); +// LOAD-BEARING register pins (cookbook §17 + §25): the residual here was NOT scheduling but +// gcc-2.7.2 COPY-COALESCING — gcc folded the index-preserve copy (idc) into the multiply operand +// (`sll $v0,$a3,3` on the copy) instead of multiplying $v1 directly. Pinning idc to its target +// reg ($a3) forces the multiply onto $v1 and emits the copy separately AFTER it; routing idc+1 +// through the dead $v0-pinned `cnt` lands it in $v0 (target's scratch), not back in $a3. +// Do NOT "simplify" the pins or the cnt reuse — each is byte-load-bearing (byte-gated). +#include "common.h" + +s32 func_80128ED8(s32 param_1, s32 *param_2) { + register s32 iVar4 __asm__("$8"); /* base ptr, lives whole fn in $t0 */ + register s32 cnt __asm__("$2"); /* decremented count in $v0 */ + register s32 cc __asm__("$3"); /* preserved count copy in $v1 (forces the bne-delay-slot copy) */ + register s32 idx __asm__("$3"); /* offset-4 index, loaded into $v1 */ + register s32 idc __asm__("$7"); /* $a3: preserved idx copy, forced SEPARATE from the multiply */ + u32 uVar3; + s32 frame_pad[4]; /* phantom 0x10 frame the target reserves (induce via clobber anchor) */ + + __asm__ __volatile__("" : : "r"(&frame_pad) : "memory"); + iVar4 = *param_2; + cnt = *(s16 *)((s32)param_2 + 6); + if (cnt == 0) { + return 1; + } + cc = cnt; + __asm__ __volatile__("" : "=r"(cc) : "0"(cc)); /* force the count-preserve copy ($v1=$v0) */ + cnt = cc - 1; + *(s16 *)((s32)param_2 + 6) = (s16)cnt; + if (cnt * 0x10000 < 1) { + idx = *(s16 *)((s32)param_2 + 4); + __asm__ __volatile__("" : "=r"(idx) : "0"(idx)); /* pin the index into $v1 */ + uVar3 = *(u32 *)(idx * 8 + iVar4 + 4); + idc = idx; + if ((uVar3 & 0xc0) == 0xc0) { + *(s16 *)((s32)param_2 + 6) = 0; + return 1; + } + if ((uVar3 & 0x80) != 0) { + *(s16 *)((s32)param_2 + 4) = 0; + } else { + cnt = idc + 1; /* reuse the dead $v0 pin so idc+1 lands in $v0, not $a3 */ + *(s16 *)((s32)param_2 + 4) = cnt; + } + *(u16 *)((s32)param_2 + 6) = + (u16)(*(u32 *)((s16)param_2[1] * 8 + iVar4 + 4) & 0x3f); + *(u16 *)(param_1 + 0x28) = *(u16 *)((s16)param_2[1] * 8 + iVar4); + *(u16 *)(param_1 + 0x2a) = *(u16 *)((s16)param_2[1] * 8 + iVar4 + 2); + } + return 0; +} + M2C_UNK func_8001534C(M2C_UNK, M2C_UNK *, M2C_UNK, M2C_UNK, s32, s32); /* extern */ M2C_UNK func_800153CC(M2C_UNK, u16, M2C_UNK, M2C_UNK, s32, s32); /* extern */