Files
BFM-decomp/src/800_c.c
T

4163 lines
119 KiB
C

#include "common.h"
#include "800_shared.h"
/* P31 S72 — split out of src/800.c at the jtbl-span TU boundary (vram 0x80035270-0x8003A444).
* 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. */
/* 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.
*/
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"); // !FAKE: pin $0 — NEEDED DIFFERS (P36 rung B tus9)
u8 result[8];
u8 param[8];
CdlLOC loc;
s32 flags;
register s32 n __asm__("$4"); // !FAKE: pin $4 — NEEDED DIFFERS (P36 rung B tus9)
s32 idx;
s32 lo;
s16 h;
s32 drv;
register s32 hi __asm__("$20"); // !FAKE: pin $20 — NEEDED DIFFERS (P36 rung B tus9)
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"); // !FAKE: pin $4 — NEEDED DIFFERS (P36 rung B tus9)
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 */ // !FAKE: barrier — NEEDED DIFFERS (P36 rung B tus9)
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;
}
}
extern u8 D_8006AEEC;
extern s32 D_80076108;
extern s32 D_8007610C;
extern u8 D_8007620C;
extern u8 D_80076214;
extern s32 D_80078F10;
extern s16 D_800A4EF8;
extern s32 D_800A5BC8;
extern u8 D_800A63E4;
extern s32 D_800A63E8;
extern s32 D_800C6D28;
extern s32 D_800C7D30[];
extern void func_8003D650(int a0, int a1, int a2);
extern s32 func_8003EDE8(s32, s32, s32);
extern void func_80036130(s32, u8 *);
extern void func_800361CC();
extern void func_8003621C(void);
extern s32 func_80043410(void);
extern s32 func_80043420(void);
extern int func_800435CC(s32, void *, void *);
extern s32 func_8004355C(s32 mode, u8 *result);
extern s32 func_80043704(u8 com, u8 *param);
s32 func_80035C4C(s32 arg0) {
u8 result[8];
u8 cmd[8];
s32 trk;
s32 st;
s32 sync;
u32 vol;
if (*(u8 *)(arg0 + 7) != 0) {
trk = *(s32 *)(arg0 + 0xC);
D_8007620C = 0;
*(u8 *)(arg0 + 7) = 0;
*(u8 *)(arg0 + 3) = 0;
if (D_800A5BC8 < trk) {
return 1;
}
if (trk != 0) {
if ((func_80043420() & 0x80) == 0) {
*(u8 *)(arg0 + 3) = 1;
}
D_80076108 = 0;
cmd[0] = 5;
func_800435CC(0xE, cmd, 0);
D_800A63E8 = *(s32 *)(arg0 + 0xC);
} else {
if (D_800C6D28 == 0) {
return 1;
}
D_800A63E8 = D_800C6D28;
func_80043704(3, 0);
D_800C6D28 = 0;
*(u8 *)(arg0 + 3) = 2;
}
}
switch (*(u8 *)(arg0 + 3)) {
case 0:
if (++D_80076108 < 3) {
return 0;
}
*(u8 *)(arg0 + 3) += 1;
/* fall through */
case 1:
vol = ((u32)D_800A4EF8 * 97) >> 7;
D_80076108 = 0;
D_8006AEEC = vol;
func_8003EDE8(0, vol & 0xFF, vol & 0xFF);
func_8003D650(0, 1, 0);
func_80043704(3, (u8 *)&D_800C7D30[*(s32 *)(arg0 + 0xC)]);
func_800361CC(func_80036130);
*(u8 *)(arg0 + 3) += 1;
/* fall through */
case 2:
if (func_80043410() & 0x40) {
if (D_80076108++ >= 0x12D) {
D_80076214 = 1;
return 1;
}
return 0;
}
sync = func_8004355C(1, result);
if (sync == 2) {
*(u8 *)(arg0 + 3) += 1;
break;
}
if (sync != 5) {
return 0;
}
if (result[0] & 0x10) {
D_80076214 = 1;
return 1;
}
return 1;
case 3:
st = func_80043410();
if ((st & 0x80) == 0) {
if (st & 0x10) {
D_80076214 = 1;
return 1;
}
return 0;
}
D_800A63E4 = 0xC;
D_8007610C = 0;
D_8007620C |= 0x80;
*(u8 *)(arg0 + 3) += 1;
break;
case 4:
if (D_800A63E4 == 0xD) {
func_8003621C();
func_8003EDE8(0, 0, 0);
func_80043704(9, 0);
D_8007620C = 0;
D_80078F10 = 0;
} else {
if (D_8007610C == 0) {
return 0;
}
st = func_80043410();
if (st & 0x80) {
return 0;
}
if (st & 0x10) {
D_80076214 = 1;
}
func_8003621C();
func_8003EDE8(0, 0, 0);
D_8007620C = 0;
D_80078F10 = 0;
if (D_80076214 != 0) {
return 1;
}
func_80043704(9, 0);
}
*(u8 *)(arg0 + 3) += 1;
return 0;
case 5:
sync = func_8004355C(1, result);
if (sync == 0) {
return 0;
}
if (sync != 5) {
return 1;
}
if (result[0] & 0x10) {
D_80076214 = 1;
}
return 1;
}
return 0;
}
extern u8 D_80076214;
extern void func_800434BC(void);
extern s32 func_8004355C(s32 mode, u8 *result);
extern s32 func_80043704(u8 com, u8 *param);
void func_8003602C(s32 arg0) {
u8 result[8];
u8 state;
s32 sync;
switch (*(u8 *)(arg0 + 3)) {
case 0:
case 1:
default:
*(u8 *)(arg0 + 2) = 0;
break;
case 2:
*(u8 *)(arg0 + 2) = 1;
func_800434BC();
*(u8 *)(arg0 + 3) += 2;
break;
case 3:
*(u8 *)(arg0 + 2) = 1;
func_800434BC();
*(u8 *)(arg0 + 3) += 1;
/* fall through */
case 4:
func_80043704(9, 0);
func_8003621C();
state = *(u8 *)(arg0 + 3);
*(u8 *)(arg0 + 2) = 1;
*(u8 *)(arg0 + 3) = state + 1;
break;
case 5:
sync = func_8004355C(1, result);
if (sync == 0) {
*(u8 *)(arg0 + 2) = 1;
return;
}
if (sync == 5 && (result[0] & 0x10)) {
D_80076214 = 1;
}
*(u8 *)(arg0 + 2) = 0;
break;
}
}
extern u8 D_800A63E4;
extern s32 D_8007610C;
extern s32 D_800A63E8;
void func_80036130(s32 a0, u8 *a1) {
u8 v1;
s32 temp;
s32 v3;
s32 v0;
s32 byte_val;
s32 low;
v1 = D_800A63E4;
if (v1 != 0xC) {
return;
}
v1 = a0 & 0xFF;
if (v1 != 0x1) {
return;
}
temp = D_8007610C;
if (temp < 0xA) {
D_8007610C = temp + 1;
return;
}
if ((a1[4] & 0x80) != 0) {
return;
}
byte_val = a1[1];
v1 = byte_val >> 4;
v0 = v1 << 2;
v0 = v0 + v1;
v0 = v0 << 1;
low = byte_val & 0xF;
v3 = D_800A63E8;
v0 = v0 + low;
if (v0 != v3) {
D_800A63E4 = 0xD;
}
}
extern void *streamLoad_savedReadyCB;
extern u8 streamLoad_cbActive;
extern void *CdReadyCallback(void *func);
void func_800361CC(void) {
if (streamLoad_cbActive == 0) {
streamLoad_savedReadyCB = ((void *(*)(void))CdReadyCallback)();
} else {
((void *(*)(void))CdReadyCallback)();
}
streamLoad_cbActive = 1;
}
extern void *CdReadyCallback(void *func);
extern void *streamLoad_savedReadyCB;
extern u8 streamLoad_cbActive;
void func_8003621C(void) {
if (streamLoad_cbActive != 0) {
CdReadyCallback(streamLoad_savedReadyCB);
streamLoad_savedReadyCB = 0;
streamLoad_cbActive = 0;
}
}
extern void func_80037334(void);
extern void func_800434BC(void);
extern void *CdReadyCallback(void *);
extern int func_800435CC(s32, void *, void *);
extern s32 func_8004355C(s32 mode, u8 *result); /* §376: adopt the TU's spelling verbatim */
extern void func_800415A8(s32);
extern u8 D_8006AEF4;
extern u16 D_800A4E8E;
extern int streamLoad_state;
extern void *streamLoad_savedReadyCB;
extern u8 streamLoad_cbActive;
extern int D_800A6544;
extern s16 D_800A46A2;
extern u8 D_800A46B0;
int func_80036260(void) {
u8 result[8];
u16 *flags;
s16 *vabp;
s32 t;
int sync;
func_80037334();
D_8006AEF4 &= 0xFD;
flags = &D_800A4E8E;
*flags &= 0xFFDF;
if (streamLoad_state != 0) {
switch (streamLoad_state) {
case 0:
case 1:
case 2:
break;
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
case 15:
case 16:
case 17:
func_800434BC();
break;
case 12:
if (streamLoad_cbActive != 0) {
CdReadyCallback(streamLoad_savedReadyCB);
streamLoad_savedReadyCB = 0;
streamLoad_cbActive = 0;
}
/* fall through */
case 13:
case 14:
func_800435CC(9, 0, 0);
streamLoad_state = 0;
D_800A6544 = 0x3C;
break;
}
}
if (D_800A6544 != 0) {
D_800A6544--;
if (D_800A6544 != 0) {
sync = func_8004355C(1, result);
if (sync != 5 && sync != 2) {
return 0;
}
}
}
vabp = &D_800A46A2;
t = *vabp;
streamLoad_state = 0;
D_800A6544 = 0;
if (t >= 0) {
func_800415A8(t);
*vabp = -1;
D_800A46B0 = 1;
}
return 1;
}
#ifdef NON_MATCHING
extern int CdControl(u8 com, u8 *param, u8 *result);
extern int CdSync(int mode, u8 *result);
extern u32 CdMode(void);
extern void CdFlush(void);
extern void *CdReadyCallback(void *func);
extern void func_800377D8(void); /* this loader's CdlReadN ready-callback */
extern int func_80036260(void); /* sub-handler passed to func_80037CD8; §376: the definition returns int */
extern void func_8002EC10(void);
extern void func_80037334(void);
extern void func_80037358(int posInt);
extern void func_80037144(int idx);
extern int func_80037CD8(void *arg);
extern int func_8003750C(void);
extern int func_800374CC(int *out);
extern int func_8003775C(void);
extern void func_80037D74(void);
extern void *func_80037368(int *out);
extern int streamLoad_state; /* 0x8006AF00 */
extern void *streamLoad_savedReadyCB;
extern u8 streamLoad_cbActive;
extern int D_800A4F28; /* tick / timeout counter */
extern int D_800A4F2C; /* CdMode-derived retry budget */
extern int D_800A4F30; /* remaining sub-stream repeat count (from param_3) */
extern int D_800A4F34; /* last sector position (stall detection) */
extern int D_800A4F38; /* end/abort flag */
extern int D_800A6544;
extern u16 D_800A4E8E; /* 16-bit status flags */
extern u8 D_8006AEF4; /* 8-bit status flags */
extern u8 D_80068B60[]; /* per-resource descriptor table (0x10 stride) */
/* Second CD loader, DISTINCT from CdReadStateMachine: an 18-state machine (streamLoad_state) with
* its OWN ready-callback (func_800377D8). Runs SetMode(0xA0)/SeekL/ReadN with retry + CdMode
* handling, looping param_3 (D_800A4F30) times over sub-streams. Returns 0 = busy, 1 = done,
* 2 = error/abort. Driven by ResourceLoadStateMachine. Provenance: static trace, Phase 3 T4 (fn id
* verified; full semantics partial).
* NON_MATCHING: faithful translation of the Ghidra decompile — logically faithful, not byte-verified. */
int StreamLoadStateMachine(int param_1, void *param_2, int param_3) { /* param_2 is a CdlLOC* */
short sVar1;
int iVar4;
u32 uVar2;
char *pcVar3;
u8 local_28[8];
u8 local_20[8];
int local_18;
int local_14;
sVar1 = *(short *)(D_80068B60 + (param_1 - 0x100) * 0x10);
D_800A4F28++;
switch (streamLoad_state) {
case 0:
D_800A4F38 = 0;
D_800A6544 = 0;
D_800A4F30 = param_3;
func_8002EC10();
streamLoad_state++;
D_800A4E8E &= 0xFFDF;
return 0;
case 1:
func_80037334();
iVar4 = CdPosToInt((CdlLOC *)param_2);
func_80037358(iVar4);
func_80037144(sVar1);
streamLoad_state++;
/* fall through */
case 2:
local_14 = CdSync(1, local_20);
if (local_14 != 5 && local_14 != 2) return 0;
uVar2 = CdMode();
D_800A4F2C = ((uVar2 & 0x80) == 0) ? 3 : 0;
streamLoad_state++;
/* fall through */
case 3:
local_28[0] = 0xA0;
iVar4 = CdControl(0x0E, local_28, local_20); /* CdlSetmode */
if (iVar4 == 0) {
if ((local_20[0] & 0x10) != 0) { func_80037334(); streamLoad_state = 0; return 2; }
return 0;
}
D_800A4F28 = 0;
streamLoad_state++;
/* fall through */
case 4:
iVar4 = CdSync(1, local_20);
if (iVar4 != 5) {
if (iVar4 == 2) {
streamLoad_state++;
local_14 = 2;
modeWait:
if (D_800A4F2C != 0) { D_800A4F2C--; return 0; }
streamLoad_state++;
goto issueSeek;
}
if (D_800A4F28 < 0x3D) return 0;
}
streamLoad_state = 3;
return 0;
case 5:
goto modeWait;
case 6:
issueSeek:
iVar4 = func_80037CD8((void *)func_80036260);
if (iVar4 == 0) return 0;
streamLoad_state = 7;
/* fall through */
case 7:
iVar4 = func_8003750C();
if (iVar4 == 0) return 0;
streamLoad_state++;
/* fall through */
case 8:
local_14 = CdSync(1, local_20);
if (local_14 != 5 && local_14 != 2) return 0;
streamLoad_state++;
/* fall through */
case 9:
D_800A4F28 = 0;
iVar4 = CdControl(0x15, (u8 *)param_2, local_20); /* CdlSeekL */
if (iVar4 == 0) return 0;
streamLoad_state++;
/* fall through */
case 10:
local_14 = CdSync(1, local_20);
if (local_14 == 5) {
iVar4 = CdControl(0x01, (u8 *)0, local_20); /* CdlNop */
if (iVar4 == 0) { streamLoad_state = 9; return 0; }
if ((local_20[0] & 0x10) != 0) {
func_80037334();
D_8006AEF4 &= 0xFD;
streamLoad_state = 0;
return 2;
}
streamLoad_state = 9;
return 0;
}
if (local_14 != 2) {
if (D_800A4F28 < 0x12D) return 0;
CdFlush();
streamLoad_state = 9;
return 2;
}
streamLoad_state++;
local_14 = 2;
/* fall through */
case 0xB:
D_800A4F28 = 0;
iVar4 = CdControl(0x06, (u8 *)param_2, local_20); /* CdlReadN */
if (iVar4 != 0) {
if (streamLoad_cbActive == 0)
streamLoad_savedReadyCB = CdReadyCallback((void *)func_800377D8);
else
CdReadyCallback((void *)func_800377D8);
streamLoad_state++;
streamLoad_cbActive = 1;
return 0;
}
if ((local_20[0] & 0x10) == 0) return 0;
D_8006AEF4 &= 0xFD;
func_80037334();
streamLoad_state = 0;
return 2;
case 0xC:
iVar4 = func_800374CC(&local_18);
if (iVar4 == 0) {
if (local_18 != D_800A4F34) { D_800A4F34 = local_18; D_800A4F28 = 0; }
if (D_800A4F28 > 300) {
if (streamLoad_cbActive != 0) {
CdReadyCallback(streamLoad_savedReadyCB);
streamLoad_savedReadyCB = 0;
streamLoad_cbActive = 0;
}
streamLoad_state++;
}
return 0;
}
if (streamLoad_cbActive != 0) {
CdReadyCallback(streamLoad_savedReadyCB);
streamLoad_savedReadyCB = 0;
streamLoad_cbActive = 0;
}
streamLoad_state++;
/* fall through */
case 0xD:
iVar4 = func_8003775C();
if (iVar4 == 0) return 0;
func_80037D74();
streamLoad_state++;
return 0;
case 0xE:
pcVar3 = (char *)func_80037368(&local_14);
if (local_14 != 1) { streamLoad_state = 0x11; return 0; }
if (*pcVar3 != 1) {
if (*pcVar3 == 2) { streamLoad_state = 0x11; D_800A4F38 = 1; return 0; }
if (D_800A4F30 != 0) {
if (D_800A4F30 - 1 == 0) { streamLoad_state = 0x11; D_800A4F30 = 0; return 0; }
streamLoad_state = 1;
D_800A4F30--;
return 0;
}
streamLoad_state = 1;
return 0;
}
streamLoad_state++;
break; /* -> CdlPause (post-switch) */
case 0xF:
break; /* -> CdlPause (post-switch) */
case 0x10:
iVar4 = CdSync(1, local_20);
if (iVar4 != 5 && iVar4 != 2) return 0;
if (D_800A4F38 == 0) { streamLoad_state = 0; return 1; }
streamLoad_state = 0;
D_800A4F38 = 0;
return 2;
case 0x11:
iVar4 = CdControl(0x09, (u8 *)0, local_20); /* CdlPause */
if (iVar4 != 0) { streamLoad_state = 0x10; return 0; }
return 0;
default:
return 0;
}
/* shared tail for states 0xE (advance) and 0xF: pause, then wait for it */
iVar4 = CdControl(0x09, (u8 *)0, local_20); /* CdlPause */
if (iVar4 != 0) { streamLoad_state++; return 0; }
if ((local_20[0] & 0x10) != 0) { streamLoad_state = 0; return 1; }
return 0;
}
#else
extern void func_80037334(void);
extern void func_800434BC(void);
extern void *CdReadyCallback(void *); /* CdReadyCallback; §376: keep the TU's void spelling */
extern int func_800435CC(s32, void *, void *); /* CdControl */
extern s32 func_8004355C(s32 mode, u8 *result); /* CdSync */
extern u8 D_8006AEF4;
extern u16 D_800A4E8E;
extern int streamLoad_state;
extern void *streamLoad_savedReadyCB;
extern u8 streamLoad_cbActive;
extern int D_800A6544;
extern int func_80036260(void); /* sub-handler passed to func_80037CD8; the definition returns int */
extern s32 func_80043420(void); /* CdMode */
extern void func_8002EC10(void);
extern void func_80037358(int posInt);
extern void func_80037144(s32 idx);
extern int func_80037CD8(void *arg);
extern s32 func_8003750C(void);
extern int func_800374CC(int *out);
extern int func_8003775C(void);
extern void func_80037D74(void);
extern void *func_80037368(int *out);
extern void func_800377D8(u8); /* this loader's CdlReadN ready-callback (defined below) */
extern int D_800A4F28; /* tick / timeout counter */
extern int D_800A4F2C; /* CdMode-derived settle budget */
extern int D_800A4F30; /* remaining sub-stream repeat count (from n) */
extern int D_800A4F34; /* last sector position (stall detection) */
extern int D_800A4F38; /* §376: TU spelling (src/800_c.c:890); reached as a byte below */
extern u8 D_80068B60[]; /* per-resource descriptor table (0x10 stride) */
/* Second CD loader, DISTINCT from CdReadStateMachine: an 18-state machine (streamLoad_state) with
* its OWN ready-callback (func_800377D8). Runs SetMode(0xA0)/SeekL/ReadN with retry + CdMode
* handling, looping n (D_800A4F30) times over sub-streams. Returns 0 = busy, 1 = done,
* 2 = error/abort. Driven by ResourceLoadStateMachine.
*
* Matching notes (P31 S73):
* - `idx` MUST be its own local: written inline, `(arg0 - 0x100) * 0x10` folds at tree level into
* `arg0*0x10 - 0x1000` and the -4096 disappears into the `lh` displacement (2 insns, wrong).
* - `sVar1` is `int` (not `short`): a HImode local live across three calls loads with `lhu` and
* pays a `sll/sra` sign-extend at the use; the int-typed read sign-extends at the load (`lh`).
* - Every held global address is its own single-set pointer local (§429) — that is what turns
* `lui/%lo` pairs into the `lui + addiu` base the target uses for D_800A4F28/2C/30/34/38 and
* D_800A4E8E.
* - `break` vs `return 0` is load-bearing and NOT interchangeable here (both mean "return 0"):
* `break` funnels through the single trailing `return 0`, so cross_jump merges the arm's tail
* into .L80036AD4/.L80036ADC; `return 0` keeps the `$v0 = 0` hard-reg set inside the arm, which
* excludes $v0 from that block's allocation. Case 11 needs `return 0` (its state++ lands in $v1
* and stays inline); every other zero-return arm needs `break`. */
int StreamLoadStateMachine(int arg0, void *loc, int n) {
u8 cmd[8];
u8 result[8];
int pos;
int sync;
int resKind;
u8 *pb;
int *p28;
int *p2C;
int *p30;
int *p34;
u16 *flags;
int t;
int idx;
idx = arg0 - 0x100;
resKind = *(short *)(D_80068B60 + idx * 0x10);
p28 = &D_800A4F28;
*p28 += 1;
switch (streamLoad_state) {
case 0:
D_800A4F30 = n;
*(u8 *)&D_800A4F38 = 0;
D_800A6544 = 0;
func_8002EC10();
flags = &D_800A4E8E;
*flags &= 0xFFDF;
streamLoad_state++;
break;
case 1:
func_80037334();
func_80037358(CdPosToInt((CdlLOC *)loc));
func_80037144(resKind);
streamLoad_state++;
/* fall through */
case 2:
sync = func_8004355C(1, result);
if (sync != 5 && sync != 2) break;
if ((func_80043420() & 0x80) != 0) {
D_800A4F2C = 0;
} else {
D_800A4F2C = 3;
}
streamLoad_state++;
/* fall through */
case 3:
cmd[0] = 0xA0;
if (func_800435CC(0x0E, cmd, result) == 0) { /* CdlSetmode */
if ((result[0] & 0x10) == 0) break;
func_80037334();
streamLoad_state = 0;
return 2;
}
D_800A4F28 = 0;
streamLoad_state++;
/* fall through */
case 4:
sync = func_8004355C(1, result);
if (sync == 5) {
streamLoad_state = 3;
break;
}
if (sync != 2) {
if (D_800A4F28 < 0x3D) break;
streamLoad_state = 3;
break;
}
streamLoad_state++;
/* fall through */
case 5:
p2C = &D_800A4F2C;
if (*p2C != 0) {
*p2C -= 1;
break;
}
streamLoad_state++;
/* fall through */
case 6:
if (func_80037CD8((void *)func_80036260) == 0) break;
streamLoad_state = 7;
/* fall through */
case 7:
if (func_8003750C() == 0) break;
streamLoad_state++;
/* fall through */
case 8:
sync = func_8004355C(1, result);
if (sync != 5 && sync != 2) break;
streamLoad_state++;
/* fall through */
case 9:
D_800A4F28 = 0;
if (func_800435CC(0x15, loc, result) == 0) break; /* CdlSeekL */
streamLoad_state++;
/* fall through */
case 10:
sync = func_8004355C(1, result);
if (sync == 5) {
if (func_800435CC(1, 0, result) == 0) { /* CdlNop */
streamLoad_state = 9;
break;
}
if ((result[0] & 0x10) == 0) {
streamLoad_state = 9;
break;
}
func_80037334();
D_8006AEF4 &= 0xFD;
streamLoad_state = 0;
return 2;
}
if (sync != 2) {
if (D_800A4F28 < 0x12D) break;
func_800434BC();
streamLoad_state = 9;
return 2;
}
streamLoad_state++;
/* fall through */
case 11:
D_800A4F28 = 0;
if (func_800435CC(6, loc, result) == 0) { /* CdlReadN */
if ((result[0] & 0x10) == 0) break;
D_8006AEF4 &= 0xFD;
func_80037334();
streamLoad_state = 0;
return 2;
}
if (streamLoad_cbActive == 0) {
streamLoad_savedReadyCB = ((void *(*)(void *))CdReadyCallback)((void *)func_800377D8);
} else {
CdReadyCallback((void *)func_800377D8);
}
streamLoad_cbActive = 1;
streamLoad_state++;
return 0; /* NOT `break` -- see the header note */
case 12:
if (func_800374CC(&pos) == 0) {
p34 = &D_800A4F34;
if (pos != *p34) {
*p34 = pos;
D_800A4F28 = 0;
}
if (D_800A4F28 < 0x12D) break;
if (streamLoad_cbActive != 0) {
CdReadyCallback(streamLoad_savedReadyCB);
streamLoad_savedReadyCB = 0;
streamLoad_cbActive = 0;
}
streamLoad_state++;
break;
}
if (streamLoad_cbActive != 0) {
CdReadyCallback(streamLoad_savedReadyCB);
streamLoad_savedReadyCB = 0;
streamLoad_cbActive = 0;
}
streamLoad_state++;
/* fall through */
case 13:
if (func_8003775C() == 0) break;
func_80037D74();
streamLoad_state++;
break;
case 14:
pb = (u8 *)func_80037368(&sync);
if (sync != 1) {
streamLoad_state = 0x11;
break;
}
if (*pb == 1) {
streamLoad_state++;
} else if (*pb == 2) {
*(u8 *)&D_800A4F38 = 1;
streamLoad_state = 0x11;
break;
} else {
p30 = &D_800A4F30;
t = *p30;
if (t == 0) {
streamLoad_state = 1;
break;
}
t -= 1;
*p30 = t;
if (t != 0) {
streamLoad_state = 1;
break;
}
streamLoad_state = 0x11;
break;
}
/* fall through */
case 15:
if (func_800435CC(9, 0, result) == 0) { /* CdlPause */
if ((result[0] & 0x10) == 0) break;
streamLoad_state = 0;
return 1;
}
streamLoad_state++;
break;
case 16:
sync = func_8004355C(1, result);
if (sync != 5 && sync != 2) break;
pb = (u8 *)&D_800A4F38;
t = *pb;
streamLoad_state = 0;
if (t != 0) {
*pb = 0;
return 2;
}
return 1;
case 17:
if (func_800435CC(9, 0, result) != 0) streamLoad_state = 0x10;
break;
}
return 0;
}
#endif
extern s32 D_8006A69C;
extern u8 D_8006A6A0;
extern s32 D_8006A6A4;
extern s32 D_8006AEE8;
extern s32 D_80078F10;
extern u8 D_800A46BA;
extern u8 D_800A4F1A;
extern s32 func_80034CF0(u8 *);
extern void func_80034DFC(short);
extern s32 func_80035270(); /* §376: def returns s32 and takes (s32) */
extern void func_800359B0(); /* §376: def takes (s32) */
extern void func_80036D24(void);
extern void func_80036FB0(s32, s32);
typedef struct {
s32 f00;
s32 f04;
s32 f08;
s32 f0c;
s32 f10;
s32 f14;
s32 f18;
s32 f1c;
s32 f20;
s32 f24;
s32 f28;
s32 f2c;
} CdReq;
void func_80036AF8(CdlLOC *loc, s32 flags) {
register s32 zr __asm__("$0"); // !FAKE: pin $0 — NEEDED DIFFERS (P36 rung B tus9)
CdReq req;
s32 mode;
s32 n;
s32 idx;
s32 lo;
s16 h;
s32 drv;
s32 hi;
u8 b;
s32 i;
s32 ret;
u8 *rec;
u8 *rec2;
u8 *tbl;
s32 hoff;
mode = flags + zr;
if (!(flags & 0x4000)) {
return;
}
n = flags & 0xF;
idx = n + zr;
lo = (s32)(flags << 16) >> 20;
drv = ((s32)(flags << 16) >> 25) & 0x1F;
hi = drv + zr;
h = lo & 0x1F;
if (lo & 1) {
if (*(u8 *)((u8 *)&D_8006A6A0 + drv * 0x48) != 0) {
idx = n + 4;
} else {
idx = n + 8;
}
}
h = h >> 1;
rec = (u8 *)*(s32 *)((u8 *)&D_8006A69C + hi * 0x48);
rec2 = rec + (h << 6);
b = *(u8 *)(rec2 + (idx << 2) + 1);
if ((b & 0xF0) == 0) {
return;
}
if (D_8006AEE8 != 0) {
if ((b & 0xF) == 0) {
return;
}
if ((b & 0xF) == 1) {
for (i = 0; i < D_8006AEE8; i++) {
func_80034DFC(*(short *)(&D_80078F10 + i));
(&D_80078F10)[i] = 0;
}
D_8006AEE8 = 0;
}
}
req.f08 = (s32)func_80035270;
D_800A46BA = 0;
if (h != 0) {
ret = CdPosToInt(loc);
hoff = hi * 0x48;
tbl = (u8 *)&D_8006A6A4;
req.f0c = ret + *(s32 *)(tbl + hoff + h * 4);
} else {
req.f0c = CdPosToInt(loc);
}
req.f10 = (s16)mode;
req.f1c = (s32)func_80036D24;
req.f24 = (s32)func_800359B0;
req.f20 = 0;
req.f28 = (s32)func_80036FB0;
ret = func_80034CF0((u8 *)&req);
if (ret != 0) {
(&D_80078F10)[D_8006AEE8] = ret;
D_8006AEE8 = D_8006AEE8 + 1;
}
D_800A4F1A = 1;
}
extern s32 D_8006AEE8;
extern s32 D_80078F10;
extern u8 D_800A4F1A;
void func_80036D24(void) {
s32 v0 = D_8006AEE8;
D_80078F10 = 0;
if (v0 < 2) {
D_8006AEE8 = 0;
D_800A4F1A = 0;
}
}
extern s32 D_8006AEE8;
extern s32 D_80078F10;
extern s32 D_800C6D28;
extern u8 D_800A46BA;
extern u8 D_800A4F1A;
extern s16 D_800A4EF8;
extern s32 func_80034CF0(u8 *);
extern void func_80034DFC(s16);
extern s32 func_8003EDE8(s32, s32, s32);
extern s32 func_80035C4C(); /* §376: def returns s32 and takes (s32) */
extern void func_80036F98(void);
extern void func_8003602C(s32); /* §376: the definition takes s32 (the use is address-taken and already cast) */
extern void func_80036FB0(s32, s32);
void func_80036D58(s16 arg0)
{
CdReq req;
s32 pad[2];
s32 i;
s16 *p;
s32 r;
s32 n;
s32 cnt;
if (arg0 != 0 || D_800C6D28 != 0) {
D_800A46BA = 0;
if (D_8006AEE8 != 0) {
i = 0;
if (D_8006AEE8 > 0) {
p = (s16 *)&D_80078F10;
do {
func_80034DFC(*p);
i++;
cnt = D_8006AEE8;
*(s32 *)p = 0;
p += 2;
} while (i < cnt);
}
D_8006AEE8 = 0;
}
req.f08 = (s32)func_80035C4C;
req.f0c = arg0;
req.f1c = (s32)func_80036F98;
req.f20 = 0;
req.f24 = (s32)func_8003602C;
req.f28 = (s32)func_80036FB0;
r = func_80034CF0((u8 *)&req);
n = D_8006AEE8;
(&D_80078F10)[n] = r;
if (r != 0) {
D_8006AEE8 = n + 1;
}
D_800A4F1A = 0;
if (arg0 != 0) {
D_800C6D28 = 0;
}
func_8003EDE8(0, ((u32)D_800A4EF8 * 97) >> 7 & 0xFF, ((u32)D_800A4EF8 * 97) >> 7 & 0xFF);
}
}
extern u8 D_800A4F1A;
extern s32 D_800C6D28;
extern void func_80036F18(void);
void func_80036EB4(void) {
if (!D_800A4F1A) {
func_80036F18();
D_800C6D28 = 0;
}
}
extern u8 D_800A4F1A;
extern s32 D_800C6D28;
extern void func_80036F18(void);
void func_80036EE8(void) {
func_80036F18();
D_800C6D28 = 0;
D_800A4F1A = 0;
}
extern s32 D_800C6D28;
extern s32 D_80078F10;
extern s32 D_800A63E8;
extern s32 D_8006AEE8;
extern void func_80034DFC(short);
void func_80036F18(void) {
s32 i;
if (D_8006AEE8 != 0) {
D_800C6D28 = D_800A63E8;
for (i = 0; i < D_8006AEE8; i++) {
func_80034DFC(*(short *)(&D_80078F10 + i));
(&D_80078F10)[i] = 0;
}
D_8006AEE8 = 0;
}
}
extern s32 D_80078F10;
extern s32 D_8006AEE8;
void func_80036F98(void) {
D_80078F10 = 0;
D_8006AEE8 = 0;
}
void func_80036FB0(s32 arg0, s32 arg1) {
extern s32 D_8006AEE8;
extern s32 D_80078F10;
f64 hole;
s32 count;
s32 i;
s32 *p;
__asm__ volatile("" :: // !FAKE: keepalive — NEEDED DIFFERS (P36 rung B tus9)
"m"(hole));
if (D_8006AEE8 > 0) {
i = 0;
count = D_8006AEE8;
p = &D_80078F10;
do {
if (*p == arg0) {
*p = arg1;
}
p++;
i++;
} while (i < count);
}
}
#define SHARED_FN func_80037004
#include "shared/main/func_80037004.h"
#undef SHARED_FN
/* func_80037028 -- resource-slot allocator (5 slots x 0x10 bytes at 0x80076244).
*
* MATCHING NOTES (P31 second pass, cookbook §31 / sched.md S1+S5):
*
* 1) The slot table MUST be modelled as struct arrays with symbol+scaled-index
* addressing (`sw $5,D_80076240+4($4)`), not as six independent `u8 X[]`
* externs indexed by a byte offset. With separate symbols gcc hoists the
* D_80064D49 load chain to the top of the block and sinks the mark-used
* store (37 mismatches); with the struct form the block is exact.
*
* 2) TWO overlapping bases are used on purpose (D_80076240 for the words,
* D_80076244 for the bytes) so that EVERY field access has a NON-ZERO
* constant offset from its base symbol. sched.c:memrefs_conflict_p reaches
* find_symbolic_term() -- and therefore proves "distinct symbols, no alias"
* -- only for the plain `(plus reg symbol_ref)` form. A zero-offset store
* thus loses its dependence on the later D_80064D49 / D_800A463C loads,
* becomes ready immediately and floats to the bottom of the block. With a
* single base at D_80076244 the `unk00 = val` store did exactly that
* (19 mismatches). Every offset here is non-zero, so all four leading
* stores stay pinned behind the loads and are emitted in source order.
* Final addresses are unchanged: D_80076240+4 == D_80076244, +8 == 248,
* +12 == 24C; D_80076244+12 == D_80076250, +13 == 251, +14 == 252.
*
* 3) `D_8007622C[0]` (not a plain scalar) is required by the /s asymmetry in
* sched.c:true_dependence -- a non-MEM_IN_STRUCT_P, non-varying store is
* assumed not to alias a MEM_IN_STRUCT_P varying load, so the D_800A463C
* reload hoisted above it. Making the store an ARRAY_REF sets /s, kills
* the exclusion clause, and pins the reload after it.
*
* 4) D_80076248 is deliberately never named: src/800.c already declares it as
* `extern Rsc16 D_80076248[]`, and a second `extern u8 D_80076248[]` here
* would be a conflicting-types error at bank time.
*/
extern Slot16A D_80076240[];
extern Slot16 D_80076244[];
extern Elm12 D_80064D49[];
extern Ent24 D_800A463C[];
extern u8 D_80076251;
extern s32 D_8007622C[];
extern W32 D_80076228;
extern W8 D_80076243;
extern W8 D_80076242;
extern W32 D_80076294;
extern W32 D_80076238;
extern s32 D_8007629C;
void func_80037028(s32 base, s32 val) {
s32 slot;
s32 i;
s32 b;
for (slot = 0, i = 0; slot < 5; slot++, i += 0x10) {
if ((&D_80076251)[i] == 0) {
break;
}
}
if (slot < 5) {
D_80076244[slot].unk0D = 1;
D_80076240[slot].unk04 = val;
D_80076244[slot].unk0C = 0;
D_80076240[slot].unk08 = base;
b = D_80064D49[base].unk00;
D_80076244[slot].unk0E = b;
D_80076240[slot].unk0C = D_800A463C[b].unk00;
if (slot == 0) {
s32 r;
D_8007622C[0] = val;
r = D_800A463C[b].unk00;
D_80076228.v = val;
D_80076240[0].unk00 = 0;
D_80076243.v = 2;
D_80076242.v = 0;
D_80076294.v = 0;
D_80076238.v = r;
}
}
D_8007629C = 0;
}
/* The 5-entry, 0x10-stride CD-resource slot table. src/800.c already declares the SAME
* memory as `Rsc16 D_80076248[]` (base = 0x80076248, .unk09 = D_80076251, .unk0A = D_80076252);
* this function also touches the word 4 bytes BELOW that base, so the array is spelled from
* D_80076244 here (offsets shift by -4; the emitted %lo values are identical, and every one of
* D_80076244/48/4C/50/51/52 is a relocation symbol in this function's own .s).
* .unk00 = D_80076244 .unk04 = D_80076248 .unk08 = D_8007624C
* .unk0C = D_80076250 .unk0D = D_80076251 .unk0E = D_80076252
* 0x80076244 + 5*0x10 == 0x80076294, which is the next scalar this function clears. */
/* 2-byte stride u16 table. Declared as an array-of-STRUCT (cookbook §18) so gcc folds
* %lo(D_80065438) into each indexed load instead of materialising the base into a register
* (a plain `extern u16 D_80065438[]` CSEs the two accesses into one lui/addiu/addu base). */
/* THE TAIL SCHEDULE LEVER (gcc-2.7.2 sched.c:817 true_dependence / :845 anti_dependence).
* The `if (i == 0)` block interleaves the varying-address load `D_800A463C[k].unk00`
* (MEM_IN_STRUCT_P=1, rtx_addr_varies_p=1) with fixed-address stores to these scalars.
* true_dependence's last guard reads
* ! (MEM_IN_STRUCT_P (x) && rtx_addr_varies_p (x) && GET_MODE (x) != QImode
* && ! MEM_IN_STRUCT_P (mem) && ! rtx_addr_varies_p (mem))
* so a /s VARYING load and a plain NON-/s FIXED store are declared non-aliasing — every
* store/load edge disappears, the load floats to the top of the block and the whole tail
* comes out permuted. Declaring these scalars as single-field structs sets MEM_IN_STRUCT_P
* on their MEMs too, which fails `! MEM_IN_STRUCT_P (mem)` and restores the real
* store->load / load->store edges. The symbol names are untouched (offset 0 of a 1-field
* struct), so every relocation is still exactly D_8007622C / D_80076228 / ... as in the .s. */
extern Slot16 D_80076244[];
extern W32 D_80076228;
extern s32 D_8007622C[];
extern W32 D_80076238;
extern Slot16A D_80076240[];
extern W8 D_80076242;
extern W8 D_80076243;
extern W32 D_80076294;
extern s32 D_8007629C; /* src/800.c already declares this one as `extern s32` */
extern u8 D_800BA320[];
extern H2 D_80065438[];
extern s32 D_800652F0[];
extern Ent24 D_800A463C[];
extern s32 D_800A469C;
extern s16 D_800A46A0;
extern s16 D_800A46A2;
extern u8 D_800A46B0;
extern void func_800415A8(s32);
void func_80037144(s32 idx) {
s32 i;
s32 k;
s32 t;
s32 v;
s32 one;
s32 ent;
for (i = 0; i < 5; i++) {
if (D_80076244[i].unk0D == 0) {
break;
}
}
if (i < 5) {
one = 1;
D_80076244[i].unk00 = (s32)D_800BA320;
/* scheduling barrier: the slot stores and the D_80065438 load DO disambiguate here
* (both /s and both varying -> memrefs_conflict_p:614 falls through to
* find_symbolic_term and the two symbols differ), so without this gcc hoists the
* D_80065438 load above all the slot stores and permutes the head block.
* Emits zero instructions. */
__asm__ __volatile__("" ::: "memory"); // !FAKE: barrier memory — NEEDED DIFFERS (P36 rung B tus9)
D_80076244[i].unk0C = 0;
D_80076244[i].unk0D = one;
D_80076244[i].unk04 = idx | 0x2000;
D_80076244[i].unk0E = 4;
v = D_800652F0[D_80065438[idx].f0];
D_800A469C = v;
D_80076244[i].unk08 = v;
k = 4;
if (D_800A46B0 == 0) {
if (D_800A46A0 == (D_80065438[idx].f0 | 0x4000)) {
D_80076244[i].unk04 |= 0x1000;
goto after;
}
t = D_800A46A2;
D_800A46B0 = one;
} else {
t = D_800A46A2;
}
if (t >= 0) {
func_800415A8(t);
D_800A46A2 = -1;
}
after:
if (i == 0) {
D_8007622C[0] = (s32)D_800BA320;
ent = D_800A463C[k].unk00;
D_80076228.v = (s32)D_800BA320;
D_80076240[0].unk00 = 0;
D_80076243.v = 1;
D_80076242.v = 0;
D_80076294.v = 0;
D_80076238.v = ent;
}
}
D_8007629C = 0;
}
#define SHARED_FN func_80037334
#include "shared/main/func_80037004.h"
#undef SHARED_FN
extern s32 D_8007623C;
void func_80037358(int posInt) {
D_8007623C = posInt;
}
extern u8 D_80076251; /* Law 2: exact form from src/shared/clearTbl40.h */
extern u8 D_80076220[];
extern u8 D_80076250[];
void *func_80037368(int *out) {
int count = 0;
u8 *ptr = D_80076220;
int i;
for (i = 0; i < 0x50; i += 0x10) {
*ptr = 0;
ptr++;
if ((&D_80076251)[i] != 0) {
D_80076220[count] = D_80076250[i];
count++;
}
}
*out = count;
return D_80076220;
}
typedef struct {
s16 unk00;
u8 pad02[4];
u16 unk06;
} StructA4E88;
/* Law 2: the destination TU (src/800.c) already declares D_80065438 as an array-of-struct
* (H2 = { u16 f0; }) rather than a plain u16[] — refuse-TYPE(D_80065438, u16 vs H2).
* Adopt the TU's spelling verbatim; the use site indexes .f0 instead of dereferencing a u16*. */
extern StructA4E88 D_800A4E88;
extern u8 D_800BA320[];
extern Rsc16 D_80076248[]; /* .unk09 = D_80076251, .unk0A = D_80076252 */
extern u8 D_80076251; /* Law 2: exact form from src/shared/clearTbl40.h (see func_80037368) */
extern u8 D_80076250[];
extern u8 D_80076298;
extern H2 D_80065438[];
extern void func_8002D7FC(s32 arg0);
extern void func_8002FDE8(s32 arg0, void *arg1);
void func_800373D0(void) {
StructA4E88 *sp2;
u8 *sp3;
Rsc16 *p;
s32 i;
sp2 = &D_800A4E88;
sp3 = D_800BA320;
p = D_80076248;
i = 0;
do {
if ((&D_80076251)[i] != 0) {
if (D_80076250[i] != 0) {
if (p->unk00 & 0x3000) {
sp2->unk00 = p->unk00 & 0xFFF;
sp2->unk06 |= 0x20;
func_8002D7FC((s32) sp3);
if (!(p->unk00 & 0x1000)) {
func_8002FDE8(D_80065438[sp2->unk00].f0, sp3 + 0x7000);
}
}
}
}
p++;
i += 0x10;
} while ((s32) p < (s32) &D_80076298);
}
int func_800374CC(int *out)
{
extern W8 D_80076243;
extern s32 D_8007623C;
s32 x = D_80076243.v;
if (x != 4 && x != 0 && x != 5) {
*out = D_8007623C;
return 0;
}
return 1;
}
extern s32 D_8007629C;
extern u8 D_8006AEF4;
extern u8 D_80076298;
extern Rsc16 D_80076248[]; /* .unk09 = D_80076251, .unk0A = D_80076252 */
extern Rsc12 D_80064D4A[];
extern Rsc24 D_800A4640[];
extern s16 D_800C5328[];
extern s16 D_800C532A[];
extern s32 func_8003C4F0(s32);
extern void func_800415A8(s32);
extern void func_80031A98(void);
s32 func_8003750C(void) {
s32 i;
s32 val;
s32 k;
s32 h;
switch (D_8007629C) {
case 0:
if (D_8006AEF4 & 2) {
return 0;
}
D_8006AEF4 |= 2;
D_8007629C = 1;
/* fallthrough */
case 1:
if (D_8006AEF4 & 1) {
if (func_8003C4F0(0) == 0) {
return 0;
}
}
D_8007629C = D_8007629C + 1;
/* fallthrough */
case 2:
for (i = 0; i < 5; i++) {
if (D_80076248[i].unk09 == 0) {
continue;
}
val = D_80076248[i].unk00;
k = D_80076248[i].unk0A;
if (val & 0x6000) {
continue;
}
h = D_800A4640[k].unk04;
if (h != 0 && h != D_80064D4A[val].unk00) {
D_800C532A[D_800A4640[k].unk08 * 2] = -1;
D_800A4640[k].unk04 = 0;
D_800A4640[k].unk08 = 0;
}
if (D_800A4640[k].unk10 != 0) {
continue;
}
D_800A4640[k].unk10 = 1;
D_800C5328[D_800A4640[k].unk00 * 2] = -1;
if (D_800A4640[i].unk02 >= 0) {
func_800415A8(D_800A4640[i].unk02);
D_800A4640[i].unk02 = -1;
}
func_80031A98();
}
D_8007629C = 0;
D_80076298 = 0;
return 1;
default:
return 0;
}
}
typedef struct { u8 v; } W8_;
extern W8_ D_80076242_ __asm__("D_80076242");
extern u8 D_8006AEF4;
extern s32 func_8003C4F0(s32);
extern void func_800373D0(void);
int func_8003775C(void) {
u32 t;
if (D_80076242_.v != 0) {
if (func_8003C4F0(0) == 0) {
return 0;
}
D_80076242_.v = 0;
t = D_8006AEF4;
} else {
t = D_8006AEF4;
}
D_8006AEF4 = t & 0xFC;
func_800373D0();
return 1;
}
/* func_800377D8 -- the CD stream loader's CdlReadN ready-callback (main/src/800.c, 316 ins).
*
* ⚠ BANKING PREREQUISITE (§376/§378, step 1 ONLY): src/800.c:21344 already carries
* extern void func_800377D8(void); // this loader's CdlReadN ready-callback
* which CONFLICTS with this definition's `(u8 arg0)`. No-proto it before gating:
* tools/fix_arity_callers.py --binary main --funcs func_800377D8 --any-proto --apply ...
* Step 2 (cast_self_callers) is NOT needed: the only two uses (src/800.c:21488/21490)
* take its ADDRESS through a `(void *)` cast, they never call it.
*
* MATCHING NOTES -- four levers, each measured on this function:
*
* 1) THE SCALARS MUST NOT BE THE TU's `W8`/`W32` SINGLE-FIELD STRUCTS HERE. With
* `W8 D_80076243` / `W32 D_80076228` / `W32 D_80076242` cc1 materialises each symbol's
* ADDRESS into a callee-saved register ($s2/$s3/$s4, frame 0x20 -> 0x28) and every access
* becomes `0($sN)`; the target folds `%lo` into each mem. Cookbook index L18
* ("an extra `la` / the address hoisted into a callee-saved register across calls" ->
* §20 + gcc-2.7.2-map/cse_expr.md §H) names the antidote: the §37 asm-label alias keeps the
* direct `%lo` mem form. Hence gD_/hD_/sD_ aliases -- they also cannot conflict with the
* TU's existing `extern W8 D_80076243;` etc. (Law 2 satisfied by construction.)
* D_80076294 was measured BOTH ways: as `W32` it hoists too, so it is aliased as well.
*
* 2) TWO ALIASES FOR D_80076240, DELIBERATELY (§326). The target reads the counter `lhu`
* (u16, the +1 RMW) in cases 2/3 and `lh` (s16) for the two comparisons. Separate decls
* give the two widths AND stop address-CSE from sharing one base register between them.
* Case 1 needs the THIRD form -- a pointer var (§20's global-RMW bullet) -- because the
* target keeps `&D_80076240` in $a0 across the RMW and the `sh $zero,0($a0)` at .L800379E4.
*
* 3) TWO ZERO-BYTE `__asm__ __volatile__("")` FENCES, for two different passes:
* a) in case 1's `= 1` arm: without it gcc's cross-jump merges case 1's one-insn
* `D_80076243 = 1; j .L80037BC0` block into case 3's identical copy (-2 ins, 314/316).
* gcc-2.7.2 compares a jump's predecessors against its TARGET LABEL's predecessors with
* a 2-insn minimum -- which is exactly why the target merges the `= 2` arm into .L80037BB8
* (2 insns: the `sb` + the `li 2`) but leaves the `= 1` arm and both `= 4` blocks alone.
* b) in the shared .L80037BC0 tail, between the two zero-stores and the D_80076294 reload:
* the /s-vs-fixed asymmetry in sched.c:true_dependence lets the (varying, /s) D_80076244[]
* loads float above the (fixed, non-/s) `sb D_80076298`/`sh D_80076240`, permuting the
* whole tail (11 -> 25 rows). Same class as the sched note above func_80037144.
*
* 4) THE $v0/$v1 PIN IN CASE 1 (memory: "don't conclude unsteerable -- try register pins").
* Last 5 rows: the target emits `sh` (counter) BEFORE `sw D_80076228`, but loads
* D_80076228 BEFORE the counter. Written in-place the stores keep source order (the
* pointer store is varying -> no disambiguation) and come out sw-then-sh; split through a
* temp the stores are right but sched1 swaps the two LOADS and the registers with them.
* Splitting AND pinning the two temps to $2/$3 gives both: the second set on each pseudo
* also rotates local-alloc's priority (cse_expr.md §H(2)). 0 residual.
*/
#include "psyq/libcd.h" /* CdlLOC / CdPosToInt -- the TU already includes it */
/* 0x10 */
/* 0x10 */
extern u8 D_8006AEF4;
extern u8 D_800762A0[];
extern s32 D_8007623C;
extern s32 gD_80076228 __asm__("D_80076228");
extern s32 gD_80076238 __asm__("D_80076238");
extern Slot16A D_80076240[];
extern u16 hD_80076240 __asm__("D_80076240");
extern s16 sD_80076240 __asm__("D_80076240");
extern u8 gD_80076242 __asm__("D_80076242");
extern u8 gD_80076243 __asm__("D_80076243");
extern Slot16 D_80076244[];
extern Rsc16 D_80076248[];
extern u8 D_80076250[];
extern u8 D_80076251;
extern s32 gD_80076294 __asm__("D_80076294");
extern u8 D_80076298;
extern s32 func_80043994(void *buf, s32 n);
extern s32 func_8003C4F0(s32);
extern void func_8003C498(s32);
extern void SpuWrite(s32, s32);
void func_800377D8(u8 arg0) {
s32 *pInt;
u8 *pSt;
s32 pos;
s32 idx;
s32 ptr;
s32 nxt;
u16 *pCnt;
s32 cnt;
if (arg0 != 1) goto err;
if (func_80043994(D_800762A0, 3) == 0) goto err;
pos = CdPosToInt((CdlLOC *)D_800762A0);
pInt = &D_8007623C;
if (pos != *pInt) goto err;
*pInt = pos + 1;
switch (gD_80076243) {
case 1:
if (func_80043994((void *)gD_80076228, 0x200) == 0) goto err;
if (sD_80076240 == 0 && *(s32 *)gD_80076228 != 0x7671732E) {
D_80076298 = 1;
D_80076250[gD_80076294 * 16] = 2;
goto err;
}
{
register s32 rnxt __asm__("$2"); // !FAKE: pin $2 — NEEDED DIFFERS (P36 rung B tus9)
s32 rcnt;
pCnt = &hD_80076240;
rnxt = gD_80076228 + 0x800;
rcnt = *pCnt + 1;
*pCnt = rcnt;
gD_80076228 = rnxt;
if ((s16)rcnt != 0xE) {
return;
}
}
if (D_80076248[gD_80076294].unk00 & 0x1000) {
D_80076250[gD_80076294 * 16] = 1;
idx = gD_80076294 + 1;
gD_80076294 = idx;
if (idx < 5 && (&D_80076251)[idx * 16] != 0) {
if (D_80076248[idx].unk00 & 0x2000) {
gD_80076243 = 1;
__asm__ __volatile__(""); // !FAKE: barrier — NEEDED DIFFERS (P36 rung B tus9)
} else {
gD_80076243 = 2;
}
D_80076298 = 0;
hD_80076240 = 0;
__asm__ __volatile__(""); // !FAKE: barrier — NEEDED DIFFERS (P36 rung B tus9)
gD_80076228 = D_80076244[gD_80076294].unk00;
gD_80076238 = D_80076244[gD_80076294].unk08;
return;
}
gD_80076243 = 4;
D_8006AEF4 = D_8006AEF4 & 0xFD;
return;
}
gD_80076243 = 2;
*pCnt = 0;
return;
case 2:
if (func_80043994((void *)gD_80076228, 0x200) == 0) goto err;
gD_80076228 = gD_80076228 + 0x800;
hD_80076240 = hD_80076240 + 1;
if ((s16)hD_80076240 != 7) {
return;
}
gD_80076243 = 3;
hD_80076240 = 0;
if (gD_80076242 != 0) {
if (func_8003C4F0(0) == 0) {
return;
}
gD_80076242 = 0;
}
return;
case 3:
if (func_80043994((void *)gD_80076228, 0x200) == 0) goto err;
hD_80076240 = hD_80076240 + 1;
if (gD_80076242 != 0) {
if (func_8003C4F0(0) == 0) goto err;
}
if (((s32 (*)(s32))func_8003C498)(gD_80076238) == 0) goto err;
ptr = gD_80076228;
if (sD_80076240 == *(s16 *)(ptr - 4)) {
SpuWrite(ptr, *(s16 *)(ptr - 2));
gD_80076242 = 1;
D_8006AEF4 = D_8006AEF4 | 1;
D_80076250[gD_80076294 * 16] = 1;
idx = gD_80076294 + 1;
gD_80076294 = idx;
if (idx < 5 && (&D_80076251)[idx * 16] != 0) {
if (D_80076248[idx].unk00 & 0x2000) {
gD_80076243 = 1;
} else {
gD_80076243 = 2;
}
D_80076298 = 0;
hD_80076240 = 0;
__asm__ __volatile__(""); // !FAKE: barrier — NEEDED DIFFERS (P36 rung B tus9)
gD_80076228 = D_80076244[gD_80076294].unk00;
gD_80076238 = D_80076244[gD_80076294].unk08;
return;
}
gD_80076243 = 4;
D_8006AEF4 = D_8006AEF4 & 0xFD;
return;
}
SpuWrite(ptr, 0x800);
gD_80076242 = 1;
D_8006AEF4 = D_8006AEF4 | 1;
gD_80076238 = gD_80076238 + 0x800;
return;
}
return;
err:
pSt = &gD_80076243;
if (*pSt == 0) return;
if (*pSt == 4) return;
if (*pSt == 5) return;
*pSt = 5;
D_8006AEF4 = D_8006AEF4 & 0xFD;
}
extern s32 D_800BA0F8;
void func_80037CC8(void) {
D_800BA0F8 = 0;
}
extern u8 D_8006AEF4;
extern s32 D_800BA0F8;
int func_80037CD8(void *arg) {
if ((D_8006AEF4 & 0x2) != 0) {
s32 *handler = (s32 *)&D_800BA0F8;
if (*handler != 0) {
int result = ((int (*)(void *))*handler)(arg);
if (result != 0) {
u8 flags = D_8006AEF4;
*handler = (s32)arg;
D_8006AEF4 = flags & 0xFD;
return 1;
}
return 0;
}
}
D_800BA0F8 = (s32)arg;
D_8006AEF4 &= 0xFD;
return 1;
}
extern u8 D_8006AEF4;
extern s32 D_800BA0F8;
void func_80037D74(void) {
D_8006AEF4 &= 0xFD;
D_800BA0F8 = 0;
}
extern u8 *D_800762B0;
extern u8 D_800A4EFE[];
extern s32 D_80073140[][1]; /* [][1] spelling: load-bearing for func_800391D4 (S79 lever; §500-I) */
extern u8 D_800C6DE0[];
extern u8 D_800C6DE4[];
extern u8 D_800C6DEC[];
extern u8 D_800C6DEE[];
extern u8 D_800C6E2A[];
extern u8 D_800C6E2B[];
extern u8 D_800C6E2C[];
extern u8 D_800C6E2D[];
extern u8 D_800C6E2E[];
extern u8 D_800B9EC8[];
extern u8 D_800B9ED2[];
extern u8 D_800B9ED3[];
extern s32 D_80079A68;
extern void func_8003D424(s32 *);
void func_80037D98(void) {
s32 i;
s32 offset;
s32 val;
s32 *table;
D_800762B0 = D_800A4EFE;
i = 0;
table = (s32 *)D_80073140;
offset = 0;
while (i < 0x10) {
val = *table;
table++;
i++;
D_800C6E2A[offset] = 0;
D_800C6E2B[offset] = 0;
D_800C6E2C[offset] = 0;
D_800C6E2D[offset] = 0;
*(s16 *)&D_800C6DEC[offset] = 0;
*(s16 *)&D_800C6DEE[offset] = 0;
*(s32 *)&D_800C6DE4[offset] = 0;
D_800C6E2E[offset] = 0;
*(s32 *)&D_800C6DE0[offset] = val;
offset += 0x60;
}
i = 0;
offset = 0;
for (; i < 2; i++) {
D_800B9ED3[offset] = 0;
D_800B9ED2[offset] = 0;
*(s16 *)&D_800B9EC8[offset] = i;
offset += 0x1FC;
}
func_8003D424(&D_80079A68);
}
extern u8 D_800C6E2E[];
void func_80037EA0(void)
{
extern void func_8003D3B4(s32, s32);
register u8 *p __asm__("$16"); // !FAKE: pin $16 — NEEDED DIFFERS (P36 rung B tus9)
s32 i;
u32 mask;
i = 0;
mask = 0xFFF9FFFF;
p = D_800C6E2E;
do {
if (p[-4] != 0 && p[-1] == 0 && p[0] != 0) {
func_8003D3B4(i, 8);
*(u32 *)(p - 0x4A) &= mask;
p[0] = 0;
}
i++;
p += 0x60;
} while (i < 0x10);
}
void func_80037F3C(void)
{
/* TU-absent names, block scope */
extern u8 D_800C6DD0[];
extern void func_8003B250(s32, void *);
register u8 *p __asm__("$16"); // !FAKE: pin $16 — NEEDED DIFFERS (P36 rung B tus9)
s32 i;
u8 *base;
base = D_800C6DD0;
i = 0;
p = base + 0x5E;
do {
if (p[-4] != 0 && p[-1] != 0) {
func_8003B250(i, base + 0x10);
*(u32 *)(p - 0x4A) = 0;
p[-1] = 0;
p[0] = 0;
}
i++;
p += 0x60;
base += 0x60;
} while (i < 0x10);
}
/* --- TU context as in src/800.c (file-scope, verbatim spellings) --- */
extern s32 D_800A2B98;
extern s32 D_800A2BA0;
extern s32 D_800C7D20;
extern s32 D_800C7D2C;
extern u8 D_800A4F1D;
extern u8 D_800C6E2E[];
extern void func_8003BE74(s32, s32);
extern void func_80037FC4(void);
void func_80037FC4(void)
{
/* TU-absent names, block scope */
extern u8 D_800C6DD0[];
extern void func_80038A58(void);
extern void func_8003D3B4(s32, s32);
extern void func_8003C23C(s32, s32);
extern void func_8003B250(s32, void *);
register u8 *p __asm__("$16"); // !FAKE: pin $16 — NEEDED DIFFERS (P36 rung B tus9)
s32 i;
u32 mask;
u8 *base;
if (D_800A4F1D == 0) {
func_80038A58();
}
i = 0;
mask = 0xFFF9FFFF;
p = D_800C6E2E;
do {
if (p[-4] != 0 && p[-1] == 0 && p[0] != 0) {
func_8003D3B4(i, 8);
*(u32 *)(p - 0x4A) &= mask;
p[0] = 0;
}
i++;
p += 0x60;
} while (i < 0x10);
if ((D_800A2B98 & 0xFFFF) != 0) {
func_8003C23C(0, D_800A2B98 & 0xFFFF);
D_800A2B98 &= 0xFF0000;
}
if ((D_800A2BA0 & 0xFFFF) != 0) {
func_8003BE74(0, D_800A2BA0 & 0xFFFF);
D_800A2BA0 &= 0xFF0000;
}
base = D_800C6DD0;
i = 0;
p = base + 0x5E;
do {
if (p[-4] != 0 && p[-1] != 0) {
func_8003B250(i, base + 0x10);
*(u32 *)(p - 0x4A) = 0;
p[-1] = 0;
p[0] = 0;
}
i++;
p += 0x60;
base += 0x60;
} while (i < 0x10);
if ((D_800C7D20 & 0xFFFF) != 0) {
func_8003C23C(1, D_800C7D20 & 0xFFFF);
D_800C7D20 &= 0xFF0000;
}
if ((D_800C7D2C & 0xFFFF) != 0) {
func_8003BE74(1, D_800C7D2C & 0xFFFF);
D_800C7D2C &= 0xFF0000;
}
}
extern u8 D_800B9CD8[];
void func_8003819C(s32 a0, s32 a1, s32 a2, s32 a3) {
u8 *base;
s16 idx;
idx = (s16)a1;
if (idx <= 0) {
base = &D_800B9CD8[((a0 << 7) - a0) << 2];
*(s16 *)(base + (idx << 3) + 0x16) = a2;
*(s16 *)(base + (idx << 3) + 0x14) = a3;
*(u8 *)(base + (idx << 3) + 0x18) = 1;
*(u8 *)(base + 0x1F4) = 1;
}
}
extern u8 D_800B9CF0[];
s32 func_800381E4(s32 a0, s32 a1) {
s32 v0;
a1 = (a1 << 16) >> 13;
v0 = (a0 << 7) - a0;
v0 = v0 << 2;
a1 = a1 + v0;
return D_800B9CF0[a1];
}
extern u8 D_800B9CD8[];
extern u8 D_800C1320[];
extern u8 *D_800A6428;
extern s32 func_80038698(void *arg0);
extern s32 func_800387C0(void *arg0);
extern void func_80038838(void *arg0);
s32 func_80038210(s32 a0, s16 a1, s32 a2)
{
u8 *entry;
s32 i;
s32 k;
u8 *q;
s32 v1;
entry = D_800B9CD8;
for (i = 0; i < 2; i++, entry += 0x1FC) {
if (entry[0x1FB] == 0) {
D_800A6428 = entry + 0x1BA;
*(s32 *)entry = a0;
*(s16 *)(entry + 0x1EC) = a1;
*(s32 *)(entry + 0x1E8) = a2;
*(u8 **)(entry + 0x1D8) = D_800C1320;
*(u8 **)(entry + 0x1DC) = D_800C1320 + 0x20;
*(u8 **)(entry + 0x1E0) = D_800C1320 + 0x820;
if (func_80038698(entry) != 0) {
return -1;
}
if (func_800387C0(entry) != 0) {
return -1;
}
func_80038838(entry);
v1 = *(s32 *)entry;
entry[0x1FB] = 1;
*(s32 *)(entry + 4) = v1;
entry[0x1FA] = 0;
for (k = 0xF, q = entry + 0xF; k >= 0; k--, q--) {
q[0x1BA] = 0;
}
return i;
}
}
return -1;
}
extern u8 D_800B9ED2[];
extern u8 D_800B9CD8[];
typedef s32 a32;
void func_80038308(s16 a0)
{
register a32 arg0 asm("$4"); // !FAKE: pin $4 — NEEDED DIFFERS (P36 rung B tus9)
s32 offset;
offset = arg0 * 127;
offset = offset * 4;
D_800B9ED2[offset] = 1;
func_80038908(&D_800B9CD8[offset]);
}
extern u8 D_800B9ECA[];
void func_8003834C(s32 a0, s16 a1) {
s32 offset = ((a0 << 7) - a0) << 2;
*(s16 *)&D_800B9ECA[offset] = a1;
}
extern u8 D_800B9ED3[];
extern u8 D_800B9ED2[];
s32 func_8003836C(s32 a0) {
s32 index;
u8 val;
index = a0 * 127;
index = index * 4;
val = D_800B9ED3[index];
if (val == 0) {
return 0;
}
return D_800B9ED2[index];
}
extern u8 D_800B9CD8[];
extern u8 D_800A4F1D;
extern u8 D_800C6E2D[];
extern s32 D_80073140[][1]; /* [][1] spelling: load-bearing for func_800391D4 (S79 lever; §500-I) */
extern void func_8003916C(s16 arg0);
extern void func_8002EFF8(s32 a0, s32 a1);
void func_800383A4(a0)
s16 a0;
{
u8 *base;
u8 *p;
u8 *q;
u8 *r;
s32 *t;
s32 *table;
s32 i;
s32 j;
s32 one;
register s32 aa __asm__("$2"); // !FAKE: pin $2 — NEEDED DIFFERS (P36 rung B tus9)
__asm__("sll %0, %1, 7\n\tsubu %0, %0, %1\n\tsll %0, %0, 2" : "=r"(aa) : "r"(a0)); // !FAKE: instruction sll — REFUSED instruction `sll` has no C spelling in the table (P36 rung B tus9)
base = &D_800B9CD8[aa];
p = base + 0x1A;
i = 0;
one = 1;
table = (s32 *)D_80073140;
D_800A4F1D = 1;
base[0x1FA] = 0;
do {
q = p + 9;
j = 0;
r = D_800C6E2D;
t = table;
do {
if (*q++ != 0) {
r[1] = one;
r[0] = 0;
func_8003916C((s16)j);
func_8002EFF8(0, *t);
}
t++;
j++;
r += 0x60;
} while (j < 0x10);
i++;
p += 0x1A;
} while (i < 0x10);
D_800A4F1D = 0;
}
extern u8 D_800A4F1D;
extern s32 D_80073140[][1]; /* [][1] spelling: load-bearing for func_800391D4 (S79 lever; §500-I) */
extern u8 D_800B9CD8[];
extern u8 D_800C6E2D[];
extern void func_8002EFF8(s32 a0, s32 a1);
extern void func_8003916C(s16 arg);
void func_800384A8(s16 arg0) {
register s32 raw __asm__("$4"); // !FAKE: pin $4 — NEEDED DIFFERS (P36 rung B tus9)
u8 *entry;
u8 *p;
u8 *q;
s32 j;
u8 *b;
s32 *m;
s32 *mb;
s32 i;
s32 one;
entry = &D_800B9CD8[raw * 0x1FC];
p = entry + 0x1A;
i = 0;
one = 1;
mb = (s32 *)D_80073140;
D_800A4F1D = 1;
entry[0x1FA] = 0;
for (; i < 0x10; i++) {
q = p + 9;
j = 0;
b = D_800C6E2D;
m = mb;
for (; j < 0x10; j++) {
if (*q++ != 0) {
b[1] = one;
b[0] = 0;
func_8003916C(j);
func_8002EFF8(0, *m);
}
m++;
b += 0x60;
}
p += 0x1A;
}
D_800A4F1D = 0;
*(s32 *)entry = *(s32 *)(entry + 4);
}
void func_800385C0(s16 a0)
{
extern u8 D_800C6E2A[];
extern u8 D_800B9ED2[];
extern u8 D_800B9ED3[];
register s32 a0v __asm__("$4"); // !FAKE: pin $4 — NEEDED DIFFERS (P36 rung B tus9)
register u8 *v1 __asm__("$3"); // !FAKE: pin $3 — NEEDED DIFFERS (P36 rung B tus9)
s32 a1;
for (a1 = 0, v1 = D_800C6E2A; a1 < 0x10; a1++, v1 += 0x60) {
if (v1[2] != 0 && *(s16 *)(*(s32 *)(v1 - 0xA) + 0x1F0) == a0v) {
v1[2] = 0;
v1[0] = 0;
}
}
D_800B9ED2[((a0v << 7) - a0v) << 2] = 0;
D_800B9ED3[((a0v << 7) - a0v) << 2] = 0;
}
extern u8 D_800B9E92[];
void func_80038638(s32 a0, s32 a1) {
u8 *ptr;
s32 offset;
offset = a0 * 127;
offset = offset * 4;
ptr = D_800B9E92 + offset;
*(ptr + a1) |= 1;
}
extern u8 D_800B9E92[];
void func_80038668(s32 a0, s32 a1) {
s32 offset = ((a0 << 7) - a0) << 2;
char *baseptr = (char *)D_800B9E92 + offset;
*(baseptr + a1) &= 0xFE;
}
s32 func_80038698(void *arg0) {
u8 *p;
register u32 len asm("$6"); // !FAKE: pin $6 — NEEDED DIFFERS (P36 rung B tus9)
u32 hi;
s32 div;
p = *(u8 **)arg0;
*(u8 **)arg0 = p + 1;
len = p[0];
*(u8 **)arg0 = p + 2;
len |= p[1] << 8;
*(u8 **)arg0 = p + 3;
len |= p[2] << 16;
*(u8 **)arg0 = p + 4;
len |= p[3] << 24;
if (len != 0x6468544D) {
return -1;
}
*(u8 **)arg0 = p + 5;
len = p[4];
*(u8 **)arg0 = p + 6;
len <<= 8;
len |= p[5];
*(u8 **)arg0 = p + 7;
len <<= 8;
len |= p[6];
*(u8 **)arg0 = p + 8;
len <<= 8;
len |= p[7];
hi = p[8];
{
u32 s = hi << 8;
s |= p[9];
if (s != 0) {
return -1;
}
}
hi = p[10];
{
u32 t = hi << 8;
t |= p[11];
if ((s16)t != 1) {
return -1;
}
}
hi = p[12];
{
u32 u = hi << 8;
u |= p[13];
div = (s16)u;
}
if (div & 0x8000) {
return -1;
}
*(u16 *)((char *)arg0 + 0x1E6) = div & 0x7FFF;
*(u8 **)arg0 += len;
return 0;
}
s32 func_800387C0(void *arg0) {
u8 *p;
s32 v;
p = *(u8 **)arg0;
(*(s32 *)arg0)++;
v = p[0];
(*(s32 *)arg0) = p + 2;
v |= p[1] << 8;
(*(s32 *)arg0) = p + 3;
v |= p[2] << 16;
(*(s32 *)arg0) = p + 4;
v |= p[3] << 24;
if (v != 0x6B72544D) {
return -1;
}
(*(s32 *)arg0) = p + 8;
return 0;
}
void func_80038838(void *arg0)
{
unsigned char *a3;
register unsigned char *a1 asm("$5"); // !FAKE: pin $5 — NEEDED DIFFERS (P36 rung B tus9)
unsigned char *v1;
register unsigned char *v0 asm("$2"); // !FAKE: pin $2 — NEEDED DIFFERS (P36 rung B tus9)
int a2;
int v0_c;
int const1;
int const2;
int const3;
a3 = (unsigned char *)arg0 + 0x1A;
a2 = 0;
const1 = 0x40;
const2 = 0x7F;
a1 = (unsigned char *)arg0 + 0x1B;
do {
v1 = a3 + 0x9;
v0_c = 0xF;
a3[0x0] = a2;
*(unsigned short *)(a1 + 0x1) = const1;
a1[0x3] = const1;
a1[0x6] = 0;
a1[0x0] = const2;
do {
v1[0x0] = 0;
v0_c--;
v1++;
} while (v0_c >= 0);
a2++;
a1 += 0x1A;
a3 += 0x1A;
} while (a2 < 0x10);
a2 = 0;
const3 = 0x4000;
v0 = (unsigned char *)arg0;
do {
v0[0x18] = 0;
*(unsigned short *)(v0 + 0x12) = const3;
v0 += 0x8;
a2++;
} while (a2 <= 0);
*(int *)((unsigned long)arg0 + 0x8) = 1;
*(int *)((unsigned long)arg0 + 0x1D0) = 0xE10;
*(int *)((unsigned long)arg0 + 0x1D4) = 0xE10;
*(int *)((unsigned long)arg0 + 0x1CC) = 0xE10;
*(unsigned char *)((unsigned long)arg0 + 0x1F4) = 0;
*(unsigned short *)((unsigned long)arg0 + 0x1E4) = 0x78;
*(unsigned char *)((unsigned long)arg0 + 0x1F7) = 0;
*(unsigned char *)((unsigned long)arg0 + 0x1F8) = 0;
*(unsigned char *)((unsigned long)arg0 + 0x1F9) = 0;
*(unsigned char *)((unsigned long)arg0 + 0x1FA) = 0;
*(unsigned char *)((unsigned long)arg0 + 0x1F6) = 0;
}
s32 func_800388E8(void *arg0, s16 arg1) {
return arg1 * *(s16 *)((u8 *)arg0 + 0x10) * 4 >> 16;
}
void func_80038908(unsigned char *arg0) {
extern short D_800A4EF8;
extern unsigned short D_800A4EE0;
int counter;
int acc;
unsigned short *ptr;
acc = D_800A4EF8 << 7;
acc *= D_800A4EE0;
ptr = (unsigned short *)(arg0 + 0x12);
counter = 0;
acc >>= 14;
do {
acc *= *ptr;
acc >>= 14;
counter--;
ptr += 4;
} while (counter >= 0);
*(unsigned short *)(arg0 + 0x10) = (unsigned short)acc;
}
extern u8 *D_800762B0;
extern u8 D_800762B4[];
extern u8 D_800C6E2A[];
void func_80038958(void) {
u8 *a3;
u8 *a2;
s32 a1;
register u8 *a0 __asm__("$4"); // !FAKE: pin $4 — NEEDED DIFFERS (P36 rung B tus9)
s32 t0;
s32 v0;
register s32 v1 __asm__("$3"); // !FAKE: pin $3 — NEEDED DIFFERS (P36 rung B tus9)
a3 = D_800762B0;
a2 = D_800762B4;
a1 = 0;
t0 = 3;
a0 = D_800C6E2A;
while (a1 < 0x10) {
v0 = *a3;
if (v0 == 0 || v0 == t0) {
if (*a2 == 0) {
v0 = *a0;
a0[1] = 0;
if (v0 != 0) {
v0 = *(s16 *)(a0 - 0x54);
v1 = v0 << 1;
v1 = v1 + v0;
v1 = v1 << 2;
v1 = v1 + v0;
v0 = *(s32 *)(a0 - 0xA);
v1 = v1 << 1;
v0 = v0 + v1;
v0 = v0 + a1;
*(u8 *)(v0 + 0x23) = 0;
a0[0] = 0;
}
}
}
a1++;
a0 += 0x60;
a3++;
a2++;
}
}
extern u8 *D_800762B0;
extern u8 D_800762B4[];
s32 func_80038A00(void) {
u8 *ptr1 = D_800762B0;
u8 *ptr2 = D_800762B4;
s32 i = 0;
while (i < 0x10) {
if (*ptr1 == 0x2 && *ptr2 == 0) {
return i;
}
i++;
ptr1++;
ptr2++;
}
return -1;
}
/* func_80038A58 (main, 347 ins) -- MATCH 347/347 (Fable escalation, S69e1).
* Levers (from the S69m1 opus draft, kept verbatim):
* - Shape: loop 2 is func_80038958's body verbatim (same TU, same pinned regs);
* the two accumulator loops are func_80038908's body inlined ($s1 == base+0x10).
* - S5a/S336 cross-jump barrier: zero-byte asm at the bottom of the first ramp arm.
* - 4-pin div block (cur/quot $v1/$a1 + loop copies c/r $a0/$s0 hoisted above the
* `cur != 0` test); both `-` results through a $v0-pinned temp.
* - ONE shared counter k ($t1) for the C68/D80/E30 loops; block B's own ($a2).
* THE ESCALATION FIX (closed the last 2, idx 178/179 — block-A acc preheader):
* target = `mult; addu $v1,0,0; addiu $a1,$s3,0x12; mflo`; every C spelling emits
* the pair swapped. ROOT CAUSE (read from tools/reference/gcc-2.7.2/sched.c
* priority():1425 + rank_for_schedule():2385, confirmed in the -dR bb trace):
* sched2 runs BACKWARD; the c2-init's ANTI-dep on `mult $a0,$v1` propagates the
* mult's priority 2 into it (anti cost clamps to 1, +cost-1 = +0), while the
* dep-free addiu stays at priority 1 -- and priority beats the LUID tie-break, so
* NO statement order / pin / barrier can flip it (matches the opus invariance).
* FIX = raise the addiu to priority 2: emit the pointer init as a non-volatile
* asm carrying a DEAD extra read of c2 (a priority donor):
* c2 = 0;
* __asm__("addiu %0,%1,18" : "=r"(hp2) : "r"(base), "r"(c2));
* The true dep on the c2-init gives it pri 2 AND blocks its release until the
* c2-init is placed; backward picks then land mult,addu,addiu,mflo = target.
* (A volatile asm CANNOT do this -- volatile = full barrier, pri 13, glues the
* tail behind the mflo. Non-volatile survives because its output is live.)
* Block B needs nothing: there the POINTER holds $v1, so the anti-dep sinks the
* pointer-init -- which is already the target order.
*/
extern u8 *D_800762B0;
extern u8 D_800762B4[];
extern u8 D_800B9CD8[];
extern u8 D_800C6DD0[];
extern u8 D_800C6E2A[];
extern s16 D_800A4EF8;
extern u16 D_800A4EE0;
extern u8 D_800A4F16;
extern s32 func_80038FC4(u8 **);
extern s32 func_80038FFC(s32 *); /* §376: the definition returns s32 and takes s32* */
void func_80038A58(void)
{
u8 *base;
register u8 *p __asm__("$17"); // !FAKE: pin $17 — NEEDED DIFFERS (P36 rung B tus9)
s32 i;
s32 one;
base = D_800B9CD8;
{
u8 *q;
q = D_800762B4;
i = 0xF;
do {
*q = 0;
i--;
q++;
} while (i >= 0);
}
{
u8 *a3;
u8 *a2;
s32 a1;
register u8 *a0 __asm__("$4"); // !FAKE: pin $4 — NEEDED DIFFERS (P36 rung B tus9)
s32 t0;
s32 v0;
register s32 v1 __asm__("$3"); // !FAKE: pin $3 — NEEDED DIFFERS (P36 rung B tus9)
a3 = D_800762B0;
a2 = D_800762B4;
a1 = 0;
t0 = 3;
a0 = D_800C6E2A;
while (a1 < 0x10) {
v0 = *a3;
if (v0 == 0 || v0 == t0) {
if (*a2 == 0) {
v0 = *a0;
a0[1] = 0;
if (v0 != 0) {
v0 = *(s16 *)(a0 - 0x54);
v1 = v0 << 1;
v1 = v1 + v0;
v1 = v1 << 2;
v1 = v1 + v0;
v0 = *(s32 *)(a0 - 0xA);
v1 = v1 << 1;
v0 = v0 + v1;
v0 = v0 + a1;
*(u8 *)(v0 + 0x23) = 0;
a0[0] = 0;
}
}
}
a1++;
a0 += 0x60;
a3++;
a2++;
}
}
i = 0;
one = 1;
p = base + 0x10;
do {
if (p[0x1EB] != 0 && p[0x1EA] != 0) {
s32 sum = *(s32 *)(p + 0x1BC) + *(s32 *)(p + 0x1C0);
s32 lim = *(s32 *)(p + 0x1C4);
s32 k;
u8 flag;
*(s32 *)(p + 0x1BC) = sum;
if (sum >= lim) {
s32 cur;
s32 quot;
s32 c;
s32 r;
s32 v;
quot = sum / lim;
cur = *(s32 *)(p - 8);
*(s32 *)(p + 0x1BC) = sum % lim;
c = cur;
r = quot;
if (cur != 0) {
if (quot >= cur) {
do {
if (c == r) {
r = 0;
} else {
r = r - c;
}
*(s32 *)(p - 8) = 0;
do {
if (p[0x1E8] != 0) {
func_80038FFC((s32 *)base);
if (p[0x1E9] != 0) {
p[0x1EA] = 0;
p[0x1E8] = 0;
goto next;
}
}
v = func_80038FC4((u8 **)base);
p[0x1E8] = one;
} while (v == 0);
*(s32 *)(p - 8) = v;
c = v;
} while (r >= v);
{
s32 d;
d = v - r;
*(s32 *)(p - 8) = d;
}
} else {
s32 d2;
d2 = cur - quot;
*(s32 *)(p - 8) = d2;
}
} else {
p[0x1EA] = 0;
p[0x1E8] = 0;
}
}
flag = 0;
if (p[0x1E4] != 0) {
u16 *hp;
register u8 *sq __asm__("$5"); // !FAKE: pin $5 — NEEDED DIFFERS (P36 rung B tus9)
hp = (u16 *)(base + 0x12);
k = 0;
sq = base + 0x18;
do {
if (*sq != 0) {
u16 cur16 = *hp;
flag = 1;
if (cur16 < *(u16 *)(sq - 2)) {
*hp = cur16 + *(u16 *)(sq - 4);
if (*hp < *(u16 *)(sq - 2)) {
goto cont1;
}
__asm__ __volatile__(""); // !FAKE: barrier — NEEDED DIFFERS (P36 rung B tus9)
*hp = *(u16 *)(sq - 2);
} else if (*(u16 *)(sq - 4) < cur16) {
*hp = cur16 - *(u16 *)(sq - 4);
if (*(u16 *)(sq - 2) < *hp) {
goto cont1;
}
*hp = *(u16 *)(sq - 2);
} else {
*hp = *(u16 *)(sq - 2);
}
*sq = 0;
}
cont1:
k++;
sq += 8;
hp += 4;
} while (k <= 0);
{
u16 *hp2;
s32 c2;
s32 acc2;
acc2 = D_800A4EF8 << 7;
acc2 *= D_800A4EE0;
c2 = 0;
__asm__("addiu %0,%1,18" : "=r"(hp2) : "r"(base), "r"(c2)); // !FAKE: instruction addiu — NEEDED DIFFERS (P36 rung B tus9)
acc2 >>= 14;
do {
acc2 *= *hp2;
acc2 >>= 14;
c2--;
hp2 += 4;
} while (c2 >= 0);
*(s16 *)p = acc2;
}
if (flag != 0 || D_800A4F16 != 0) {
u8 *b;
register u8 *e __asm__("$4"); // !FAKE: pin $4 — NEEDED DIFFERS (P36 rung B tus9)
b = D_800C6DD0;
k = 0;
e = b + 0x5A;
do {
if (*e == one) {
if (*(s16 *)(*(s32 *)(e - 0xA) + 0x1F0) == i) {
*(s16 *)(e - 0x42) = (u32)(*(s16 *)b * *(s16 *)p) >> 14;
*(s16 *)(e - 0x40) = (u32)(*(s16 *)(e - 0x58) * *(s16 *)p) >> 14;
e[3] = one;
*(u32 *)(e - 0x46) |= 3;
}
} else if (*e != 0) {
*e = one;
}
k++;
e += 0x60;
b += 0x60;
} while (k < 0x10);
} else {
u8 *c;
s32 two;
s32 uno;
p[0x1E4] = 0;
k = 0;
two = 2;
uno = 1;
c = D_800C6E2A;
do {
if (*c == two && *(s16 *)(*(s32 *)(c - 0xA) + 0x1F0) == i) {
*c = uno;
}
k++;
c += 0x60;
} while (k < 0x10);
}
} else if (D_800A4F16 != 0) {
u16 *hp3;
register s32 c3 __asm__("$5"); // !FAKE: pin $5 — NEEDED DIFFERS (P36 rung B tus9)
u8 *b2;
register u8 *e2 __asm__("$4"); // !FAKE: pin $4 — NEEDED DIFFERS (P36 rung B tus9)
s32 k2;
s32 acc3;
acc3 = D_800A4EF8 << 7;
acc3 *= D_800A4EE0;
hp3 = (u16 *)(base + 0x12);
c3 = 0;
acc3 >>= 14;
do {
acc3 *= *hp3;
acc3 >>= 14;
c3--;
hp3 += 4;
} while (c3 >= 0);
*(s16 *)p = acc3;
b2 = D_800C6DD0;
k2 = 0;
e2 = b2 + 0x5A;
do {
if (*e2 == one) {
if (*(s16 *)(*(s32 *)(e2 - 0xA) + 0x1F0) == i) {
*(s16 *)(e2 - 0x42) = (u32)(*(s16 *)b2 * *(s16 *)p) >> 14;
*(s16 *)(e2 - 0x40) = (u32)(*(s16 *)(e2 - 0x58) * *(s16 *)p) >> 14;
e2[3] = one;
*(u32 *)(e2 - 0x46) |= 3;
}
} else if (*e2 != 0) {
*e2 = one;
}
k2++;
e2 += 0x60;
b2 += 0x60;
} while (k2 < 0x10);
}
}
next:
i++;
p += 0x1FC;
base += 0x1FC;
} while (i < 2);
D_800A4F16 = 0;
}
s32 func_80038FC4(u8 **a0) {
s32 result = 0;
u8 b;
do {
u8 *p = *a0;
b = *p++;
*a0 = p;
result += b & 0x7F;
if (!(b & 0x80)) {
break;
}
result <<= 7;
} while (1);
return result;
}
s32 func_80038FFC(s32 *param_1) {
extern void func_80039B20(s32 *, s32);
extern void func_80039308(s32 *, s32);
extern void func_80039C5C(s32 *, s32);
extern void func_80039F50(s32 *, s32);
extern void func_8003A098(s32 *, s32);
extern void func_8003A0D0(s32 *, s32);
extern void func_8003A0E4(s32 *, s32);
extern void func_8003A234(s32 *);
u8 *np;
u8 byte;
s32 acc;
acc = *(u8 *)*param_1;
if (acc & 0x80) {
*param_1 = (s32)((u8 *)*param_1 + 1);
*((u8 *)param_1 + 0x1F7) = (u8)acc;
} else {
acc = *((u8 *)param_1 + 0x1F7);
}
switch ((u32)acc >> 4) {
case 8:
func_80039B20(param_1, acc & 0xF);
break;
case 9:
func_80039308(param_1, acc & 0xF);
break;
case 10:
func_80039C5C(param_1, acc & 0xF);
break;
case 11:
func_80039F50(param_1, acc & 0xF);
break;
case 12:
func_8003A098(param_1, acc & 0xF);
break;
case 13:
func_8003A0D0(param_1, acc & 0xF);
break;
case 14:
func_8003A0E4(param_1, acc & 0xF);
break;
case 15:
acc &= 0xF;
if (acc == 7) {
goto set_zero;
}
if (acc < 8) {
if (acc == 0) {
goto set_zero;
}
return 0;
}
if (acc == 15) {
goto call_234;
}
return 0;
set_zero:
acc = 0;
loop_start:
while (1) {
byte = *(u8 *)*param_1;
np = (u8 *)*param_1 + 1;
*param_1 = (s32)np;
acc += byte & 0x7F;
if (!(byte & 0x80)) {
break;
}
acc <<= 7;
}
*param_1 = (s32)np + (s16)acc;
break;
call_234:
func_8003A234(param_1);
break;
}
return 0;
}
void func_8003916C(s16 arg0)
{
extern u8 D_800C6DD0[];
u8 *a1;
s32 off;
a1 = &D_800C6DD0[arg0 * 0x60];
if (a1[0x5A] != 0) {
off = *(s16 *)&a1[6] * 26;
*(u8 *)(*(u32 *)&a1[0x50] + off + arg0 + 0x23) = 0;
a1[0x5A] = 0;
}
}
/* func_800391D4 (main / src/800_c.c, 75 ins) -- MATCH in match_one AND rtu_match (real TU), Fable T5x 2026-09-05.
* Levers, all measured (see .run/P32/t5x/reports/func_800391D4.md):
* - `register s32 i __asm__("$7")`: a hard reg is not a biv (loop.c:3572), so D_80073140[i] is never a giv ->
* the target's per-iteration sll/lui/addu/lw stays (S79).
* - `extern s32 D_80073140[][1]` + `[i][0]`: load-bearing spelling of the table access (S79; the TU now carries it).
* - `a1v = arg1;` BEFORE `off = 0;`: the s16 parameter's sign-extend becomes preheader SOURCE code emitted before
* off's init. Left implicit, the extend is an in-loop invariant that move_movables splices in front of
* NOTE_INSN_LOOP_BEG, i.e. AFTER `off = 0` (loop.c:1652/1708) -- the S79 closeness-3 residual.
* - NINE `__asm__("")` pads: insn_count knife-edge. move_movables hoists the D_800C6DD0 address iff
* threshold(58) * savings(1) * lifetime(1) >= insn_count (loop.c:1631). The target does NOT hoist it, so the
* loop must count >= 59 real insns; moving the extend out of the body cost 2, so 7 pads -> 9.
*/
void func_800391D4(s32 arg0, s16 arg1, s16 arg2) {
extern u8 D_800C6DD0[];
extern u8 D_800C6DD4[];
extern s32 D_80073140[][1];
extern s32 D_800C7D20;
extern s32 D_800A2B98;
extern u8 *D_800762B0;
extern u8 D_800762B4[];
u8 *base;
u8 *entry;
register s32 i __asm__("$7"); // !FAKE: pin $7 — NEEDED DIFFERS (P36 rung B tus9)
s32 off;
s32 mask;
s32 a1v;
i = 0;
base = arg0 + arg2 * 0x1A;
a1v = arg1;
off = 0;
do {
__asm__(""); // !FAKE: barrier — NEEDED DIFFERS (P36 rung B tus9)
__asm__(""); // !FAKE: barrier — NEEDED DIFFERS (P36 rung B tus9)
__asm__(""); // !FAKE: barrier — NEEDED DIFFERS (P36 rung B tus9)
__asm__(""); // !FAKE: barrier — NEEDED DIFFERS (P36 rung B tus9)
__asm__(""); // !FAKE: barrier — NEEDED DIFFERS (P36 rung B tus9)
__asm__(""); // !FAKE: barrier — NEEDED DIFFERS (P36 rung B tus9)
__asm__(""); // !FAKE: barrier — NEEDED DIFFERS (P36 rung B tus9)
__asm__(""); // !FAKE: barrier — NEEDED DIFFERS (P36 rung B tus9)
__asm__(""); // !FAKE: barrier — NEEDED DIFFERS (P36 rung B tus9)
if (*(base + i + 0x23) != 0 && *(s16 *)&D_800C6DD4[off] == a1v) {
entry = &D_800C6DD0[(s16)i * 0x60];
if (entry[0x5A] != 0) {
s32 off2;
u8 *base2;
off2 = *(s16 *)(entry + 6) * 0x1A;
base2 = *(s32 *)(entry + 0x50);
*(base2 + off2 + (s16)i + 0x23) = 0;
entry[0x5A] = 0;
}
mask = D_80073140[i][0];
D_800C7D20 &= ~mask;
D_800A2B98 |= mask;
D_800762B0[i] = 2;
D_800762B4[i] = 0;
}
i++;
off += 0x60;
} while (i < 0x10);
}
void func_80039300(void) {
}
/* func_80039308 (main, src/800_c.c, 518 ins) -- BANKED byte-identical, P32 T4c hand pass (S85, 2026-09-06),
* ZERO register pins, zero fences, zero asm bodies. Sequencer note-on / voice allocation: walks the track's
* 16 voice records (D_800C6DD0, 0x60 each), allocates or steals a voice for note b2 at velocity b3, computes
* pan/volume/pitch through D_8006AF08 / D_8006ACD8 / D_8006AB30 / D_8006ABD8, and updates the D_800A2B98 /
* D_800C7D20 / D_800C7D2C / D_800A2BA0 voice masks; the else arm releases the voices playing note b2.
*
* The three mechanisms that closed the S84 PLATEAU (cookbook §501-Q, §501-R, accelerators (15)-(16)):
* 1. THE PHANTOM 8-BYTE FRAME SLOT ([arg1 @0][8 no-traffic bytes @8][cnt @0x10]) is a combine GHOST: the chain
* `gx = s0[1]; gx -= 0x100; v = b3 * (u8)gx;` compiles to the same `lbu` as `s0[1]`, but combine deletes the
* self-update with `i2dest_in_i2src` (combine.c:2306 skips the reference decrement), the load then merges into
* the (u8) use, and the pseudo `gx` keeps stale refs with no insns -- reload's initial alter_reg loop mints an
* 8-byte slot for it in regno order, between arg1's spill and cnt's eviction slot. Reproducers: .run/P32/t4e/ghost/.
* 2. THE HOISTED VOLUME BASE `sll $s2,$s5,8` sits between two hoisted constants ([li 2][sll][li 1]) and is read
* three times ($s2 in the copy and both pan arms): loop.c's combine_movables merges the three inline
* `(b2 * 0x100)` temps into ONE hoisted movable (savings 3), which needs (a) a compiler TEMP, not a named
* variable (a user variable set after the inner loop's jumps is never a movable: loop.c:695-700), and (b) cse1
* NOT folding the arms onto `vol`: with `u16 vol`, the copy `vol = b2 * 0x100` is a subreg move, so `vol` never
* joins the shift's quantity (cse.c make_regs_eqv prefers the later-mentioned register) and the arms keep the
* temp. The copy-first form is what puts `vol` in $a1 (born while pan is live in $a0) and in the first
* branch's delay slot; every copy-last / named-vbase / pinned form was measured (b13-b51, NOTES.md).
* 3. THE ELSE HEAD ($t1/$t0): the release loop's pointer and compare temp are the note-on arm's `s17`/`s18`
* variables reused (the target's rows 410/411 and 440/441 share the registers); a fresh `tb`/`k2` pair lands in
* $t0/$s2 instead.
* Kept from the S83/S84 drafts: `s16 b4` + `n = b4` (the widening copy), the pan sum split, `bb` as the first pan
* load, the offset local `v` computed before t9, the cross-arm k2 reading of the +6 store ... see the S83 notes in
* git history (this header replaces them).
*/
typedef struct { u32 w; } VMask;
extern u8 *D_800762B0;
extern u8 D_800762B3[];
extern u8 D_800762B4[];
extern s32 D_80073140[][1]; /* [][1] spelling: load-bearing for func_800391D4 (S79 lever; §500-I) */
extern u16 D_8006AB30[];
extern u16 D_8006ABD8[];
extern u16 D_8006ACD8[];
extern s16 D_8006AF08[];
extern s32 D_800A2B98;
extern s32 D_800A2BA0;
extern u8 D_800A4F19;
extern u8 D_800C6DD0[];
extern u8 D_800C6DD4[];
extern u8 D_800C6DDD[];
extern s32 D_800C7D20;
extern s32 D_800C7D2C;
void func_80039308(u8 **arg0, s16 arg1) {
u8 *src;
u8 *s0;
u8 *t9;
u8 *a3;
u8 *t1;
u8 *a1p;
u8 *a0p;
u8 *p;
u8 *q;
u8 *r;
u8 *tb;
s32 b2;
s32 b3;
s16 b4;
s32 bb;
u8 t3;
u8 t5;
s16 t7;
s16 cc;
s32 i;
s32 cnt;
s32 a2;
s32 t0;
s32 v1;
s32 res;
s32 idx1;
u8 *cb;
s32 *mm;
s32 *mp;
s32 mv2;
s32 two;
s32 tmp;
s32 pan;
s32 pan1;
s32 x;
s32 s17;
s32 s18;
s32 v;
s32 u26;
s32 n;
s32 off;
u32 t2;
u16 vol;
u32 vv;
u32 prod;
s32 k2;
u8 *tbl;
s32 tmp2;
s32 coff;
s32 xoff;
s32 mv;
s32 j;
s32 ax;
s32 ax2;
u8 *pb;
s32 c7;
u32 gx;
src = *arg0;
*arg0 = src + 1;
b2 = src[0];
*arg0 = src + 2;
b3 = src[1];
if (b3 != 0) {
if ((((u8 *)arg0 + arg1)[0x1BA] & 1) == 0) {
s0 = (u8 *)arg0 + (arg1 * 26 + 26);
i = 0;
b4 = *s0;
n = b4;
v = n * 0x10;
t9 = *(u8 **)((u8 *)arg0 + 0x1E0) + n * 0x200;
cnt = *(*(u8 **)((u8 *)arg0 + 0x1DC) + v);
if (cnt != 0) {
u26 = b2;
do {
if (u26 >= t9[6] && u26 <= t9[7]) {
t2 = 0x100;
t3 = 0;
t5 = 0;
t7 = -1;
t0 = 0;
a3 = D_800C6DDD;
a2 = 1;
t1 = D_800762B0;
do {
if (a3[0x4E] != 0) {
bb = a3[0];
if ((u8)bb < (t2 & 0xFF)) {
t3 = a2;
t2 = bb & 0xFF;
} else if ((u8)bb == (t2 & 0xFF)) {
if (D_800762B3[a2] == 0 && *t1 == 2) {
t3 = a2;
}
}
} else {
t5 = 1;
t7 = t0;
break;
}
a2++;
t1++;
t0++;
a3 += 0x60;
} while (t0 < 0x10);
if (t5 == 0) {
if (*t9 >= t2) {
t7 = t3 - 1;
} else {
a1p = D_800762B0;
a0p = D_800762B4;
v1 = 0;
while (v1 < 0x10) {
if (*a1p == 2 && *a0p == 0) {
res = v1;
goto found;
}
v1++;
a1p++;
a0p++;
}
res = -1;
found:
t7 = res;
}
}
if (t7 >= 0) {
p = &D_800C6DD0[t7 * 0x60];
q = p + 0x10;
p[0xD] = *t9;
if (p[0x5C] != 0 && *(s16 *)(p + 8) == b4 && p[0xC] == i &&
*(s16 *)(*(u32 *)(p + 0x50) + 0x1EC) == *(s16 *)((u8 *)arg0 + 0x1EC)) {
*(s32 *)(p + 0x14) = 0x13;
} else {
tmp = *(s16 *)(t9 + 0x16) - 1;
tbl = *(u8 **)((u8 *)arg0 + 0x1DC) + (tmp >> 1) * 0x10;
if (tmp & 1) {
x = *(s16 *)(tbl + 0xE) << 3;
} else {
x = *(s16 *)(tbl + 0xC) << 3;
}
*(s32 *)(q + 0x1C) = x;
*(u16 *)(q + 0x3A) = *(u16 *)(t9 + 0x10);
*(u16 *)(q + 0x3C) = *(u16 *)(t9 + 0x12);
*(s32 *)(q + 4) = 0x6009F;
}
gx = s0[1];
gx -= 0x100;
v = b3 * (u8)gx;
v >>= 7;
v = v * t9[2];
v >>= 7;
v = D_8006ACD8[v];
v = v * *(s16 *)((u8 *)arg0 + 0x1F2);
v >>= 7;
if (D_800A4F19 != 0) {
bb = s0[4];
pan1 = bb + t9[3]; pan1 -= 0x40;
cc = pan1;
if (pan1 < 0) {
cc = 0;
} else if (pan1 >= 0x80) {
cc = 0x7F;
}
if (cc > 0) {
s17 = v * D_8006AF08[0x80 - cc] * 4 >> 16;
} else {
s17 = (s16)v;
}
s18 = v * D_8006AF08[cc] * 4 >> 16;
} else {
s17 = s18 = v * 0x2D41 >> 14;
}
*(s16 *)(q + 8) = (u32)((s16)s17 * *(s16 *)((u8 *)arg0 + 0x10)) >> 14;
*(s16 *)(q + 0xA) = (u32)((s16)s18 * *(s16 *)((u8 *)arg0 + 0x10)) >> 14;
pan = *(s16 *)(s0 + 2);
vol = b2 * 0x100;
if (pan >= 0x41) {
vol = (b2 * 0x100) + (u32)((pan - 0x40) * t9[0xD] * 4);
} else if (pan < 0x40) {
vol = (b2 * 0x100) - (u32)((0x40 - pan) * t9[0xC] * 4);
}
tmp2 = t9[4] * 0x100 - t9[5];
*(s32 *)(p + 0x54) = tmp2;
tmp2 -= 0x3C00;
vol -= (u32)tmp2;
p[0x58] = t9[0xC];
p[0x59] = t9[0xD];
vv = (u16)vol;
if (vv >= 0x5301) {
*(s16 *)(q + 0x14) = 0x3FFF;
} else {
prod = D_8006AB30[vv >> 8];
prod *= D_8006ABD8[(vv & 0xFE) / 2];
*(s16 *)(q + 0x14) = prod >> 15;
}
p[0x5D] = 1;
D_800A2B98 &= ~((VMask *)q)->w;
D_800C7D20 |= ((VMask *)q)->w;
D_800762B4[t7] = 1;
if (t9[1] & 4) {
D_800A2BA0 &= ~((VMask *)q)->w;
D_800C7D2C |= ((VMask *)q)->w;
} else {
D_800C7D2C &= ~((VMask *)q)->w;
D_800A2BA0 |= ((VMask *)q)->w;
}
idx1 = t7;
r = &D_800C6DD0[idx1 * 0x60];
p = r;
if (r[0x5A] != 0) {
coff = *(s16 *)&r[6] * 26;
*(u8 *)(*(u32 *)&r[0x50] + coff + idx1 + 0x23) = 0;
r[0x5A] = 0;
}
r = 0;
*(s0 + idx1 + 9) = 1;
*(s16 *)(p + 4) = b2;
*(s16 *)(p + 8) = b4;
p[0xC] = i;
p[0x5C] = 1;
*(s16 *)(p + 0) = s17;
*(s16 *)(p + 2) = s18;
*(s16 *)(p + 6) = arg1;
*(u32 *)(p + 0x50) = (u32)arg0;
p[0x5B] = 1;
if (*((u8 *)arg0 + 0x1F4) != 0) {
p[0x5A] = 2;
} else {
p[0x5A] = 1;
}
}
}
i++;
t9 += 0x20;
} while (i < cnt);
}
}
} else {
j = 0;
s17 = (s32)((u8 *)arg0 + arg1 * 26);
s18 = b2;
off = 0;
do {
if (((u8 *)s17 + j)[0x23] != 0 && *(s16 *)&D_800C6DD4[off] == s18) {
idx1 = (s16)j;
xoff = idx1 * 0x60;
cb = D_800C6DD0;
r = cb + xoff;
if (r[0x5A] != 0) {
coff = *(s16 *)&r[6] * 26;
*(u8 *)(*(u32 *)&r[0x50] + coff + idx1 + 0x23) = 0;
r[0x5A] = 0;
}
mm = (s32 *)D_80073140;
D_800C7D20 &= ~mm[j];
D_800A2B98 |= mm[j];
pb = D_800762B0 + j;
two = 2;
*pb = two;
D_800762B4[j] = 0;
}
cb = 0;
mm = 0;
two = 0;
j++;
off += 0x60;
} while (j < 0x10);
}
}
extern s32 D_80073140[][1]; /* [][1] spelling: load-bearing for func_800391D4 (S79 lever; §500-I) */
extern u8 *D_800762B0;
extern s32 D_800C7D20;
extern u8 D_800762B4[];
extern s32 D_800A2B98;
extern u8 D_800C6DD0[];
extern u8 D_800C6DD4[];
void func_80039B20(s32 *arg0, s16 arg1) {
register s32 i __asm__("$6"); // !FAKE: pin $6 — NEEDED DIFFERS (P36 rung B tus9)
register s32 off __asm__("$7"); // !FAKE: pin $7 — NEEDED DIFFERS (P36 rung B tus9)
u8 c;
s32 t1;
i = 0;
t1 = (s32)arg0 + arg1 * 26;
c = *(u8 *)((*arg0)++);
off = 0;
do {
if (*(u8 *)(t1 + i + 0x23) != 0 && (*(s16 *)(D_800C6DD4 + off) == c)) {
u8 *p = D_800C6DD0 + (s16)i * 0x60;
if (p[0x5A] != 0) {
s16 f6 = *(s16 *)(p + 6);
s32 off2 = f6 * 26;
s32 base = *(s32 *)(p + 0x50);
*(u8 *)(base + off2 + (s16)i + 0x23) = 0;
p[0x5A] = 0;
}
{
s32 base1 = (s32)D_80073140;
__asm__ __volatile__("" : "=r"(base1) : "0"(base1)); // !FAKE: launder — NEEDED DIFFERS (P36 rung B tus9)
D_800C7D20 &= ~((s32 *)base1)[i];
D_800A2B98 |= ((s32 *)base1)[i];
}
D_800762B0[i] = 2;
D_800762B4[i] = 0;
}
i++;
off += 0x60;
} while (i < 0x10);
}
void func_80039C5C(s32 *param_1) {
*param_1 += 2;
}
extern void func_8003B45C(s32 *);
extern s32 D_80079A68;
extern s32 D_8006B008[];
extern s32 D_800A4ECC;
extern s32 D_800A4ED0;
extern u16 D_8006ADD8[];
extern u16 D_800A4ED4;
extern u16 D_800A4ED6;
extern u16 D_800A4F20;
extern u16 D_800A4F22;
void func_80039C70(u8 *arg0, s16 arg1, s16 arg2) {
u8 *rec = arg0 + (arg1 * 0x1A + 0x1A);
if ((*(u16 *)(rec + 6) & 0x300) != 0x300) {
arg0[0x1F9] = 1;
} else {
switch (*(u8 *)(rec + 8)) {
case 0x10: {
s32 old = D_80079A68;
s32 val = *(s32 *)((u8 *)D_8006B008 + ((arg2 << 16) >> 14));
if (old != val) {
s32 *p = &D_800A4ECC;
D_80079A68 = val;
*p = 1;
D_800A4ED0 = val;
func_8003B45C(p);
}
break;
}
case 0x11: {
s32 *p = &D_800A4ECC;
*p = 6;
D_800A4ED4 = *(u16 *)((u8 *)D_8006ADD8 + ((arg2 << 16) >> 15));
D_800A4ED6 = D_800A4ED4;
func_8003B45C(p);
break;
}
case 0x18:
*(s32 *)(arg0 + 0xC) = *(s32 *)arg0;
arg0[0x1F5] = arg2;
arg0[0x1F6] = 1;
break;
case 0x1A: {
u16 *p = &D_800A4F20;
if (*p != 0) {
arg0[0x1F9] = 1;
D_800A4F22 = *p;
*p = 0;
}
break;
}
case 0x12:
case 0x13:
case 0x14:
case 0x15:
case 0x16:
case 0x17:
case 0x19:
break;
}
rec[7] &= 0xFC;
}
}
void func_80039DEC(a0, a1, a2)
void *a0;
s16 a1;
s16 a2;
{
u8 cnt;
s32 tmp;
switch (a2) {
case 0x14: {
u8 *p = (u8 *)a0 + a1 * 26;
p[0x1F] = a2;
p[0x22] = 0x18;
p[0x21] |= 3;
break;
}
case 0x1E:
if (*(u8 *)((u8 *)a0 + 0x1F6) == 0) {
*(u8 *)((u8 *)a0 + 0x1F9) = 1;
return;
}
cnt = *(u8 *)((u8 *)a0 + 0x1F5);
if ((u8)cnt != 0x7F) {
*(u8 *)((u8 *)a0 + 0x1F5) = cnt + 0xFF;
if ((u8)cnt == 0) {
return;
}
}
tmp = *(s32 *)((u8 *)a0 + 0xC);
*(u8 *)((u8 *)a0 + 0x1F7) = a1 | 0xB0;
*(s32 *)a0 = tmp;
break;
case 0x28: {
u8 *p = (u8 *)a0 + a1 * 26;
p[0x1F] = a2;
p[0x22] = 0x1A;
p[0x21] |= 3;
break;
}
default: {
u8 *p = (u8 *)a0 + a1 * 26;
p[0x1F] = a2;
p[0x21] |= 1;
break;
}
}
}
void func_80039F14(u8 *arg0, s16 arg1, u8 arg2) {
u8 b;
arg0 += arg1 * 26;
b = arg0[0x21];
arg0[0x20] = arg2;
arg0[0x22] = arg2 + 1;
arg0[0x21] = b | 2;
}
extern void func_80039C70(u8 *arg0, s16 arg1, s16 arg2); /* §376: matches the definition */
extern void func_80039DEC(); /* no-proto (§376/§495): the definition is K&R with narrow params — a narrow-typed prototype is incompatible */
void func_80039F50(u8 **a0, s16 a1)
{
u8 **pvVar4; /* $a3 */
u8 *pbVar3;
register s32 bVar1 __asm__("$4"); /* $a0 */ // !FAKE: pin $4 — NEEDED DIFFERS (P36 rung B tus9)
u8 bVar2;
register u8 *pbVar5 __asm__("$2"); /* $v0 */ // !FAKE: pin $2 — NEEDED DIFFERS (P36 rung B tus9)
u8 bVar6;
pvVar4 = a0;
pbVar3 = *pvVar4;
*pvVar4 = pbVar3 + 1;
bVar1 = *pbVar3;
*pvVar4 = pbVar3 + 2;
bVar2 = pbVar3[1];
switch (bVar1) {
case 6:
func_80039C70(pvVar4, a1, bVar2);
break;
case 7:
pbVar5 = (u8 *)pvVar4 + a1 * 0x1A;
pbVar5[0x1B] = bVar2;
break;
case 8:
break;
case 0xA:
pbVar5 = (u8 *)pvVar4 + a1 * 0x1A;
pbVar5[0x1E] = bVar2;
break;
case 0x62:
pbVar5 = (u8 *)pvVar4 + a1 * 0x1A;
bVar6 = pbVar5[0x21];
pbVar5[0x20] = bVar2;
pbVar5[0x22] = bVar2 + 1;
pbVar5[0x21] = bVar6 | 2;
break;
case 0x63:
func_80039DEC(pvVar4, a1, bVar2);
break;
}
}
typedef struct {
u8 b0;
u8 pad[25];
} A098Rec;
typedef struct {
u8 *stream;
u8 pad04[0x16];
A098Rec rec[1];
} A098Ctx;
void func_8003A098(A098Ctx *arg0, s16 arg1) {
u8 *v1;
v1 = arg0->stream;
arg0->stream = v1 + 1;
arg0->rec[arg1].b0 = *v1;
}
void func_8003A0D0(s32 *arg0) {
(*arg0)++;
}
extern u16 D_8006AB30[];
extern u16 D_8006ABD8[];
extern u8 D_800C6DD0[];
void func_8003A0E4(void *arg0, s16 arg1) {
u8 *src;
u8 *t2;
u8 *t1;
u8 *a2;
u8 *a1;
s32 i;
s32 pan;
u32 vol;
u32 tmp;
u32 prod;
t2 = (u8 *)arg0 + (arg1 * 26 + 26);
t1 = t2 + 9;
src = *(u8 **)arg0;
*(u32 *)arg0 = (u32)src + 1;
*(s16 *)(t2 + 2) = src[0] & 0x7F;
for (i = 0; i < 16; i++) {
if (*t1++ != 0) {
a2 = D_800C6DD0 + i * 0x60;
vol = *(s16 *)(a2 + 4) << 8;
pan = *(s16 *)(t2 + 2);
if (pan >= 65) {
vol += (u32)((pan - 64) * a2[0x59] * 4);
} else if (pan < 64) {
vol -= (u32)((64 - pan) * a2[0x58] * 4);
}
tmp = *(s32 *)(a2 + 0x54) - 0x3C00;
vol -= tmp;
a1 = a2 + 0x10;
if (vol >= 0x5301) {
*(s16 *)(a2 + 0x24) = 0x3FFF;
} else {
prod = D_8006AB30[vol >> 8];
prod *= D_8006ABD8[(vol & 0xFE) / 2];
*(s16 *)(a2 + 0x24) = prod >> 15;
}
*(u32 *)(a1 + 4) |= 0x10;
a2[0x5D] = 1;
}
}
}
typedef struct {
/* 0x000 */ u8 *ptr;
/* 0x004 */ u8 pad_004[0x1D0 - 0x004];
/* 0x1D0 */ s32 unk1D0;
/* 0x1D4 */ u8 pad_1D4[0x1E4 - 0x1D4];
/* 0x1E4 */ s16 unk1E4;
/* 0x1E6 */ s16 unk1E6;
/* 0x1E8 */ u8 pad_1E8[0x1F9 - 0x1E8];
/* 0x1F9 */ u8 unk1F9;
} func_8003A234_Ctx;
void func_8003A234(func_8003A234_Ctx *a0) {
u8 *a2 = a0->ptr;
u8 v1;
a0->ptr = a2 + 1;
v1 = *a2;
switch (v1) {
case 0x20:
a0->ptr = a2 + 3;
break;
case '/':
a0->ptr = a2 + 2;
a0->unk1F9 = 1;
break;
case 'Q':
{
s32 num;
s32 den;
s32 b3;
s32 b4;
s32 q;
a0->ptr = a2 + 2;
den = a2[1];
if (den != 3) {
a0->unk1F9 = 1;
break;
}
num = 0x3938700;
a0->ptr = a2 + 3;
den = a2[2];
a0->ptr = a2 + 4;
b3 = a2[3];
a0->ptr = a2 + 5;
b4 = a2[4];
den = den << 16;
den += b3 << 8;
den += b4;
q = num / den;
a0->unk1E4 = (s16)q;
a0->unk1D0 = q * a0->unk1E6;
}
break;
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 'T':
case 0x58:
case 0x59:
case 0x7F:
{
u8 *p = a0->ptr;
u8 *np = p + 1;
a0->ptr = np;
{
register s32 byte __asm__("$5") = p[0]; // !FAKE: pin $5 — NEEDED DIFFERS (P36 rung B tus9)
a0->ptr = np + byte;
}
}
break;
case 0:
a0->ptr = a2 + 2;
{
register s32 b1 __asm__("$5") = a2[1]; // !FAKE: pin $5 — NEEDED DIFFERS (P36 rung B tus9)
if (b1 != 2) {
a0->unk1F9 = 1;
break;
}
}
a0->ptr = a2 + 4;
break;
default:
a0->unk1F9 = 1;
break;
}
}
u32 func_8003A3D8(u32 a) {
return ((a & 0xFF) << 24) + (((a >> 8) & 0xFF) << 16) + (((a >> 16) & 0xFF) << 8) | (a >> 24);
}
s32 func_8003A404(u32 arg)
{
u32 h = arg >> 8;
u32 l = (arg & 0xFF) << 8;
return (s16)((h & 0xFF) + l);
}
extern void _SpuInit(s32);
void func_8003A424(void) {
_SpuInit(0);
}