feat(phase-31): wave R — 18 main functions banked (EXE 143dbb89 byte-identical)

This commit is contained in:
Drew T
2026-08-16 20:03:03 -06:00
parent 472ff5806a
commit e960382de7
5 changed files with 1465 additions and 18 deletions
+939 -10
View File
File diff suppressed because it is too large Load Diff
+195 -3
View File
@@ -142,7 +142,89 @@ INCLUDE_ASM("asm/nonmatchings/800c", func_80059658);
INCLUDE_ASM("asm/nonmatchings/800c", func_800596F4);
INCLUDE_ASM("asm/nonmatchings/800c", func_80059760);
/* func_80059760 ("checkRECT" per Ghidra) is NOT independently C-compilable: the target's own
* 0xD8-byte range ends with a bare fallthrough into a sibling symbol (SYS_OBJ_604) with ZERO
* epilogue of its own, and its earlier exits are plain "j SYS_OBJ_604"/"j SYS_OBJ_640" with no
* jal and no local restore. SYS_OBJ_604's own body (asm/nonmatchings/800c/SYS_OBJ_604.s) reads
* $t0/$s0 directly with NO prologue copy of its own (Ghidra: "unaff_s0") -- these three symbols
* (func_80059760 / SYS_OBJ_604 / SYS_OBJ_640) share ONE register allocation and ONE stack frame,
* i.e. they are the compiled output of a single original function that this project's tooling
* split into 3 addressable chunks. Empirically verified (scratch tests): gcc-2.7.2 -O2 ALWAYS
* synthesizes a trailing return/jump for a C function (even one whose body is pure inline asm,
* even with __attribute__((noreturn)), even with every path ending in an asm jump) -- there is
* no way to get a bare "j SYS_OBJ_640" out of ordinary (or asm-augmented) C-function codegen; a
* real cross-function jal+return always grows the frame (confirmed: 61 ins vs target's 54, extra
* epilogue at each exit). File-scope raw asm (outside any C function) is therefore the only way
* to reproduce this byte range exactly -- same idiom as the cookbook's "full-inline-asm TRAMPOLINE"
* entry (a $sp-switch body "NOT expressible in C"), just at file scope so gcc adds no trailer.
*/
__asm__(
".text\n"
".align\t2\n"
".globl\tfunc_80059760\n"
".ent\tfunc_80059760\n"
"func_80059760:\n"
" .set\tnoreorder\n"
" addiu $sp, $sp, -32\n"
" addu $t0, $a0, $zero\n"
" sw $s0, 24($sp)\n"
" addu $s0, $a1, $zero\n"
" lui $v1, %hi(D_8007278A)\n"
" lbu $v1, %lo(D_8007278A)($v1)\n"
" addiu $v0, $zero, 1\n"
" beq $v1, $v0, .L80059798\n"
" sw $ra, 28($sp)\n"
" addiu $v0, $zero, 2\n"
" beq $v1, $v0, .L80059830\n"
" nop\n"
" j SYS_OBJ_640\n"
" nop\n"
".L80059798:\n"
" lh $a1, 4($s0)\n"
" lui $v1, %hi(D_8007278C)\n"
" lh $v1, %lo(D_8007278C)($v1)\n"
" nop\n"
" slt $v0, $v1, $a1\n"
" bnez $v0, .L80059820\n"
" nop\n"
" lh $a3, 0($s0)\n"
" nop\n"
" addu $v0, $a1, $a3\n"
" slt $v0, $v1, $v0\n"
" bnez $v0, .L80059820\n"
" nop\n"
" lh $v1, 2($s0)\n"
" lui $a0, %hi(D_8007278E)\n"
" lh $a0, %lo(D_8007278E)($a0)\n"
" nop\n"
" slt $v0, $a0, $v1\n"
" bnez $v0, .L80059820\n"
" nop\n"
" lh $a2, 6($s0)\n"
" nop\n"
" addu $v0, $v1, $a2\n"
" slt $v0, $a0, $v0\n"
" bnez $v0, .L80059820\n"
" nop\n"
" blez $a1, .L80059820\n"
" nop\n"
" bltz $a3, .L80059820\n"
" nop\n"
" bltz $v1, .L80059820\n"
" nop\n"
" bgtz $a2, SYS_OBJ_640\n"
" nop\n"
".L80059820:\n"
" lui $a0, %hi(D_80074154)\n"
" addiu $a0, $a0, %lo(D_80074154)\n"
" j SYS_OBJ_604\n"
" nop\n"
".L80059830:\n"
" lui $a0, %hi(D_80074174)\n"
" addiu $a0, $a0, %lo(D_80074174)\n"
".end\tfunc_80059760\n"
);
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_604);
@@ -160,7 +242,44 @@ INCLUDE_ASM("asm/nonmatchings/800c", MoveImage);
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_8F4);
INCLUDE_ASM("asm/nonmatchings/800c", ClearOTag);
extern u8 D_8007278A;
extern u32 D_80072784;
extern char D_800741A8;
extern char D_80072844;
void *ClearOTag(u32 *otag, s32 n)
{
u32 mask_low;
u32 mask_high;
u32 next_addr;
u32 val;
if (D_8007278A >= 2) {
void (*func)(u32, u32, s32) = (void (*)(u32, u32, s32))D_80072784;
func((u32)&D_800741A8, (u32)otag, n);
}
n--;
if (n != 0) {
mask_low = 0xFFFFFF;
mask_high = 0xFF000000;
while (n) {
n--;
next_addr = (u32)otag + 4;
*(u8 *)((u32)otag + 3) = 0;
val = *otag;
val = (val & mask_high);
val = val | (next_addr & mask_low);
*otag = val;
otag = (u32 *)next_addr;
}
}
*otag = (u32)&D_80072844 & 0xFFFFFF;
return otag;
}
INCLUDE_ASM("asm/nonmatchings/800c", func_80059BFC);
@@ -174,7 +293,80 @@ INCLUDE_ASM("asm/nonmatchings/800c", DrawOTagEnv);
INCLUDE_ASM("asm/nonmatchings/800c", GetDrawEnv);
INCLUDE_ASM("asm/nonmatchings/800c", func_80059FC0);
/*
* func_80059FC0 -- part of the SYS_OBJ_XXXX GPU-primitive dispatch family (splat's naming for
* hex offsets into a shared handler table). Like GsTMDfastG3GL (src/800b2.c), this is reproduced
* as handwritten assembly: BOTH branches end with a raw, unlinked tail jump into SYS_OBJ_E34
* (args left in $v0/$v1, not $a0/$a1; $ra/$s0-$s3 saved but never restored by this function) --
* SYS_OBJ_E34 owns the shared epilogue for this family, using the fixed 0x28-byte / s0-s3+ra
* frame layout every sibling in the family shares. There is NO trailing "jr $ra" anywhere in the
* target (function size is exactly 0xA8 bytes, ending mid-basic-block) -- gcc-2.7.2 has no
* general sibcall optimization AND unconditionally appends its own return sequence to every
* ordinary (even __asm__-bodied) C function (function.c:expand_function_end, no noreturn guard,
* confirmed empirically both on the callee and on this function itself), so wrapping the body in
* a normal C function can only ever get within +2 instructions (the phantom trailing jr/nop) of
* this target. FILE-SCOPE asm (outside any C function body) is the only spelling that emits
* exactly the target bytes with nothing appended: the compiler treats it as opaque text, no
* .ent-triggered epilogue machinery ever runs.
*/
__asm__(
".text\n"
".align\t2\n"
".globl\tfunc_80059FC0\n"
".ent\tfunc_80059FC0\n"
"func_80059FC0:\n"
".frame\t$sp,40,$31\n"
".mask\t0x800f0000,-8\n"
".fmask\t0x00000000,0\n"
".set\tnoreorder\n"
"lui $2, %hi(D_8007278A)\n"
"lbu $2, %lo(D_8007278A)($2)\n"
"addiu $sp, $sp, -40\n"
"sw $16, 16($sp)\n"
"addu $16, $4, $0\n"
"sw $19, 28($sp)\n"
"lui $19, 0x0800\n"
"sw $31, 32($sp)\n"
"sw $18, 24($sp)\n"
"sltiu $2, $2, 2\n"
"bnez $2, 1f\n"
" sw $17, 20($sp)\n"
"lui $4, %hi(D_80074220)\n"
"addiu $4, $4, %lo(D_80074220)\n"
"lui $2, %hi(D_80072784)\n"
"lw $2, %lo(D_80072784)($2)\n"
"nop\n"
"jalr $2\n"
" addu $5, $16, $0\n"
"1:\n"
"lui $2, %hi(D_80072788)\n"
"lbu $2, %lo(D_80072788)($2)\n"
"nop\n"
"addiu $2, $2, -1\n"
"sltiu $2, $2, 2\n"
"beqz $2, 2f\n"
" nop\n"
"jal func_8005ADB8\n"
" addu $4, $16, $0\n"
"lhu $3, 2($16)\n"
"andi $2, $2, 0xfff\n"
"andi $3, $3, 0xfff\n"
"sll $3, $3, 12\n"
"or $3, $3, $2\n"
"j SYS_OBJ_E34\n"
" lui $2, 0x0500\n"
"2:\n"
"lhu $2, 2($16)\n"
"lhu $3, 0($16)\n"
"andi $2, $2, 0x3ff\n"
"sll $2, $2, 10\n"
"andi $3, $3, 0x3ff\n"
"or $2, $2, $3\n"
"lui $3, 0x0500\n"
".set\treorder\n"
".end\tfunc_80059FC0\n"
);
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_E34);
+49 -1
View File
@@ -109,7 +109,55 @@ INCLUDE_ASM("asm/nonmatchings/800c3", func_8005D118);
INCLUDE_ASM("asm/nonmatchings/800c3", func_8005D138);
INCLUDE_ASM("asm/nonmatchings/800c3", func_8005D184);
extern void* (*D_80072970)(void);
s32 func_8005D184(s32 arg0) {
void* v0;
register s32 v1 __asm__("$3");
v0 = D_80072970();
if ((*(u32*)((u8*)v0 + 0x34) & 0xFFFF0000) != 0) {
goto do_switch;
}
if ((u32)v0 == *(u32*)((u8*)v0 + 0x10)) {
goto check30;
}
if (*(u8*)((u8*)v0 + 0x38) != 0) {
goto do_switch;
}
check30:
if (*(u8*)*(u32*)((u8*)v0 + 0x30) == 0) {
goto return_byte;
}
do_switch:
v1 = *(u8*)((u8*)v0 + 0x49);
if (v1 == 3) {
goto return_one;
}
if (v1 < 4) {
if (v1 == 2) {
goto return_one;
}
goto return_byte;
}
if (v1 == 6) {
goto return_four;
}
goto return_byte;
return_one:
return 1;
return_four:
return 4;
return_byte:
return *(u8*)((u8*)v0 + 0x49);
}
INCLUDE_ASM("asm/nonmatchings/800c3", func_8005D244);
+36 -1
View File
@@ -60,7 +60,42 @@ INCLUDE_ASM("asm/nonmatchings/boot", func_80010E7C);
INCLUDE_ASM("asm/nonmatchings/boot", func_80010ED4);
INCLUDE_ASM("asm/nonmatchings/boot", func_80010F80);
extern void func_800CEEC8(void);
extern void func_80011B7C(s32);
extern void func_8001C044(void);
extern void func_80015310(void);
extern void func_80011818(s32);
extern void func_80029514(s32);
extern u8 D_800AF630[];
extern u8 D_80078E78[];
extern s32 D_800629C8;
void func_80010F80(void) {
register u8 *p = D_800AF630;
u8 *sp10 = D_80078E78;
func_800CEEC8();
if (*(u16 *)(p + 0xA3B6) != 0) {
func_80011B7C(0);
func_8001C044();
func_80015310();
if (*(s16 *)(p + 0xA3B8) == 4) {
*(u8 *)(p + 0xA434) = 1;
func_80011818(0xF);
} else if (*(s16 *)(p + 0xA3B8) < 2) {
*(s16 *)(p + 0xA3D8) = 0x3005;
*(s16 *)(p + 0xA3DA) = 0x3000;
func_80029514(D_800629C8);
if (*(s16 *)(p + 0xA3B8) == 1) {
func_80011818(0xA);
func_80011B7C(0xB);
} else {
func_80011818(0xA);
}
}
}
(void)sp10;
}
INCLUDE_ASM("asm/nonmatchings/boot", func_800110CC);
+246 -3
View File
@@ -2,12 +2,255 @@
INCLUDE_ASM("asm/nonmatchings/gsgap3", func_800525DC);
INCLUDE_ASM("asm/nonmatchings/gsgap3", func_80052654);
extern void func_80059234(s32 a0);
extern void func_80059D68(u8 *a0);
extern s32 func_80043078(void);
extern void func_80059FC0(u8 *a0);
extern s16 D_800A6440;
extern s16 D_800A6442;
extern s16 D_800A6444;
extern s16 D_800A6446;
extern s16 D_800A6448;
extern s16 D_800A644A;
extern s16 D_800A644C;
extern u8 D_800A644E;
extern u8 D_800A644F;
extern u8 D_800A6450;
extern s16 D_800A6498;
extern s16 D_800A649A;
extern s16 D_800A649C;
extern s16 D_800A649E;
extern s16 D_800A64A0;
extern s16 D_800A64A2;
extern s16 D_800A64A4;
extern s16 D_800A64A6;
extern u8 D_800A64A8;
extern u8 D_800A64A9;
extern u8 D_800A64AA;
extern s16 D_800C7C88;
void func_80052654(u16 w, u16 h, u16 intmode, u16 dither, u16 varh)
{
s16 *p;
s16 *q;
func_80059234((((intmode >> 4) & 3) == 3) ? 3 : 0);
p = &D_800A6440;
D_800A6442 = 0;
*p = 0;
D_800A644A = 0;
D_800A6448 = 0;
D_800A6446 = 0;
D_800A6444 = 0;
D_800A644C = 0;
D_800A644E = dither;
D_800A644F = 0;
D_800A6450 = 0;
func_80059D68((u8 *)p - 8);
q = &D_800A6498;
*q = 0;
D_800A649A = 0;
D_800A649C = w;
D_800A649E = h;
D_800A64A0 = 0;
D_800A64A2 = 0;
D_800A64A4 = 0;
D_800A64A6 = 0;
if (func_80043078() == 1) {
D_800A64A2 = 0x18;
D_800A64AA = 1;
}
D_800A64A8 = intmode & 1;
D_800C7C88 = intmode & 4;
D_800A64A9 = varh;
func_80059FC0((u8 *)q);
}
INCLUDE_ASM("asm/nonmatchings/gsgap3", GsInitGraph2);
INCLUDE_ASM("asm/nonmatchings/gsgap3", func_8005283C);
INCLUDE_ASM("asm/nonmatchings/gsgap3", GsSortClear);
typedef struct {
s16 m[3][3];
s32 t[3];
} Mtx32;
extern volatile s32 D_800AE618;
extern volatile s32 D_800AE61C;
extern Mtx32 D_800AE620;
extern Mtx32 D_800AE7F0;
extern Mtx32 D_800A63F0;
extern Mtx32 D_800A6558;
extern s16 D_800A4F3C;
extern s16 D_800A4F3E;
extern s16 D_800A4F40;
extern s16 D_800A4F42;
extern s16 D_800A5E50;
extern s16 D_800A5E52;
extern s16 D_800AE820;
extern s16 D_800AE822;
extern s16 D_800AE824;
extern s16 D_800AE826;
extern u8 D_80078813;
extern u8 D_80078817;
extern u8 D_80078823;
extern u8 D_80078827;
extern s32 D_800C7C70;
void func_8005283C(s32 arg0, s32 arg1) {
s32 h;
s32 w;
s32 q;
D_800AE61C = (u16)arg1;
h = D_800AE61C;
D_800AE618 = (u16)arg0;
w = D_800AE618;
q = (h << 14) / w;
D_800AE620.m[0][2] = 0;
D_800AE620.m[0][1] = 0;
D_800AE620.m[1][2] = 0;
D_800AE620.m[1][0] = 0;
D_800AE620.m[2][1] = 0;
D_800AE620.m[2][0] = 0;
D_800AE620.t[2] = 0;
D_800AE620.t[1] = 0;
D_800AE620.t[0] = 0;
D_800AE620.m[0][0] = 0x1000;
D_800AE620.m[1][1] = 0x1000;
D_800AE620.m[2][2] = 0x1000;
D_800AE7F0 = D_800AE620;
D_800A63F0 = D_800AE620;
D_800A63F0.m[2][2] = 0;
D_800A63F0.m[1][1] = 0;
D_800A63F0.m[0][0] = 0;
D_800A6558 = D_800A63F0;
D_800A4F3C = 0;
D_800A4F3E = 0;
D_800A4F40 = 0;
D_800A4F42 = 0;
D_800A5E52 = 0;
D_800A5E50 = 0;
D_800AE822 = 0;
D_800AE7F0.m[1][1] = q / 3;
D_800AE820 = 0;
D_800AE824 = w;
D_800AE826 = h;
D_80078813 = 3;
D_80078817 = 2;
D_80078823 = 3;
D_80078827 = 2;
D_800C7C70 = 1;
}
/*
* GsSortClear -- writes the clear-color bytes (r,g,b) plus the width/height/z fields of the
* current double-buffer's sort-tile entry (a 16-byte-stride record based at D_80078810, whose
* individual fields never got a struct symbol -- each is its own splat-auto D_######## label,
* per this TU's convention of one symbol per referenced address). Like func_80059FC0 /
* SYS_OBJ_E34 (src/800c.c) and GsTMDfastG3GL (src/800b2.c), BOTH branches end with a raw,
* unlinked tail jump: the taken (if D_800A64A9) branch ends "j GS_001_OBJ_5D0" (args left live
* in $a1==idx*16, $a3 untouched from our own caller); the not-taken branch has NO jump and NO
* "jr $ra" at all -- it falls straight through into GS_001_OBJ_5D0's own code, which owns the
* shared epilogue (lw $ra,0x10($sp); addiu $sp,$sp,0x18; jr $ra) for this frame. gcc-2.7.2 has
* no sibcall / cross-function tail-merge pass (matching-cookbook.md §179-C) and unconditionally
* appends its own return sequence to any ordinary C function body, so this can only be written
* as FILE-SCOPE __asm__ -- opaque text the compiler never runs expand_function_end over.
*/
__asm__(
".text\n"
".align\t2\n"
".globl\tGsSortClear\n"
".ent\tGsSortClear\n"
"GsSortClear:\n"
".frame\t$sp,24,$31\n"
".mask\t0x80000000,-8\n"
".fmask\t0x00000000,0\n"
".set\tnoreorder\n"
"lui $2, %hi(D_800C7C74)\n"
"lh $2, %lo(D_800C7C74)($2)\n"
"addiu $sp, $sp, -24\n"
"sw $31, 16($sp)\n"
"sll $2, $2, 4\n"
"lui $1, %hi(D_80078814)\n"
"addu $1, $1, $2\n"
"sb $4, %lo(D_80078814)($1)\n"
"lui $2, %hi(D_800C7C74)\n"
"lh $2, %lo(D_800C7C74)($2)\n"
"nop\n"
"sll $2, $2, 4\n"
"lui $1, %hi(D_80078815)\n"
"addu $1, $1, $2\n"
"sb $5, %lo(D_80078815)($1)\n"
"lui $2, %hi(D_800C7C74)\n"
"lh $2, %lo(D_800C7C74)($2)\n"
"nop\n"
"sll $2, $2, 4\n"
"lui $1, %hi(D_80078816)\n"
"addu $1, $1, $2\n"
"sb $6, %lo(D_80078816)($1)\n"
"lui $2, %hi(D_800C7C74)\n"
"lh $2, %lo(D_800C7C74)($2)\n"
"nop\n"
"sll $4, $2, 1\n"
"sll $5, $2, 4\n"
"lui $1, %hi(D_800794E0)\n"
"addu $1, $1, $4\n"
"lhu $3, %lo(D_800794E0)($1)\n"
"lui $2, %hi(D_800AE61C)\n"
"lw $2, %lo(D_800AE61C)($2)\n"
"lui $1, %hi(D_80078818)\n"
"addu $1, $1, $5\n"
"sh $3, %lo(D_80078818)($1)\n"
"lui $1, %hi(D_800794E4)\n"
"addu $1, $1, $4\n"
"lhu $3, %lo(D_800794E4)($1)\n"
"lui $1, %hi(D_8007881E)\n"
"addu $1, $1, $5\n"
"sh $2, %lo(D_8007881E)($1)\n"
"lui $1, %hi(D_8007881A)\n"
"addu $1, $1, $5\n"
"sh $3, %lo(D_8007881A)($1)\n"
"lui $2, %hi(D_800A64A9)\n"
"lbu $2, %lo(D_800A64A9)($2)\n"
"nop\n"
"beqz $2, 1f\n"
" nop\n"
"lui $2, %hi(D_800AE618)\n"
"lw $2, %lo(D_800AE618)($2)\n"
"nop\n"
"sll $3, $2, 1\n"
"addu $3, $3, $2\n"
"srl $2, $3, 31\n"
"addu $3, $3, $2\n"
"sra $3, $3, 1\n"
"lui $1, %hi(D_8007881C)\n"
"addu $1, $1, $5\n"
"sh $3, %lo(D_8007881C)($1)\n"
"j GS_001_OBJ_5D0\n"
" nop\n"
"1:\n"
"lui $2, %hi(D_800AE618)\n"
"lw $2, %lo(D_800AE618)($2)\n"
"lui $1, %hi(D_8007881C)\n"
"addu $1, $1, $5\n"
"sh $2, %lo(D_8007881C)($1)\n"
".set\treorder\n"
".end\tGsSortClear\n"
);
INCLUDE_ASM("asm/nonmatchings/gsgap3", GS_001_OBJ_5D0);