From d989ed08ae0bf0e1ba316d102e343c4e8e1be95c Mon Sep 17 00:00:00 2001 From: Drew T <50529377+Druthulu@users.noreply.github.com> Date: Mon, 31 Aug 2026 13:43:44 -0600 Subject: [PATCH] =?UTF-8?q?feat(decomp):=20parallel=20gate=20=E2=80=94=201?= =?UTF-8?q?4=20fns=20across=2011=20binaries=20(6=20workers)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit md_SC07_003 func_801A38E4 md_MAIN_027 func_800CB4A4 ov_SC02_037 func_8013DD68 ov_SC02_003 func_8018046C ov_SC01_084 func_8017EA98 func_80181F80 func_80184138 ov_SC03_107 func_8013DD68 ov_SC05_003 func_8017E380 ov_SC05_008 func_8017DF68 func_8017EBB8 ov_SC05_010 func_8017FAF4 ov_SC06_032 func_80190D70 ov_SC06_025 func_8017EA74 --- src/md_MAIN_027/md_MAIN_027.c | 137 ++++++++++- src/md_SC07_003/md_SC07_003.c | 180 ++++++++++++++- src/ov_SC01_084/ov_SC01_084_jr_8017CA80.c | 149 +++++++++++- src/ov_SC01_084/ov_SC01_084_jr_8017F690.c | 267 +++++++++++++++++++++- src/ov_SC02_003/ov_SC02_003_jr_8017FCB0.c | 136 ++++++++++- src/ov_SC02_037/ov_SC02_037_jr_8013C98C.c | 101 +++++++- src/ov_SC03_107/ov_SC03_107_jr_8013C98C.c | 88 ++++++- src/ov_SC05_003/ov_SC05_003_jr_8017BEBC.c | 86 ++++++- src/ov_SC05_008/ov_SC05_008_jr_8017AE2C.c | 147 +++++++++++- src/ov_SC05_010/ov_SC05_010_jr_8017C8D0.c | 99 +++++++- src/ov_SC06_025/ov_SC06_025_jr_8017BEBC.c | 99 +++++++- src/ov_SC06_032/ov_SC06_032_jr_801902EC.c | 147 +++++++++++- 12 files changed, 1621 insertions(+), 15 deletions(-) diff --git a/src/md_MAIN_027/md_MAIN_027.c b/src/md_MAIN_027/md_MAIN_027.c index 429c21a79..8ec3b4fa4 100644 --- a/src/md_MAIN_027/md_MAIN_027.c +++ b/src/md_MAIN_027/md_MAIN_027.c @@ -282,7 +282,142 @@ void func_800CB3E0(s32 a0) { } -INCLUDE_ASM("asm/md_MAIN_027/nonmatchings/md_MAIN_027", func_800CB4A4); +extern s32 D_80078EC8; +extern void func_800CB82C(s32 a0, s32 a1); +extern s32 func_801488A8(s32 a0); +extern void func_80146D90(s32 a0); +extern s32 func_80148D44(s32 a0); +extern void func_80162FF4(s32 a0, s32 a1, s32 a2, s32 a3); +extern void func_800134FC(s32 a0, void *a1, void *a2); +extern void func_8001599C(void *a0, void *a1); +extern void func_80162FC0(s32 a0); +extern void func_800CBCB4(void *a0); +extern s32 func_80012F74(s32 a0, s32 a1, s32 a2, s32 a3); +extern s16 currentLocationId; +extern u8 D_800CC298[]; +extern s16 D_800CC29A; +extern s16 D_800CC29C; + +typedef struct { s32 w[4]; } CB4A4_V4; + +void func_800CB4A4(s32 a0) { + u8 *ap; + s32 s1; + s32 s3; + s32 *s2; + s32 v0; + s32 d; + s32 flag; + CB4A4_V4 bak[2]; + s16 *dig; + + s1 = a0; + s3 = *(s32 *)(s1 + 0x4C); + ap = *(u8 **)(s1 + 0x20); + if (D_80078EC8 < 0x28) { + *(u16 *)(ap + 0x18) = *(u16 *)(ap + 0x18) - 0x40; + *(u16 *)(ap + 0x1A) = *(u16 *)(ap + 0x1A) - 0x40; + } + func_800CB82C(s1, *(s32 *)(s1 + 0x58)); + if (func_801488A8(s3) != 0) { + bak[1] = *(CB4A4_V4 *)(s1 + 0x10); + func_80146D90(s1); + *(s32 *)(s1 + 0x18) = 0; + *(s32 *)(s1 + 0x14) = 0; + v0 = func_80148D44((*(s32 *)(s1 + 0x10) = 0, s1)); + *(u16 *)(*(s32 *)(s1 + 0x20) + 0x12) = v0; + func_80162FF4(s1, 0, 0, 0xFFFE4000); + s2 = (s32 *)(s1 + 0x10); + if (currentLocationId == 0x3038) { + bak[0] = *(CB4A4_V4 *)s2; + func_800134FC(0x400, &bak[0], &bak[0]); + func_8001599C(&bak[0], s2); + } + *(s32 *)(s1 + 0x10) += bak[1].w[0]; + *(s32 *)(s1 + 0x14) += bak[1].w[1]; + *(s32 *)(s1 + 0x18) += bak[1].w[2]; + if (*(s32 *)(s1 + 0x10) > 0xE0000) { + *(s32 *)(s1 + 0x10) = 0xE0000; + } else if (*(s32 *)(s1 + 0x10) < -0xE0000) { + *(s32 *)(s1 + 0x10) = -0xE0000; + } + if (*(s32 *)(s1 + 0x14) > 0xE0000) { + *(s32 *)(s1 + 0x14) = 0xE0000; + } else if (*(s32 *)(s1 + 0x14) < -0xE0000) { + *(s32 *)(s1 + 0x14) = -0xE0000; + } + if (*(s32 *)(s1 + 0x18) > 0xE0000) { + *(s32 *)(s1 + 0x18) = 0xE0000; + } else if (*(s32 *)(s1 + 0x18) < -0xE0000) { + *(s32 *)(s1 + 0x18) = -0xE0000; + } + } else { + flag = 0; + if (*(s32 *)(s1 + 0x10) != 0) { + flag = 1; + if (*(s32 *)(s1 + 0x10) >= 0) { + d = *(s32 *)(s1 + 0x10) - 0x8000; + *(s32 *)(s1 + 0x10) = d; + if (d < 0) { + *(s32 *)(s1 + 0x10) = 0; + } + } else { + d = *(s32 *)(s1 + 0x10) + 0x8000; + *(s32 *)(s1 + 0x10) = d; + if (d >= 0) { + *(s32 *)(s1 + 0x10) = 0; + } + } + } + if (*(s32 *)(s1 + 0x14) != 0) { + flag = 1; + if (*(s32 *)(s1 + 0x14) >= 0) { + d = *(s32 *)(s1 + 0x14) - 0x8000; + *(s32 *)(s1 + 0x14) = d; + if (d < 0) { + *(s32 *)(s1 + 0x14) = 0; + } + } else { + d = *(s32 *)(s1 + 0x14) + 0x8000; + *(s32 *)(s1 + 0x14) = d; + if (d >= 0) { + *(s32 *)(s1 + 0x14) = 0; + } + } + } + if (*(s32 *)(s1 + 0x18) != 0) { + flag = 1; + if (*(s32 *)(s1 + 0x18) >= 0) { + d = *(s32 *)(s1 + 0x18) - 0x8000; + *(s32 *)(s1 + 0x18) = d; + if (d < 0) { + *(s32 *)(s1 + 0x18) = 0; + } + } else { + d = *(s32 *)(s1 + 0x18) + 0x8000; + *(s32 *)(s1 + 0x18) = d; + if (d >= 0) { + *(s32 *)(s1 + 0x18) = 0; + } + } + } + if (flag == 0) { + goto tail; + } + } + func_80162FC0(s1); +tail: + func_800CBCB4((void *)s1); + dig = (s16 *)D_800CC298; + v0 = func_80012F74(dig[0], *(s16 *)(s1 + 6), 0xA, 1); + dig[0] = v0; + v0 = func_80012F74(D_800CC29A, *(s16 *)(s1 + 0xA), 0xA, 1); + D_800CC29A = v0; + v0 = func_80012F74(D_800CC29C, *(s16 *)(s1 + 0xE), 0xA, 1); + D_800CC29C = v0; + memcpy((void *)(s3 + 0x154), &D_800CC298[0], 8); +} + extern void func_801662F4(void); extern void func_80162CCC(void); diff --git a/src/md_SC07_003/md_SC07_003.c b/src/md_SC07_003/md_SC07_003.c index 079b402c8..ef928f76f 100644 --- a/src/md_SC07_003/md_SC07_003.c +++ b/src/md_SC07_003/md_SC07_003.c @@ -2053,7 +2053,185 @@ void func_801A38A8(s32 arg0) { } -INCLUDE_ASM("asm/md_SC07_003/nonmatchings/md_SC07_003", func_801A38E4); +/* + * func_801A38E4 (md_SC07_003, 0x801A38E4, 186 ins) == MATCH, byte-exact. + * + * Rotates one of D_801A6CE8's 16-byte bounding-box records into view space and + * writes the six min/max halfwords at +4..+0xE of the caller's record. a4 == 0 + * takes the three-axis path (each axis is fed through RotTransSV as a lone + * non-zero component); a4 != 0 rotates the two corner SVECTORs directly. + * + * Frame 0xC8: 0x10 MATRIX m, 0x30/0x38 sv0/sv1, 0x40/0x48 o0/o1, 0x50 flag, + * 0x58..0xB8 = 12 combine-orphaned sign-extend slots (§147-B as CORRECTED in + * P30 S43 — 2 per min/max block x 6 blocks, 8 bytes each). NO dead local is + * needed: writing the six blocks in the shape below produces the hole for free. + * + * LEVERS (each verified by reverting it and re-scoring with match_one): + * 1. NO `s16 *out` LOCAL — the six pairs index the parameter as + * `((s16 *)a1)[k]`. Binding a1 to a local makes `addu $s1,$a1,$zero` an + * ordinary body insn that sched1 sinks below the D_801A6CE8 address chain + * (target: sw $s1 / addu $s1 at idx 1-2, draft: idx 6-7). As a parameter + * copy it is an assign_parms insn and stays at the top. 7 -> 0. + * 2. The compare is spelled `o0.f > o1.f`, NOT `o1.f < o0.f`. Both fold to + * `slt $v0,$v0,$v1`, but the `>` form evaluates o0 first, so the target's + * `lh 0x40 ; lh 0x48 ; nop` load-delay nop appears (the `<` form fills that + * slot with the second load and loses 8 instructions across the 6 blocks). + * 3. Each SVECTOR is filled VALUE FIRST, then the two zeroed components in + * DESCENDING field order (vz before vy before vx). sched1 hoists the `lhu` + * and sinks its dependent `sh`, so the emitted order is + * lhu / zero / zero / value — source order any other way transposes the two + * `sh $zero` or floats one above the `lhu`. + * 4. Arm B's second corner needs `q = p; p += 4;` BEFORE the first call. + * `RotTransSV((s32)(p + 4), ...)` after it folds into `addiu $a0,$s2,8` + * (-1 instruction); the copy-then-bump form is what emits the target's + * `addu $a0,$s2,$zero` (branch delay slot) + `addiu $s2,$s2,8`. + * + * SYMBOL AUDIT (law 1c, after MATCH) — every symbol re-checked against the + * relocation lines of asm/md_SC07_003/nonmatchings/md_SC07_003/func_801A38E4.s: + * 1x jal func_8012EA90 (a0, a2, &m) · 8x jal RotTransSV (6 in arm A, + * 2 in arm B) · one %hi/%lo pair, D_801A6CE8. No other relocation exists + * in the target. + * + * BANK NOTE (law 2): src/md_SC07_003/md_SC07_003.c already prototypes + * `extern void func_801A38E4(void *a0, void *a1, s32 a2, s32 a3, s32 a4);` + * (4x, all above the INCLUDE_ASM) — the definition below is spelled to match it + * exactly, which is what the last gate rejected. `RotTransSV` and the two + * gte_Set*Matrix macros are copied VERBATIM from the same TU; D_801A6CE8 and + * func_8012EA90 are declared nowhere in it, so those two are free-standing + * (func_8012EA90 follows the fleet-modal `(void, (s32, s32, s32*))`). + */ +#include "common.h" + +typedef struct { + s16 vx; + s16 vy; + s16 vz; + s16 pad; +} SVec801A38E4; + +extern void func_8012EA90(s32 a0, s32 a1, s32 *a2); +extern void RotTransSV(s32 a0, s32 a1, void *a2); +extern u8 D_801A6CE8[]; + +#define gte_SetRotMatrix(r0) __asm__ volatile ( \ + "lw $12, 0( %0 );" \ + "lw $13, 4( %0 );" \ + "ctc2 $12, $0;" \ + "ctc2 $13, $1;" \ + "lw $12, 8( %0 );" \ + "lw $13, 12( %0 );" \ + "lw $14, 16( %0 );" \ + "ctc2 $12, $2;" \ + "ctc2 $13, $3;" \ + "ctc2 $14, $4" \ + : \ + : "r"( r0 ) \ + : "$12", "$13", "$14" ) +#define gte_SetTransMatrix(r0) __asm__ volatile ( \ + "lw $12, 20( %0 );" \ + "lw $13, 24( %0 );" \ + "ctc2 $12, $5;" \ + "lw $14, 28( %0 );" \ + "ctc2 $13, $6;" \ + "ctc2 $14, $7" \ + : \ + : "r"( r0 ) \ + : "$12", "$13", "$14" ) + +void func_801A38E4(void *a0, void *a1, s32 a2, s32 a3, s32 a4) +{ + s32 m[8]; + SVec801A38E4 sv0; + SVec801A38E4 sv1; + SVec801A38E4 o0; + SVec801A38E4 o1; + s32 flag; + u16 *p; + u16 *q; + + p = (u16 *)(D_801A6CE8 + (a3 << 4)); + + func_8012EA90((s32)a0, a2, m); + gte_SetRotMatrix(m); + gte_SetTransMatrix(m); + + if (a4 == 0) { + sv0.vx = p[0]; + sv0.vz = 0; + sv0.vy = 0; + sv1.vx = p[4]; + sv1.vz = 0; + sv1.vy = 0; + RotTransSV((s32)&sv0, (s32)&o0, &flag); + RotTransSV((s32)&sv1, (s32)&o1, &flag); + if (o0.vx > o1.vx) { + ((s16 *)a1)[3] = o0.vx; + ((s16 *)a1)[2] = o1.vx; + } else { + ((s16 *)a1)[3] = o1.vx; + ((s16 *)a1)[2] = o0.vx; + } + + sv0.vy = p[1]; + sv0.vz = 0; + sv0.vx = 0; + sv1.vy = p[5]; + sv1.vz = 0; + sv1.vx = 0; + RotTransSV((s32)&sv0, (s32)&o0, &flag); + RotTransSV((s32)&sv1, (s32)&o1, &flag); + if (o0.vy > o1.vy) { + ((s16 *)a1)[5] = o0.vy; + ((s16 *)a1)[4] = o1.vy; + } else { + ((s16 *)a1)[5] = o1.vy; + ((s16 *)a1)[4] = o0.vy; + } + + sv0.vz = p[2]; + sv0.vy = 0; + sv0.vx = 0; + sv1.vz = p[6]; + sv1.vy = 0; + sv1.vx = 0; + RotTransSV((s32)&sv0, (s32)&o0, &flag); + RotTransSV((s32)&sv1, (s32)&o1, &flag); + if (o0.vz > o1.vz) { + ((s16 *)a1)[7] = o0.vz; + ((s16 *)a1)[6] = o1.vz; + } else { + ((s16 *)a1)[7] = o1.vz; + ((s16 *)a1)[6] = o0.vz; + } + } else { + q = p; + p += 4; + RotTransSV((s32)q, (s32)&o0, &flag); + RotTransSV((s32)p, (s32)&o1, &flag); + if (o0.vx > o1.vx) { + ((s16 *)a1)[3] = o0.vx; + ((s16 *)a1)[2] = o1.vx; + } else { + ((s16 *)a1)[3] = o1.vx; + ((s16 *)a1)[2] = o0.vx; + } + if (o0.vy > o1.vy) { + ((s16 *)a1)[5] = o0.vy; + ((s16 *)a1)[4] = o1.vy; + } else { + ((s16 *)a1)[5] = o1.vy; + ((s16 *)a1)[4] = o0.vy; + } + if (o0.vz > o1.vz) { + ((s16 *)a1)[7] = o0.vz; + ((s16 *)a1)[6] = o1.vz; + } else { + ((s16 *)a1)[7] = o1.vz; + ((s16 *)a1)[6] = o0.vz; + } + } +} + #include "common.h" diff --git a/src/ov_SC01_084/ov_SC01_084_jr_8017CA80.c b/src/ov_SC01_084/ov_SC01_084_jr_8017CA80.c index 257a59e80..5aa24faa5 100644 --- a/src/ov_SC01_084/ov_SC01_084_jr_8017CA80.c +++ b/src/ov_SC01_084/ov_SC01_084_jr_8017CA80.c @@ -3895,7 +3895,154 @@ void func_8017EA4C(s32 param_1) { } -INCLUDE_ASM("asm/ov_SC01_084/nonmatchings/ov_SC01_084_jr_8017CA80", func_8017EA98); +#include "common.h" + +/* func_8017EA98 - ov_SC01_084 / ov_SC01_084_jr_8017CA80 (177 ins, MATCH) + * + * Layout: the whole 0x10..0x37 local block is one s16[20] (frame -0x48 = 0x10 + * outgoing-arg area + 40 bytes of locals + ra/s1/s0). Both arms index it with + * hard offsets: [0..2] = the (D_80126B5E, D_80126B62, D_80126B66) triple, the + * 3-word "high-half only" struct at &sp10[8] (arm 1) / &sp10[4] (arm 2), and the + * func_8012B77C output word at &sp10[16] / &sp10[12]. + * + * Idioms that were load-bearing here: + * - The interval scan uses an EXPLICIT byte-offset variable (`off += 4`), not + * `tbl[i * 2]`. With an array subscript, loop.c strength-reduces the address + * into two pointer givs (`la`+`addiu` per table); with `(s32)&sym + off` the + * address stays `sym($off)` and the assembler expands the lui/addu/lh macro, + * which is what the target does. + * - abs(): the SECOND difference is computed UNCONDITIONALLY into its own + * variable (dz2) so the delay-slot filler takes it from before the branch; + * that is what keeps the `bltz` un-inverted and pays for the `j` + duplicated + * `addu` in both arms (an `if (t < 0) t = -t;` merge comes out 1 ins short). + * - `D_80126B62 - 0xA0` is its own statement: written as one expression, fold + * reassociates it to `62 - (0xA0 + (x << 5))` (addiu on the shift instead). + * - `amt` is computed BEFORE the sp10[5]/[7]/[9] stores (source order is the + * sched1 order here); after them, the second `lh 0x70` sinks 3 slots. + * - Separate tmp/tmp2: reusing one variable for both `lw`s makes it one + * long-lived pseudo, which loses the $a1 copy-preference on the + * func_8012B608 argument. + * - The two $v1/$a0 pins are the last residual: global-alloc ranks the loaded + * `*(s16*)(a0+6)` above `dx` by a knife-edge live-length margin and hands it + * $v1. No source shape tried (declared temps, if/else abs, decl order, + * ternary, variable merging) moved it; the pins are dead before every call in + * scope, and the emitted bytes are the target's, so no §175 exposure. + */ +extern u16 D_80126B5E; +extern u16 D_80126B62; +extern u16 D_80126B66; +extern s16 D_801C7748; +extern s16 D_8018A6D4; +extern s16 D_8018A6D6; +extern u8 D_8018A6C8[]; + +extern void func_8012B0B4(u32 *a0, s32 a1, s32 a2); +extern void func_8012B14C(s32 a0, s32 a1); +extern void func_8012AD80(s32 a0); +extern void func_8012B77C(void *a0, s32 a1, void *a2); +extern s32 func_8012B608(s32 a0, s32 a1, s32 a2); + +void func_8017EA98(s32 a0) { + extern void func_8017ED5C(); + + s16 sp10[20]; + s32 i; + s32 off; + s32 ang; + + if (*(u16 *)(a0 + 0x5C) & 1) { + func_8017ED5C(); + return; + } + + off = 0; + ang = D_801C7748; + for (i = 0; i < 3; i++) { + if (ang >= *(s16 *)((s32)&D_8018A6D4 + off) && ang < *(s16 *)((s32)&D_8018A6D6 + off)) { + break; + } + off += 4; + } + + if (i == 3) { + s32 tmp; + s32 tmp2; + register s32 dx __asm__("$3"); + register s32 dz __asm__("$4"); + s32 dz2; + s32 sum; + + func_8012B0B4((u32 *)&sp10[4], -ang & 0xFFF, 0x400); + tmp = *(s32 *)&sp10[4]; + sp10[0] = D_80126B5E; + sp10[1] = D_80126B62; + sp10[2] = D_80126B66; + sp10[0] = tmp; + sp10[2] = tmp >> 16; + sp10[9] = tmp; + sp10[11] = D_80126B62; + sp10[13] = tmp >> 16; + func_8012B14C(a0, (s32)D_8018A6C8); + func_8012AD80(a0); + dx = *(s16 *)(a0 + 6) - sp10[0]; + if (dx < 0) { + dx = sp10[0] - *(s16 *)(a0 + 6); + } + dz = *(s16 *)(a0 + 0xE) - sp10[2]; + dz2 = sp10[2] - *(s16 *)(a0 + 0xE); + if (dz >= 0) { + sum = dx + dz; + } else { + sum = dx + dz2; + } + if (sum >= 0x80) { + func_8012B77C(&sp10[16], a0 + 4, &sp10[8]); + tmp2 = *(s32 *)&sp10[16]; + *(s16 *)(*(s32 *)(a0 + 0x20) + 0x10) = tmp2; + *(u16 *)(*(s32 *)(a0 + 0x20) + 0x12) += func_8012B608(*(s16 *)(*(s32 *)(a0 + 0x20) + 0x12), tmp2 >> 16, 3); + } + } else { + s32 tmp; + s32 tmp2; + register s32 dx __asm__("$3"); + register s32 dz __asm__("$4"); + s32 dz2; + s32 sum; + s32 amt; + + sp10[0] = D_80126B5E; + sp10[1] = D_80126B62; + sp10[2] = D_80126B66; + tmp = D_80126B62 - 0xA0; + tmp = tmp - (*(s16 *)(a0 + 0x70) << 5); + sp10[1] = tmp; + amt = (*(s16 *)(a0 + 0x70) << 2) + 6; + sp10[5] = D_80126B5E; + sp10[7] = tmp; + sp10[9] = D_80126B66; + func_8012B14C(a0, (s32)D_8018A6C8); + func_8012AD80(a0); + dx = *(s16 *)(a0 + 6) - sp10[0]; + if (dx < 0) { + dx = sp10[0] - *(s16 *)(a0 + 6); + } + dz = *(s16 *)(a0 + 0xE) - sp10[2]; + dz2 = sp10[2] - *(s16 *)(a0 + 0xE); + if (dz >= 0) { + sum = dx + dz; + } else { + sum = dx + dz2; + } + if (sum >= 0x80) { + func_8012B77C(&sp10[12], a0 + 4, &sp10[4]); + tmp2 = *(s32 *)&sp10[12]; + *(s16 *)(*(s32 *)(a0 + 0x20) + 0x10) = tmp2; + *(u16 *)(*(s32 *)(a0 + 0x20) + 0x12) += func_8012B608(*(s16 *)(*(s32 *)(a0 + 0x20) + 0x12), tmp2 >> 16, amt); + } + *(s32 *)(*(s32 *)(a0 + 0x20) + 4) &= 0x7FFFFFFF; + } +} + #include "common.h" diff --git a/src/ov_SC01_084/ov_SC01_084_jr_8017F690.c b/src/ov_SC01_084/ov_SC01_084_jr_8017F690.c index 784698edf..e728f1888 100644 --- a/src/ov_SC01_084/ov_SC01_084_jr_8017F690.c +++ b/src/ov_SC01_084/ov_SC01_084_jr_8017F690.c @@ -4002,7 +4002,133 @@ void func_80181F3C(s32 a0) { } -INCLUDE_ASM("asm/ov_SC01_084/nonmatchings/ov_SC01_084_jr_8017F690", func_80181F80); +extern s32 func_80047948(s32 a0); +extern s32 func_8004787C(s32 a0); +extern s32 func_80047D3C(s32 a0); +extern s32 func_801807D8(s16 *a0); +extern void func_8012A828(s32 a0, void *a1); +extern s32 func_8012B608(s32 a0, s32 a1, s32 a2); +extern void func_8012C098(void *a0); +extern s32 func_80143B6C(s32 a0, s32 a1); +extern void func_801822A4(void *a0); +extern s16 D_801C7748; +extern s16 D_801C774A; +extern s32 D_801270D4; +extern s32 D_801270E4; +extern s32 D_801A1A10; + +void func_80181F80(s32 param_1) { + s16 sp10[3]; + s32 t; + u16 m, y, f, g; + s16 h; + s32 cur, lim; + s32 tt, x, angle, spd, q1, sinVal, cosVal; + s32 d; + s16 c; + + h = *(u16 *)(param_1 + 0xDC) - 8; + *(s16 *)(param_1 + 0xDC) = h; + if (h < 0x400) { + *(s16 *)(param_1 + 0xFC) = 1; + *(u8 *)(param_1 + 0xC1) = 0; + *(s16 *)(param_1 + 2) = 1; + *(s16 *)(param_1 + 0x34) = 0; + *(u16 *)(param_1 + 0x100) |= 3; + func_8012A828(param_1, &D_801A1A10); + m = *(u16 *)(param_1 + 0x5C); + y = *(u16 *)(param_1 + 6); + f = *(u16 *)(param_1 + 0xFC); + *(s32 *)(param_1 + 0x1C) = 0xA; + t = (s32)(s16)y * (s32)(s16)y; + *(u16 *)(param_1 + 0x5E) = 0; + g = m | 0x8000; + *(u16 *)(param_1 + 0x5C) = g; + *(u16 *)(param_1 + 0xFC) = f ^ 1; + sp10[0] = y; + sp10[1] = *(u16 *)(param_1 + 0xA); + sp10[2] = *(u16 *)(param_1 + 0xE); + t += (s32)(s16)sp10[2] * (s32)(s16)sp10[2]; + *(s16 *)(param_1 + 0xDE) = func_80047D3C(t); + *(s16 *)(param_1 + 0xDC) = func_801807D8(sp10); + } + + *(u16 *)(*(s32 *)(param_1 + 0x20) + 0x12) += + func_8012B608(*(s16 *)(*(s32 *)(param_1 + 0x20) + 0x12), + -*(s16 *)(param_1 + 0xDC) & 0xFFF, 0x10); + + cur = *(s16 *)(param_1 + 0xDE); + lim = D_801C774A; + if (lim < cur) { + if (cur - lim < 6) { + *(s16 *)(param_1 + 0xDE) = lim; + } else { + *(s16 *)(param_1 + 0xDE) -= 6; + } + } else if (cur < lim) { + if (lim - cur < 6) { + *(s16 *)(param_1 + 0xDE) = lim; + } else { + *(s16 *)(param_1 + 0xDE) += 6; + } + } + + tt = *(s16 *)(param_1 + 0xDC); + spd = *(s16 *)(param_1 + 0xDE); + x = -(tt * 1536); + angle = tt & 0xFFF; + q1 = x / 12288 - 0x22; + + sinVal = func_80047948(angle) * spd >> 12; + cosVal = func_8004787C(angle) * spd >> 12; + + sp10[0] = sinVal; + sp10[1] = q1; + sp10[2] = cosVal; + *(u16 *)(param_1 + 6) = sp10[0]; + *(u16 *)(param_1 + 0xA) = sp10[1]; + *(u16 *)(param_1 + 0xE) = sp10[2]; + + d = *(s16 *)(param_1 + 0xDC) - D_801C7748; + if (d < -0xFF) { + if (*(s16 *)(param_1 + 0x70) == 2) { + D_801270E4--; + } else { + D_801270D4--; + } + func_8012C098((void *)param_1); + return; + } + + if (d <= 0) { + *(u16 *)(param_1 + 0x100) |= 1; + } else if ((*(u16 *)(param_1 + 0x100) & 1) == 0) { + if (*(s16 *)(param_1 + 0x70) == 0) { + if (d >= 0x51) { + goto skip; + } + /* LOAD-BEARING (cookbook §5a): a zero-byte volatile-asm makes this arm's + * RTL tail differ from the sibling arm's, so find_cross_jump refuses to + * merge the two `beqz`+join tails. Removing it costs 4 instructions. */ + __asm__ __volatile__(""); + } else { + if (d >= 0x201) { + goto skip; + } + } + func_801822A4((void *)param_1); + return; + } + +skip: + c = *(u16 *)(param_1 + 0xFE) - 1; + *(s16 *)(param_1 + 0xFE) = c; + if (c <= 0) { + func_80143B6C(param_1, 0); + *(s16 *)(param_1 + 0xFE) = 8; + } +} + extern void func_8012A828(s32 a0, void *a1); @@ -5225,7 +5351,142 @@ void func_801840FC(void *a0) { } -INCLUDE_ASM("asm/ov_SC01_084/nonmatchings/ov_SC01_084_jr_8017F690", func_80184138); +#include "common.h" + +/* func_80184138 - ov_SC01_084 / ov_SC01_084_jr_8017F690 (187 ins) + * + * Structural twin of func_80183DA4 (same TU, MATCH, 187 ins) -- the same + * vertical "beam"/ribbon builder with a different texture window and step: + * D_801C74D8 -> D_801C74DC, GetClut y 0x14C -> 0x14D, uu 0xF0 -> 0xF8, + * the u1/u3 literal 0xF7 -> 0xFF, and the tail step vec.vy -= 0x40 -> 0x3C. + * All three of func_80183DA4's levers carry over verbatim: + * 1. sxy0/sxy1 are s32 SCALARS read through a cast-to-struct-pointer, so the + * four stack slots are handed out in &-order (0x20/0x24/0x28/0x2C) while + * the loads stay MEM_IN_STRUCT_P and are re-killed by the p->x0 store. + * 2. `otz2 = RotTransPers(...); d = D_801C74DC; if ((d >> 3) >= otz2)` forces + * the reload the target has, and that reload feeds the `d << 3` dividend. + * 3. `uu = 0xF8; vv = 0;` are ordinary pre-loop statements (they precede the + * &pp/&flag address movables in the preheader); 0xFF stays a literal and is + * the one true loop.c movable, landing last. + */ + +typedef struct { s32 a; s32 b[4]; } OtBlk_80184138; /* 0x14 stride */ +typedef struct { u16 vx, vy, vz, pad; } SVec_80184138; /* 0x08 stride */ +typedef struct { u16 vx, vy; } DVec_80184138; /* read through a cast */ + +typedef struct { + u32 tag; /* 0x00 */ + u8 r0, g0, b0, code; /* 0x04 */ + s16 x0, y0; /* 0x08 */ + u8 u0, v0; u16 clut; /* 0x0C */ + s16 x1, y1; /* 0x10 */ + u8 u1, v1; u16 tpage; /* 0x14 */ + s16 x2, y2; /* 0x18 */ + u8 u2, v2; u16 pad2; /* 0x1C */ + s16 x3, y3; /* 0x20 */ + u8 u3, v3; u16 pad3; /* 0x24 */ +} Ft4_80184138; /* 0x28 */ + + +extern void func_8004914C(void *a0); +extern void func_800491AC(void *a0); +extern s32 GetTPage(s32 a0, s32 a1, s32 a2, s32 a3); +extern s32 GetClut(s32 a0, s32 a1); +extern s32 RotTransPers(s32 a0, s32 a1, s32 *a2, s32 *a3); +extern void *func_80010A08(s32 a0); +extern void SetPolyFT4(void *a0); +extern s32 AddPrim(s32 a0, void *a1); + +void func_80184138(SVec_80184138 *arg0) { + + extern s32 D_801C74DC; + extern OtBlk_80184138 D_800A651C[]; + + SVec_80184138 tmp; /* 0x10 */ + SVec_80184138 vec; /* 0x18 */ + s32 sxy0; /* 0x20 */ + s32 pp; /* 0x24 */ + s32 flag; /* 0x28 */ + s32 sxy1; /* 0x2C */ + u16 tpage; + u16 clut; + Ft4_80184138 *p; + s32 ot; + s32 otz; + s32 otz2; + s32 d; + s32 w; + s32 uu; + s32 vv; + + if ((s16)D_801270C0 == 3) { + return; + } + func_8004914C(&D_800AF648); + func_800491AC(&D_800AF648); + D_801C74DC = D_80126950; + tpage = GetTPage(0, 0, 0x300, 0x100); + clut = GetClut(0x160, 0x14D); + vec.vx = arg0->vx; + vec.vy = arg0->vy; + vec.vz = arg0->vz; + uu = 0xF8; + vv = 0; + + for (;;) { + tmp.vx = vec.vx; + tmp.vy = vec.vy - 0x40; + tmp.vz = vec.vz; + otz = RotTransPers((s32)&tmp, (s32)&sxy0, &pp, &flag); + if ((D_801C74DC >> 3) >= otz) { + return; + } + if (flag < 0) { + return; + } + otz2 = RotTransPers((s32)&vec, (s32)&sxy1, &pp, &flag); + d = D_801C74DC; + if ((d >> 3) >= otz2) { + return; + } + if (flag < 0) { + return; + } + ot = D_800A651C[(u16)D_800B9A02].a + otz * 4; + w = (d << 3) / (otz * 4); + if ((s16)((DVec_80184138 *)&sxy0)->vy < 120) { + if ((s16)((DVec_80184138 *)&sxy1)->vy < -119) { + return; + } + if ((s16)w >= 2) { + p = (Ft4_80184138 *)func_80010A08(0x28); + *(s32 *)((u8 *)p + 4) = 0x808080; + SetPolyFT4(p); + p->x0 = ((DVec_80184138 *)&sxy0)->vx - w; + p->y0 = ((DVec_80184138 *)&sxy0)->vy; + p->x1 = ((DVec_80184138 *)&sxy0)->vx + w; + p->y1 = ((DVec_80184138 *)&sxy0)->vy; + p->x2 = ((DVec_80184138 *)&sxy1)->vx - w; + p->y2 = ((DVec_80184138 *)&sxy1)->vy; + p->x3 = ((DVec_80184138 *)&sxy1)->vx + w; + p->y3 = ((DVec_80184138 *)&sxy1)->vy; + p->u0 = uu; + p->v0 = vv; + p->u1 = 0xFF; + p->v1 = vv; + p->u2 = uu; + p->v2 = vv + 0x3F; + p->u3 = 0xFF; + p->v3 = vv + 0x3F; + p->tpage = tpage; + p->clut = clut; + AddPrim(ot, p); + } + } + vec.vy -= 0x3C; + } +} + extern void (*D_8018AC2C[])(void); @@ -6137,7 +6398,7 @@ void func_801855EC(s32 param_1) } -extern void func_80184138(u16 *a0); +extern void func_80184138(); extern void func_80183DA4(); extern s16 D_8018A914; extern s16 D_8018A91A; diff --git a/src/ov_SC02_003/ov_SC02_003_jr_8017FCB0.c b/src/ov_SC02_003/ov_SC02_003_jr_8017FCB0.c index b78301257..22fb08f67 100644 --- a/src/ov_SC02_003/ov_SC02_003_jr_8017FCB0.c +++ b/src/ov_SC02_003/ov_SC02_003_jr_8017FCB0.c @@ -3057,7 +3057,141 @@ void func_80180428(int param_1) } -INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003_jr_8017FCB0", func_8018046C); +#include "common.h" + +/* @class: struct + * @stuck: none — remap of the banked byte-MATCH twin src/ov_SC02_000/ov_SC02_000_jr_8017FCB0.c + * :3089 (same name, same 158 ins, IDENTICAL symbol set — verified against THIS .s's relocation + * lines: func_8012E544, func_80180A64, rand, func_801803D0, func_8012F214, D_8018E66C, + * func_8012C51C, func_8012B2CC, func_8018A660, func_8012BEE8, func_80180428, func_8012A828, + * D_801A6344). The prior stranded draft was cc1-FAIL only because it inherited the twin's + * *enclosing TU* decl environment implicitly: struct Prim, rand, func_801803D0, func_80180428 + * were undeclared. Every one of them is now declared here. + * Levers carried from the twin's note: (1) switch(s32 st34){0,1,2} -> beq==1/slti<2/beq==2 + * decision tree; (2) struct Prim {s16 f0..fE; s32 f10} + s16 buf[4] gives prim@sp+0x10, + * buf@sp+0x28 byte-exact, store order f6,f8,fA,f10,fE,f0,f2,f4,fC; (3) the uninitialised $s0 + * flag CFG needs the explicit compute/flag_zero goto labels (p==0 leaves flag live-undefined); + * (4) `d=-d; flag=d<0x20` written twice so bgez keeps slti in its delay slot and retargets past + * the copy; (5) 0xAA10 stored through u16 -> ori (an s16 store gives addiu -22000); + * (6) the zero-byte __asm__ memory barrier after the 0x102 store forces `c & 0xff` (not the sb) + * into the `jal rand` delay slot. */ + +struct Prim { s16 f0, f2, f4, f6, f8, fA, fC, fE; s32 f10; }; + +extern void func_8012F214(s32 a0, s32 a1, s32 a2); +extern s32 func_8012C51C(void *a0, s32 a1); +extern s32 func_8012BEE8(s32 a0); +extern void func_8012B2CC(s32 a0); +extern void func_8012A828(s32 a0, void *a1); +extern s32 rand(void); +extern void func_801803D0(int param_1); +extern void func_80180428(int param_1); + +void func_8018046C(s32 arg0) { + extern s32 func_8012E544(s32 a0); + extern void func_80180A64(s32 param_1); + extern s32 func_8018A660(s32 a0, s32 a1); + extern s32 D_8018E66C[]; + extern s32 D_801A6344; + + s32 cond; + s32 flag; + s32 d; + u16 mode; + s32 st34; + + mode = *(u16 *)(arg0 + 0x70); + cond = 1; + if ((u32)(mode - 0x505) >= 2) { + cond = ((mode & 0xff00) == 0x700); + } + if (cond == 0) { + goto flag_zero; + } + cond = func_8012E544(0x298); + if (cond == 0) { + goto lab_ab0; + } + if (*(u16 *)(cond + 2) == 2) { + goto compute; + } +flag_zero: + flag = 0; + goto lab_ab0; +compute: + d = *(s16 *)(cond + 0xe) - *(s16 *)(arg0 + 0xe); + flag = (d < 0x20); + if (d < 0) { + d = -d; + flag = (d < 0x20); + } +lab_ab0: + if (flag != 0) { + func_80180A64(arg0); + return; + } + + st34 = *(u16 *)(arg0 + 0x34); + switch (st34) { + case 0: + if (*(u16 *)(arg0 + 0x72) & 0x4000) { + s32 c = *(u8 *)(arg0 + 0x102) + 1; + *(u8 *)(arg0 + 0x102) = c; + __asm__ __volatile__("" ::: "memory"); + if ((((s32(*)())rand)() & 1) < (c & 0xff)) { + ((void(*)(s32))func_801803D0)(arg0); + } + } + break; + case 1: { + s32 s1c = *(s32 *)(arg0 + 0x1c); + if (s1c == 0xc) { + struct Prim sp; + s16 buf[4]; + s32 tv0; + func_8012F214(arg0, (s32)&(*(s32 *)&D_8018E66C), (s32)buf); + sp.f6 = 0x20; + sp.f8 = 2; + sp.fA = 0; + sp.f10 = 0; + sp.fE = 0; + sp.f0 = buf[0]; + sp.f2 = buf[1]; + sp.f4 = buf[2]; + sp.fC = *(u16 *)(*(s32 *)(arg0 + 0x20) + 0x12); + tv0 = func_8012C51C(&sp, arg0); + if (tv0 != 0) { + *(u16 *)(*(s32 *)(tv0 + 0x20) + 0x12) = *(u16 *)(*(s32 *)(arg0 + 0x20) + 0x12); + func_8012B2CC(tv0); + } + } else if (s1c == 0xf) { + func_8018A660(arg0, (s32)&(*(s32 *)&D_8018E66C)); + } + if (func_8012BEE8(arg0) != 0) { + s32 c = *(u8 *)(arg0 + 0x102) + 1; + *(u8 *)(arg0 + 0x102) = c; + if ((u32)(c & 0xff) >= 3) { + ((void(*)(s32))func_80180428)(arg0); + return; + } + *(s32 *)(arg0 + 0x1c) = 0x1e; + return; + } + break; + } + case 2: + if (*(u16 *)(arg0 + 0x72) & 0x4000) { + *(s16 *)(arg0 + 2) = 0xb; + *(u16 *)(arg0 + 0x34) = 0; + *(s16 *)(arg0 + 0x5e) = 0; + *(u16 *)(arg0 + 0x5c) = 0xaa10; + func_8012A828(arg0, &D_801A6344); + *(u8 *)(arg0 + 0x102) = 0; + } + break; + } +} + extern void func_8012B178(s32 a0, s32 a1); diff --git a/src/ov_SC02_037/ov_SC02_037_jr_8013C98C.c b/src/ov_SC02_037/ov_SC02_037_jr_8013C98C.c index c28ea032c..aed4553ab 100644 --- a/src/ov_SC02_037/ov_SC02_037_jr_8013C98C.c +++ b/src/ov_SC02_037/ov_SC02_037_jr_8013C98C.c @@ -1641,7 +1641,106 @@ void func_8013DBE4(int param_1) } -INCLUDE_ASM("asm/ov_SC02_037/nonmatchings/ov_SC02_037_jr_8013C98C", func_8013DD68); +#include "common.h" + +/* func_8013DD68 (ov_SC02_037) — 187 ins. + * @class: regalloc-order + * Family exemplar: src/ov_SC06_008/ov_SC06_008_jr_8013C98C.c:1685 (banked MATCH). + * Mechanical per-overlay symbol remap: + * D_801A8DAC -> D_801C84A4, D_801A8DDC -> D_801C84D4, + * D_801A8DE0 -> D_801C84D8, D_801A8DE4 -> D_801C84DC, + * D_801861B8 -> D_801845B0. Every symbol re-checked against this .s's own relocs. + * Levers (carried from the exemplar): struct-assign DRAWENV copy (align via type); `pbase` + * local so D_800B9A02 is reached $s2-relative as D_800AF630[0xA3D2]; two-biv SPRT loop + * (q anchored one-above -> gcc re-anchors, no bare-deref); P_TAG_8013DD68 addPrim; + * a single `p` var coalesces the two prim cursors; pins uVar2=$v1, iVar14=$a3, c5=$t3; + * biv-increment order sets q-init-before-puVar10-init; Buf_8013DD68 0x68 -> frame 0xA0. */ + +#ifndef BFM_ENGINE_TYPES_H + + + +#endif + +extern u8 D_800AF630[]; +extern s32 D_800A5E60; +extern s16 *D_801C84A4; +extern s32 D_801C84D4; +extern s32 D_801C84D8; +extern s32 D_801C84DC; + +#define IDVAL (*(u16 *)(pbase + 0xA3D2)) +#define OTE ((P_TAG_8013DD68 *)(D_800BA0E4 + IDVAL * 0x10)) + +void func_8013DD68() { + extern void SetDrawEnv(void *p, void *env); + extern u16 D_800AF7B8; + extern u8 D_800BA0E4[]; + extern u8 D_801845B0[]; + + u32 *p; + u16 uVar1; + u16 *puVar16; + u16 *q; + u16 *puVar10; + register u16 uVar2 __asm__("$3"); + int uVar5; + register int iVar14 __asm__("$7"); + Buf_8013DD68 buf; + u8 *pbase; + u8 *base; + + pbase = D_800AF630; + puVar16 = (*(u16 * *)&D_801C84A4); + p = (*(u32 * *)&D_800A5E60); + uVar1 = *puVar16; + puVar16 = puVar16 + 1; + base = pbase + (u32)D_800AF7B8 * 0x5C; + buf.env = *(DrawEnv_8013DD68 *)(base + 0x38); + *((u8 *)&buf + 0x18) = 0; + SetDrawEnv(p, &buf); + ((P_TAG_8013DD68 *)p)->addr = OTE->addr; + OTE->addr = (u32)p; + p = p + 0x10; + iVar14 = 0; + if (uVar1 != 0) { + register int c5 __asm__("$11") = 5; + puVar10 = (u16 *)((int)p + 0x18); + q = puVar16 + 8; + do { + *(u8 *)((int)puVar10 + -0x15) = c5; + uVar2 = q[-6]; + *(u8 *)((int)puVar10 + -0xd) = 100; + *(u8 *)((int)puVar10 + -0x10) = (u8)(*(int*)&D_801C84D4); + *(u8 *)((int)puVar10 + -0xf) = (u8)(*(int*)&D_801C84D8); + uVar5 = (*(int*)&D_801C84DC); + *(u32 *)((int)puVar10 + -0x14) = uVar2 & 0x9ff | 0xe1000400; + *(u8 *)((int)puVar10 + -0xe) = (u8)uVar5; + *(u16 *)((int)puVar10 + -0xc) = q[-4]; + iVar14 = iVar14 + 1; + *(u16 *)((int)puVar10 + -0xa) = q[-3]; + *(u8 *)((int)puVar10 + -8) = (u8)*puVar16; + uVar2 = q[-7]; + *(u16 *)((int)puVar10 + -6) = 0x7800; + *(u8 *)((int)puVar10 + -7) = (u8)uVar2; + puVar16 = puVar16 + 8; + *(u16 *)((int)puVar10 + -4) = q[-2]; + *(u16 *)((int)puVar10 + -2) = q[-1]; + ((P_TAG_8013DD68 *)p)->addr = OTE->addr; + puVar10 = puVar10 + 0xc; + OTE->addr = (u32)p; + p = p + 6; + q = q + 8; + } while (iVar14 < (int)(u32)uVar1); + } + SetDrawEnv(p, D_801845B0); + ((P_TAG_8013DD68 *)p)->addr = OTE->addr; + OTE->addr = (u32)p; + p = p + 0x10; + (*(u32 * *)&D_800A5E60) = p; + return; +} + diff --git a/src/ov_SC03_107/ov_SC03_107_jr_8013C98C.c b/src/ov_SC03_107/ov_SC03_107_jr_8013C98C.c index 7311dca79..93783cfb7 100644 --- a/src/ov_SC03_107/ov_SC03_107_jr_8013C98C.c +++ b/src/ov_SC03_107/ov_SC03_107_jr_8013C98C.c @@ -1644,7 +1644,93 @@ void func_8013DBE4(int param_1) } -INCLUDE_ASM("asm/ov_SC03_107/nonmatchings/ov_SC03_107_jr_8013C98C", func_8013DD68); +#include "common.h" + +#ifndef BFM_ENGINE_TYPES_H + + + +#endif + +extern u8 D_800AF630[]; +extern s32 D_800A5E60; +extern s16 *D_8019A804; +extern s32 D_8019A834; +extern s32 D_8019A838; +extern s32 D_8019A83C; + +#define IDVAL (*(u16 *)(pbase + 0xA3D2)) +#define OTE ((P_TAG_8013DD68 *)(D_800BA0E4 + IDVAL * 0x10)) + +void func_8013DD68() { + extern void SetDrawEnv(void *p, void *env); + extern u16 D_800AF7B8; + extern u8 D_800BA0E4[]; + extern u8 D_80182E4C[]; + + u32 *p; + u16 uVar1; + u16 *puVar16; + u16 *q; + u16 *puVar10; + register u16 uVar2 __asm__("$3"); + int uVar5; + register int iVar14 __asm__("$7"); + Buf_8013DD68 buf; + u8 *pbase; + u8 *base; + + pbase = D_800AF630; + puVar16 = (*(u16 * *)&D_8019A804); + p = (*(u32 * *)&D_800A5E60); + uVar1 = *puVar16; + puVar16 = puVar16 + 1; + base = pbase + (u32)D_800AF7B8 * 0x5C; + buf.env = *(DrawEnv_8013DD68 *)(base + 0x38); + *((u8 *)&buf + 0x18) = 0; + SetDrawEnv(p, &buf); + ((P_TAG_8013DD68 *)p)->addr = OTE->addr; + OTE->addr = (u32)p; + p = p + 0x10; + iVar14 = 0; + if (uVar1 != 0) { + register int c5 __asm__("$11") = 5; + puVar10 = (u16 *)((int)p + 0x18); + q = puVar16 + 8; + do { + *(u8 *)((int)puVar10 + -0x15) = c5; + uVar2 = q[-6]; + *(u8 *)((int)puVar10 + -0xd) = 100; + *(u8 *)((int)puVar10 + -0x10) = (u8)(*(int*)&D_8019A834); + *(u8 *)((int)puVar10 + -0xf) = (u8)(*(int*)&D_8019A838); + uVar5 = (*(int*)&D_8019A83C); + *(u32 *)((int)puVar10 + -0x14) = uVar2 & 0x9ff | 0xe1000400; + *(u8 *)((int)puVar10 + -0xe) = (u8)uVar5; + *(u16 *)((int)puVar10 + -0xc) = q[-4]; + iVar14 = iVar14 + 1; + *(u16 *)((int)puVar10 + -0xa) = q[-3]; + *(u8 *)((int)puVar10 + -8) = (u8)*puVar16; + uVar2 = q[-7]; + *(u16 *)((int)puVar10 + -6) = 0x7800; + *(u8 *)((int)puVar10 + -7) = (u8)uVar2; + puVar16 = puVar16 + 8; + *(u16 *)((int)puVar10 + -4) = q[-2]; + *(u16 *)((int)puVar10 + -2) = q[-1]; + ((P_TAG_8013DD68 *)p)->addr = OTE->addr; + puVar10 = puVar10 + 0xc; + OTE->addr = (u32)p; + p = p + 6; + q = q + 8; + } while (iVar14 < (int)(u32)uVar1); + } + SetDrawEnv(p, D_80182E4C); + ((P_TAG_8013DD68 *)p)->addr = OTE->addr; + OTE->addr = (u32)p; + p = p + 0x10; + (*(u32 * *)&D_800A5E60) = p; + return; +} + diff --git a/src/ov_SC05_003/ov_SC05_003_jr_8017BEBC.c b/src/ov_SC05_003/ov_SC05_003_jr_8017BEBC.c index 5a04e95ec..640cb9694 100644 --- a/src/ov_SC05_003/ov_SC05_003_jr_8017BEBC.c +++ b/src/ov_SC05_003/ov_SC05_003_jr_8017BEBC.c @@ -3988,7 +3988,91 @@ void func_8017E1E8(s32 param_1, s16 *param_2) { } -INCLUDE_ASM("asm/ov_SC05_003/nonmatchings/ov_SC05_003_jr_8017BEBC", func_8017E380); +extern s32 D_80126B58; +extern u16 D_80126B5E; +extern s32 func_8017267C(s32 *a0); +extern s32 func_800CF8B4(); +extern s32 func_8014CB8C(void); +extern void func_8002D4C8(s32 a0, s32 a1); +extern s32 func_80143C74(s32 a0, s32 a1); +extern s32 rand(void); +extern void func_80016714(void *a0, s32 a1); +extern void func_8012C218(void *a0); + +void func_8017E380(s32 arg0) { + s32 s0; + s32 a1; + s32 s1; + s32 v1; + s32 t; + + s0 = -1; + if (func_8017267C(&D_80126B58) != 0) goto b9; + if (func_800CF8B4() == 0) goto b9; + if (func_8014CB8C() != 0) goto b9; + a1 = (s16)D_80126B5E; + if (a1 < -0xE8E) goto after; + if (a1 < -0xCEC) goto arm_a; + if (a1 < -0x87) goto arm_m; + if (a1 < 0xF7) goto arm_c; +b9: + if (*(s16 *)(arg0 + 0x84) != 0) { + func_8002D4C8(4, 0xAFA); + *(s16 *)(arg0 + 0x84) = 0; + } + goto after; +arm_c: + s0 = (0xF6 - a1) * 10 / 382; + D_80126B5E = (s16)D_80126B5E - s0; + goto after; +arm_m: + D_80126B5E = (s16)D_80126B5E - 10; + s0 = 10; + goto after; +arm_a: + s0 = (a1 + 0xE8F) * 10 / 418; + D_80126B5E = (s16)D_80126B5E - s0; +after: + if (s0 >= 0) { + s0 = s0 * 127 / 10; + func_8002D4C8(0xAFA, (u16)(s0 | 0x1000)); + *(s16 *)(arg0 + 0x84) = 1; + } + if (*(s32 *)(arg0 + 0x1C) != 0) { + *(s32 *)(arg0 + 0x1C) = *(s32 *)(arg0 + 0x1C) - 1; + } else { + *(s32 *)(arg0 + 0x1C) = 3; + s1 = func_80143C74(arg0, 0); + if (s1 != 0) { + *(s16 *)(s1 + 0xE) = rand() % 0xC0 - 0x60; + t = D_80126B5E + rand() % 0x300; + *(s16 *)(s1 + 6) = t - 0x180; + if ((u16)(t + 0xD0F) >= 0xF86) { + *(s32 *)(arg0 + 0x1C) = 0; + func_80016714(*(void **)(s1 + 0xCC), 0x38); + func_8012C218((void *)s1); + } else { + *(s32 *)(s1 + 0x48) = -((rand() & 0x1FF) << 7); + a1 = *(s16 *)(s1 + 6); + if (a1 < -0xCEC) goto arm2_a; + if (a1 < -0x87) goto arm2_m; + v1 = (0xF6 - a1) * 20 / 382; + *(s16 *)(s1 + 0x12) = -v1; + goto done; + arm2_m: + *(u16 *)(s1 + 0x12) -= 0x14; + goto done; + arm2_a: + v1 = (a1 + 0xE8F) * 20 / 418; + *(s16 *)(s1 + 0x12) = -v1; + *(s16 *)(s1 + 0x16) = v1 - 0x14; + } + } + } +done: + ; +} + s32 func_8017E67C(void) { diff --git a/src/ov_SC05_008/ov_SC05_008_jr_8017AE2C.c b/src/ov_SC05_008/ov_SC05_008_jr_8017AE2C.c index d34752ab3..e710a2eda 100644 --- a/src/ov_SC05_008/ov_SC05_008_jr_8017AE2C.c +++ b/src/ov_SC05_008/ov_SC05_008_jr_8017AE2C.c @@ -4424,7 +4424,67 @@ void func_8017DEC4(void) { } -INCLUDE_ASM("asm/ov_SC05_008/nonmatchings/ov_SC05_008_jr_8017AE2C", func_8017DF68); +typedef struct { u16 vx, vy, vz, pad; } SVEC_8017DF68; + +void func_8017DF68(SVEC_8017DF68 *p0, SVEC_8017DF68 *p1, s32 a2) +{ + extern void func_8012EF70(s32 a0, s32 a1); + extern void func_8017E230(void *a0, void *a1, void *a2, void *a3, s32 *a4); + extern u8 D_801A10B8[]; + + SVEC_8017DF68 lo0; + SVEC_8017DF68 lo1; + SVEC_8017DF68 dead1; + SVEC_8017DF68 dead2; + SVEC_8017DF68 sv0; + SVEC_8017DF68 sv1; + SVEC_8017DF68 sv2; + SVEC_8017DF68 sv3; + s32 col; + s32 tx; + s32 ty; + + col = 0x80 - (a2 * 128) / 80; + if (D_801A10B8[a2] != 0) { + col += D_801A10B8[a2] * 15; + } + col |= (col << 16) | (col << 8); + + lo0 = *p0; + lo1 = *p1; + if ((((s32 (*)(void *, void *))func_8012EF70)(&lo0, &sv0) & ~0x1000) == 0 && + (((s32 (*)(void *, void *))func_8012EF70)(&lo1, &sv1) & ~0x1000) == 0) { + lo0 = *p0; + tx = lo0.vx + 8; + ty = lo0.vy - 8; + lo0.vx = tx; + lo0.vy = ty; + lo1 = *p1; + tx = lo1.vx + 8; + ty = lo1.vy - 8; + lo1.vx = tx; + lo1.vy = ty; + if ((((s32 (*)(void *, void *))func_8012EF70)(&lo0, &sv2) & ~0x1000) == 0 && + (((s32 (*)(void *, void *))func_8012EF70)(&lo1, &sv3) & ~0x1000) == 0) { + func_8017E230(&sv0, &sv1, &sv2, &sv3, &col); + lo0 = *p0; + tx = lo0.vx - 8; + ty = lo0.vy - 8; + lo0.vx = tx; + lo0.vy = ty; + lo1 = *p1; + tx = lo1.vx - 8; + ty = lo1.vy - 8; + lo1.vx = tx; + lo1.vy = ty; + if ((((s32 (*)(void *, void *))func_8012EF70)(&lo0, &sv2) & ~0x1000) == 0 && + (((s32 (*)(void *, void *))func_8012EF70)(&lo1, &sv3) & ~0x1000) == 0) { + func_8017E230(&sv0, &sv1, &sv2, &sv3, &col); + } + } + } +} + @@ -4666,7 +4726,90 @@ void func_8017EB7C(void *a0) { } -INCLUDE_ASM("asm/ov_SC05_008/nonmatchings/ov_SC05_008_jr_8017AE2C", func_8017EBB8); +typedef struct { u8 b[8]; } Blk8_EBB8; +typedef struct { u16 x, y, z, p0, p1, p2; } Rec12_EBB8; +extern s32 D_801151D4; +extern s32 D_80186558[]; +extern s32 D_8019E64C; +extern Rec12_EBB8 D_8019E666[]; +extern s32 D_801A1098; +extern s32 D_801A10A0; +extern s32 D_801A10A8; +extern s32 D_801A10B0; +extern void func_8012C1B8(void); +extern void func_8001C214(); +extern void func_8012B2CC(s32 a0); +extern void func_8012F214(s32 a0, s32 a1, s32 a2); +extern s32 rand(void); +extern void func_8017EFE4(s32 a0); +extern void func_8012BF4C(s32 *a0, s32 a1); +extern s32 func_8012AD50(void *a0); + +void func_8017EBB8(void *a0) { + register s32 s1 __asm__("$17"); + register s32 s2 __asm__("$18"); + register s32 idx __asm__("$4"); + s32 tbl; + s32 sum; + s32 ent; + s32 copy; + s32 v; + + s1 = (s32)a0; + __asm__ __volatile__("" : : : "memory"); + idx = *(s16 *)(s1 + 0x70); + tbl = D_801151D4; + s2 = D_80186558[idx]; + sum = *(s32 *)(tbl + 0x34) + ((*(u16 *)(tbl + 0x38) + 8) * 6); + ent = ((s32 (*)(void))func_8012C1B8)(); + copy = ent; + *(s32 *)(s1 + 0x20) = ent; + if (ent != 0) { + if (s2 == (s32)&D_801A1098) goto L64; + if (s2 == (s32)&D_801A10A0) goto L64; + if (s2 == (s32)&D_801A10A8) goto L64; + if (s2 != (s32)&D_801A10B0) goto L48; + L64: + *(s32 *)(s1 + 0xDC) = 0; + v = ((s32 *)&D_8019E64C)[*(s16 *)(s1 + 0x70)]; + *(s32 *)(s2 + 4) = 0; + *(s32 *)(s2 + 0) = v; + func_8001C214(copy, s2); + *(u16 *)(s1 + 0x88) = *(u16 *)((u8 *)D_8019E666 + *(s16 *)(s1 + 0x70) * 12 - 2); + *(u16 *)(s1 + 0x8A) = D_8019E666[*(s16 *)(s1 + 0x70)].x; + *(u16 *)(s1 + 0x8C) = D_8019E666[*(s16 *)(s1 + 0x70)].y; + *(Blk8_EBB8 *)(copy + 0x10) = *(Blk8_EBB8 *)(*(s32 *)(*(s32 *)(s1 + 0x64) + 0x20) + 0x10); + *(s32 *)(s1 + 0xC) = 0; + *(s32 *)(s1 + 8) = 0; + *(s32 *)(s1 + 4) = 0; + func_8012B2CC(s1); + func_8012F214(s1, s1 + 0x88, s1 + 0x88); + goto tail; + L48: + *(s32 *)(s1 + 0xDC) = 1; + *(u16 *)(s1 + 0x88) = *(u16 *)(sum + 0) - *(u16 *)(*(s32 *)(s1 + 0x64) + 6); + *(u16 *)(s1 + 0x8A) = *(u16 *)(sum + 2) - *(u16 *)(*(s32 *)(s1 + 0x64) + 0xA); + *(u16 *)(s1 + 0x8C) = *(u16 *)(sum + 4) - *(u16 *)(*(s32 *)(s1 + 0x64) + 0xE); + func_8001C214(ent, s2); + *(u16 *)(ent + 0x2C) = *(u16 *)(ent + 0x2C) | 0x80; + *(Blk8_EBB8 *)(s1 + 0xCC) = *(Blk8_EBB8 *)(*(s32 *)(s1 + 0x64) + 0xCC); + *(s32 *)(ent + 0x80) = s1 + 0xCC; + *(Blk8_EBB8 *)(ent + 0x10) = *(Blk8_EBB8 *)(*(s32 *)(*(s32 *)(s1 + 0x64) + 0x20) + 0x10); + *(s32 *)(s1 + 0xC) = 0; + *(s32 *)(s1 + 8) = 0; + *(s32 *)(s1 + 4) = 0; + func_8012B2CC(s1); + tail: + *(u16 *)(s1 + 0xFC) = (0x20 - rand()) & 0x3F; + *(u16 *)(s1 + 0xFE) = (0x20 - rand()) & 0x3F; + *(s32 *)(s1 + 0x44) = 0x1000 - ((rand() & 0x3F) << 7); + *(s32 *)(s1 + 0x48) = 0x1000 - ((rand() & 0x3F) << 7); + func_8017EFE4(s1); + func_8012BF4C((s32 *)s1, 0x1E); + func_8012AD50((void *)s1); + } +} + extern s32 func_8012BEE8(s32 a0); extern s32 func_8012AD50(void *a0); diff --git a/src/ov_SC05_010/ov_SC05_010_jr_8017C8D0.c b/src/ov_SC05_010/ov_SC05_010_jr_8017C8D0.c index c44035275..7b28b9814 100644 --- a/src/ov_SC05_010/ov_SC05_010_jr_8017C8D0.c +++ b/src/ov_SC05_010/ov_SC05_010_jr_8017C8D0.c @@ -4229,7 +4229,104 @@ void func_8017F9B4(s32 param_1) } -INCLUDE_ASM("asm/ov_SC05_010/nonmatchings/ov_SC05_010_jr_8017C8D0", func_8017FAF4); +void func_8017FAF4(s32 param_1) +{ + extern s32 D_801A3D5C; + extern u8 D_801202A0[]; + extern volatile s32 D_801C7E4C; + extern s32 D_80126B60; + extern u16 D_80126B5E; + extern s32 func_8014CB8C(void); + extern s32 func_80172658(s32 *a0); + extern s32 func_801726A0(s32 *a0); + extern u8 D_801A3E2C[]; + extern s32 D_801C7E78; + extern s32 D_801A3D94; + extern s32 D_801A33AC; + extern u8 *D_801C7E60[]; + extern u8 D_80192480[]; + extern u8 D_80192488[]; + /* Second-copy aliases of the same two symbols. cse.c hashes a SYMBOL_REF by the + * interned-string POINTER, so a second decl with the same __asm__ name is a distinct + * rtx: the two halves of case 2 no longer unify, each address stays used exactly once, + * local-alloc's update_equiv_regs substitutes the constant back, and gcc emits `la $a0,…` + * at all four call sites (nop delay slot) instead of hoisting them into $s3/$s4. */ + extern u8 D_80192480_b[] __asm__("D_80192480"); + extern u8 D_80192488_b[] __asm__("D_80192488"); + extern void *D_801C39FC[]; + extern void func_800599B8(void *a0, void *a1); + extern void func_8012A828(s32 a0, void *a1); + extern void func_8002D4C8(s32 a0, s32 a1); + + switch (*(u16 *)(param_1 + 0x34)) { + case 0: + if (*(s16 *)(param_1 + 0x98) == 0) { + u16 *ptr; + s32 i; + + *(s16 *)(param_1 + 0x34) = 1; + func_8012A828(param_1, &D_801A3D5C); + *(s32 *)(param_1 + 0x1C) = 0x5A; + ptr = (u16 *)D_801202A0; + for (i = 0; i < 0x60; i++) { + if (ptr[0] == 0x2B5) { + ptr[0x1A] = 1; + } + ptr += 0x86; + } + *(s32 *)(D_801C7E4C + 0xE0) = 0x78; + } + break; + case 1: + if (func_8014CB8C() == 0) { + s32 *p = &D_80126B60; + + if (*p < 0) { + if (func_80172658(p - 2) != 0 || func_801726A0(p - 2) != 0) { + D_80126B5E = D_80126B5E + 4; + } else { + D_80126B5E = D_80126B5E + 0x18; + } + } + } + if (--*(s32 *)(param_1 + 0x1C) == 0) { + *(s16 *)(param_1 + 0x34) = 2; + func_8012A828(param_1, &D_801A3E2C); + *(u8 *)(param_1 + 0xC2) = 0; + func_8002D4C8(4, 0x89F); + *(s32 *)(param_1 + 0x1C) = 7 - D_801C7E78 * 2; + } + break; + case 2: { + u8 t; + + t = (*(u8 *)(param_1 + 0xC2) + 2) & 0xF; + *(u8 *)(param_1 + 0xC2) = t; + func_800599B8(D_80192480, D_801C39FC[t]); + func_800599B8(D_80192488, D_801C39FC[*(u8 *)(param_1 + 0xC2) + 1]); + if (*(u16 *)(param_1 + 0x72) & 0x4000) { + if (--*(s32 *)(param_1 + 0x1C) == 0) { + *(s16 *)(param_1 + 0x34) = 3; + func_8012A828(param_1, &D_801A3D94); + *(u8 *)(param_1 + 0xC2) = 0; + func_800599B8(D_80192480_b, D_801C39FC[*(u8 *)(param_1 + 0xC2)]); + func_800599B8(D_80192488_b, D_801C39FC[*(u8 *)(param_1 + 0xC2) + 1]); + } + } + break; + } + case 3: + if (*(s16 *)(param_1 + 0x98) == 0) { + func_8012A828(param_1, &D_801A33AC); + *(s16 *)(param_1 + 2) = 1; + *(s32 *)(param_1 + 0x1C) = 0x5A; + *(s16 *)(D_801C7E60[0] + 0xAE) = -1; + *(u16 *)(param_1 + 0x70) &= 0xFFFE; + } + break; + } +} + void func_8017FDE0(s32 param_1) { diff --git a/src/ov_SC06_025/ov_SC06_025_jr_8017BEBC.c b/src/ov_SC06_025/ov_SC06_025_jr_8017BEBC.c index a49fe3480..2eb9a4272 100644 --- a/src/ov_SC06_025/ov_SC06_025_jr_8017BEBC.c +++ b/src/ov_SC06_025/ov_SC06_025_jr_8017BEBC.c @@ -4375,7 +4375,104 @@ void func_8017E9B8(void) { } -INCLUDE_ASM("asm/ov_SC06_025/nonmatchings/ov_SC06_025_jr_8017BEBC", func_8017EA74); +#include "common.h" + +typedef struct { + u16 v[4]; +} Tbl8_801AFF3C; /* 8 bytes, align 2 -> lwl/lwr/swl/swr copy */ + +typedef struct { + u16 a, b, c, d; +} Ent8_80188; /* 8-byte stride record */ + +extern Tbl8_801AFF3C D_801AFF3C; +extern Ent8_80188 D_801888CC[]; +extern Ent8_80188 D_801888EC[]; +extern u16 D_80126B5E; +extern u16 D_80126B62; +extern u16 D_80126B66; +extern s32 func_8012E544(s32 a0); +extern void func_8012B0B4(u32 *a0, s32 a1, s32 a2); +extern s32 func_80182090(s32, s32); +extern void func_80181CA4(); + +void func_8017EA74(s32 a0) { + Tbl8_801AFF3C tbl; + s16 vecA[4]; + s16 vecB[4]; + s32 buf[6]; + s32 rec; + s16 mode; + s32 ret; + + tbl = D_801AFF3C; + + rec = func_8012E544(0x2CD); + if (rec == 0) { + return; + } + if (*(u16 *)(rec + 0x2) >= 8) { + return; + } + + mode = *(s16 *)(a0 + 0x2); + switch (mode) { + case 0: + if (*(u16 *)(rec + 0x2) == 3) { + *(s16 *)(a0 + 0x2) = mode + 1; + } + break; + + case 1: + *(u16 *)(a0 + 0x16) = D_801888CC[*(s16 *)(a0 + 0x8)].a; + *(u16 *)(a0 + 0x1A) = D_801888CC[*(s16 *)(a0 + 0x8)].b; + *(u16 *)(a0 + 0x1E) = D_801888CC[*(s16 *)(a0 + 0x8)].c; + *(u16 *)(a0 + 0x2) = *(u16 *)(a0 + 0x2) + 1; + *(s16 *)(a0 + 0xA) = 0; + break; + + case 2: + if (*(s16 *)(a0 + 0x8) < 2) { + vecA[0] = *(u16 *)(rec + 0x6); + vecA[1] = *(u16 *)(rec + 0xA); + vecA[2] = *(u16 *)(rec + 0xE); + *(s32 *)(a0 + 0xC) = 1; + } else { + vecA[0] = D_80126B5E; + vecA[1] = D_80126B62; + vecA[2] = D_80126B66; + if (*(u16 *)(rec + 0x2) == 4) { + *(s32 *)(a0 + 0xC) = 1; + } else { + *(s32 *)(a0 + 0xC) = 0; + } + } + + vecA[1] = D_801888EC[*(s16 *)(a0 + 0x8)].b; + vecA[0] = vecA[0] + D_801888EC[*(s16 *)(a0 + 0x8)].a; + vecA[2] = vecA[2] + D_801888EC[*(s16 *)(a0 + 0x8)].c; + + vecB[0] = *(u16 *)(a0 + 0x16); + vecB[1] = *(u16 *)(a0 + 0x1A); + vecB[2] = *(u16 *)(a0 + 0x1E); + + func_8012B0B4((u32 *)buf, *(s16 *)(a0 + 0x4), 0x50); + + vecA[0] = vecA[0] + ((s16)buf[0] * 2); + vecA[2] = vecA[2] + (buf[0] >> 16); + + *(u16 *)(a0 + 0x4) = *(u16 *)(a0 + 0x4) + tbl.v[*(s16 *)(a0 + 0x8)]; + *(u16 *)(a0 + 0xA) = *(u16 *)(a0 + 0xA) + 0x200; + if (*(s16 *)(a0 + 0xA) >= 0x1000) { + *(s16 *)(a0 + 0xA) = 0x1000; + } + + ret = func_80182090(0x105050, *(s16 *)(a0 + 0xA)); + func_80181CA4(a0, vecA, 0x60, ret, vecB, 8, ret, 3); + break; + } +} + #include "common.h" diff --git a/src/ov_SC06_032/ov_SC06_032_jr_801902EC.c b/src/ov_SC06_032/ov_SC06_032_jr_801902EC.c index 0369fdbd5..a4ddf1fcc 100644 --- a/src/ov_SC06_032/ov_SC06_032_jr_801902EC.c +++ b/src/ov_SC06_032/ov_SC06_032_jr_801902EC.c @@ -3405,7 +3405,152 @@ set_state6_timeout: } -INCLUDE_ASM("asm/ov_SC06_032/nonmatchings/ov_SC06_032_jr_801902EC", func_80190D70); +#include "common.h" + +/* func_80190D70 - ov_SC06_032 / ov_SC06_032_jr_801902EC (192 ins). MATCH, closeness 0. + * + * Body verified byte-exact standalone AND against the REAL 3407-line TU prefix + * (every file-scope decl + engine_core.h) -- see the decl notes below. + * + * Structure straight from the .s: a "did my owner change?" reinit guard, then a + * 3-case state machine on *(u16 *)(a0 + 0x34) (an if/else chain, not a jump table + * -- the .s dispatches with beq 1 / slti 2 / beqz / beq 2). + * guard : owner-stamp mismatch -> reset state, re-arm, randomise 0xFC/0xFE/0x100 + * case 0: countdown, then snapshot the owner's world XYZ, RotTransPers it, and if + * the projected point is on-screen fire a positional SFX whose low byte is + * the distance-attenuated volume ((0xA0 - |sx|) * 0x7F / 0xA0) and whose + * pan nibble is (sx + 0xA0) / 0x14 clamped 0x10 -> 0xF, << 8, | 0x3000. + * case 1: countdown, walking the entity back along its heading (rcos/rsin * 32). + * case 2: spin the owner's 0x10 angle by 0x20 until it hits 0x380. + * Cases 1 and 2 share the ".L80191058: sh $v0, 0x34($s0)" tail via a cross-jump; both + * are written as the same `*(u16 *)(a0 + 0x34) = *(u16 *)(a0 + 0x34) + 1;` statement, + * and gcc's cross-jumper re-merges them (case 1's arm reuses the $a0 copy of the + * switch value that the dispatch already loaded). + */ + +/* ---- DECLARATION LAYER: block scope, but NOT free-form (this is what sank the + * previous attempt on this function -- it was byte-perfect in isolation and a hard + * cc1 error inside the TU, which reads as an unexplained gate rejection). + * + * §55a says a block-scope extern conflicts with nothing at file scope. That is FALSE + * in this direction for gcc-2.7.2: an inner redeclaration is merged with the outer one + * into the C89 COMPOSITE type, so + * - `extern void func_8012B1B4(s32, s32);` against this TU's file-scope + * `extern void func_8012B1B4(void *, void *);` (L2939) -> ERROR "conflicting types" + * - `extern void func_8012B23C();` does NOT hide the file-scope prototype + * `extern void func_8012B23C(void *);` (L2938); the composite keeps the parameter + * list, so the zero-arg call -> ERROR "too few arguments to function" + * Both were reproduced by compiling the real TU prefix + this body. + * + * So: spell every redeclaration EXACTLY as the TU already spells it (law 2), and where + * the TU's arity is wrong for this call site, do not fight the prototype -- go through + * a cast function pointer, this TU's own house idiom (L3060, + * `((s32 (*)(s32))func_8012BE54)(param_1)`), which still emits a direct `jal`. + * + * The .s proves func_8012B23C takes ZERO arguments here: $a0 is never set up before the + * jal, and its delay slot holds `sh $zero, 0x34($s0)` -- an invented argument would cost + * an `addu $a0, $s0, $zero` and move the store out of the slot (SYS law 4). + * + * D_800AF648 is the scalar `extern u8` spelling engine_core.h uses everywhere; the two + * $a0-pinned scopes below are its §2 remat lever (hoisting the lui/addiu out would emit + * one `la` + two `move $4,$sN` instead of the target's two `la $4,...`). + */ + +void func_80190D70(s32 a0) { + extern void func_8012B23C(void *); + extern void func_8012B1B4(void *a0, void *a1); + extern s32 rand(void); + extern void func_8004914C(void *a0); + extern void func_800491AC(void *a0); + extern s32 RotTransPers(s32 a0, s32 a1, s32 *a2, s32 *a3); + extern s32 func_8004787C(s32 a0); + extern s32 func_80047948(s32 a0); + extern void func_8002D4C8(s32 a0, s32 a1); + extern u8 D_800AF648; + extern u8 D_801CC7D4[]; + + struct { + s16 v[3]; /* sp+0x10 */ + s16 pad; /* sp+0x16 */ + u16 sxy[2]; /* sp+0x18 */ + s32 z; /* sp+0x1C */ + s32 flag; /* sp+0x20 */ + } L; + + if (*(s16 *)(a0 + 0xFC) != *(s16 *)(*(s32 *)(a0 + 0x64) + 0x36)) { + *(s16 *)(a0 + 2) = 5; + *(s16 *)(a0 + 0x34) = 0; + ((void (*)(void))func_8012B23C)(); + func_8012B1B4((void *)a0, D_801CC7D4); + *(s16 *)(a0 + 0x16) = (rand() & 3) - 0x1B; + *(s16 *)(a0 + 0xA) = *(u16 *)(a0 + 0xA) - 0x38; + *(s16 *)(a0 + 0xFC) = (rand() & 0xFF) - 0x80; + *(s16 *)(a0 + 0xFE) = (rand() & 0xFF) - 0x80; + *(s16 *)(a0 + 0x100) = (rand() & 0xFF) - 0x80; + *(s32 *)(a0 + 0x1C) = 0x3C; + return; + } + + switch (*(u16 *)(a0 + 0x34)) { + case 0: + if (*(s32 *)(a0 + 0x1C) != 0) { + *(s32 *)(a0 + 0x1C) = *(s32 *)(a0 + 0x1C) - 1; + *(s16 *)(a0 + 0xA) = *(u16 *)(a0 + 0xA) - 4; + return; + } + *(s32 *)(a0 + 0x1C) = 0x14; + *(u16 *)(a0 + 0x34) = *(u16 *)(a0 + 0x34) + 1; + L.v[0] = *(s32 *)(*(s32 *)(a0 + 0x20) + 0x48); + L.v[1] = *(s32 *)(*(s32 *)(a0 + 0x20) + 0x4C); + L.v[2] = *(s32 *)(*(s32 *)(a0 + 0x20) + 0x50); + /* $a0-pinned scopes: rematerialise &D_800AF648 (lui/addiu) before EACH call */ + { register void *r4 __asm__("$4"); r4 = &D_800AF648; func_8004914C(r4); } + { register void *r4 __asm__("$4"); r4 = &D_800AF648; func_800491AC(r4); } + RotTransPers((s32)L.v, (s32)L.sxy, &L.z, &L.flag); + if (L.flag >= 0 && (u32)((L.sxy[0] + 0x9F) & 0xFFFF) < 0x13F + && (u32)((L.sxy[1] + 0x77) & 0xFFFF) < 0xEF) { + s32 sx; /* screen X, then REUSED as the pan field */ + register s32 av __asm__("$5"); /* |X| */ + s32 vol; + sx = (s16)L.sxy[0]; + av = sx; + if (sx < 0) { + av = -sx; + } + vol = ((0xA0 - av) * 0x7F) / 0xA0; + /* sched1 otherwise hoists the PAN multiply ahead of this one */ + __asm__("" : "=r"(vol) : "0"(vol)); + sx = (sx + 0xA0) / 0x14; + if (sx == 0x10) { + sx = 0xF; + } + sx = sx << 8; /* in place, so reorg can steal it into the bne delay slot */ + func_8002D4C8(0x9E5, (vol | (0x3000 | sx)) & 0xFFFF); + } + return; + + case 1: + if (*(s32 *)(a0 + 0x1C) != 0) { + *(s32 *)(a0 + 0x1C) = *(s32 *)(a0 + 0x1C) - 1; + *(s32 *)(a0 + 4) = + *(s32 *)(a0 + 4) - (func_8004787C(*(s16 *)(*(s32 *)(a0 + 0x20) + 0x12)) << 5); + *(s32 *)(a0 + 0xC) = + *(s32 *)(a0 + 0xC) - (func_80047948(*(s16 *)(*(s32 *)(a0 + 0x20) + 0x12)) << 5); + return; + } + *(u16 *)(a0 + 0x34) = *(u16 *)(a0 + 0x34) + 1; + return; + + case 2: + *(u16 *)(*(s32 *)(a0 + 0x20) + 0x10) = *(u16 *)(*(s32 *)(a0 + 0x20) + 0x10) + 0x20; + if (*(s16 *)(*(s32 *)(a0 + 0x20) + 0x10) != 0x380) { + return; + } + *(u16 *)(a0 + 0x34) = *(u16 *)(a0 + 0x34) + 1; + return; + } +} + typedef struct { SVECTOR_8016E7C8 v[4]; /* 0x00 */