feat(decomp): bank 9 main functions, including main itself and the 670-ins giant

BANKED 9 of 28 after bisection, 143dbb89 BYTE-IDENTICAL. Verified from the
SOURCE (every stub gone), not from the gate's own count.

  main            509 ins  the game's entry point
  func_800226C0   670 ins  the largest function in the project
  func_800215F4   465
  func_800623A4    36 · func_80062434 36 · func_8005D410 42
  func_8005D4B8    14 · func_8005D4F0 18 · StopRCnt 13

Reached by iterating the gate and dropping the compile-conflict culprit it
named each round: func_8005E79C, func_8005E3AC, func_8005EAE8, func_8001FC08.
Each of those is a §376/§378 declaration conflict, not a bad body — they go to
the recovery chain, not the bin.

Several were only reachable because of this session's oracle fixes: the 800c3
functions had been recorded as §182/§188 epilogue walls by an oracle modelling
maspsx + as -O1 for a TU the Makefile builds through reorder_passthrough +
as -O2. func_800226C0 came from the §476 finding that a hard-register pin
strips nonzero_bits and reg_n_sets==1.
This commit is contained in:
Drew T
2026-09-03 17:05:47 -06:00
parent 5bb71db7a9
commit fc644dddb4
4 changed files with 1194 additions and 9 deletions
+893 -2
View File
@@ -12126,7 +12126,441 @@ void func_80021284(s32 arg0)
}
INCLUDE_ASM("asm/nonmatchings/800", func_800215F4);
/* ---- PsyQ GTE inline macros (same spelling as the matched src/800.c blocks) ---- */
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_ldv3(r0, r1, r2) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 );" \
"lwc2 $2, 0( %1 );" \
"lwc2 $3, 4( %1 );" \
"lwc2 $4, 0( %2 );" \
"lwc2 $5, 4( %2 )" \
: \
: "r"( r0 ), "r"( r1 ), "r"( r2 ) )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_rtpt() __asm__ volatile ("nop;nop;rtpt")
#define gte_nclip() __asm__ volatile ("nop;nop;nclip")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_stsxy3(r0, r1, r2) __asm__ volatile ( \
"swc2 $12, 0( %0 );" \
"swc2 $13, 0( %1 );" \
"swc2 $14, 0( %2 )" \
: \
: "r"( r0 ), "r"( r1 ), "r"( r2 ) \
: "memory" )
#define gte_stopz(r0) __asm__ volatile ( \
"swc2 $24, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
#define gte_stszotz(r0) __asm__ volatile ( \
"mfc2 $12, $19;" \
"nop;" \
"sra $12, $12, 2;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
typedef struct {
s16 vx, vy, vz, pad;
} SV_215F4; /* 8 */
typedef struct {
/* 0x00 */ s32 unk00;
/* 0x04 */ u32 unk04;
/* 0x08 */ u8 pad08[6];
/* 0x0E */ s16 unk0E;
/* 0x10 */ u8 pad10[14];
/* 0x1E */ s16 unk1E;
/* 0x20 */ u8 *unk20;
/* 0x24 */ u8 pad24[8];
/* 0x2C */ u16 unk2C;
/* 0x2E */ u16 unk2E;
/* 0x30 */ u16 unk30;
/* 0x32 */ u16 unk32;
/* 0x34 */ s32 unk34;
} Obj_215F4;
extern u8 D_800A6610[];
extern u16 D_800B9A02;
/* func_8001E094 / func_8001E378 are DEFINED in src/800.c (file-scope decls at
* 10238/10239, bodies at 10453/10588) with these exact prototypes -- do not
* narrow them (cookbook 376/378). The target's missing `move $a0,$s1` before
* the E094 call is cse_insn deleting the argument copy in the FALL-THROUGH arm
* (a0 still equals the parameter); the else arm is a fresh basic block, so its
* copy survives.
*
* func_800226C0 MUST stay unprototyped here: src/800.c already carries a
* file-scope `extern void func_800226C0(Obj_80021D38 *, u8 *, DVec_80021D38 *,
* u8 *)` at 12214, i.e. AFTER this function's slot at 12129, so a prototyped
* decl of our own would be a conflicting-types build error. An unspecified
* parameter list is compatible with both that decl and the `extern void
* func_800226C0()` at 12556, and it is codegen-identical here (all four
* arguments are pointers, unaffected by the default argument promotions).
* func_80023138's spelling below is verbatim from its definition at 12688. */
extern void func_8001E094(s32 arg0);
extern void func_8001E378(s32 param_1);
extern void func_800226C0();
extern void func_80023138(s32 *arg0, u8 *col, u8 *pts, u32 *ot);
void func_800215F4(Obj_215F4 *obj)
{
SV_215F4 v[4]; /* 0x10 */
s32 xy[36]; /* 0x30 */
s32 flag; /* 0xC0 */
s32 otz; /* 0xC4 */
s32 flag2; /* 0xC8 */
u32 *ot;
u8 *vp;
/* pinned to the registers the target itself allocates (cookbook 179-F / 347) */
register s32 i __asm__("$8"); /* $t0 loop counter, every loop */
register u8 *q __asm__("$7"); /* $a3 loop1/3 walked ptr */
register s32 o1 __asm__("$9"); /* $t1 */
register s32 o2 __asm__("$10"); /* $t2 */
register s32 d1 __asm__("$11"); /* $t3 */
register s32 d2 __asm__("$12"); /* $t4 */
register s32 d3 __asm__("$13"); /* $t5 */
register u8 *xb __asm__("$14"); /* $t6 */
register SV_215F4 *pv1 __asm__("$25");
register SV_215F4 *pv2 __asm__("$24");
register SV_215F4 *pv3 __asm__("$15");
register u16 bx __asm__("$5");
register u16 by __asm__("$4");
register u16 bz __asm__("$6");
register u8 *rs __asm__("$3");
/* loop2 */
register SV_215F4 *pw1 __asm__("$13");
register u8 *xb2 __asm__("$11");
register s32 *pf __asm__("$10");
register s32 *dzp __asm__("$9");
register s32 e __asm__("$7");
register u8 *rw __asm__("$6");
/* The three clamp sites: `x & 0xFFF` is computed SEPARATELY IN EACH ARM,
* never hoisted above the `== 0xC000` test. reorg then merges the two
* identical copies into the bne's delay slot -- which is the only way the
* andi can reuse the $v0 that held the 0xC000 compare constant (a hoisted
* copy is born BEFORE the bne, so it overlaps the constant and has to take
* a third register). In the two inner loops the temp additionally has to
* be PINNED off c2: fill_slots_from_thread rejects a delay-slot candidate
* that sets a resource the opposite arm still reads, so an in-place
* `andi $a0,$a0,0xFFF` over c2's own $a0 blocks the merge and costs +2.
* `oz` likewise stops the otz load coalescing into dz's pinned $v1. */
/* loop4 */
register SV_215F4 *pw4 __asm__("$11");
register u8 *xb4 __asm__("$10");
/* loopC */
register SV_215F4 *pa1 __asm__("$24");
register SV_215F4 *pa2 __asm__("$15");
register SV_215F4 *pa3 __asm__("$14");
register u8 *xbc __asm__("$13");
register s32 dc3 __asm__("$12");
register s32 oc2 __asm__("$11");
register s32 oc1 __asm__("$10");
register u8 *qc __asm__("$9");
register u32 dm __asm__("$2");
register s32 oz __asm__("$2");
u16 qx;
u32 k;
register s32 *pd __asm__("$4");
register s32 dz __asm__("$3");
register u32 c2 __asm__("$4");
s32 *pz;
u32 t, c;
ot = (u32 *)(D_800B9A02 * 0x4000 + (u32)D_800A6610);
vp = obj->unk20;
if (obj->unk34 != 0) {
func_8001E094((s32)obj);
} else {
func_8001E378((s32)obj);
}
if (obj->unk04 & 0x100) {
v[2].vx = 0x10;
v[3].vx = -0x10;
v[1].vy = -0x13;
v[3].vy = 8;
v[2].vy = 8;
v[1].vx = 0;
v[3].vz = 0;
v[2].vz = 0;
v[1].vz = 0;
gte_ldv3(&v[1], &v[2], &v[3]);
gte_rtpt();
gte_stflg(&flag);
if (flag & ~0x1000) {
return;
}
gte_nclip();
gte_stopz(&otz);
if (otz <= 0) {
return;
}
}
v[0].vx = obj->unk2E;
v[0].vy = obj->unk30;
v[0].vz = obj->unk32;
gte_ldv0(&v[0]);
gte_rtps();
gte_stsxy(&xy[0]);
gte_stflg(&flag);
gte_stszotz(&otz);
if (flag & ~0x1000) {
return;
}
t = otz + 1;
c = obj->unk2C;
if (c & 0xC000) {
if ((c & 0xC000) == 0xC000) {
t -= c & 0xFFF;
if ((s32)t < 0) {
t = 0;
}
} else {
t += c & 0xFFF;
}
}
if (t < 0x1000) {
i = 0;
if ((obj->unk1E & 0x8000) || obj->unk0E != 0) {
pv1 = &v[1];
pv2 = &v[2];
pv3 = &v[3];
xb = (u8 *)xy;
d3 = 0x14;
d2 = 0xC;
d1 = 4;
o2 = 0x10;
o1 = 8;
q = vp;
do {
bx = v[0].vx;
qx = *(u16 *)(q + 0x10);
bz = v[0].vz;
by = v[0].vy;
v[1].vx = bx + qx;
v[1].vy = by + *(u16 *)(q + 0x12);
v[1].vz = bz;
rs = vp + o1;
v[2].vx = bx + *(u16 *)(rs + 0x10);
v[2].vy = by + *(u16 *)(rs + 0x12);
v[2].vz = bz;
rs = vp + o2;
v[3].vx = bx + *(u16 *)(rs + 0x10);
v[3].vy = by + *(u16 *)(rs + 0x12);
v[3].vz = bz;
gte_ldv3(pv1, pv2, pv3);
gte_rtpt();
gte_stsxy3(xb + d1, xb + d2, xb + d3);
d3 += 0x18;
d2 += 0x18;
d1 += 0x18;
o2 += 0x18;
o1 += 0x18;
i += 6;
q += 0x18;
} while (i < 12);
i = 1;
pw1 = &v[1];
xb2 = (u8 *)xy;
pf = &flag2;
dzp = &xy[13];
e = 8;
rw = vp + 4;
do {
v[1].vx = v[0].vx + *(u16 *)(rw + 0x10);
v[1].vy = v[0].vy + *(u16 *)(rw + 0x12);
v[1].vz = v[0].vz;
gte_ldv0(pw1);
gte_rtps();
gte_stsxy(xb2 + e);
gte_stflg(pf);
pz = &otz;
gte_stszotz(pz);
oz = otz;
dz = oz + 1;
c2 = obj->unk2C;
if (c2 & 0xC000) {
k = 0xC000;
if ((c2 & 0xC000) == k) {
dm = c2 & 0xFFF;
dz -= dm;
if (dz < 1) {
dz = 0;
}
} else {
dm = c2 & 0xFFF;
dz += dm;
}
}
if (dz >= 0x1000) {
k = 0xFFF;
dz = k;
}
pz = &dzp[i >> 1];
*pz = dz;
e += 8;
i += 2;
rw += 8;
} while (i < 12);
if (obj->unk0E != 0) {
i = 0;
pv1 = &v[1];
pv2 = &v[2];
pv3 = &v[3];
xb = (u8 *)xy;
d3 = 0x5C;
d2 = 0x54;
d1 = 0x4C;
o2 = 0x10;
o1 = 8;
q = vp;
v[0].vz = v[0].vz + obj->unk0E;
do {
bx = v[0].vx;
qx = *(u16 *)(q + 0x10);
bz = v[0].vz;
by = v[0].vy;
v[1].vx = bx + qx;
v[1].vy = by + *(u16 *)(q + 0x12);
v[1].vz = bz;
rs = vp + o1;
v[2].vx = bx + *(u16 *)(rs + 0x10);
v[2].vy = by + *(u16 *)(rs + 0x12);
v[2].vz = bz;
rs = vp + o2;
v[3].vx = bx + *(u16 *)(rs + 0x10);
v[3].vy = by + *(u16 *)(rs + 0x12);
v[3].vz = bz;
gte_ldv3(pv1, pv2, pv3);
gte_rtpt();
gte_stsxy3(xb + d1, xb + d2, xb + d3);
d3 += 0x18;
d2 += 0x18;
d1 += 0x18;
o2 += 0x18;
o1 += 0x18;
i += 6;
q += 0x18;
} while (i < 12);
i = 1;
pw4 = &v[1];
xb4 = (u8 *)xy;
dzp = &xy[13];
e = 0x50;
rw = vp + 4;
do {
v[1].vx = v[0].vx + *(u16 *)(rw + 0x10);
v[1].vy = v[0].vy + *(u16 *)(rw + 0x12);
v[1].vz = v[0].vz;
gte_ldv0(pw4);
gte_rtps();
gte_stsxy(xb4 + e);
pz = &flag2;
gte_stflg(pz);
pz = &otz;
gte_stszotz(pz);
oz = otz;
dz = oz + 1;
c2 = obj->unk2C;
if (c2 & 0xC000) {
k = 0xC000;
if ((c2 & 0xC000) == k) {
dm = c2 & 0xFFF;
dz -= dm;
if (dz < 1) {
dz = 0;
}
} else {
dm = c2 & 0xFFF;
dz += dm;
}
}
if (dz >= 0x1000) {
k = 0xFFF;
dz = k;
}
pd = &dzp[i >> 1];
if (dz < *pd) {
*pd = dz;
}
e += 8;
i += 2;
rw += 8;
} while (i < 12);
func_80023138((s32 *)obj, vp, (u8 *)xy, ot);
} else {
func_800226C0((s32 *)obj, vp, (u8 *)xy, ot);
}
} else {
pa1 = &v[1];
pa2 = &v[2];
pa3 = &v[3];
xbc = (u8 *)xy;
dc3 = 0xC;
oc2 = 8;
oc1 = 4;
qc = vp;
do {
bx = v[0].vx;
qx = *(u16 *)(qc + 0x10);
bz = v[0].vz;
by = v[0].vy;
v[1].vx = bx + qx;
v[1].vy = by + *(u16 *)(qc + 0x12);
v[1].vz = bz;
rs = vp + oc1;
v[2].vx = bx + *(u16 *)(rs + 0x10);
v[2].vy = by + *(u16 *)(rs + 0x12);
v[2].vz = bz;
rs = vp + oc2;
v[3].vx = bx + *(u16 *)(rs + 0x10);
v[3].vy = by + *(u16 *)(rs + 0x12);
v[3].vz = bz;
gte_ldv3(pa1, pa2, pa3);
gte_rtpt();
gte_stsxy3(xbc + oc1, xbc + oc2, xbc + dc3);
dc3 += 0xC;
oc2 += 0xC;
oc1 += 0xC;
i += 3;
qc += 0xC;
} while (i < 12);
func_800226C0((s32 *)obj, vp, (u8 *)xy, ot + t);
}
}
}
/* func_80021D38 — main / src/800.c — 284 ins. Splat marks it "Handwritten
* function" only because of the cop2 opcodes: it is ordinary gcc-2.7.2 -O2 C
@@ -12680,7 +13114,464 @@ void func_800221A8(Obj221A8 *o) {
}
INCLUDE_ASM("asm/nonmatchings/800", func_800226C0);
/* func_800226C0 (main, src/800.c) — emit the 12-segment POLY_G4 strip for one Obj_80021D38
* (plus the E1 draw-mode prims around it) into the D_800A5E60 bump allocator.
*
* Levers that closed it (S76y, from the S75 pinned draft at closeness 545 -> MATCH):
* - `t` is ONE plain `s16` local, read UNINITIALISED at the top (`sll $v0,$s2,16; beqz` =
* an HImode pseudo whose nonzero-bits are unknown before its set) and later assigned from
* the s32 `tt`; the `addu $v0,$s2,$zero; beqz $v0; addu $t2,$v0,$zero` chain at 228E4 is
* the sign-extension of that HImode pseudo folded to a copy (combine get_last_value) and
* then reused by cse2 for the loop's hoisted multiplier -- a pinned $18 can never do it
* (hard regs have no nonzero-bits). `mul` must stay an unpinned pseudo (global alloc never
* coalesces a pseudo copy; a $10 pin swallows the $v0 temp).
* - `o`, `col`, `sh23`, `abr` unpinned: gcc's own param copies give the prologue order and the
* t/flags callee-saved order (density tie); the `or $v0,$v1,$v0` tie needs `abr` as a pseudo.
* - The !useIdx single-prim block at 850 is the inline addPrim form with block-local temps:
* a pinned `$a1` mask has reg_n_sets != 1 -> no birthing boost -> placed first in the block.
* Symbols: only D_800A5E60 (14 %hi/%lo pairs in the .s) -- verified against the relocations.
* The two struct typedefs are copies of src/800.c:12191-12209 for the standalone compile; the
* harvest strips them (cdecl.typedef_names above the splice point).
*/
extern u8 *D_800A5E60;
void func_800226C0(Obj_80021D38 *arg0, u8 *col, DVec_80021D38 *pts, u8 *ot)
{
s16 t;
s16 work[24];
u32 flags;
u16 f16;
s32 tt;
s32 uu;
s32 tsh;
u32 sh23;
u8 *p;
u8 *s;
u8 *w;
u8 *e;
s32 k;
s32 m;
s32 h;
u32 x;
u32 y;
register u32 useIdx __asm__("$25");
register u8 code __asm__("$24");
register s32 i __asm__("$11");
register s32 shadow __asm__("$17");
register s32 *zp __asm__("$4");
f16 = *(u16 *)((u8 *)arg0 + 0x1E);
flags = arg0->flags;
useIdx = f16 & 0x8000;
shadow = 0;
if (flags & 0x800000) {
p = D_800A5E60;
shadow = 1;
if (useIdx) {
if (t) {
register u8 *q __asm__("$5");
register u32 e1 __asm__("$13");
register u8 one __asm__("$14");
register u32 maskAddr __asm__("$10");
register u32 maskLen __asm__("$12");
D_800A5E60 = p + 0x60;
i = 0;
one = 1;
e1 = 0xE1000000;
maskAddr = 0x00FFFFFF;
maskLen = 0xFF000000;
q = p + 4;
do {
h = i >> 1;
i++;
zp = (s32 *)((h << 2) + (u32)((u8 *)pts));
q[-1] = one;
*(u32 *)q = e1;
q += 8;
x = *(u32 *)p;
y = ((u32 *)ot)[zp[13]];
x &= maskLen;
y &= maskAddr;
x |= y;
*(u32 *)p = x;
((u32 *)ot)[zp[13]] = (((u32 *)ot)[zp[13]] & maskLen) | ((u32)p & maskAddr);
p += 8;
} while (i < 12);
} else {
register u8 *q __asm__("$10");
register s32 *zq __asm__("$5");
register u32 e1 __asm__("$14");
register u8 one __asm__("$15");
register u32 maskAddr __asm__("$12");
register u32 maskLen __asm__("$13");
D_800A5E60 = p + 0x30;
i = 0;
one = 1;
e1 = 0xE1000000;
maskAddr = 0x00FFFFFF;
maskLen = 0xFF000000;
q = p + 4;
zq = (s32 *)((u8 *)pts);
do {
i++;
q[-1] = one;
*(u32 *)q = e1;
q += 8;
x = *(u32 *)p;
y = ((u32 *)ot)[zq[13]];
x &= maskLen;
y &= maskAddr;
x |= y;
*(u32 *)p = x;
((u32 *)ot)[zq[13]] = (((u32 *)ot)[zq[13]] & maskLen) | ((u32)p & maskAddr);
zq = (s32 *)((u8 *)zq + 4);
p += 8;
} while (i < 6);
}
} else {
D_800A5E60 = p + 8;
p[3] = 1;
*(u32 *)(p + 4) = 0xE1000000;
*(u32 *)p = (*(u32 *)p & 0xFF000000) | (((u32 *)ot)[0] & 0x00FFFFFF);
((u32 *)ot)[0] = (((u32 *)ot)[0] & 0xFF000000) | ((u32)p & 0x00FFFFFF);
}
}
f16 = *(u16 *)((u8 *)arg0 + 0x1E);
p = D_800A5E60;
tt = f16 & 0x1FFF;
t = tt;
D_800A5E60 = tt ? p + 0x1B0 : p + 0xD8;
code = (flags & 0x40000000) ? 0x3A : 0x38;
if (t) {
{
s32 mul;
register s16 *dst __asm__("$5");
register s16 *src __asm__("$4");
i = 0;
mul = t;
dst = work;
src = (s16 *)((u8 *)pts);
do {
*dst = *(s16 *)((u8 *)pts) + (((src[2] - *(s16 *)((u8 *)pts)) * mul) >> 12);
dst[1] = *(s16 *)(((u8 *)pts) + 2) + (((src[3] - *(s16 *)(((u8 *)pts) + 2)) * mul) >> 12);
i++;
src += 2;
dst += 2;
} while (i < 12);
}
{
register u32 maskAddr __asm__("$12");
register u32 maskLen __asm__("$15");
register s32 kk __asm__("$14");
register u8 *ww __asm__("$13");
register u8 *ss __asm__("$10");
register u8 *d __asm__("$5");
i = 0;
maskAddr = 0x00FFFFFF;
maskLen = 0xFF000000;
d = p + 0x22;
kk = 4;
ww = (u8 *)work;
ss = ((u8 *)pts);
do {
d[-0x1F] = 8;
d[-0x1B] = code;
d[-0x1E] = col[4];
d[-0x1D] = col[5];
d[-0x1C] = col[6];
d[-0x16] = col[4];
d[-0x15] = col[5];
d[-0x14] = col[6];
d[-0x0E] = col[0];
d[-0x0D] = col[1];
d[-0x0C] = col[2];
d[-0x06] = col[0];
d[-0x05] = col[1];
d[-0x04] = col[2];
*(u16 *)(d - 0x1A) = *(u16 *)(ss + 4);
*(u16 *)(d - 0x18) = *(u16 *)(ss + 6);
*(u16 *)(d - 0x12) = *(u16 *)(ss + 8);
*(u16 *)(d - 0x10) = *(u16 *)(ss + 0xA);
*(u16 *)(d - 0x0A) = *(u16 *)(ww);
*(u16 *)(d - 0x08) = *(u16 *)(ww + 2);
e = (u8 *)work + kk;
*(u16 *)(d - 0x02) = *(u16 *)e;
*(u16 *)(d) = *(u16 *)(e + 2);
if (useIdx) {
h = i >> 1;
zp = (s32 *)((h << 2) + (u32)((u8 *)pts));
x = *(u32 *)p;
y = ((u32 *)ot)[zp[13]];
x &= maskLen;
y &= maskAddr;
x |= y;
*(u32 *)p = x;
((u32 *)ot)[zp[13]] = (((u32 *)ot)[zp[13]] & maskLen) | ((u32)p & maskAddr);
} else {
x = *(u32 *)p;
y = ((u32 *)ot)[0];
x &= maskLen;
y &= maskAddr;
x |= y;
*(u32 *)p = x;
((u32 *)ot)[0] = (((u32 *)ot)[0] & maskLen) | ((u32)p & maskAddr);
}
kk += 4;
ww += 4;
ss += 4;
i++;
d += 0x24;
p += 0x24;
} while (i < 12);
}
*(u16 *)(p - 0x14) = *(u16 *)(((u8 *)pts) + 4);
*(u16 *)(p - 0x12) = *(u16 *)(((u8 *)pts) + 6);
*(u16 *)(p - 0x04) = *(u16 *)work;
*(u16 *)(p - 0x02) = *(u16 *)((u8 *)work + 2);
if (*(u16 *)((u8 *)arg0 + 0x1E) & 0x4000) {
register u32 maskAddr __asm__("$10");
register u32 maskLen __asm__("$15");
register s32 mm __asm__("$14");
register s32 kk __asm__("$13");
register u8 *ww __asm__("$12");
register u8 *d __asm__("$5");
i = 0;
maskAddr = 0x00FFFFFF;
maskLen = 0xFF000000;
mm = 8;
kk = 4;
p = D_800A5E60;
ww = (u8 *)work;
d = p + 0x22;
D_800A5E60 = p + 0xD8;
do {
d[-0x1F] = 8;
d[-0x1B] = code;
d[-0x1E] = col[0x0C];
d[-0x1D] = col[0x0D];
d[-0x1C] = col[0x0E];
d[-0x16] = col[0x0C];
d[-0x15] = col[0x0D];
d[-0x14] = col[0x0E];
d[-0x0E] = col[0x08];
d[-0x0D] = col[0x09];
d[-0x0C] = col[0x0A];
d[-0x06] = col[0x0C];
d[-0x05] = col[0x0D];
d[-0x04] = col[0x0E];
*(u16 *)(d - 0x1A) = *(u16 *)(ww);
*(u16 *)(d - 0x18) = *(u16 *)(ww + 2);
e = (u8 *)work + kk;
*(u16 *)(d - 0x12) = *(u16 *)e;
*(u16 *)(d - 0x10) = *(u16 *)(e + 2);
*(u16 *)(d - 0x0A) = *(u16 *)(((u8 *)pts));
*(u16 *)(d - 0x08) = *(u16 *)(((u8 *)pts) + 2);
e = (u8 *)work + mm;
*(u16 *)(d - 0x02) = *(u16 *)e;
*(u16 *)(d) = *(u16 *)(e + 2);
if (useIdx) {
h = i >> 1;
zp = (s32 *)((h << 2) + (u32)work);
x = *(u32 *)p;
y = ((u32 *)ot)[zp[13]];
x &= maskLen;
y &= maskAddr;
x |= y;
*(u32 *)p = x;
((u32 *)ot)[zp[13]] = (((u32 *)ot)[zp[13]] & maskLen) | ((u32)p & maskAddr);
} else {
x = *(u32 *)p;
y = ((u32 *)ot)[0];
x &= maskLen;
y &= maskAddr;
x |= y;
*(u32 *)p = x;
((u32 *)ot)[0] = (((u32 *)ot)[0] & maskLen) | ((u32)p & maskAddr);
}
mm += 8;
kk += 8;
ww += 8;
i += 2;
d += 0x24;
p += 0x24;
} while (i < 12);
*(u16 *)(p - 0x04) = *(u16 *)work;
*(u16 *)(p - 0x02) = *(u16 *)((u8 *)work + 2);
}
} else {
register u32 maskAddr __asm__("$12");
register u32 maskLen __asm__("$13");
register u8 *ss __asm__("$10");
register u8 *d __asm__("$5");
i = 1;
maskAddr = 0x00FFFFFF;
maskLen = 0xFF000000;
d = p + 0x22;
ss = ((u8 *)pts) + 4;
do {
d[-0x1F] = 8;
d[-0x1B] = code;
d[-0x1E] = col[4];
d[-0x1D] = col[5];
d[-0x1C] = col[6];
d[-0x16] = col[4];
d[-0x15] = col[5];
d[-0x14] = col[6];
d[-0x0E] = col[0];
d[-0x0D] = col[1];
d[-0x0C] = col[2];
d[-0x06] = col[4];
d[-0x05] = col[5];
d[-0x04] = col[6];
*(u16 *)(d - 0x1A) = *(u16 *)(ss);
*(u16 *)(d - 0x18) = *(u16 *)(ss + 2);
*(u16 *)(d - 0x12) = *(u16 *)(ss + 4);
*(u16 *)(d - 0x10) = *(u16 *)(ss + 6);
*(u16 *)(d - 0x0A) = *(u16 *)(((u8 *)pts));
*(u16 *)(d - 0x08) = *(u16 *)(((u8 *)pts) + 2);
*(u16 *)(d - 0x02) = *(u16 *)(ss + 8);
*(u16 *)(d) = *(u16 *)(ss + 0x0A);
if (useIdx) {
h = i >> 1;
zp = (s32 *)((h << 2) + (u32)((u8 *)pts));
x = *(u32 *)p;
y = ((u32 *)ot)[zp[13]];
x &= maskLen;
y &= maskAddr;
x |= y;
*(u32 *)p = x;
((u32 *)ot)[zp[13]] = (((u32 *)ot)[zp[13]] & maskLen) | ((u32)p & maskAddr);
} else {
x = *(u32 *)p;
y = ((u32 *)ot)[0];
x &= maskLen;
y &= maskAddr;
x |= y;
*(u32 *)p = x;
((u32 *)ot)[0] = (((u32 *)ot)[0] & maskLen) | ((u32)p & maskAddr);
}
ss += 8;
i += 2;
d += 0x24;
p += 0x24;
} while (i < 13);
*(u16 *)(p - 0x04) = *(u16 *)(((u8 *)pts) + 4);
*(u16 *)(p - 0x02) = *(u16 *)(((u8 *)pts) + 6);
}
if (flags & 0x40000000) {
u32 abr;
sh23 = flags >> 23;
abr = sh23 & 0x60;
if (useIdx) {
i = 0;
if (t) {
register u8 *q __asm__("$5");
u32 e1s;
u32 e1n;
register u8 one __asm__("$14");
register u32 maskAddr __asm__("$9");
register u32 maskLen __asm__("$10");
one = 1;
e1s = abr | 0xE1000200;
e1n = abr | 0xE1000000;
maskAddr = 0x00FFFFFF;
maskLen = 0xFF000000;
q = p + 4;
D_800A5E60 = D_800A5E60 + 0x60;
do {
q[-1] = one;
if (shadow) {
*(u32 *)q = e1s;
} else {
*(u32 *)q = e1n;
}
h = i >> 1;
i++;
zp = (s32 *)((h << 2) + (u32)((u8 *)pts));
q += 8;
x = *(u32 *)p;
y = ((u32 *)ot)[zp[13]];
x &= maskLen;
y &= maskAddr;
x |= y;
*(u32 *)p = x;
((u32 *)ot)[zp[13]] = (((u32 *)ot)[zp[13]] & maskLen) | ((u32)p & maskAddr);
p += 8;
} while (i < 12);
} else {
register u8 *q __asm__("$5");
u32 e1s;
u32 e1n;
register u8 one __asm__("$14");
register u32 maskAddr __asm__("$9");
register u32 maskLen __asm__("$10");
register s32 *zq __asm__("$6");
one = 1;
e1s = abr | 0xE1000200;
e1n = abr | 0xE1000000;
maskAddr = 0x00FFFFFF;
maskLen = 0xFF000000;
q = p + 4;
D_800A5E60 = D_800A5E60 + 0x30;
zq = (s32 *)((u8 *)pts);
do {
q[-1] = one;
if (shadow) {
*(u32 *)q = e1s;
} else {
*(u32 *)q = e1n;
}
i++;
q += 8;
x = *(u32 *)p;
y = ((u32 *)ot)[zq[13]];
x &= maskLen;
y &= maskAddr;
x |= y;
*(u32 *)p = x;
((u32 *)ot)[zq[13]] = (((u32 *)ot)[zq[13]] & maskLen) | ((u32)p & maskAddr);
zq = (s32 *)((u8 *)zq + 4);
p += 8;
} while (i < 6);
}
} else {
register u32 maskAddr __asm__("$4");
register u32 maskLen __asm__("$5");
D_800A5E60 = D_800A5E60 + 8;
p[3] = 1;
*(u32 *)(p + 4) = abr | (shadow ? 0xE1000200 : 0xE1000000);
maskAddr = 0x00FFFFFF;
maskLen = 0xFF000000;
x = *(u32 *)p;
y = ((u32 *)ot)[0];
x &= maskLen;
y &= maskAddr;
x |= y;
*(u32 *)p = x;
((u32 *)ot)[0] = (((u32 *)ot)[0] & maskLen) | ((u32)p & maskAddr);
}
}
}
extern u8 *D_800A5E60;
+41 -2
View File
@@ -24,10 +24,49 @@ s32 func_80062394(void)
return D_80072A24;
}
INCLUDE_ASM("asm/nonmatchings/800c2_2", func_800623A4);
extern void func_80062768(void);
extern void func_8005CF08(void);
extern void func_800626F0(void);
extern void func_8005CF18(void);
extern s32 ChangeClearPAD(s32 mode);
extern void func_8006252C(void);
extern s32 PAD_init2(s32, s32, s32, s32);
extern s32 D_80072A24;
void func_800623A4(s32 a0, s32 a1, s32 a2, s32 a3)
{
func_80062768();
func_8005CF08();
func_800626F0();
func_8005CF18();
ChangeClearPAD(0);
func_8006252C();
PAD_init2(a0, a1, a2, a3);
D_80072A24 = 1;
}
INCLUDE_ASM("asm/nonmatchings/800c2_2", func_80062434);
extern void func_80062768(void);
extern void func_8005CF08(void);
extern void func_800626F0(void);
extern void func_8005CF18(void);
extern s32 ChangeClearPAD(s32 mode);
extern void func_8006252C(void);
extern void InitPAD2(s32 a0, s32 a1, s32 a2, s32 a3);
extern s32 D_80072A24;
void func_80062434(s32 a0, s32 a1, s32 a2, s32 a3)
{
func_80062768();
func_8005CF08();
func_800626F0();
func_8005CF18();
ChangeClearPAD(0);
func_8006252C();
InitPAD2(a0, a1, a2, a3);
D_80072A24 = 1;
}
extern void StartPAD2(void);
extern s32 ChangeClearPAD(s32 mode);
+42 -4
View File
@@ -299,7 +299,16 @@ s32 StartRCnt(s32 spec) {
return t < 3;
}
INCLUDE_ASM("asm/nonmatchings/800c3", StopRCnt);
extern s32 D_80072934;
extern s32 D_8007293C[];
s32 StopRCnt(s32 spec) {
s32 t;
t = spec & 0xFFFF;
*(s32 *)(D_80072934 + 4) &= ~D_8007293C[t];
return 1;
}
extern u32 D_80072938;
@@ -427,11 +436,40 @@ extern void* (*D_80072970)(void);
extern void* (*D_80072970)(void);
INCLUDE_ASM("asm/nonmatchings/800c3", func_8005D410);
extern void* (*D_80072970)(void);
INCLUDE_ASM("asm/nonmatchings/800c3", func_8005D4B8);
s32 func_8005D410(s32 arg0, s32 arg1, s32 arg2) {
u8 *p;
INCLUDE_ASM("asm/nonmatchings/800c3", func_8005D4F0);
p = (u8 *)(*D_80072970)();
if (arg1 < 0) {
return *(p + 0xEA);
}
if (arg1 >= *(p + 0xEA)) {
return 0;
}
p = *(u8 **)(p + 8) + (arg1 << 3);
if (arg2 < 0) {
return *p;
}
if (arg2 >= *p) {
return 0;
}
return *(*(u8 **)(p + 4) + arg2);
}
extern void* (*D_80072970)(void);
extern void func_8005E79C();
void func_8005D4B8(void *a0, void *a1) {
func_8005E79C(D_80072970(), a1);
}
extern void* (*D_80072970)(void);
void func_8005D4F0(s32 arg0, s32 arg1, s32 arg2) {
func_8005E8E8(D_80072970(), (u8)arg1, (u8)arg2);
}
INCLUDE_ASM("asm/nonmatchings/800c3", func_8005D538);
+218 -1
View File
@@ -175,7 +175,224 @@ __asm__(".text\n"
".set\treorder\n"
".end\t__do_global_dtors\n");
INCLUDE_ASM("asm/nonmatchings/boot", main);
extern u8 D_800BA118;
extern u8 D_800AF630[];
extern s32 D_80074778;
extern s32 D_800A2B7C;
extern s32 D_800C7C70;
extern s16 D_800C7C74;
extern s32 D_800A5E60;
extern u8 D_8007BA70[];
extern u8 D_800A4F48[];
extern s32 D_800A651C;
extern u8 D_800A6528[];
extern u8 D_800A6610[];
extern u8 D_800AA60C[];
extern s32 D_800AE7BC;
extern s32 D_800AE7C8;
extern u8 D_800BA0D8[];
extern u8 D_800BA0E4[];
extern void func_80043060(s32);
extern void func_800141F0(void);
extern void func_8005FC68(s32);
extern void func_8005FCB8(void);
extern void func_80018918(void);
extern s32 func_80043300(void);
extern void func_8002C8F4(void);
extern void LoaderInitFileTable(void);
extern void func_80014238(void);
extern void func_80014390(void);
extern void func_800191A8(void);
extern void func_80010A98(void);
extern void func_800189A8(void);
extern void func_80015208(void);
extern void func_80059BFC(s32, s32);
extern void GameModeDispatch(void);
extern void func_80015498(void);
extern void func_8001C00C(void);
extern void func_800D25FC(void);
extern void func_800184F0(void);
extern void func_800596F4(s32);
extern s32 VSync(s32);
extern void func_80059FC0(u8 *);
extern void func_80059D68(u8 *);
extern void CatPrim(s32, s32);
extern s32 func_80059CF4(s32);
extern void func_8003500C(void);
extern void func_8002D034(void);
extern void func_8001AF34(void);
extern void func_8001513C(void);
extern void func_80042610(void (*)(void));
struct MainSlot { s32 unk0; s32 unk4; s32 unk8; };
// @class: other
// @stuck: none -- MATCH (509 ins, -O0 boot object).
/*
* main (0x80010178) -- the game's outer frame loop, compiled -O0 like the rest of
* src/boot.c (frame-pointer prologue, every global re-loaded per use).
*
* The four gcc-2.7.2 -O0 levers this needed (all NEW, none were in the cookbook):
*
* 1. TWO `register` locals, in declaration order, hold the two bases the whole
* function addresses through: $s0 = &D_800BA118 (loaded, NEVER used again --
* it must still be declared or the lui/addiu pair and the $s0 save/restore
* both vanish) and $s1 = D_800AF630. Same lever GameModeDispatch/func_8001099C
* already use in this TU; the >0x7FFF member offsets then assemble to the
* +0x10000/-0x5Cxx split.
*
* 2. `s32 pad[6];` -- 24 bytes of DECLARED-BUT-UNUSED stack. At -O0 gcc reserves a
* slot for every local whether or not it is read, and the target's frame is
* 0x38 (16 outgoing-arg + 24 vars + 16 saved). Without it the frame is 0x20 and
* every sp offset in the prologue/epilogue is wrong. The original's six words
* were presumably dead locals left in the source.
*
* 3. THE SHIFT-FORM MULTIPLY. Inside a MEMORY ADDRESS, `base + i * K` with a
* CONSTANT K expands (expand_expr MULT under EXPAND_SUM) to a `(mult reg K)`
* rtx that force_operand emits with the INDEX FIRST: `addu d,index,base`.
* Writing the same value as `base + ((i * (K>>n)) << n)` materialises the index
* into a plain register first, and the address then comes out BASE-first --
* `addu $v0,$s1,$a0` / `addu $at,$at,$v0` + `%lo(sym)($at)` -- which is what the
* target has. Measured: `p + i*12` -> `addu $4,$3,$2` (wrong), `p + ((i*3)<<2)`
* -> `addu $4,$2,$3` (right). Only address context is affected; in VALUE context
* (`(s32)(D_800A6610 + i*16384)`) the plain multiply already comes out base-first.
*
* 4. The three 12-byte-strided stores go through a struct pointer, not
* `*(s32 *)(p + ... + 8)`: only a COMPONENT_REF folds the member offset into the
* store (`sw $v1,0x8($v0)`); the pointer-arithmetic spelling materialises it as
* a separate `addiu`.
*
* Two smaller ones: `(*(u16 *)(p + 0xA3A8))++` emits the extra `addu $v0,$v1,$zero`
* that `+= 1` does not; and CatPrim's second argument is written
* `<load> + D_80074778 * 4` (NOT `D_80074778 * 4 + <load>`) -- with a MEM as operand
* 0 gcc emits the MEM's address first, then operand 1, then the load, and the addu
* comes out operand-1-first, exactly the target's interleave.
*
* The two scratchpad-stack switches around func_80015498/func_8001C00C/func_800D25FC
* are the §261 idiom: the $sp repointing is inline asm, the calls stay C (so -O0
* supplies the `jal` + delay-slot nop). $a2 here, not the overlays' $v1.
*/
void main(void) {
register u8 *q = &D_800BA118;
register u8 *p = D_800AF630;
s32 pad[6];
func_80043060(0);
D_80074778 = 0x3E0;
func_800141F0();
func_8005FC68(0);
func_8005FCB8();
func_80018918();
D_800A2B7C = func_80043300();
func_8002C8F4();
LoaderInitFileTable();
while (1) {
func_80014238();
func_80014390();
func_800191A8();
func_80010A98();
while (*(u16 *)(p + 0xA3D4) == 0) {
D_800C7C70++;
D_800C7C70 = D_800C7C70 ? D_800C7C70 : 1;
D_800C7C74 = !D_800C7C74;
*(u16 *)(p + 0xA3D2) = D_800C7C74;
D_800A5E60 = (s32)(D_8007BA70 + *(u16 *)(p + 0xA3D2) * 80000);
((struct MainSlot *)(p + ((*(u16 *)(p + 0xA3D2) * 3) << 2)))->unk8 =
(s32)(D_800A4F48 + *(u16 *)(p + 0xA3D2) * 1600);
((struct MainSlot *)(p + ((*(u16 *)(p + 0xA3D2) * 3) << 2)))->unk0 = 0x640;
((struct MainSlot *)(p + ((*(u16 *)(p + 0xA3D2) * 3) << 2)))->unk4 = 0;
func_800189A8();
func_80015208();
if (*(u8 *)(p + 0xA3E3) == 0) {
(*(u16 *)(p + 0xA3A8))++;
*(u16 *)(p + 0xA3AC) += *(u16 *)(p + 0xA3A8);
*(s32 *)((u8 *)&D_800A651C + ((*(u16 *)(p + 0xA3D2) * 5) << 2)) =
(s32)(D_800A6610 + *(u16 *)(p + 0xA3D2) * 16384);
*(s32 *)(D_800A6528 + ((*(u16 *)(p + 0xA3D2) * 5) << 2)) =
*(u16 *)(p + 0xA3D2) * 16384 + (s32)D_800AA60C;
func_80059BFC(*(s32 *)((u8 *)&D_800A651C + ((*(u16 *)(p + 0xA3D2) * 5) << 2)), 0x1000);
*(s32 *)((u8 *)&D_800AE7BC + ((*(u16 *)(p + 0xA3D2) * 5) << 2)) =
(s32)(D_800BA0D8 + *(u16 *)(p + 0xA3D2) * 16);
*(s32 *)((u8 *)&D_800AE7C8 + ((*(u16 *)(p + 0xA3D2) * 5) << 2)) =
*(u16 *)(p + 0xA3D2) * 16 + (s32)D_800BA0E4;
func_80059BFC(*(s32 *)((u8 *)&D_800AE7BC + ((*(u16 *)(p + 0xA3D2) * 5) << 2)), 4);
GameModeDispatch();
__asm__ __volatile__(
"lui $a2, 0x1f80\n"
"ori $a2, $a2, 0x03fc\n"
"addu $t0, $a2, $zero\n"
"sw $sp, 0($t0)\n"
"addiu $t0, $t0, -4\n"
"addu $sp, $t0, $zero\n" : : : "memory");
func_80015498();
__asm__ __volatile__(
"addiu $sp, $sp, 4\n"
"lw $sp, 0($sp)\n" : : : "memory");
__asm__ __volatile__(
"lui $a2, 0x1f80\n"
"ori $a2, $a2, 0x03fc\n"
"addu $t0, $a2, $zero\n"
"sw $sp, 0($t0)\n"
"addiu $t0, $t0, -4\n"
"addu $sp, $t0, $zero\n" : : : "memory");
func_8001C00C();
__asm__ __volatile__(
"addiu $sp, $sp, 4\n"
"lw $sp, 0($sp)\n" : : : "memory");
} else {
*(s32 *)((u8 *)&D_800AE7BC + ((*(u16 *)(p + 0xA3D2) * 5) << 2)) =
(s32)(D_800BA0D8 + *(u16 *)(p + 0xA3D2) * 16);
*(s32 *)((u8 *)&D_800AE7C8 + ((*(u16 *)(p + 0xA3D2) * 5) << 2)) =
*(u16 *)(p + 0xA3D2) * 16 + (s32)D_800BA0E4;
func_80059BFC(*(s32 *)((u8 *)&D_800AE7BC + ((*(u16 *)(p + 0xA3D2) * 5) << 2)), 4);
__asm__ __volatile__(
"lui $a2, 0x1f80\n"
"ori $a2, $a2, 0x03fc\n"
"addu $t0, $a2, $zero\n"
"sw $sp, 0($t0)\n"
"addiu $t0, $t0, -4\n"
"addu $sp, $t0, $zero\n" : : : "memory");
func_800D25FC();
__asm__ __volatile__(
"addiu $sp, $sp, 4\n"
"lw $sp, 0($sp)\n" : : : "memory");
}
func_800184F0();
func_800596F4(0);
VSync(*(s32 *)(p + 0xA3E8));
*(u16 *)(p + 0x188) = *(u16 *)(p + 0x18A);
(*(u16 *)(p + 0x18A))++;
if (*(u16 *)(p + 0x18A) > 1) {
*(u16 *)(p + 0x18A) = 0;
}
func_80059FC0(&p[*(u16 *)(p + 0x188) * 20 + 0x14C]);
func_80059D68(&p[*(u16 *)(p + 0x18A) * 92 + 0x38]);
CatPrim(*(s32 *)((u8 *)&D_800A651C + ((*(u16 *)(p + 0xA3D2) * 5) << 2)) + 0x3FF0,
*(s32 *)((u8 *)&D_800A651C + ((*(u16 *)(p + 0xA3D2) * 5) << 2)) + D_80074778 * 4);
func_80059CF4(*(s32 *)((u8 *)&D_800A651C + ((*(u16 *)(p + 0xA3D2) * 5) << 2)) + 0x3FFC);
func_80059CF4(*(s32 *)((u8 *)&D_800AE7BC + ((*(u16 *)(p + 0xA3D2) * 5) << 2)) + 0xC);
func_8003500C();
func_8002D034();
func_8001AF34();
func_8001513C();
}
func_80042610(0);
}
}
void func_8001096C(void) {
extern void func_8002CDD8(void);