Files
BFM-decomp/src/800c.c
T
Drew T 3b90d2db39 feat(decomp): main lane m40bba — 1 banked
One clean whole-EXE rebuild verified the batch (gate_main), and main re-checked
BYTE-IDENTICAL against config/check.us.sha before anything was credited.

  SYS_OBJ_21A4
2026-08-25 15:22:34 -06:00

2879 lines
90 KiB
C

#include "common.h"
/* hoisted by gate_main so drafts above can reuse them (§181) */
typedef struct {
u32 tag;
} PrimHdr;
/* func_80059234 is one of MANY tiny "object type dispatcher" functions in this file that
* share pre-baked helper/epilogue code (SYS_OBJ_11C = default-type dispatch, SYS_OBJ_16C =
* the shared epilogue for this exact frame shape: ra@0x18/s1@0x14/s0@0x10, 0x20 bytes) via a
* BARE tail jump ("j", no "jal", no local epilogue restore first) -- this is gcc-2.7.2's
* cross-jump pass merging this function's default/exit tails with an IDENTICAL tail emitted
* by a sibling function elsewhere in the SAME translation unit, something only visible when
* the whole 800c.c is compiled together (both siblings' RTL present). Isolated single-function
* compilation can NEVER reproduce a bare tail-jump this way: gcc-2.7.2 has no sibcall
* optimization, and the function epilogue ("jr $ra; nop") is unconditionally emitted at the
* end of RTL expansion regardless of __attribute__((noreturn)) on the callee OR on this
* function itself (empirically probed: both leave the dead epilogue in place). This is the
* same class of problem as the project's proven $sp-switch TRAMPOLINE idiom (matching-cookbook
* §"full-inline-asm TRAMPOLINE", func_8014D04C/func_8014F468 family): the control transfer is
* not expressible in C, so the whole body is hand-written inline asm, transcribed 1:1 from the
* target .s (asm/nonmatchings/800c/func_80059234.s), with every symbol spelled EXACTLY as the
* target's own relocation lines name them.
*
* REPAIR NOTE (this pass): a plain C-function-body inline asm (`void f(...) { __asm__(...); }`,
* even with __attribute__((noreturn))) leaves a dead "jr $ra; nop" epilogue tacked on after the
* bare "j SYS_OBJ_16C" tail -- cc1 unconditionally emits the function epilogue at the end of RTL
* expansion and neither noreturn nor __builtin_unreachable() (not even available in gcc-2.7.2)
* suppresses it. Fix: emit the WHOLE function as FILE-SCOPE (top-level) inline asm -- a raw text
* blob cc1 copies verbatim with no RTL function wrapping it, so no epilogue is ever generated.
* The literal ".ent\tfunc_80059234" / ".end\tfunc_80059234" pair (tab-separated, exactly as cc1
* itself emits for a real function) is load-bearing: maspsx's `process_line` special-cases lines
* starting with ".ent\t" to emit a FRESH ".set\tnoreorder" into its own output (maspsx/__init__.py
* ~L856); an ordinary ".set\tnoreorder" line is normally SWALLOWED (tracked only as internal state,
* never re-emitted, ~L844-848). Using the "glabel"/"endlabel" .s-macros here instead does NOT
* trigger that path (they're unexpanded opaque text to maspsx, which runs BEFORE `as` expands
* assembler macros) -- GNU `as` then assembles in its default REORDER/macro mode, auto-inserting a
* nop after every branch and silently displacing our hand-placed delay-slot instructions (byte-
* verified: produced a 79-instruction jumble). Writing the real ".ent"/".end" text directly is the
* fix; the body (jal/j targets, %hi/%lo symbols) is unchanged, transcribed 1:1 from the target .s.
*/
__asm__(
".text\n"
".align\t2\n"
".globl\tfunc_80059234\n"
".ent\tfunc_80059234\n"
"func_80059234:\n"
".set\tnoreorder\n"
"addiu $sp, $sp, -0x20\n"
"sw $s1, 20($sp)\n"
"addu $s1, $a0, $zero\n"
"andi $v1, $s1, 0x7\n"
"addiu $v0, $zero, 0x3\n"
"sw $ra, 24($sp)\n"
"beq $v1, $v0, 1f\n"
"sw $s0, 16($sp)\n"
"slti $v0, $v1, 0x4\n"
"beqz $v0, 2f\n"
"nop\n"
"beqz $v1, 1f\n"
"nop\n"
"j SYS_OBJ_11C\n"
"nop\n"
"2:\n"
"addiu $v0, $zero, 0x5\n"
"beq $v1, $v0, 3f\n"
"nop\n"
"j SYS_OBJ_11C\n"
"nop\n"
"1:\n"
"lui $a0, %hi(D_80074084)\n"
"addiu $a0, $a0, %lo(D_80074084)\n"
"lui $a1, %hi(D_80072740)\n"
"addiu $a1, $a1, %lo(D_80072740)\n"
"lui $a2, %hi(D_80072788)\n"
"addiu $a2, $a2, %lo(D_80072788)\n"
"jal func_8005C604\n"
"nop\n"
"3:\n"
"lui $s0, %hi(D_80072788)\n"
"addiu $s0, $s0, %lo(D_80072788)\n"
"addu $a0, $s0, $zero\n"
"addu $a1, $zero, $zero\n"
"jal func_8005C29C\n"
"addiu $a2, $zero, 0x80\n"
"jal ResetCallback\n"
"nop\n"
"lui $v0, 0xff\n"
"lui $a0, %hi(D_80072780)\n"
"lw $a0, %lo(D_80072780)($a0)\n"
"ori $v0, $v0, 0xffff\n"
"jal func_8005CE38\n"
"and $a0, $a0, $v0\n"
"jal func_8005BD7C\n"
"addu $a0, $s1, $zero\n"
"addiu $a0, $s0, 0x10\n"
"addiu $v1, $zero, 0x1\n"
"sb $v0, 0($s0)\n"
"andi $v0, $v0, 0xff\n"
"sll $v0, $v0, 2\n"
"lui $at, %hi(D_80072789)\n"
"sb $v1, %lo(D_80072789)($at)\n"
"lui $at, %hi(D_80072808)\n"
"addu $at, $at, $v0\n"
"lw $v1, %lo(D_80072808)($at)\n"
"addiu $a1, $zero, -0x1\n"
"lui $at, %hi(D_8007278C)\n"
"sh $v1, %lo(D_8007278C)($at)\n"
"lui $at, %hi(D_8007281C)\n"
"addu $at, $at, $v0\n"
"lw $v0, %lo(D_8007281C)($at)\n"
"lui $at, %hi(D_8007278E)\n"
"sh $v0, %lo(D_8007278E)($at)\n"
"jal func_8005C29C\n"
"addiu $a2, $zero, 0x5c\n"
"addiu $a0, $s0, 0x6c\n"
"addiu $a1, $zero, -0x1\n"
"jal func_8005C29C\n"
"addiu $a2, $zero, 0x14\n"
"lbu $v0, 0($s0)\n"
"j SYS_OBJ_16C\n"
"nop\n"
".set\treorder\n"
".end\tfunc_80059234\n"
);
__asm__(
".text\n"
".align\t2\n"
".globl\tSYS_OBJ_11C\n"
".ent\tSYS_OBJ_11C\n"
"SYS_OBJ_11C:\n"
".set\tnoreorder\n"
"lui $v0, %hi(D_8007278A)\n"
"lbu $v0, %lo(D_8007278A)($v0)\n"
"nop\n"
"sltiu $v0, $v0, 0x2\n"
"bnez $v0, 1f\n"
"nop\n"
"lui $a0, %hi(D_800740A4)\n"
"addiu $a0, $a0, %lo(D_800740A4)\n"
"lui $v0, %hi(D_80072784)\n"
"lw $v0, %lo(D_80072784)($v0)\n"
"nop\n"
"jalr $v0\n"
"addu $a1, $s1, $zero\n"
"1:\n"
"lui $v0, %hi(D_80072780)\n"
"lw $v0, %lo(D_80072780)($v0)\n"
"nop\n"
"lw $v0, 52($v0)\n"
"nop\n"
"jalr $v0\n"
"addiu $a0, $zero, 0x1\n"
".set\treorder\n"
".end\tSYS_OBJ_11C\n"
);
__asm__(
".text\n"
".align\t2\n"
".globl\tSYS_OBJ_16C\n"
".ent\tSYS_OBJ_16C\n"
"SYS_OBJ_16C:\n"
".set\tnoreorder\n"
"lw $ra, 24($sp)\n"
"lw $s1, 20($sp)\n"
"lw $s0, 16($sp)\n"
"addiu $sp, $sp, 0x20\n"
"jr $ra\n"
"nop\n"
".set\treorder\n"
".end\tSYS_OBJ_16C\n"
);
__asm__(
".text\n"
".align\t2\n"
".globl\tSetGraphReverse\n"
".ent\tSetGraphReverse\n"
"SetGraphReverse:\n"
".set\tnoreorder\n"
" lui $v0, %hi(D_8007278A)\n"
" lbu $v0, %lo(D_8007278A)($v0)\n"
" addiu $sp, $sp, -32\n"
" sw $s1, 20($sp)\n"
" sw $s0, 16($sp)\n"
" lui $s0, %hi(D_8007278B)\n"
" addiu $s0, $s0, %lo(D_8007278B)\n"
" sw $ra, 28($sp)\n"
" sw $s2, 24($sp)\n"
" lbu $s2, 0($s0)\n"
" sltiu $v0, $v0, 2\n"
" bnez $v0, 1f\n"
" addu $s1, $a0, $zero\n"
" lui $a0, %hi(D_800740B8)\n"
" addiu $a0, $a0, %lo(D_800740B8)\n"
" lui $v0, %hi(D_80072784)\n"
" lw $v0, %lo(D_80072784)($v0)\n"
" nop\n"
" jalr $v0\n"
" addu $a1, $s1, $zero\n"
"1:\n"
" lui $v0, %hi(D_80072780)\n"
" lw $v0, %lo(D_80072780)($v0)\n"
" sb $s1, 0($s0)\n"
" lw $v0, 40($v0)\n"
" nop\n"
" jalr $v0\n"
" addiu $a0, $zero, 8\n"
" lbu $v1, 0($s0)\n"
" nop\n"
" beqz $v1, 2f\n"
" addu $a0, $v0, $zero\n"
" lui $v0, (0x8000080 >> 16)\n"
" j SYS_OBJ_210\n"
" ori $v0, $v0, (0x8000080 & 0xFFFF)\n"
"2:\n"
" lui $v0, (0x8000000 >> 16)\n"
".set\treorder\n"
".end\tSetGraphReverse\n"
);
__asm__(
".text\n"
".align\t2\n"
".globl\tSYS_OBJ_210\n"
".ent\tSYS_OBJ_210\n"
"SYS_OBJ_210:\n"
".frame\t$sp,32,$31\n"
".mask\t0x80070000,-4\n"
".fmask\t0x00000000,0\n"
".set\tnoreorder\n"
"or $a0, $a0, $v0\n"
"lui $v0, %hi(D_80072780)\n"
"lw $v0, %lo(D_80072780)($v0)\n"
"nop\n"
"lw $v0, 16($v0)\n"
"nop\n"
"jalr $v0\n"
"nop\n"
"lui $v1, %hi(D_80072788)\n"
"lbu $v1, %lo(D_80072788)($v1)\n"
"addiu $v0, $zero, 0x2\n"
"bne $v1, $v0, .L800594B0\n"
"addu $v0, $s2, $zero\n"
"lui $a0, (0x20000504 >> 16)\n"
"lui $v0, %hi(D_8007278B)\n"
"lbu $v0, %lo(D_8007278B)($v0)\n"
"lui $v1, %hi(D_80072780)\n"
"lw $v1, %lo(D_80072780)($v1)\n"
"beqz $v0, .L8005949C\n"
"ori $a0, $a0, (0x20000504 & 0xFFFF)\n"
"lui $a0, (0x20000501 >> 16)\n"
"ori $a0, $a0, (0x20000501 & 0xFFFF)\n"
".L8005949C:\n"
"lw $v0, 16($v1)\n"
"nop\n"
"jalr $v0\n"
"nop\n"
"addu $v0, $s2, $zero\n"
".L800594B0:\n"
"lw $ra, 28($sp)\n"
"lw $s2, 24($sp)\n"
"lw $s1, 20($sp)\n"
"lw $s0, 16($sp)\n"
"addiu $sp, $sp, 0x20\n"
"jr $ra\n"
"nop\n"
".set\treorder\n"
".end\tSYS_OBJ_210\n"
);
extern u8 D_8007278A;
extern u32 D_80072784;
extern u8 D_80072788;
extern u8 D_8007278B;
extern u8 D_800740D0;
s32 func_800594CC(s32 a0) {
u8 *p = &D_8007278A;
u8 old = *p;
*p = a0;
if (a0 & 0xFF) {
((void (*)(void *, s32, u8, u8))D_80072784)(&D_800740D0, a0 & 0xFF, D_80072788, D_8007278B);
}
return old;
}
extern u8 D_8007278A;
extern u8 D_80072789;
extern u32 D_80072784;
extern void *D_80072780;
extern u8 D_800740FC;
extern void DMACallback(s32, s32);
s32 SetGraphQueue(s32 a0)
{
register u8 *s1 __asm__("s1") = &D_80072789;
u8 check;
u8 s2;
check = D_8007278A;
s2 = *s1;
if (check >= 2) {
((s32 (*)(void *, s32))D_80072784)(&D_800740FC, a0);
}
if (a0 != *s1) {
(*(s32 (**)(s32))((u8 *)D_80072780 + 0x34))(1);
*s1 = a0;
DMACallback(2, 0);
}
return s2;
}
INCLUDE_ASM("asm/nonmatchings/800c", GetGraphType);
INCLUDE_ASM("asm/nonmatchings/800c", GetGraphDebug);
extern u8 D_8007278A;
extern u32 D_80072784;
extern u8 D_80074110;
extern void (*D_80072794)(void);
void (*DrawSyncCallback(void (*func)(void)))(void)
{
void (*old)(void);
if (D_8007278A >= 2) {
((void (*)(void *, void (*)(void)))D_80072784)(&D_80074110, func);
}
old = D_80072794;
D_80072794 = func;
return old;
}
extern u8 D_8007278A;
extern u32 D_80072784;
extern void *D_80072780;
extern void func_8005C29C(void*, s32, s32);
extern s32 D_8007412C;
void func_80059658(s32 a0) {
u8 *s1 = &D_8007278A;
if (*s1 >= 2) {
((void (*)(void*, s32))D_80072784)(&D_8007412C, a0);
}
if (a0 == 0) {
func_8005C29C(s1 + 0x6A, -1, 0x14);
}
{
u32 val = 0x3000001;
void *ptr = D_80072780;
if (a0 != 0) {
val = 0x3000000;
}
(*(void (**)(u32))((u8 *)ptr + 0x10))(val);
}
}
extern u8 D_8007278A;
extern u32 D_80072784;
extern void *D_80072780;
extern u8 D_80074140;
void func_800596F4(s32 a0) {
if (D_8007278A >= 2) {
((void (*)(void *, s32))D_80072784)(&D_80074140, a0);
}
(*(void (**)(void *))((u8 *)D_80072780 + 0x3C))(a0);
}
/* 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"
);
__asm__(
".text\n"
".globl\tSYS_OBJ_604\n"
".type\tSYS_OBJ_604, @function\n"
"SYS_OBJ_604:\n"
".ent\tSYS_OBJ_604\n"
".set\tnoat\n"
".set\tnoreorder\n"
" lui $v0, %hi(D_80072784)\n"
" lw $v0, %lo(D_80072784)($v0)\n"
" nop\n"
" jalr $v0\n"
" addu $a1, $t0, $zero\n"
" lh $a1, 0($s0)\n"
" lh $a2, 2($s0)\n"
" lh $a3, 4($s0)\n"
" lh $v0, 6($s0)\n"
" lui $v1, %hi(D_80072784)\n"
" lw $v1, %lo(D_80072784)($v1)\n"
" lui $a0, %hi(D_80074160)\n"
" addiu $a0, $a0, %lo(D_80074160)\n"
" jalr $v1\n"
" sw $v0, 16($sp)\n"
".set\treorder\n"
".set\tat\n"
".size\tSYS_OBJ_604, . - SYS_OBJ_604\n"
".end\tSYS_OBJ_604\n"
);
__asm__(
".text\n"
".align\t2\n"
".globl\tSYS_OBJ_640\n"
".ent\tSYS_OBJ_640\n"
"SYS_OBJ_640:\n"
".set\tnoreorder\n"
"lw $ra, 28($sp)\n"
"lw $s0, 24($sp)\n"
"addiu $sp, $sp, 32\n"
"jr $ra\n"
"nop\n"
".set\treorder\n"
".end\tSYS_OBJ_640\n"
);
extern void *D_80072780;
extern char D_80074178;
extern void func_80059760();
s32 func_80059888(void *rect, u8 r, u8 g, u8 b)
{
func_80059760(&D_80074178, rect);
return (*(s32 (**)(void *, void *, s32, s32))((u8 *)D_80072780 + 0x8))(
*(void **)((u8 *)D_80072780 + 0xC), rect, 8,
(((b << 16) | (g << 8)) | r));
}
extern void *D_80072780;
extern char D_80074178;
extern void func_80059760();
void ClearImage2(void *rect, u8 r, u8 g, u8 b)
{
func_80059760(&D_80074178, rect);
(*(s32 (**)(void *, void *, s32, s32))((u8 *)D_80072780 + 0x8))(
*(void **)((u8 *)D_80072780 + 0xC), rect, 8,
((((b & 0xFF) << 16) | 0x80000000) | ((g & 0xFF) << 8)) | (r & 0xFF));
}
extern void *D_80072780;
extern char D_80074184;
extern void func_80059760();
s32 func_800599B8(void *rect, void *p)
{
func_80059760(&D_80074184, rect);
return (*(s32 (**)(void *, void *, s32, s32))((u8 *)D_80072780 + 0x8))(
*(void **)((u8 *)D_80072780 + 0x20), rect, 8, p);
}
extern void *D_80072780;
extern char D_80074190;
extern void func_80059760();
s32 StoreImage(void *rect, void *p)
{
func_80059760(&D_80074190, rect);
return (*(s32 (**)(void *, void *, s32, s32))((u8 *)D_80072780 + 0x8))(
*(void **)((u8 *)D_80072780 + 0x1C), rect, 8, p);
}
/* ===========================================================================
* MERGED FUNCTION — MoveImage absorbs SYS_OBJ_8F4.
*
* splat split ONE function into two symbols:
* MoveImage 0x80059A80..0x80059B27 (0xA8, 42 insns)
* SYS_OBJ_8F4 0x80059B28..0x80059B43 (0x1C, 7 insns)
* Combined range: 0x80059A80..0x80059B43, 0xC4 bytes, 49 instructions.
*
* SYS_OBJ_8F4 is not an independent function — it is MoveImage's own epilogue:
* it pops ra/s2/s1/s0 out of MoveImage's OWN 0x20-byte frame (ra@0x1C, s2@0x18,
* s1@0x14, s0@0x10 — the exact slots MoveImage's prologue pushed), adds 0x20 to
* sp and returns. MoveImage's two early "return -1" paths branch INTO it
* (`beqz $v0, SYS_OBJ_8F4` at 0x80059AB8 and `j SYS_OBJ_8F4` at 0x80059AD0) and
* MoveImage's own tail falls THROUGH into it. Nothing else in the binary
* mentions SYS_OBJ_8F4 (grep of asm/nonmatchings/800c: only its own .s and
* MoveImage.s). The label exists only because the PsyQ libgpu object carried a
* local symbol on the epilogue block.
*
* Written here as one C function: both `return -1;` statements share gcc's
* single function epilogue, which is byte-identical to SYS_OBJ_8F4's body.
*
* The two early exits come from ONE `||` test, not two separate `if`s — two
* `if`s make gcc cross-jump the -1 returns into a single tail block placed
* AFTER the call, which costs an extra insn and moves the -1 out of the delay
* slots. With `||` the layout is exactly the target's:
* beq w,0 -> epilogue (delay: li -1) [the delay-slot filler copied the -1
* out of the shared L_ret block and
* retargeted the branch past the j]
* bne h,0 -> body (delay: sll y,16)
* j epilogue (delay: li -1)
*
* The 5-word MOVE_IMAGE packet lives at 0x80072830 (asm/data/53198.data.s):
* 0x80072830 .word 0x04FFFFFF tag (len 4, next = end-of-list)
* 0x80072834 .word 0x80000000 GPU cmd: VRAM->VRAM rectangle copy
* 0x80072838 .word <src x|y> written here
* 0x8007283C .word <dst x|y> written here
* 0x80072840 .word <size w|h> written here
* splat emitted NO symbol at 0x80072830 (it falls inside the D_8007281C dlabel
* block) because the compiler never materialized that address directly: it kept
* &D_80072838 in $a1 for the store and reached the packet base with
* `addiu $a1, $a1, -8` in the jalr delay slot. So the base is spelled the same
* way here — `(u8 *)p - 8`.
*
* Why the store to 0x80072838 goes through a STRUCT pointer (MovePktSrc) and
* not through a plain `u32 *`: it is the only form that lets gcc-2.7.2 hoist
* `lw $v1, D_80072780` ABOVE the packet stores, which the target does (that load
* sits at 0x80059AEC/AF0, before both `sw`s). A store through a plain scalar
* `u32 *` is an opaque MEM the scheduler will not reorder against a global load,
* so the load sinks two slots and 6 of 49 instructions land out of place. A
* struct-typed MEM sets MEM_IN_STRUCT_P, gcc-2.7.2's scalar-vs-aggregate
* disambiguation fires, and the schedule becomes byte-identical. Measured:
* plain `u32 *` = 6 mismatched; struct pointer = MATCH. (A 120-variant sweep
* over statement order, hoisted temporaries and local-vs-inline GPU pointer
* never got below 6 without the struct type.)
* ===========================================================================*/
typedef struct {
s16 x;
s16 y;
s16 w;
s16 h;
} GpuRect;
/* the packet's src word, at 0x80072838; the packet itself starts 8 bytes lower */
typedef struct {
u32 src;
} MovePktSrc;
typedef s32 (*GpuFn)(void *, void *, s32, s32);
/* spelled exactly as the rest of src/800c.c already spells it
* (SetGraphQueue, func_80059658) */
extern void *D_80072780;
/* checkRECT-style validator + its name string ("MoveImage"); the direct
* analogue of StoreImage's D_80074190 immediately above in the same TU */
extern char D_8007419C;
extern void func_80059760(char *name, GpuRect *rect);
extern u32 D_80072838;
extern u32 D_8007283C;
extern u32 D_80072840;
s32 MoveImage(GpuRect *rect, s32 x, s32 y)
{
MovePktSrc *p;
func_80059760(&D_8007419C, rect);
if (rect->w == 0 || rect->h == 0) {
return -1;
}
p = (MovePktSrc *)&D_80072838;
p->src = *(u32 *)rect;
D_8007283C = (y << 16) | (x & 0xFFFF);
D_80072840 = *(u32 *)&rect->w;
return (*(GpuFn *)((u8 *)D_80072780 + 0x8))(
*(void **)((u8 *)D_80072780 + 0x18), (u8 *)p - 8, 0x14, 0);
}
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;
}
extern u8 D_8007278A;
extern volatile u8 D_800741C0[4];
extern u32 D_80072784;
extern void *D_80072780;
extern char D_80072844;
void func_80059BFC(s32 a0, s32 a1) {
s32 s0 = a0;
s32 s1 = a1;
u8 byte_val;
void (*func_ptr)(u32, s32, s32);
void (*func_ptr2)(s32, s32);
u32 addr;
u32 *v0;
u32 v1;
u32 mask;
byte_val = D_8007278A;
if (byte_val >= 2) {
addr = (u32)D_800741C0;
func_ptr = (void (*)(u32, s32, s32))D_80072784;
func_ptr(addr, s0, s1);
}
func_ptr2 = *(void (**)(s32, s32))((u8 *)D_80072780 + 0x2C);
func_ptr2(s0, s1);
{
register u32 outAddr __asm__("$2");
mask = 0xFFFFFF;
__asm__ volatile("" : "=r"(mask) : "0"(mask));
outAddr = (u32)s0;
__asm__ volatile("" : "=r"(outAddr) : "0"(outAddr));
v1 = (u32)&D_80072844;
__asm__ volatile("" : "=r"(v1) : "0"(v1));
v1 &= mask;
*(u32 *)outAddr = v1;
}
}
extern void *D_80072780;
void DrawPrim(void *prim) {
u8 len;
len = *(u8 *)((u8 *)prim + 3);
(*(void (**)(s32))((u8 *)D_80072780 + 0x3C))(0);
(*(void (**)(void *, s32))((u8 *)D_80072780 + 0x14))((u8 *)prim + 4, len);
}
extern u8 D_8007278A;
extern u32 D_80072784;
extern void *D_80072780;
extern u8 D_800741D8;
/* PsyQ DrawOTag: guard call passes the "DrawOTag(%08x)...\n" debug string
* (D_800741D8), then dispatches through GPU fn-table slot +0x8 with the draw
* env pointer at +0x18, the OT, and two zero args. Canonical signature per
* src/resident/resident.c (`extern s32 func_80059CF4(s32);`) -- the tail GPU-fn
* call's result is left in $v0 and becomes this function's return value.
*
* Integration: replace the INCLUDE_ASM("asm/nonmatchings/800c", func_80059CF4)
* stub at line 483 of src/800c.c. D_8007278A/D_80072784/D_80072780 are already
* declared at lines 134-137 of that TU with identical types -- keep those, add
* only `extern u8 D_800741D8;`.
*/
s32 func_80059CF4(s32 a0) {
if (D_8007278A >= 2) {
((void (*)(void *, s32))D_80072784)(&D_800741D8, a0);
}
return (*(s32 (**)(void *, void *, s32, s32))((u8 *)D_80072780 + 0x8))(
*(void **)((u8 *)D_80072780 + 0x18), (void *)a0, 0, 0);
}
void *func_80059D68(void *env)
{
typedef struct {
u32 w[4];
} EnvQuad;
typedef struct {
u32 w[3];
} EnvTail;
typedef void (*EnvGpuFn)(void *, void *, s32, s32);
extern u8 D_8007278A;
extern u32 D_80072784;
extern void *D_80072780;
extern char D_800741EC;
extern void func_8005A870();
u8 *flagp = &D_8007278A;
u32 *s0;
PrimHdr *t;
EnvQuad *src;
EnvQuad *dst;
EnvQuad *end;
if (*flagp >= 2) {
((void (*)(void *, void *))D_80072784)(&D_800741EC, env);
}
s0 = (u32 *)((u8 *)env + 0x1C);
func_8005A870(s0, env);
t = (PrimHdr *)s0;
t->tag |= 0xFFFFFF;
(*(EnvGpuFn *)((u8 *)D_80072780 + 0x8))(
*(void **)((u8 *)D_80072780 + 0x18), s0, 0x40, 0);
dst = (EnvQuad *)(flagp + 0xE);
src = (EnvQuad *)env;
end = (EnvQuad *)((u8 *)env + 0x50);
do {
*dst++ = *src++;
} while (src != end);
*(EnvTail *)dst = *(EnvTail *)src;
return env;
}
/* DrawOTagEnv - all auxiliary decls block-scoped */
extern u8 D_8007278A;
extern u32 D_80072784;
extern void *D_80072780;
void DrawOTagEnv(void *p, u32 *otag)
{
typedef struct {
u32 w[4];
} OTagQuad;
typedef struct {
u32 w[3];
} OTagTail;
typedef s32 (*OTagEnvGpuFn)(void *, void *, s32, s32);
extern char D_80074204;
extern void func_8005A870();
u8 *flagp = &D_8007278A;
u32 *s0;
PrimHdr *t;
OTagQuad *src;
OTagQuad *dst;
OTagQuad *end;
if (*flagp >= 2) {
((void (*)(void *, u32 *, u32 *))D_80072784)(&D_80074204, p, otag);
}
s0 = otag + 7;
func_8005A870(s0, otag);
t = (PrimHdr *)s0;
t->tag = (t->tag & 0xFF000000) | ((u32)p & 0xFFFFFF);
(*(OTagEnvGpuFn *)((u8 *)D_80072780 + 0x8))(
*(void **)((u8 *)D_80072780 + 0x18), s0, 0x40, 0);
dst = (OTagQuad *)(flagp + 0xE);
src = (OTagQuad *)otag;
end = src + 5;
do {
*dst++ = *src++;
} while (src != end);
*(OTagTail *)dst = *(OTagTail *)src;
}
extern void func_8005C324(s32 dst, s32 src, s32 n);
extern u8 D_80072798[0x5C];
void *GetDrawEnv(void *a0) {
func_8005C324((s32)a0, (s32)D_80072798, 0x5C);
return a0;
}
/*
* 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"
);
__asm__(
".text\n"
".align\t2\n"
".globl\tSYS_OBJ_E34\n"
".ent\tSYS_OBJ_E34\n"
"SYS_OBJ_E34:\n"
".set\tnoreorder\n"
"or $4, $2, $3\n"
"lui $2, %hi(D_80072780)\n"
"lw $2, %lo(D_80072780)($2)\n"
"nop\n"
"lw $2, 16($2)\n"
"nop\n"
"jalr $2\n"
"nop\n"
"lui $2, %hi(D_800727FC)\n"
"addiu $2, $2, %lo(D_800727FC)\n"
"lhu $2, 0($2)\n"
"lh $3, 8($16)\n"
"sll $2, $2, 16\n"
"sra $2, $2, 16\n"
"bne $2, $3, .L8005A0FC\n"
"nop\n"
"lui $2, %hi(D_800727FE)\n"
"lhu $2, %lo(D_800727FE)($2)\n"
"lh $3, 10($16)\n"
"sll $2, $2, 16\n"
"sra $2, $2, 16\n"
"bne $2, $3, .L8005A0FC\n"
"nop\n"
"lui $2, %hi(D_80072800)\n"
"lhu $2, %lo(D_80072800)($2)\n"
"lh $3, 12($16)\n"
"sll $2, $2, 16\n"
"sra $2, $2, 16\n"
"bne $2, $3, .L8005A0FC\n"
"nop\n"
"lui $2, %hi(D_80072802)\n"
"lhu $2, %lo(D_80072802)($2)\n"
"lh $3, 14($16)\n"
"sll $2, $2, 16\n"
"sra $2, $2, 16\n"
"beq $2, $3, .L8005A2C4\n"
"nop\n"
".L8005A0FC:\n"
"jal func_80043078\n"
"nop\n"
"lh $4, 8($16)\n"
"sb $2, 18($16)\n"
"andi $2, $2, 0xFF\n"
"sll $3, $4, 2\n"
"addu $3, $3, $4\n"
"sll $3, $3, 1\n"
"lh $4, 10($16)\n"
"beqz $2, .L8005A130\n"
"addiu $3, $3, 0x260\n"
"j SYS_OBJ_F00\n"
"addiu $17, $4, 0x13\n"
".L8005A130:\n"
"addiu $17, $4, 0x10\n"
".set\treorder\n"
".end\tSYS_OBJ_E34\n"
);
__asm__(
".text\n"
".align\t2\n"
".globl\tSYS_OBJ_F00\n"
".ent\tSYS_OBJ_F00\n"
"SYS_OBJ_F00:\n"
".set\tnoreorder\n"
" lh $a1, 12($s0)\n"
" nop\n"
" beqz $a1, .L8005A154\n"
" sll $v0, $a1, 2\n"
" addu $v0, $v0, $a1\n"
" sll $v0, $v0, 1\n"
" j SYS_OBJ_F24\n"
" addu $a2, $v1, $v0\n"
".L8005A154:\n"
" addiu $a2, $v1, 2560\n"
".set\treorder\n"
".end\tSYS_OBJ_F00\n"
);
__asm__(
".text\n"
".align\t2\n"
".globl\tSYS_OBJ_F24\n"
".ent\tSYS_OBJ_F24\n"
"SYS_OBJ_F24:\n"
".set\tnoreorder\n"
"lh $v0, 14($s0)\n"
"nop\n"
"bnez $v0, 1f\n"
"addu $s2, $s1, $v0\n"
"addiu $s2, $s1, 0xF0\n"
"1:\n"
"slti $v0, $v1, 0x1F4\n"
"bnez $v0, 2f\n"
"slti $v0, $v1, 0xCDB\n"
"beqz $v0, 3f\n"
"addiu $a1, $zero, 0xCDA\n"
"j SYS_OBJ_F58\n"
"addu $a1, $v1, $zero\n"
"2:\n"
"addiu $a1, $zero, 0x1F4\n"
"3:\n"
".set\treorder\n"
".end\tSYS_OBJ_F24\n"
);
/* SYS_OBJ_F58 reads $s0/$s1/$s2 as live globals (same frame shape as its sibling
* SYS_OBJ_FD8), so plain C cannot carry the register allocation: emit the whole
* function as FILE-SCOPE inline asm, transcribed 1:1 from
* asm/nonmatchings/800c/SYS_OBJ_F58.s (cookbook 179-C: no epilogue of its own --
* every exit is a raw unlinked j/beqz into SYS_OBJ_FD8, and .L8005A208 falls
* through into the sibling's entry, so a normal C body would gain a phantom
* jr/nop pair).
* Real ".ent"/".end" text (not glabel/endlabel) so maspsx emits the fresh
* ".set noreorder" and our hand-placed delay slots survive (179-B rules 1-2).
* NOTE: maspsx parses ALL displacements AND immediates with bare int() -- every
* number below must be DECIMAL (179-B rule 3 / 265): 0x50=80, 0x10=16,
* 0xCDB=3291, 0xCDA=3290, 0x12=18, 0x137=311, 0x101=257, 0x100=256, 0x136=310.
* Load-delay nops after the two lbu are already in the target and stay (maspsx
* only splices its own when a consumer follows the load).
* PLACEMENT: this block REPLACES the INCLUDE_ASM("asm/nonmatchings/800c",
* SYS_OBJ_F58) stub at src/800c.c:634 -- do not keep both (duplicate symbol). */
__asm__(
".text\n"
".align\t2\n"
".globl\tSYS_OBJ_F58\n"
".ent\tSYS_OBJ_F58\n"
"SYS_OBJ_F58:\n"
".set\tnoreorder\n"
"addu $v1, $a1, $zero\n"
"addiu $a1, $v1, 80\n"
"slt $v0, $a2, $a1\n"
"bnez $v0, .L8005A1B4\n"
"slti $v0, $s1, 16\n"
"slti $v0, $a2, 3291\n"
"beqz $v0, .L8005A1B0\n"
"addiu $a1, $zero, 3290\n"
"addu $a1, $a2, $zero\n"
".L8005A1B0:\n"
"slti $v0, $s1, 16\n"
".L8005A1B4:\n"
"bnez $v0, .L8005A208\n"
"addu $a2, $a1, $zero\n"
"lbu $v0, 18($s0)\n"
"nop\n"
"beqz $v0, .L8005A1DC\n"
"slti $v0, $s1, 311\n"
"beqz $v0, .L8005A1E8\n"
"nop\n"
"j SYS_OBJ_FD8\n"
"addu $a0, $s1, $zero\n"
".L8005A1DC:\n"
"slti $v0, $s1, 257\n"
"bnez $v0, .L8005A200\n"
"nop\n"
".L8005A1E8:\n"
"lbu $v0, 18($s0)\n"
"nop\n"
"beqz $v0, SYS_OBJ_FD8\n"
"addiu $a0, $zero, 256\n"
"j SYS_OBJ_FD8\n"
"addiu $a0, $zero, 310\n"
".L8005A200:\n"
"j SYS_OBJ_FD8\n"
"addu $a0, $s1, $zero\n"
".L8005A208:\n"
"addiu $a0, $zero, 16\n"
".set\treorder\n"
".end\tSYS_OBJ_F58\n"
);
__asm__(
".text\n"
".align\t2\n"
".globl\tSYS_OBJ_FD8\n"
".ent\tSYS_OBJ_FD8\n"
"SYS_OBJ_FD8:\n"
".set\tnoreorder\n"
"addu $s1, $a0, $zero\n"
"addiu $a1, $s1, 2\n"
"slt $v0, $s2, $a1\n"
"bnez $v0, SYS_OBJ_1034\n"
"nop\n"
"lbu $v0, 18($s0)\n"
"nop\n"
"beqz $v0, .L8005A240\n"
"slti $v0, $s2, 313\n"
"beqz $v0, .L8005A24C\n"
"nop\n"
"j SYS_OBJ_1034\n"
"addu $a1, $s2, $zero\n"
".L8005A240:\n"
"slti $v0, $s2, 259\n"
"bnez $v0, .L8005A264\n"
"nop\n"
".L8005A24C:\n"
"lbu $v0, 18($s0)\n"
"nop\n"
"beqz $v0, SYS_OBJ_1034\n"
"addiu $a1, $zero, 258\n"
"j SYS_OBJ_1034\n"
"addiu $a1, $zero, 312\n"
".L8005A264:\n"
"addu $a1, $s2, $zero\n"
".set\treorder\n"
".end\tSYS_OBJ_FD8\n"
);
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_1034);
__asm__(
".text\n"
".align\t2\n"
".globl\tSYS_OBJ_11C0\n"
".ent\tSYS_OBJ_11C0\n"
"SYS_OBJ_11C0:\n"
".set\tnoreorder\n"
"lbu $2, 18($16)\n"
"lh $3, 6($16)\n"
"bnez $2, .L8005A408\n"
" slti $2, $3, 289\n"
"slti $2, $3, 257\n"
".L8005A408:\n"
"bnez $2, .L8005A414\n"
" nop\n"
"ori $19, $19, 36\n"
".L8005A414:\n"
"lui $2, %hi(D_80072780)\n"
"lw $2, %lo(D_80072780)($2)\n"
"nop\n"
"lw $2, 16($2)\n"
"nop\n"
"jalr $2\n"
" addu $4, $19, $0\n"
".L8005A430:\n"
"lui $4, %hi(D_800727F4)\n"
"addiu $4, $4, %lo(D_800727F4)\n"
"addu $5, $16, $0\n"
"jal func_8005C324\n"
" addiu $6, $0, 20\n"
"addu $2, $16, $0\n"
"lw $31, 32($29)\n"
"lw $19, 28($29)\n"
"lw $18, 24($29)\n"
"lw $17, 20($29)\n"
"lw $16, 16($29)\n"
"addiu $29, $29, 40\n"
"jr $31\n"
" nop\n"
".set\treorder\n"
".end\tSYS_OBJ_11C0\n"
);
extern void func_8005C324(s32 dst, s32 src, s32 n);
extern u8 D_800727F4[0x14];
void *GetDispEnv(void *a0) {
func_8005C324((s32)a0, (s32)D_800727F4, 0x14);
return a0;
}
extern void *D_80072780;
s32 GetODE(void)
{
return (*(u32 (**)(void))((u8 *)D_80072780 + 0x38))() >> 31;
}
extern s32 func_8005AD34(s32 a0);
void SetTexWindow(void *a0, s32 a1)
{
*(u8 *)(a0 + 3) = 2;
*(s32 *)(a0 + 4) = func_8005AD34(a1);
*(s32 *)(a0 + 8) = 0;
}
INCLUDE_ASM("asm/nonmatchings/800c", SetDrawArea);
extern s32 func_8005ACF0(s32 x, s32 y);
void SetDrawOffset(void *a0, s16 *a1)
{
*(u8 *)(a0 + 3) = 2;
*(s32 *)(a0 + 4) = func_8005ACF0(a1[0], a1[1]);
*(s32 *)(a0 + 8) = 0;
}
void SetPriority(unsigned char *arg0, int arg1, int arg2) {
unsigned int temp;
arg0[3] = 2;
temp = 0xE6000000;
if (arg1 != 0) {
temp |= 2;
}
if (arg2 != 0) {
temp |= 1;
}
*(unsigned int *)(arg0 + 4) = temp;
*(unsigned int *)(arg0 + 8) = 0;
}
extern s32 func_8005AB00(s32 a0, s32 a1, u16 a2);
extern s32 func_8005AD34(s32 a0);
s32 func_8005A600(s32 a0, s32 a1, s32 a2, s32 a3, s32 a4) {
*(u8 *)(a0 + 3) = 2;
*(s32 *)(a0 + 4) = func_8005AB00(a1, a2, a3);
return *(s32 *)(a0 + 8) = func_8005AD34(a4);
}
INCLUDE_ASM("asm/nonmatchings/800c", SetDrawEnv);
__asm__(
".text\n"
".align\t2\n"
".globl\tSYS_OBJ_1578\n"
".ent\tSYS_OBJ_1578\n"
"SYS_OBJ_1578:\n"
".frame\t$sp,64,$31\n"
".mask\t0x80030000,-16\n"
".fmask\t0,0\n"
".set\tnoreorder\n"
"sll $a2, $a3, 2\n"
"addiu $a3, $a3, 1\n"
"sll $a1, $a3, 2\n"
"addiu $a3, $a3, 1\n"
"sh $v0, 22($sp)\n"
"lhu $v0, 16($sp)\n"
"lhu $v1, 8($s0)\n"
"addu $a2, $a2, $s1\n"
"subu $v0, $v0, $v1\n"
"sh $v0, 16($sp)\n"
"lhu $v0, 18($sp)\n"
"lhu $v1, 10($s0)\n"
"lui $a0, 24576\n"
"subu $v0, $v0, $v1\n"
"sh $v0, 18($sp)\n"
"lbu $v0, 27($s0)\n"
"lbu $v1, 26($s0)\n"
"sll $v0, $v0, 16\n"
"sll $v1, $v1, 8\n"
"or $v1, $v1, $a0\n"
"lbu $a0, 25($s0)\n"
"or $v0, $v0, $v1\n"
"or $v0, $v0, $a0\n"
"sw $v0, 0($a2)\n"
"lw $v0, 16($sp)\n"
"addu $a1, $a1, $s1\n"
"sw $v0, 0($a1)\n"
"sll $v0, $a3, 2\n"
"lw $v1, 20($sp)\n"
"addu $v0, $v0, $s1\n"
"sw $v1, 0($v0)\n"
"lhu $v0, 16($sp)\n"
"lhu $v1, 8($s0)\n"
"nop\n"
"addu $v0, $v0, $v1\n"
"sh $v0, 16($sp)\n"
"lhu $v0, 18($sp)\n"
"lhu $v1, 10($s0)\n"
"addiu $a3, $a3, 1\n"
"addu $v0, $v0, $v1\n"
"sh $v0, 18($sp)\n"
".L8005A850:\n"
"addiu $v0, $a3, -1\n"
"sb $v0, 3($s1)\n"
"lw $ra, 56($sp)\n"
"lw $s1, 52($sp)\n"
"lw $s0, 48($sp)\n"
"addiu $sp, $sp, 64\n"
"jr $ra\n"
"nop\n"
".set\treorder\n"
".end\tSYS_OBJ_1578\n"
);
INCLUDE_ASM("asm/nonmatchings/800c", func_8005A870);
/* SYS_OBJ_1790 (0x8005A9C4, 0x11C, 71 insns) -- REPLACES the
* INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_1790) entry at this exact spot
* (between func_8005A870 and SYS_OBJ_18AC).
*
* NOT a callable C function: it is the TAIL FRAGMENT of func_8005A870 (that
* parent stashes x/y/w/h in its own 0x40-byte frame slots 0x10/0x12/0x14/0x16,
* clamps them against D_8007278C/D_8007278E, and enters here via
* `bnez $v0, SYS_OBJ_1790` / `j SYS_OBJ_1790` with the clamped width in $v0,
* consumed by this fragment's first pair lhu $v1,16($sp)/sh $v0,22($sp)).
* Both exits leave via bare tail `j SYS_OBJ_18AC` -- the shared family
* epilogue (lw ra/s1/s0, addiu sp,0x40, jr ra). gcc-2.7.2 unconditionally
* appends a jr $ra epilogue to every C-function body (even noreturn/pure-asm),
* so the fragment is FILE-SCOPE inline asm -- the idiom already used by
* func_80059234, func_80059760, func_80059FC0/SYS_OBJ_E34 and SYS_OBJ_1DC0 in
* this TU. The tab-separated ".ent\t"/".end\t" pair is load-bearing (maspsx
* re-emits .set noreorder only on ".ent\t"; a plain .set line is swallowed, so
* GNU as would assemble in reorder mode and displace the delay slots).
* .frame/.mask/.fmask copied from the working func_80059FC0 blob (declares the
* PARENT frame: 64=0x40 bytes, mask ra|s1|s0=0x80030000).
*
* Body transcribed 1:1 from asm/nonmatchings/800c/SYS_OBJ_1790.s.
* SYMBOL AUDIT: the ONLY relocation in range is `j SYS_OBJ_18AC`
* (word 0x08016AB8 -> 0x8005AAE0, confirmed against SYS_OBJ_18AC.s); the two
* luis are pure literals (0x60000000>>16 GPU cmd base, 0x2000000>>16 blend
* tag), no %hi/%lo, no jal, no data symbols. Local labels numeric (1f/2f;
* branch offsets 6/0x28 encode identically to the target's .L names).
* Load/store offsets DECIMAL: maspsx hard-fails hex mem offsets ("invalid
* literal for int() with base 10"); lui/addiu/andi/or immediates stay hex.
*/
__asm__(
".text\n"
".align\t2\n"
".globl\tSYS_OBJ_1790\n"
".ent\tSYS_OBJ_1790\n"
"SYS_OBJ_1790:\n"
".frame\t$sp,64,$31\n"
".mask\t0x80030000,-8\n"
".fmask\t0x00000000,0\n"
".set\tnoreorder\n"
"lhu $v1, 16($sp)\n"
"sh $v0, 22($sp)\n"
"andi $v0, $v1, 0x3f\n"
"bnez $v0, 1f\n"
" sll $a2, $t0, 2\n"
"lhu $v0, 20($sp)\n"
"nop\n"
"andi $v0, $v0, 0x3f\n"
"beqz $v0, 2f\n"
" sll $a1, $t0, 2\n"
"1:\n"
"addiu $t0, $t0, 0x1\n"
"sll $a1, $t0, 2\n"
"addiu $t0, $t0, 0x1\n"
"lhu $v0, 8($s0)\n"
"addu $a2, $a2, $s1\n"
"subu $v0, $v1, $v0\n"
"sh $v0, 16($sp)\n"
"lhu $v0, 18($sp)\n"
"lhu $v1, 10($s0)\n"
"lui $a0, 0x6000\n"
"subu $v0, $v0, $v1\n"
"sh $v0, 18($sp)\n"
"lbu $v0, 27($s0)\n"
"lbu $v1, 26($s0)\n"
"sll $v0, $v0, 16\n"
"sll $v1, $v1, 8\n"
"or $v1, $v1, $a0\n"
"lbu $a0, 25($s0)\n"
"or $v0, $v0, $v1\n"
"or $v0, $v0, $a0\n"
"sw $v0, 0($a2)\n"
"lw $v0, 16($sp)\n"
"addu $a1, $a1, $s1\n"
"sw $v0, 0($a1)\n"
"sll $v0, $t0, 2\n"
"lw $v1, 20($sp)\n"
"addu $v0, $v0, $s1\n"
"sw $v1, 0($v0)\n"
"lhu $v0, 16($sp)\n"
"lhu $v1, 8($s0)\n"
"nop\n"
"addu $v0, $v0, $v1\n"
"sh $v0, 16($sp)\n"
"lhu $v0, 18($sp)\n"
"lhu $v1, 10($s0)\n"
"addiu $t0, $t0, 0x1\n"
"addu $v0, $v0, $v1\n"
"j SYS_OBJ_18AC\n"
" sh $v0, 18($sp)\n"
"2:\n"
"addiu $t0, $t0, 0x1\n"
"sll $a2, $t0, 2\n"
"addiu $t0, $t0, 0x1\n"
"sll $a3, $t0, 2\n"
"addiu $t0, $t0, 0x1\n"
"addu $a1, $a1, $s1\n"
"lui $a0, 0x200\n"
"lbu $v0, 27($s0)\n"
"lbu $v1, 26($s0)\n"
"sll $v0, $v0, 16\n"
"sll $v1, $v1, 8\n"
"or $v1, $v1, $a0\n"
"lbu $a0, 25($s0)\n"
"or $v0, $v0, $v1\n"
"or $v0, $v0, $a0\n"
"sw $v0, 0($a1)\n"
"lw $v0, 16($sp)\n"
"addu $a2, $a2, $s1\n"
"sw $v0, 0($a2)\n"
"lw $v0, 20($sp)\n"
"addu $a3, $a3, $s1\n"
"sw $v0, 0($a3)\n"
".set\treorder\n"
".end\tSYS_OBJ_1790\n"
);
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_18AC);
__asm__(
".text\n"
".align\t2\n"
".globl\tfunc_8005AB00\n"
".ent\tfunc_8005AB00\n"
"func_8005AB00:\n"
".frame\t$sp,0,$31\n"
".mask\t0x00000000,0\n"
".fmask\t0x00000000,0\n"
".set\tnoreorder\n"
"lui $v0, %hi(D_80072788)\n"
"lbu $v0, %lo(D_80072788)($v0)\n"
"nop\n"
"addiu $v0, $v0, -1\n"
"sltiu $v0, $v0, 2\n"
"beqz $v0, .L8005AB38\n"
"nop\n"
"beqz $a1, .L8005AB28\n"
"lui $v1, 57600\n"
"ori $v1, $v1, 2048\n"
".L8005AB28:\n"
"beqz $a0, SYS_OBJ_191C\n"
"andi $v0, $a2, 10239\n"
"j SYS_OBJ_191C\n"
"ori $v0, $v0, 4096\n"
".L8005AB38:\n"
"beqz $a1, .L8005AB44\n"
"lui $v1, 57600\n"
"ori $v1, $v1, 512\n"
".L8005AB44:\n"
"beqz $a0, SYS_OBJ_191C\n"
"andi $v0, $a2, 2559\n"
"ori $v0, $v0, 1024\n"
".set\treorder\n"
".end\tfunc_8005AB00\n"
);
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_191C);
INCLUDE_ASM("asm/nonmatchings/800c", func_8005AB58);
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_1964);
__asm__(
".text\n"
".align\t2\n"
".globl\tSYS_OBJ_19A4\n"
".ent\tSYS_OBJ_19A4\n"
"SYS_OBJ_19A4:\n"
".frame\t$sp,0,$31\n"
".mask\t0x00000000,0\n"
".fmask\t0x00000000,0\n"
".set\tnoreorder\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"
"bnez $2, 1f\n"
" andi $3, $5, 0xfff\n"
"andi $3, $5, 0x3ff\n"
"sll $3, $3, 10\n"
"j SYS_OBJ_19D8\n"
" andi $2, $7, 0x3ff\n"
"1:\n"
"sll $3, $3, 12\n"
"andi $2, $7, 0xfff\n"
".set\treorder\n"
".end\tSYS_OBJ_19A4\n"
);
s32 SYS_OBJ_19D8(s32 a0, s32 a1, s32 a2, s32 a3) {
register s32 v0 __asm__("$2");
register s32 v1 __asm__("$3");
__asm__ __volatile__("" : "=r"(v0));
__asm__ __volatile__("" : "=r"(v1));
a0 = 0xE3000000;
v0 = v1 | (v0 | a0);
__asm__ __volatile__("addiu\t$sp, $sp, 0x10");
return v0;
}
INCLUDE_ASM("asm/nonmatchings/800c", func_8005AC24);
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_1A30);
__asm__(
".text\n"
".align\t2\n"
".globl\tSYS_OBJ_1A70\n"
".ent\tSYS_OBJ_1A70\n"
"SYS_OBJ_1A70:\n"
".frame\t$sp,0,$31\n"
".mask\t0x00000000,0\n"
".fmask\t0x00000000,0\n"
".set\tnoreorder\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"
"bnez $2, 1f\n"
" andi $3, $5, 0xfff\n"
"andi $3, $5, 0x3ff\n"
"sll $3, $3, 10\n"
"j SYS_OBJ_1AA4\n"
" andi $2, $7, 0x3ff\n"
"1:\n"
"sll $3, $3, 12\n"
"andi $2, $7, 0xfff\n"
".set\treorder\n"
".end\tSYS_OBJ_1A70\n"
);
s32 SYS_OBJ_1AA4(s32 a0, s32 a1, s32 a2, s32 a3) {
register s32 v0 __asm__("$2");
register s32 v1 __asm__("$3");
__asm__ __volatile__("" : "=r"(v0));
__asm__ __volatile__("" : "=r"(v1));
a0 = 0xE4000000;
v0 = v1 | (v0 | a0);
__asm__ __volatile__("addiu\t$sp, $sp, 0x10");
return v0;
}
__asm__(
".text\n"
".align\t2\n"
".globl\tfunc_8005ACF0\n"
".ent\tfunc_8005ACF0\n"
"func_8005ACF0:\n"
".frame\t$sp,0,$31\n"
".mask\t0x00000000,0\n"
".fmask\t0x00000000,0\n"
".set\tnoreorder\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"
"bnez $2, 1f\n"
" andi $3, $5, 0xfff\n"
"andi $3, $5, 0x7ff\n"
"sll $3, $3, 11\n"
"j SYS_OBJ_1AF0\n"
" andi $2, $4, 0x7ff\n"
"1:\n"
"sll $3, $3, 12\n"
"andi $2, $4, 0xfff\n"
".set\treorder\n"
".end\tfunc_8005ACF0\n"
);
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_1AF0);
__asm__(
".text\n"
".align\t2\n"
".globl\tfunc_8005AD34\n"
".ent\tfunc_8005AD34\n"
"func_8005AD34:\n"
" .set\tnoreorder\n"
" bnez $a0, .L8005AD44\n"
" addiu $sp, $sp, -16\n"
" j SYS_OBJ_1B78\n"
" addu $v0, $zero, $zero\n"
".L8005AD44:\n"
" lbu $a1, 0($a0)\n"
" nop\n"
" srl $a1, $a1, 3\n"
" sw $a1, 0($sp)\n"
" lh $a2, 4($a0)\n"
" nop\n"
" negu $a2, $a2\n"
" andi $a2, $a2, 0xFF\n"
" sra $a2, $a2, 3\n"
" sw $a2, 8($sp)\n"
" lbu $v0, 2($a0)\n"
" sll $a1, $a1, 10\n"
" srl $v0, $v0, 3\n"
" sw $v0, 4($sp)\n"
" sll $v0, $v0, 15\n"
" lh $v1, 6($a0)\n"
" lui $a0, 0xe200\n"
" or $a1, $a1, $a0\n"
" or $v0, $v0, $a1\n"
" negu $v1, $v1\n"
" andi $v1, $v1, 0xFF\n"
" sra $v1, $v1, 3\n"
" sll $a0, $v1, 5\n"
" or $v0, $v0, $a0\n"
" or $v0, $v0, $a2\n"
" sw $v1, 12($sp)\n"
".set\treorder\n"
".end\tfunc_8005AD34\n"
);
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_1B78);
__asm__(
".text\n"
".align\t2\n"
".globl\tfunc_8005ADB8\n"
".ent\tfunc_8005ADB8\n"
"func_8005ADB8:\n"
".set\tnoreorder\n"
"lui $v1, %hi(D_80072788)\n"
"lbu $v1, %lo(D_80072788)($v1)\n"
"addiu $v0, $zero, 0x1\n"
"beq $v1, $v0, .L8005ADDC\n"
"addiu $v0, $zero, 0x2\n"
"beq $v1, $v0, .L8005AE04\n"
"nop\n"
"j SYS_OBJ_1C28\n"
"nop\n"
".L8005ADDC:\n"
"lui $v0, %hi(D_8007278B)\n"
"lbu $v0, %lo(D_8007278B)($v0)\n"
"nop\n"
"beqz $v0, SYS_OBJ_1C28\n"
"addiu $v0, $zero, 0x400\n"
"lh $v1, 4($a0)\n"
"lh $a0, 0($a0)\n"
".set\treorder\n"
".end\tfunc_8005ADB8\n"
);
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_1BC4);
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_1C28);
void SYS_OBJ_1C2C(void) {
}
extern volatile u32 *D_8007285C;
u32 _status(void) {
return *D_8007285C;
}
extern s32 **D_8007286C;
extern s32 *D_80072870;
extern volatile s32 *D_80072874;
extern s32 *D_80072878;
extern s32 func_8005C020(void);
extern s32 func_8005C054(void);
s32 func_8005AE80(s32 *a0, s32 a1) {
s32 s0 = a1;
*D_80072878 |= 0x8000000;
*D_80072874 = 0;
*D_8007286C = &a0[s0 - 1];
*D_80072870 = s0;
*D_80072874 = 0x11000002;
func_8005C020();
while (*D_80072874 & 0x1000000) {
if (func_8005C054() != 0) {
return -1;
}
}
return s0;
}
__asm__(
".text\n"
".align\t2\n"
".globl\t_clr\n"
".ent\t_clr\n"
"_clr:\n"
".set\tnoreorder\n"
"addiu $sp, $sp, -64\n"
"addu $t0, $a0, $zero\n"
"sw $ra, 56($sp)\n"
"sw $s1, 52($sp)\n"
"sw $s0, 48($sp)\n"
"lh $a0, 4($t0)\n"
"addu $t1, $a1, $zero\n"
"bltz $a0, .L8005AFB4\n"
"addu $a1, $a0, $zero\n"
"lui $v0, %hi(D_8007278C)\n"
"lh $v0, %lo(D_8007278C)($v0)\n"
"nop\n"
"addu $v1, $v0, $zero\n"
"addiu $v0, $v0, -1\n"
"slt $v0, $v0, $a0\n"
"bnez $v0, SYS_OBJ_1D84\n"
"addiu $v0, $v1, -1\n"
"j SYS_OBJ_1D84\n"
"addu $v0, $a1, $zero\n"
".L8005AFB4:\n"
"addu $v0, $zero, $zero\n"
".set\treorder\n"
".end\t_clr\n"
);
__asm__(
".text\n"
".align\t2\n"
".globl\tSYS_OBJ_1D84\n"
".ent\tSYS_OBJ_1D84\n"
"SYS_OBJ_1D84:\n"
".set\tnoreorder\n"
"lh $a1, 6($t0)\n"
"sh $v0, 4($t0)\n"
"bltz $a1, .L8005AFF0\n"
"addu $a0, $a1, $zero\n"
"lui $v0, %hi(D_8007278E)\n"
"lh $v0, %lo(D_8007278E)($v0)\n"
"nop\n"
"addu $v1, $v0, $zero\n"
"addiu $v0, $v0, -1\n"
"slt $v0, $v0, $a1\n"
"bnez $v0, SYS_OBJ_1DC0\n"
"addiu $v1, $v1, -1\n"
"j SYS_OBJ_1DC0\n"
"addu $v1, $a0, $zero\n"
".L8005AFF0:\n"
"addu $v1, $zero, $zero\n"
".set\treorder\n"
".end\tSYS_OBJ_1D84\n"
);
/* SYS_OBJ_1DC0 (0x8005AFF4) is NOT a callable function: it is the third code FRAGMENT of one
* larger routine that begins at _clr (0x8005AF68) and ends in SYS_OBJ_1F64 (0x8005B198).
*
* _clr -> falls through into SYS_OBJ_1D84 (also reached via `j SYS_OBJ_1D84`)
* SYS_OBJ_1D84 -> falls through into SYS_OBJ_1DC0 (also reached via `j SYS_OBJ_1DC0`)
* SYS_OBJ_1DC0 -> `j SYS_OBJ_1F64` on one path, falls through on the other
* SYS_OBJ_1F64 -> carries the ONLY epilogue (lw $ra,0x38($sp) ... jr $ra) for the chain
*
* SYS_OBJ_1DC0 therefore has NO prologue, NO epilogue, NO `jr $ra`, and is entered with live
* values already in $t0 (the object pointer, set by _clr), $t1 (the second argument, set by
* _clr) and $v1 (the clamped Y computed by SYS_OBJ_1D84). None of that is expressible as a C
* function: any C function body cc1 expands gets an unconditional `jr $ra` epilogue appended
* (proven in this same TU for func_80059234 -- neither __attribute__((noreturn)) nor a bare
* tail `j` suppresses it), and a C function cannot take arguments pre-placed in $t0/$t1/$v1
* nor fall off its end into the next symbol.
*
* A PREVIOUS attempt reconstructed the WHOLE _clr..SYS_OBJ_1F64 chain as a single C function
* and dropped `.global SYS_OBJ_1DC0` asm labels mid-body so a byte-comparable slice existed.
* That draft reported MATCH from match_one (the sliced region really was byte-exact) but made
* the FULL BINARY DIFFER, and was bisect-rejected: match_one only compares the sliced region,
* while the object file ALSO carried the reconstructed _clr/SYS_OBJ_1D84 prologue code and an
* extra `SYS_combined_1DC0` / `SYS_OBJ_1DC0_END` symbol pair, none of which exist in the
* retail binary -- and _clr / SYS_OBJ_1D84 / SYS_OBJ_1F64 are still INCLUDE_ASM in 800c.c, so
* that reconstructed code was pure ADDITION to the link.
*
* Correct form (the byte-verified idiom already used five times in this TU): emit the fragment
* as FILE-SCOPE inline asm -- a raw text blob cc1 copies verbatim with no RTL function wrapper,
* so no prologue and no epilogue are ever generated and no extra symbol is defined. The literal
* ".ent\t" / ".end\t" pair (tab-separated, exactly as cc1 emits) is load-bearing: maspsx's
* process_line special-cases lines starting with ".ent\t" and emits a FRESH ".set\tnoreorder"
* into its own output, whereas a plain ".set\tnoreorder" line is swallowed as internal state and
* never re-emitted -- without it GNU `as` assembles in reorder mode and displaces every
* hand-placed delay-slot instruction.
*
* Body transcribed 1:1 from asm/nonmatchings/800c/SYS_OBJ_1DC0.s. SYMBOL AUDIT -- every
* relocation in that .s, decoded from the raw instruction words and cross-checked against
* config/symbols.us.txt:
* jal 0x0C016DD7 x3 -> 0x016DD7<<2 | 0x80000000 = 0x8005B75C = func_8005B75C
* j 0x08016C66 -> 0x016C66<<2 | 0x80000000 = 0x8005B198 = SYS_OBJ_1F64
* lui 0x8008 + addiu 0x8854 -> 0x80080000-0x77AC = 0x80078854 = D_80078854 (address taken,
* masked with 0x00FFFFFF and also used as the `sw $a3,0($a2)` base)
* lui 0x8007 + lw 0x285C -> 0x8007285C = D_8007285C (pointer load, then `lw $a0,0($v0)`)
* %hi/%lo store targets, all in the D_80078830 block:
* D_80078830 D_80078834 D_80078838 D_8007883C D_80078840 D_80078844 D_80078848
* D_8007884C D_80078850 D_80078858 D_8007885C D_80078860
* (note D_80078854 is written through $a2, NOT through a %hi/%lo $at pair, and D_8007284C /
* D_80078830's neighbours are NOT touched -- there is no other relocation in the file.)
*/
__asm__(
".text\n"
".align\t2\n"
".globl\tSYS_OBJ_1DC0\n"
".ent\tSYS_OBJ_1DC0\n"
"SYS_OBJ_1DC0:\n"
".set\tnoreorder\n"
"lhu $v0, 0($t0)\n"
"nop\n"
"andi $v0, $v0, 0x3f\n"
"bnez $v0, 1f\n"
"sh $v1, 6($t0)\n"
"lhu $v0, 4($t0)\n"
"nop\n"
"andi $v0, $v0, 0x3f\n"
"beqz $v0, 2f\n"
"lui $v0, 0x5ff\n"
"1:\n"
"lui $a1, 0xff\n"
"ori $a1, $a1, 0xffff\n"
"lui $a0, 0xe4ff\n"
"ori $a0, $a0, 0xffff\n"
"lui $a3, 0x3ff\n"
"lui $a2, %hi(D_80078854)\n"
"addiu $a2, $a2, %lo(D_80078854)\n"
"and $v0, $a2, $a1\n"
"lui $v1, 0x800\n"
"or $v0, $v0, $v1\n"
"lui $s0, 0xe300\n"
"lui $s1, 0xe500\n"
"lui $at, %hi(D_80078830)\n"
"sw $v0, %lo(D_80078830)($at)\n"
"lui $v0, 0xe600\n"
"and $a1, $t1, $a1\n"
"lui $v1, 0x6000\n"
"or $a1, $a1, $v1\n"
"lui $at, %hi(D_80078840)\n"
"sw $v0, %lo(D_80078840)($at)\n"
"lui $v0, %hi(D_8007285C)\n"
"lw $v0, %lo(D_8007285C)($v0)\n"
"lui $v1, 0xe100\n"
"lui $at, %hi(D_80078834)\n"
"sw $s0, %lo(D_80078834)($at)\n"
"lui $at, %hi(D_80078838)\n"
"sw $a0, %lo(D_80078838)($at)\n"
"lui $at, %hi(D_8007883C)\n"
"sw $s1, %lo(D_8007883C)($at)\n"
"lw $a0, 0($v0)\n"
"srl $v0, $t1, 31\n"
"sll $v0, $v0, 10\n"
"or $v0, $v0, $v1\n"
"lui $at, %hi(D_80078848)\n"
"sw $a1, %lo(D_80078848)($at)\n"
"andi $a0, $a0, 0x7ff\n"
"or $a0, $a0, $v0\n"
"lui $at, %hi(D_80078844)\n"
"sw $a0, %lo(D_80078844)($at)\n"
"lw $v0, 0($t0)\n"
"ori $a3, $a3, 0xffff\n"
"lui $at, %hi(D_8007884C)\n"
"sw $v0, %lo(D_8007884C)($at)\n"
"lw $v0, 4($t0)\n"
"sw $a3, 0($a2)\n"
"lui $at, %hi(D_80078850)\n"
"sw $v0, %lo(D_80078850)($at)\n"
"jal func_8005B75C\n"
"addiu $a0, $zero, 0x3\n"
"or $v0, $v0, $s0\n"
"lui $at, %hi(D_80078858)\n"
"sw $v0, %lo(D_80078858)($at)\n"
"jal func_8005B75C\n"
"addiu $a0, $zero, 0x4\n"
"lui $v1, 0xe400\n"
"or $v0, $v0, $v1\n"
"lui $at, %hi(D_8007885C)\n"
"sw $v0, %lo(D_8007885C)($at)\n"
"jal func_8005B75C\n"
"addiu $a0, $zero, 0x5\n"
"or $v0, $v0, $s1\n"
"lui $at, %hi(D_80078860)\n"
"sw $v0, %lo(D_80078860)($at)\n"
"j SYS_OBJ_1F64\n"
"nop\n"
"2:\n"
"ori $v0, $v0, 0xffff\n"
"lui $v1, 0xff\n"
"ori $v1, $v1, 0xffff\n"
"lui $at, %hi(D_80078830)\n"
"sw $v0, %lo(D_80078830)($at)\n"
"lui $v0, 0xe600\n"
"and $v1, $t1, $v1\n"
"lui $a1, 0x200\n"
"lui $at, %hi(D_80078834)\n"
"sw $v0, %lo(D_80078834)($at)\n"
"lui $v0, %hi(D_8007285C)\n"
"lw $v0, %lo(D_8007285C)($v0)\n"
"or $v1, $v1, $a1\n"
"lw $a0, 0($v0)\n"
"srl $v0, $t1, 31\n"
"sll $v0, $v0, 10\n"
"lui $at, %hi(D_8007883C)\n"
"sw $v1, %lo(D_8007883C)($at)\n"
"lui $v1, 0xe100\n"
"or $v0, $v0, $v1\n"
"andi $a0, $a0, 0x7ff\n"
"or $a0, $a0, $v0\n"
"lui $at, %hi(D_80078838)\n"
"sw $a0, %lo(D_80078838)($at)\n"
"lw $v0, 0($t0)\n"
"lui $at, %hi(D_80078840)\n"
"sw $v0, %lo(D_80078840)($at)\n"
"lw $v0, 4($t0)\n"
"lui $at, %hi(D_80078844)\n"
"sw $v0, %lo(D_80078844)($at)\n"
".set\treorder\n"
".end\tSYS_OBJ_1DC0\n"
);
/* SYS_OBJ_1F64 (0x8005B198) is NOT a callable function: it is the TAIL FRAGMENT of one larger
* routine that begins at _clr (0x8005AF68) and runs _clr -> SYS_OBJ_1D84 -> SYS_OBJ_1DC0 ->
* SYS_OBJ_1F64 (see the SYS_OBJ_1DC0 block above). SYS_OBJ_1F64 carries the ONLY epilogue of the
* chain: it tears down the 0x40-byte frame BUILT BY _CLR (ra@0x38, s1@0x34, s0@0x30) -- a frame
* this fragment never created. No C function body can express that: cc1 unconditionally appends
* its own prologue/epilogue around any C body (proven in this TU for func_80059234), so the
* correct form is the byte-verified FILE-SCOPE inline asm idiom already used for SYS_OBJ_1DC0,
* replacing the INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_1F64); stub. The literal
* ".ent\t"/".end\t" pair (tab-separated) is load-bearing: maspsx special-cases lines starting
* with ".ent\t" and re-emits a fresh ".set\tnoreorder", whereas a bare ".set\tnoreorder" line is
* swallowed and never re-emitted. NOTE: maspsx parses load/store displacements with int(x)
* base 10 -- memory offsets must be written in DECIMAL (0x38=56, 0x34=52, 0x30=48, 0x40=64).
*
* Body transcribed 1:1 from asm/nonmatchings/800c/SYS_OBJ_1F64.s. SYMBOL AUDIT -- every
* relocation in that .s, decoded from the raw instruction words:
* lui 0x3C048008 + addiu 0x24848830 -> 0x80080000-0x77D0 = 0x80078830 = D_80078830
* (address taken, passed as $a0)
* jal 0x0C016DC4 -> 0x016DC4<<2 | 0x80000000 = 0x8005B710 = func_8005B710
* (defined in this TU; writes D_8007285C/D_80072860/
* D_80072864/D_80072868 -- the GPU clear/draw-env kick)
* (no other relocation in the file.)
*/
__asm__(
".text\n"
".align\t2\n"
".globl\tSYS_OBJ_1F64\n"
".ent\tSYS_OBJ_1F64\n"
"SYS_OBJ_1F64:\n"
".set\tnoreorder\n"
"lui $a0, %hi(D_80078830)\n"
"addiu $a0, $a0, %lo(D_80078830)\n"
"jal func_8005B710\n"
"nop\n"
"addu $v0, $zero, $zero\n"
"lw $ra, 56($sp)\n"
"lw $s1, 52($sp)\n"
"lw $s0, 48($sp)\n"
"addiu $sp, $sp, 64\n"
"jr $ra\n"
"nop\n"
".set\treorder\n"
".end\tSYS_OBJ_1F64\n"
);
/* _dws (0x8005B1C4) is NOT a callable function: it is the HEAD FRAGMENT of one larger routine
* that continues at SYS_OBJ_1FF4 (0x8005B228, the very next address after this symbol's 25
* instructions end). _dws has NO epilogue and NO `jr $ra` anywhere in its 25 instructions,
* while it builds a full 0x50-byte frame (ra@0x48, s5@0x44, s4@0x40, s3@0x3C, s2@0x38,
* s1@0x34, s0@0x30) that only the continuation tears down, and it ends in a BARE FALLTHROUGH
* into SYS_OBJ_1FF4 at .L8005B224. None of that is expressible as a C function: any C function
* body cc1 expands gets an unconditional `jr $ra` epilogue appended (proven three times in
* this same TU: func_80059234 / SYS_OBJ_16C-family / SYS_OBJ_1DC0 -- neither
* __attribute__((noreturn)) nor a bare tail `j` suppresses it), and a C function cannot fall
* off its end into the next symbol. Correct form (the byte-verified idiom already used five
* times in this TU): emit the fragment as FILE-SCOPE inline asm -- a raw text blob cc1 copies
* verbatim with no RTL function wrapper, so no prologue and no epilogue are ever generated.
*
* The literal ".ent\t" / ".end\t" pair (tab-separated, exactly as cc1 emits) is load-bearing:
* maspsx's process_line special-cases lines starting with ".ent\t" and emits a FRESH
* ".set\tnoreorder" into its own output, whereas a plain ".set\tnoreorder" line is swallowed as
* internal state and never re-emitted -- without it GNU `as` assembles in reorder mode and
* displaces every hand-placed delay-slot instruction.
*
* IMMEDIATE SPELLING LAW (byte-proven this session): maspsx int()s MEM-OPERAND OFFSETS with
* base 10 ONLY -- writing the target's own hex spelling ("sw $s1, 0x34($sp)") dies with
* "MASPSX: invalid literal for int() with base 10: '0x34'", while non-mem immediates
* (addiu -0x50 etc.) pass through untouched. Decimal mem offsets are therefore MANDATORY,
* every banked blob in this TU spells them decimally (20($sp)/24($sp)/...), and textual
* parity with the splat .s is impossible by design -- the bytes are identical regardless.
*
* The local branch-back label keeps the TARGET .s's own spelling `.L8005B224` (law 2: spell
* every symbol from the target); the TU's other banked blobs use exactly this named-.L style
* (.L80059798/.L80059820/.L8005A0FC/...), labels are address-unique so no collision exists,
* and SYS_OBJ_1FF4.s was checked: nothing branches back into _dws's range.
*
* Body transcribed 1:1 from asm/nonmatchings/800c/_dws.s. SYMBOL AUDIT -- every relocation in
* that .s, decoded from the raw instruction words:
* jal 0x0C017008 -> 0x017008<<2 | 0x80000000 = 0x8005C020 = func_8005C020 -- called with NO
* arguments and its result discarded, exactly as this TU's existing declaration
* (src/800c.c: `extern s32 func_8005C020(void);`) and the atlas tu-row ('s32', ()) say;
* lui 0x8007 + lh 0x278C -> 0x8007278C = D_8007278C
* beqz 0x10400004 @0x8005B214 / j 0x08016C8A -> both target 0x8005B228 = SYS_OBJ_1FF4
* (the continuation fragment)
* bltz 0x04A0000A @0x8005B1F8 -> 0x8005B224 = the local fallthrough label .L8005B224
* (there is no other relocation in the file.)
*/
__asm__(
".text\n"
".align\t2\n"
".globl\t_dws\n"
".ent\t_dws\n"
"_dws:\n"
".set\tnoreorder\n"
"addiu $sp, $sp, -80\n"
"sw $s1, 52($sp)\n"
"addu $s1, $a0, $zero\n"
"sw $s2, 56($sp)\n"
"addu $s2, $a1, $zero\n"
"sw $ra, 72($sp)\n"
"sw $s5, 68($sp)\n"
"sw $s4, 64($sp)\n"
"sw $s3, 60($sp)\n"
"jal func_8005C020\n"
"sw $s0, 48($sp)\n"
"lh $a1, 4($s1)\n"
"addu $s5, $zero, $zero\n"
"bltz $a1, .L8005B224\n"
"addu $v1, $a1, $zero\n"
"lui $v0, %hi(D_8007278C)\n"
"lh $v0, %lo(D_8007278C)($v0)\n"
"nop\n"
"addu $a0, $v0, $zero\n"
"slt $v0, $v0, $a1\n"
"beqz $v0, SYS_OBJ_1FF4\n"
"nop\n"
"j SYS_OBJ_1FF4\n"
"addu $v1, $a0, $zero\n"
".L8005B224:\n"
"addu $v1, $zero, $zero\n"
".set\treorder\n"
".end\t_dws\n"
);
__asm__(
".text\n"
".align\t2\n"
".globl\tSYS_OBJ_1FF4\n"
".ent\tSYS_OBJ_1FF4\n"
"SYS_OBJ_1FF4:\n"
".set\tnoreorder\n"
"lh $a1, 6($s1)\n"
"sh $v1, 4($s1)\n"
"bltz $a1, .L8005B25C\n"
"addu $v1, $a1, $zero\n"
"lui $v0, %hi(D_8007278E)\n"
"lh $v0, %lo(D_8007278E)($v0)\n"
"addu $a0, $v1, $zero\n"
"addu $v1, $v0, $zero\n"
"slt $v0, $v0, $a1\n"
"beqz $v0, .L8005B264\n"
"sll $v0, $a0, 16\n"
"j SYS_OBJ_202C\n"
"addu $a0, $v1, $zero\n"
".L8005B25C:\n"
"addu $a0, $zero, $zero\n"
".set\treorder\n"
".end\tSYS_OBJ_1FF4\n"
);
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_202C);
/* SYS_OBJ_21A4 -- SHARED EPILOGUE of caller SYS_OBJ_202C's 0x50-byte frame
* (ra@0x48, s5@0x44, s4@0x40, s3@0x3C, s2@0x38, s1@0x34, s0@0x30).
* NOT independently C-compilable: SYS_OBJ_202C reaches it with BARE tail transfers
* ("j SYS_OBJ_21A4" / "bnez $v0, SYS_OBJ_21A4" with -1 in $v0 -- its error exits,
* asm/nonmatchings/800c/SYS_OBJ_202C.s lines 17/35) and its own last block FALLS
* THROUGH into this address (8005B3D8) with the return value already in $v0. There
* is no prologue and no body: any real C definition forces cc1 to synthesize its own
* return sequence after the hand-written restore (empirically probed in this TU:
* neither __attribute__((noreturn)) nor __builtin_unreachable__ suppresses it), so
* file-scope raw asm is the only form -- same family as the banked SYS_OBJ_16C /
* SYS_OBJ_210 / func_80059760+SYS_OBJ_604+SYS_OBJ_640 blobs above.
*
* PLACEMENT (MANDATORY -- cookbook §236 item 10 / ADD-3, see the func_8005C054 block
* at ~line 2604): this blob REPLACES the INCLUDE_ASM("asm/nonmatchings/800c",
* SYS_OBJ_21A4); line at src/800c.c:2109. The stub itself .includes the .s and thus
* DEFINES the symbol (include_asm.h), so keeping both double-defines .globl
* SYS_OBJ_21A4 -- and the stub's `nonmatching` macro additionally defines a SECOND
* global, SYS_OBJ_21A4.NON_MATCHING (include/labels.inc) -- the whole binary goes red
* with ZERO instruction diff. Like func_80059234/func_80059760/SYS_OBJ_E34/SYS_OBJ_1DC0/
* func_8005C054, no stub line may remain next to this blob.
*
* The literal ".ent\t"/".end\t" pair is load-bearing (maspsx re-emits .set noreorder
* after ".ent\t"; a plain .set\tnoreorder line is swallowed and as assembles in
* reorder mode, displacing the hand-placed delay-slot nop). NOTE: maspsx parses
* lw/sw offsets as decimal ints -- hex offsets like 0x48($sp) crash it ('invalid
* literal for int() with base 10'); write 72($sp)..80($sp).
*
* Body transcribed 1:1 from asm/nonmatchings/800c/SYS_OBJ_21A4.s (10 ins, oracle-
* verified MATCH). The .s contains exactly one symbol (glabel SYS_OBJ_21A4) and zero
* jal/%hi/%lo relocation lines -- no data/function/jtbl references exist to spell.
*/
__asm__(
".text\n"
".align\t2\n"
".globl\tSYS_OBJ_21A4\n"
".ent\tSYS_OBJ_21A4\n"
"SYS_OBJ_21A4:\n"
".set\tnoreorder\n"
"lw $ra, 72($sp)\n"
"lw $s5, 68($sp)\n"
"lw $s4, 64($sp)\n"
"lw $s3, 60($sp)\n"
"lw $s2, 56($sp)\n"
"lw $s1, 52($sp)\n"
"lw $s0, 48($sp)\n"
"addiu $sp, $sp, 80\n"
"jr $ra\n"
"nop\n"
".set\treorder\n"
".end\tSYS_OBJ_21A4\n"
);
__asm__(
".text\n"
".align\t2\n"
".globl\t_drs\n"
".ent\t_drs\n"
"_drs:\n"
".set\tnoreorder\n"
"addiu $sp, $sp, -72\n"
"sw $s1, 52($sp)\n"
"addu $s1, $a0, $zero\n"
"sw $s2, 56($sp)\n"
"addu $s2, $a1, $zero\n"
"sw $ra, 68($sp)\n"
"sw $s4, 64($sp)\n"
"sw $s3, 60($sp)\n"
"jal func_8005C020\n"
"sw $s0, 48($sp)\n"
"lh $a1, 4($s1)\n"
"nop\n"
"bltz $a1, .L8005B45C\n"
"addu $v1, $a1, $zero\n"
"lui $v0, %hi(D_8007278C)\n"
"lh $v0, %lo(D_8007278C)($v0)\n"
"nop\n"
"addu $a0, $v0, $zero\n"
"slt $v0, $v0, $a1\n"
"beqz $v0, SYS_OBJ_222C\n"
"nop\n"
"j SYS_OBJ_222C\n"
"addu $v1, $a0, $zero\n"
".L8005B45C:\n"
"addu $v1, $zero, $zero\n"
".set\treorder\n"
".end\t_drs\n"
);
__asm__(
".text\n"
".align\t2\n"
".globl\tSYS_OBJ_222C\n"
".ent\tSYS_OBJ_222C\n"
"SYS_OBJ_222C:\n"
".set\tnoreorder\n"
"lh $a1, 6($s1)\n"
"sh $v1, 4($s1)\n"
"bltz $a1, .L8005B494\n"
"addu $v1, $a1, $zero\n"
"lui $v0, %hi(D_8007278E)\n"
"lh $v0, %lo(D_8007278E)($v0)\n"
"addu $a0, $v1, $zero\n"
"addu $v1, $v0, $zero\n"
"slt $v0, $v0, $a1\n"
"beqz $v0, .L8005B49C\n"
"sll $v0, $a0, 16\n"
"j SYS_OBJ_2264\n"
"addu $a0, $v1, $zero\n"
".L8005B494:\n"
"addu $a0, $zero, $zero\n"
".set\treorder\n"
".end\tSYS_OBJ_222C\n"
);
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_2264);
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_242C);
extern volatile u32 *D_8007285C;
extern u8 D_80078874[];
void func_8005B684(u32 arg) {
*D_8007285C = arg;
D_80078874[arg >> 24] = arg;
}
extern u8 D_80078874[];
u8 _getctl(s32 a0)
{
return D_80078874[a0];
}
extern volatile u32 *D_8007285C;
extern volatile u32 *D_80072858;
s32 _cwb(u32 *src, s32 n) {
s32 i;
*D_8007285C = 0x04000000;
for (i = n - 1; i != -1; i--) {
*D_80072858 = *src++;
}
return 0;
}
extern volatile u32 *D_8007285C;
extern volatile u32 *D_80072860;
extern volatile u32 *D_80072864;
extern volatile u32 *D_80072868;
void func_8005B710(s32 a0) {
*D_8007285C = 0x04000002;
*D_80072860 = a0;
*D_80072864 = 0;
*D_80072868 = 0x01000401;
}
extern volatile u32 *D_8007285C;
extern volatile u32 *D_80072858;
u32 func_8005B75C(u32 a0) {
*D_8007285C = a0 | 0x10000000;
return *D_80072858 & 0xFFFFFF;
}
extern s32 func_8005B7B0(void (*f)(s32, s32), s32 *p, s32 n, s32 r);
s32 _addque(void (*f)(s32, s32), s32 *p, s32 r) {
return func_8005B7B0(f, p, 0, r);
}
/* ============================================================================================
* MERGED FUNCTION — this draft defines func_8005B7B0, NOT SYS_OBJ_26EC.
*
* SYS_OBJ_26EC is not an independent function. splat carved ONE PsyQ libgpu queue-push routine
* (0x8005B7B0..0x8005BA8F, 184 instructions) into SIX symbols:
*
* func_8005B7B0 0x8005B7B0..0x8005B7E3 prologue + `j` to the queue-full TEST
* func_8005B7E4 0x8005B7E4..0x8005B7FB the queue-full wait-loop BODY
* SYS_OBJ_25C8 0x8005B7FC..0x8005B91F the wait-loop TEST + the synchronous path
* SYS_OBJ_26EC 0x8005B920..0x8005B9DB the payload-copy loop + the n==0 arm
* SYS_OBJ_27A8 0x8005B9DC..0x8005BA6F the shared tail: publish, advance, drain
* SYS_OBJ_283C 0x8005BA70..0x8005BA8F the epilogue
*
* Proof they are one function, not six:
* - func_8005B7B0 ends in `j SYS_OBJ_25C8` with NO epilogue, and the frame it builds
* (0x28; ra@0x20, s3@0x1C, s2@0x18, s1@0x14, s0@0x10) is the frame SYS_OBJ_283C tears down;
* - SYS_OBJ_25C8 branches BACKWARD into func_8005B7E4 (`beq $v0,$v1,func_8005B7E4`) — a loop;
* - SYS_OBJ_25C8's `beqz $s1,.L8005B9B8` targets a label INSIDE SYS_OBJ_26EC (the reported
* blocker) and SYS_OBJ_26EC's back-edge is `j SYS_OBJ_26EC` — its own head, the copy loop;
* - $s0/$s1/$s2/$s3 are the four incoming arguments and are live across ALL six ranges.
*
* The owner of the merged function is func_8005B7B0: it is the range's entry point and the only
* symbol an external caller can name (every other symbol is a branch/`j` target from inside).
*
* The queue element type and the global names are NOT invented — they are the ones the ALREADY
* MATCHED sibling func_8005BA90 (src/800c.c:600) uses to DRAIN this same queue, copied verbatim
* per this session's law 1. The declaration block below therefore duplicates src/800c.c:579-598
* only so this file compiles standalone for match_one; when the body is pasted into the TU it is
* inserted AFTER that existing block (see "notes" — no block needs moving).
* ============================================================================================ */
typedef struct {
void (*f)(s32, s32);
s32 a;
s32 b;
s32 pad[21];
} GpuQue; /* 0x60 */
extern volatile GpuQue D_800C5510[];
extern volatile u32 *D_8007285C;
extern volatile u32 *D_80072868;
extern u8 D_80072789;
extern volatile s32 D_8007287C[3];
extern volatile s32 D_8007288C;
extern volatile s32 D_80072890;
extern s32 D_80072894;
/* SCALAR, not [1]: this function stores it ONCE, which gcc-2.7.2 emits as a direct
* `sw $v0,%lo(D_80072790)($at)`; the array form emits an extra `la` address materialization
* (byte-measured: 185 ins instead of 184). func_8005BA90 needs the `la` because it touches the
* same object TWICE and CSEs the address — with the scalar declaration `(&D_80072790)[0]` there
* reproduces that byte-identically (verified: cc1 output diff is empty). */
extern volatile s32 D_80072790;
extern void (*D_80072794)(void);
extern s32 func_800426FC(s32);
extern void DMACallback(s32, s32);
extern s32 func_8005C020(void);
extern s32 func_8005C054(void);
extern s32 func_8005BA90(void);
s32 func_8005B7B0(void (*f)(s32, s32), s32 *p, s32 n, s32 r) {
s32 i;
func_8005C020();
while (((D_8007288C + 1) & 0x3F) == D_80072890) {
if (func_8005C054() != 0) {
return -1;
}
func_8005BA90();
}
D_80072894 = func_800426FC(0);
D_80072790 = 1;
if (D_80072789 == 0 ||
(D_8007288C == D_80072890 && !(*D_80072868 & 0x01000000) && D_80072794 == 0)) {
while (!(*D_8007285C & 0x04000000)) {
;
}
f((s32) p, r);
D_8007287C[0] = (s32) f;
D_8007287C[1] = (s32) p;
D_8007287C[2] = r;
func_800426FC(D_80072894);
return 0;
}
DMACallback(2, (s32) func_8005BA90);
if (n != 0) {
for (i = 0; i < n / 4; i++) {
D_800C5510[D_8007288C].pad[i] = p[i];
}
D_800C5510[D_8007288C].a = (s32) D_800C5510[D_8007288C].pad;
} else {
D_800C5510[D_8007288C].a = (s32) p;
}
D_800C5510[D_8007288C].b = r;
D_800C5510[D_8007288C].f = f;
D_8007288C = (D_8007288C + 1) & 0x3F;
func_800426FC(D_80072894);
func_8005BA90();
return (D_8007288C - D_80072890) & 0x3F;
}
extern volatile u32 *D_8007285C;
extern volatile u32 *D_80072868;
extern volatile s32 D_8007287C[3];
extern volatile s32 D_8007288C;
extern volatile s32 D_80072890;
extern s32 D_80072898;
extern void (*D_80072794)(void);
extern s32 func_800426FC(s32);
extern void DMACallback(s32, s32);
s32 func_8005BA90(void) {
if (*D_80072868 & 0x01000000) {
return 1;
}
D_80072898 = func_800426FC(0);
while (D_8007288C != D_80072890 && !(*D_80072868 & 0x01000000)) {
if (((D_80072890 + 1) & 0x3F) == D_8007288C && D_80072794 == 0) {
DMACallback(2, 0);
}
while (!(*D_8007285C & 0x04000000)) {
;
}
D_800C5510[D_80072890].f(D_800C5510[D_80072890].a, D_800C5510[D_80072890].b);
D_8007287C[0] = (s32) D_800C5510[D_80072890].f;
D_8007287C[1] = D_800C5510[D_80072890].a;
D_8007287C[2] = D_800C5510[D_80072890].b;
D_80072890 = (D_80072890 + 1) & 0x3F;
}
func_800426FC(D_80072898);
if (D_8007288C == D_80072890 && !(*D_80072868 & 0x01000000) && (&D_80072790)[0] != 0 &&
D_80072794 != 0) {
(&D_80072790)[0] = 0;
D_80072794();
}
return (D_8007288C - D_80072890) & 0x3F;
}
__asm__(
".text\n"
".align\t2\n"
".globl\tfunc_8005BD7C\n"
".ent\tfunc_8005BD7C\n"
"func_8005BD7C:\n"
".frame\t$sp,24,$31\n"
".mask\t0x80010000,-4\n"
".fmask\t0x00000000,0\n"
".set\tnoreorder\n"
"addiu $sp, $sp, -24\n"
"sw $s0, 16($sp)\n"
"addu $s0, $a0, $zero\n"
"sw $ra, 20($sp)\n"
"jal func_800426FC\n"
" addu $a0, $zero, $zero\n"
"lui $at, %hi(D_80072890)\n"
"sw $zero, %lo(D_80072890)($at)\n"
"lui $v1, %hi(D_80072890)\n"
"lw $v1, %lo(D_80072890)($v1)\n"
"lui $at, %hi(D_8007289C)\n"
"sw $v0, %lo(D_8007289C)($at)\n"
"addiu $v0, $zero, 1\n"
"lui $at, %hi(D_8007288C)\n"
"sw $v1, %lo(D_8007288C)($at)\n"
"andi $v1, $s0, 7\n"
"beq $v1, $v0, 3f\n"
" slti $v0, $v1, 2\n"
"beqz $v0, 1f\n"
" nop\n"
"beqz $v1, 2f\n"
" nop\n"
"j SYS_OBJ_2C6C\n"
" nop\n"
"1:\n"
"addiu $v0, $zero, 3\n"
"beq $v1, $v0, 3f\n"
" addiu $v0, $zero, 5\n"
"bne $v1, $v0, SYS_OBJ_2C6C\n"
" nop\n"
"2:\n"
"lui $v1, %hi(D_80072868)\n"
"lw $v1, %lo(D_80072868)($v1)\n"
"addiu $v0, $zero, 1025\n"
"sw $v0, 0($v1)\n"
"lui $v1, %hi(D_80072878)\n"
"lw $v1, %lo(D_80072878)($v1)\n"
"lui $a0, %hi(D_80078874)\n"
"addiu $a0, $a0, %lo(D_80078874)\n"
"lw $v0, 0($v1)\n"
"addu $a1, $zero, $zero\n"
"ori $v0, $v0, 2048\n"
"sw $v0, 0($v1)\n"
"lui $v0, %hi(D_8007285C)\n"
"lw $v0, %lo(D_8007285C)($v0)\n"
"addiu $a2, $zero, 256\n"
"sw $zero, 0($v0)\n"
"jal func_8005C29C\n"
" nop\n"
"lui $a0, %hi(D_800C5510)\n"
"addiu $a0, $a0, %lo(D_800C5510)\n"
"addu $a1, $zero, $zero\n"
"jal func_8005C29C\n"
" addiu $a2, $zero, 6144\n"
"j SYS_OBJ_2C6C\n"
" nop\n"
"3:\n"
"lui $v1, %hi(D_80072868)\n"
"lw $v1, %lo(D_80072868)($v1)\n"
"addiu $v0, $zero, 1025\n"
"sw $v0, 0($v1)\n"
"lui $v1, %hi(D_80072878)\n"
"lw $v1, %lo(D_80072878)($v1)\n"
"nop\n"
"lw $v0, 0($v1)\n"
"nop\n"
"ori $v0, $v0, 2048\n"
"sw $v0, 0($v1)\n"
"lui $v1, %hi(D_8007285C)\n"
"lw $v1, %lo(D_8007285C)($v1)\n"
"lui $v0, 0x200\n"
"sw $v0, 0($v1)\n"
"lui $v1, %hi(D_8007285C)\n"
"lw $v1, %lo(D_8007285C)($v1)\n"
"lui $v0, 0x100\n"
"sw $v0, 0($v1)\n"
".set\treorder\n"
".end\tfunc_8005BD7C\n"
);
__asm__(
".text\n"
".align\t2\n"
".globl\tSYS_OBJ_2C6C\n"
".ent\tSYS_OBJ_2C6C\n"
"SYS_OBJ_2C6C:\n"
".frame\t$sp,24,$31\n"
".mask\t0x80010000,-4\n"
".fmask\t0x00000000,0\n"
".set\tnoreorder\n"
"lui $a0, %hi(D_8007289C)\n"
"lw $a0, %lo(D_8007289C)($a0)\n"
"jal func_800426FC\n"
"nop\n"
"andi $v0, $s0, 0x7\n"
"bnez $v0, .L8005BEC4\n"
"addu $v0, $zero, $zero\n"
"jal func_8005C1C0\n"
"addu $a0, $s0, $zero\n"
".L8005BEC4:\n"
"lw $ra, 20($sp)\n"
"lw $s0, 16($sp)\n"
"addiu $sp, $sp, 24\n"
"jr $ra\n"
"nop\n"
".set\treorder\n"
".end\tSYS_OBJ_2C6C\n"
);
__asm__(
".text\n"
".align\t2\n"
".globl\tfunc_8005BED8\n"
".ent\tfunc_8005BED8\n"
".frame\t$sp,24,$31\n"
".mask\t0x80010000,-4\n"
".fmask\t0x00000000,0\n"
".set\tnoreorder\n"
"func_8005BED8:\n"
"addiu $sp, $sp, -24\n"
"sw $ra, 20($sp)\n"
"bnez $a0, .L8005BF8C\n"
" sw $s0, 16($sp)\n"
"jal func_8005C020\n"
" nop\n"
"j SYS_OBJ_2CDC\n"
" nop\n"
".set\treorder\n"
".end\tfunc_8005BED8\n"
);
__asm__(
".text\n"
".align\t2\n"
".globl\tSYS_OBJ_2CC4\n"
".type\tSYS_OBJ_2CC4, @function\n"
".ent\tSYS_OBJ_2CC4\n"
"SYS_OBJ_2CC4:\n"
".set\tnoreorder\n"
" jal func_8005BA90\n"
" nop\n"
" jal func_8005C054\n"
" nop\n"
" bnez $v0, SYS_OBJ_2DD8\n"
" addiu $v0, $zero, -1\n"
".set\treorder\n"
".size\tSYS_OBJ_2CC4, . - SYS_OBJ_2CC4\n"
".end\tSYS_OBJ_2CC4\n"
);
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_2CDC);
/* SYS_OBJ_2DD8 is the SHARED EPILOGUE TAIL for the 0x18-byte frame family in this slice
* (ra@0x14 / s0@0x10): SYS_OBJ_2CDC reaches it via "j SYS_OBJ_2DD8", SYS_OBJ_2CC4 via
* "bnez $v0, SYS_OBJ_2DD8" -- callers arrive mid-stream with THIS frame already built, i.e.
* the symbol's whole body is another function's epilogue (cookbook SS179-C). A C-function
* body always grows a phantom prologue/epilogue of its own (expand_function_end +
* function_epilogue append unconditionally), so the 5 instructions are transcribed 1:1 as
* file-scope basic asm with literal tab-formed .ent/.end, decimal displacements, and no
* hand-written load-delay nops (no instruction here consumes a just-loaded register).
*/
__asm__(
".text\n"
".align\t2\n"
".globl\tSYS_OBJ_2DD8\n"
".ent\tSYS_OBJ_2DD8\n"
"SYS_OBJ_2DD8:\n"
".set\tnoreorder\n"
"lw $ra, 20($sp)\n"
"lw $s0, 16($sp)\n"
"addiu $sp, $sp, 24\n"
"jr $ra\n"
"nop\n"
".set\treorder\n"
".end\tSYS_OBJ_2DD8\n"
);
INCLUDE_ASM("asm/nonmatchings/800c", func_8005C020);
/* func_8005C054 ("get_alarm"): GPU-timeout poller -- VENDOR-COMPILED libgpu code (polls VSync),
* NOT gcc-2.7.2 output. Measured, not assumed: the best honest-C body prices at 93 ins vs the
* target's 87 (LENGTH-DRIFT, 75 mismatched) and carries the vendor tells in every prologue slot --
* frame addiu -24 with NO 16-byte alignment padding (gcc emits -0x20), sltu for the pointer
* compare (target: slt), ZERO nops after global loads (target: one after each of D_800728A0/
* D_800728A4/D_80072878), and the -1 return materialized as `li` in a branch shadow instead of
* the target's delay-slot `addiu $v0,$zero,-1` riding a bare tail `j SYS_OBJ_2F7C`. This is the
* cookbook §265 class ("no C source can score MATCH ... stop drafting C"), banked via §265 FORM 1:
* FILE-SCOPE asm -- raw text cc1 copies verbatim, opt-level-independent, no RTL function wrapper,
* so no epilogue machinery ever runs. Both exits leave without any local epilogue: the alarm path
* tail-jumps SYS_OBJ_2F7C with -1 pre-set in the DELAY SLOT; the ok path (.L8005C1AC) sets $v0=0
* and FALLS THROUGH into SYS_OBJ_2F7C -- read first-hand this session: it is a 4-instruction
* epilogue FRAGMENT (lw $ra,0x18($sp); addiu $sp,$sp,0x20; jr $ra; nop) that tears down THIS
* function's own frame, so func_8005C054+SYS_OBJ_2F7C are one vendor routine split by splat,
* exactly like the _clr/SYS_OBJ_1D84/SYS_OBJ_1DC0/SYS_OBJ_1F64 chain already banked above.
*
* The literal ".ent\t"/".end\t" pair is load-bearing (maspsx re-emits .set noreorder after
* ".ent\t"; a plain .set\tnoreorder line is swallowed and as assembles in reorder mode,
* displacing every hand-placed delay-slot instruction). NOTE: maspsx parses sw/lw offsets as
* decimal ints -- hex offsets like 0x18($sp) crash it ('invalid literal for int() with base 10');
* write 24($sp).
*
* PLACEMENT (cookbook §236 item 10 / ADD-3 -- THE UN-DELETED INCLUDE_ASM STUB IS A DUPLICATE
* DEFINITION): this blob REPLACES the INCLUDE_ASM("asm/nonmatchings/800c", func_8005C054); line
* at src/800c.c:1107 -- as was done for the five banked siblings above (func_80059234,
* func_80059760, func_80059FC0/SYS_OBJ_E34, SYS_OBJ_1DC0 keep no stub line next to their blobs;
* include_asm.h confirms the stub itself .includes the .s and thus DEFINES the symbol, so keeping
* both double-defines .globl func_8005C054 and the whole binary goes red with zero instruction
* diff). The two existing `extern s32 func_8005C054(void);` declarations (~712, ~992) stay.
* Local-label collision checked: .L8005C0A4/.L8005C1AC exist ONLY in this target's .s across the
* whole asm tree -- no cross-stub clash.
*
* Body transcribed 1:1 from asm/nonmatchings/800c/func_8005C054.s (87 ins, oracle-verified MATCH).
* Every symbol below appears in that .s's own relocation lines: VSync, D_800728A0, D_800728A4,
* D_8007285C, D_80074238, D_8007288C, D_80072860, D_80072890, D_80072868, func_8005C604 (the TU's
* printf), D_8007287C, D_80072880, D_80072884, D_8007426C, func_800426FC, D_8007289C, D_80072878,
* SYS_OBJ_2F7C.
*/
__asm__(
".text\n"
".align\t2\n"
".globl\tfunc_8005C054\n"
".ent\tfunc_8005C054\n"
"func_8005C054:\n"
".set\tnoreorder\n"
"addiu $sp, $sp, -32\n"
"sw $ra, 24($sp)\n"
"jal VSync\n"
"addiu $a0, $zero, -1\n"
"lui $v1, %hi(D_800728A0)\n"
"lw $v1, %lo(D_800728A0)($v1)\n"
"nop\n"
"slt $v1, $v1, $v0\n"
"bnez $v1, .L8005C0A4\n"
"nop\n"
"lui $v1, %hi(D_800728A4)\n"
"lw $v1, %lo(D_800728A4)($v1)\n"
"nop\n"
"addiu $v0, $v1, 1\n"
"lui $at, %hi(D_800728A4)\n"
"sw $v0, %lo(D_800728A4)($at)\n"
"lui $v0, 0xF\n"
"slt $v0, $v0, $v1\n"
"beqz $v0, .L8005C1AC\n"
"nop\n"
".L8005C0A4:\n"
"lui $v1, %hi(D_8007285C)\n"
"lw $v1, %lo(D_8007285C)($v1)\n"
"lui $a0, %hi(D_80074238)\n"
"addiu $a0, $a0, %lo(D_80074238)\n"
"lw $v0, 0($v1)\n"
"lui $a1, %hi(D_8007288C)\n"
"lw $a1, %lo(D_8007288C)($a1)\n"
"lui $v0, %hi(D_80072860)\n"
"lw $v0, %lo(D_80072860)($v0)\n"
"lui $t0, %hi(D_80072890)\n"
"lw $t0, %lo(D_80072890)($t0)\n"
"lw $v0, 0($v0)\n"
"subu $a1, $a1, $t0\n"
"sw $v0, 16($sp)\n"
"lui $v0, %hi(D_80072868)\n"
"lw $v0, %lo(D_80072868)($v0)\n"
"lw $a2, 0($v1)\n"
"lw $a3, 0($v0)\n"
"jal func_8005C604\n"
"andi $a1, $a1, 0x3F\n"
"lui $v0, %hi(D_8007287C)\n"
"addiu $v0, $v0, %lo(D_8007287C)\n"
"lw $a1, 0($v0)\n"
"lui $a2, %hi(D_80072880)\n"
"lw $a2, %lo(D_80072880)($a2)\n"
"lui $a3, %hi(D_80072884)\n"
"lw $a3, %lo(D_80072884)($a3)\n"
"lui $a0, %hi(D_8007426C)\n"
"addiu $a0, $a0, %lo(D_8007426C)\n"
"jal func_8005C604\n"
"nop\n"
"jal func_800426FC\n"
"addu $a0, $zero, $zero\n"
"lui $at, %hi(D_80072890)\n"
"sw $zero, %lo(D_80072890)($at)\n"
"lui $v1, %hi(D_80072890)\n"
"lw $v1, %lo(D_80072890)($v1)\n"
"lui $at, %hi(D_8007289C)\n"
"sw $v0, %lo(D_8007289C)($at)\n"
"lui $at, %hi(D_8007288C)\n"
"sw $v1, %lo(D_8007288C)($at)\n"
"lui $v1, %hi(D_80072868)\n"
" lw $v1, %lo(D_80072868)($v1)\n"
"addiu $v0, $zero, 0x401\n"
"sw $v0, 0($v1)\n"
"lui $v1, %hi(D_80072878)\n"
"lw $v1, %lo(D_80072878)($v1)\n"
"nop\n"
"lw $v0, 0($v1)\n"
"nop\n"
"ori $v0, $v0, 0x800\n"
"sw $v0, 0($v1)\n"
"lui $v1, %hi(D_8007285C)\n"
"lw $v1, %lo(D_8007285C)($v1)\n"
"lui $v0, 0x200\n"
"sw $v0, 0($v1)\n"
"lui $v1, %hi(D_8007285C)\n"
"lw $v1, %lo(D_8007285C)($v1)\n"
"lui $v0, 0x100\n"
"sw $v0, 0($v1)\n"
"lui $a0, %hi(D_8007289C)\n"
"lw $a0, %lo(D_8007289C)($a0)\n"
"jal func_800426FC\n"
"nop\n"
"j SYS_OBJ_2F7C\n"
"addiu $v0, $zero, -1\n"
".L8005C1AC:\n"
"addu $v0, $zero, $zero\n"
".set\treorder\n"
".end\tfunc_8005C054\n"
);
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_2F7C);
/*
* func_8005C1C0 -- GPU-primitive dispatch sibling (same family as func_80059FC0/SYS_OBJ_E34,
* src/800c.c:508). The target has NO trailing "jr $ra": all four exits are raw, unlinked tail
* jumps into SYS_OBJ_3060 with the return value materialised in the DELAY SLOT ($v0 = 0/1/2/3),
* and SYS_OBJ_3060 (banked as the C stub immediately below) owns the shared epilogue for this
* frame. gcc-2.7.2 unconditionally appends its own return sequence to any ordinary C function
* body (function.c:expand_function_end, no noreturn guard -- matching-cookbook.md §179-C, whose
* follow-up list names THIS function), so a C spelling can only get within +2 instructions.
* FILE-SCOPE asm is the only spelling that emits exactly the target bytes. Per §179-C sub-rules:
* literal ".ent"/".end" (not glabel), %hi/%lo un-doubled, ".L" local labels only. No second
* ".ent SYS_OBJ_3060" is needed after ".end" (sub-rule c) because the following symbol is a real
* gcc-compiled C function carrying its own header.
*
* BANKING: this block REPLACES the line
* INCLUDE_ASM("asm/nonmatchings/800c", func_8005C1C0);
* at src/800c.c:1111, in place (between SYS_OBJ_2F7C and the SYS_OBJ_3060 stub) so link order
* is unchanged: func_8005C1C0 @0x8005C1C0 (0xD4 bytes) -> SYS_OBJ_3060 @0x8005C294 ->
* func_8005C29C @0x8005C29C.
*/
__asm__(
".text\n"
".align\t2\n"
".globl\tfunc_8005C1C0\n"
".ent\tfunc_8005C1C0\n"
"func_8005C1C0:\n"
".frame\t$sp,0,$31\n"
".mask\t0x00000000,0\n"
".fmask\t0x00000000,0\n"
".set\tnoreorder\n"
"lui $3, 0x1000\n"
"lui $2, %hi(D_8007285C)\n"
"lw $2, %lo(D_8007285C)($2)\n"
"ori $3, $3, 7\n"
"sw $3, 0($2)\n"
"lui $5, %hi(D_80072858)\n"
"lw $5, %lo(D_80072858)($5)\n"
"lui $3, 0xff\n"
"lw $2, 0($5)\n"
"ori $3, $3, 0xffff\n"
"and $2, $2, $3\n"
"addiu $3, $0, 2\n"
"beq $2, $3, .L8005C268\n"
" lui $3, 0xe100\n"
"lui $2, %hi(D_8007285C)\n"
"lw $2, %lo(D_8007285C)($2)\n"
"nop\n"
"lw $2, 0($2)\n"
"ori $3, $3, 0x1000\n"
"andi $2, $2, 0x3fff\n"
"or $2, $2, $3\n"
"sw $2, 0($5)\n"
"lui $2, %hi(D_80072858)\n"
"lw $2, %lo(D_80072858)($2)\n"
"lui $3, %hi(D_8007285C)\n"
"lw $3, %lo(D_8007285C)($3)\n"
"lw $2, 0($2)\n"
"lw $2, 0($3)\n"
"nop\n"
"andi $2, $2, 0x1000\n"
"bnez $2, .L8005C248\n"
" andi $2, $4, 8\n"
"j SYS_OBJ_3060\n"
" addu $2, $0, $0\n"
".L8005C248:\n"
"bnez $2, .L8005C258\n"
" lui $2, 0x2000\n"
"j SYS_OBJ_3060\n"
" addiu $2, $0, 1\n"
".L8005C258:\n"
"ori $2, $2, 0x504\n"
"sw $2, 0($3)\n"
"j SYS_OBJ_3060\n"
" addiu $2, $0, 2\n"
".L8005C268:\n"
"andi $2, $4, 8\n"
"beqz $2, .L8005C290\n"
" lui $4, 0x900\n"
"ori $4, $4, 1\n"
"lui $3, %hi(D_8007285C)\n"
"lw $3, %lo(D_8007285C)($3)\n"
"addiu $2, $0, 4\n"
"sw $4, 0($3)\n"
"j SYS_OBJ_3060\n"
"nop\n"
".L8005C290:\n"
"addiu $2, $0, 3\n"
".set\treorder\n"
".end\tfunc_8005C1C0\n"
);
void SYS_OBJ_3060(void) {
}
void func_8005C29C(void *arg0, s32 arg1, s32 arg2)
{
s32 i;
s32 frame_pad[2];
(void)&frame_pad;
i = arg2 - 1;
if (arg2 != 0) {
do {
*(u8 *)arg0 = (u8)arg1;
arg0 = (u8 *)arg0 + 1;
} while (--i != -1);
}
}