mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-28 14:59:48 -04:00
2aea2261d4
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. ResetRCnt SYS_OBJ_E34 func_80015118 func_800159C0 func_80015A08 func_80015A50 func_80017168 func_800178EC func_80017910 func_80017E68 func_8001CF30 func_8001D050 func_8001D70C func_800291A0 func_800291B4 func_800291C8 func_800291DC func_800291F0 func_80029204 func_80029524 func_80029A94 func_80029EC0 func_8002A520 func_8002A9DC func_8002AEE4 func_8002AF48 func_8002D844 func_8002F0D0 func_8002F12C func_8003A0D0 func_8005E374 func_8005FB70
1117 lines
38 KiB
C
1117 lines
38 KiB
C
#include "common.h"
|
|
|
|
|
|
/* 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"
|
|
);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_11C);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_16C);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SetGraphReverse);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_210);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", func_800594CC);
|
|
|
|
|
|
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);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", DrawSyncCallback);
|
|
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", func_800596F4);
|
|
|
|
|
|
/* 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);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_640);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", func_80059888);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", ClearImage2);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", func_800599B8);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", StoreImage);
|
|
|
|
|
|
/* ===========================================================================
|
|
* 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;
|
|
}
|
|
}
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", DrawPrim);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", func_80059CF4);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", func_80059D68);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", DrawOTagEnv);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", GetDrawEnv);
|
|
|
|
|
|
/*
|
|
* 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"
|
|
);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_F00);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_F24);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_F58);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_FD8);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_1034);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_11C0);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", GetDispEnv);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", GetODE);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SetTexWindow);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SetDrawArea);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SetDrawOffset);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SetPriority);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", func_8005A600);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SetDrawEnv);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_1578);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", func_8005A870);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_1790);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_18AC);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", func_8005AB00);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_191C);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", func_8005AB58);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_1964);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_19A4);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_19D8);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", func_8005AC24);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_1A30);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_1A70);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_1AA4);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", func_8005ACF0);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_1AF0);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", func_8005AD34);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_1B78);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", func_8005ADB8);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_1BC4);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_1C28);
|
|
|
|
void SYS_OBJ_1C2C(void) {
|
|
}
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", _status);
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", _clr);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_1D84);
|
|
|
|
|
|
/* 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"
|
|
);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_1F64);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", _dws);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_1FF4);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_202C);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_21A4);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", _drs);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_222C);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_2264);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_242C);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", func_8005B684);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", _getctl);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", _cwb);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", func_8005B710);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", func_8005B75C);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", _addque);
|
|
|
|
|
|
/* ============================================================================================
|
|
* 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;
|
|
}
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", func_8005BD7C);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_2C6C);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", func_8005BED8);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_2CC4);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_2CDC);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_2DD8);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", func_8005C020);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", func_8005C054);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_2F7C);
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", func_8005C1C0);
|
|
|
|
void SYS_OBJ_3060(void) {
|
|
}
|
|
|
|
INCLUDE_ASM("asm/nonmatchings/800c", func_8005C29C);
|