#include "common.h" #include "psyq/libcd.h" #include "shared/clearTbl40.h" /* dedup group I0: func_80037004 / func_80037334 share one body */ INCLUDE_ASM("asm/nonmatchings/800", func_800123F0); INCLUDE_ASM("asm/nonmatchings/800", func_80012558); INCLUDE_ASM("asm/nonmatchings/800", func_800126C4); INCLUDE_ASM("asm/nonmatchings/800", func_8001282C); INCLUDE_ASM("asm/nonmatchings/800", func_800128B4); INCLUDE_ASM("asm/nonmatchings/800", func_800128EC); INCLUDE_ASM("asm/nonmatchings/800", func_800129CC); INCLUDE_ASM("asm/nonmatchings/800", func_80012A60); s32 func_80012AB0(s32 arg0, s32 arg1) { return (arg0 - arg1) & 0xFFF; } INCLUDE_ASM("asm/nonmatchings/800", func_80012ABC); INCLUDE_ASM("asm/nonmatchings/800", func_80012B04); INCLUDE_ASM("asm/nonmatchings/800", func_80012B58); INCLUDE_ASM("asm/nonmatchings/800", func_80012C6C); INCLUDE_ASM("asm/nonmatchings/800", func_80012CB8); INCLUDE_ASM("asm/nonmatchings/800", func_80012D0C); INCLUDE_ASM("asm/nonmatchings/800", func_80012DBC); INCLUDE_ASM("asm/nonmatchings/800", func_80012E0C); INCLUDE_ASM("asm/nonmatchings/800", func_80012E6C); INCLUDE_ASM("asm/nonmatchings/800", func_80012F74); INCLUDE_ASM("asm/nonmatchings/800", func_80012FC8); INCLUDE_ASM("asm/nonmatchings/800", func_80013028); INCLUDE_ASM("asm/nonmatchings/800", func_800130D0); INCLUDE_ASM("asm/nonmatchings/800", func_8001311C); INCLUDE_ASM("asm/nonmatchings/800", func_80013154); INCLUDE_ASM("asm/nonmatchings/800", func_80013200); INCLUDE_ASM("asm/nonmatchings/800", func_80013228); INCLUDE_ASM("asm/nonmatchings/800", func_80013294); INCLUDE_ASM("asm/nonmatchings/800", func_800132BC); INCLUDE_ASM("asm/nonmatchings/800", func_80013328); INCLUDE_ASM("asm/nonmatchings/800", func_80013350); INCLUDE_ASM("asm/nonmatchings/800", func_800133BC); INCLUDE_ASM("asm/nonmatchings/800", func_800133E4); INCLUDE_ASM("asm/nonmatchings/800", func_80013450); INCLUDE_ASM("asm/nonmatchings/800", func_80013478); INCLUDE_ASM("asm/nonmatchings/800", func_800134FC); INCLUDE_ASM("asm/nonmatchings/800", func_80013694); INCLUDE_ASM("asm/nonmatchings/800", func_8001382C); INCLUDE_ASM("asm/nonmatchings/800", func_800139C8); INCLUDE_ASM("asm/nonmatchings/800", func_80013B64); INCLUDE_ASM("asm/nonmatchings/800", func_80013CFC); INCLUDE_ASM("asm/nonmatchings/800", func_80013E94); INCLUDE_ASM("asm/nonmatchings/800", func_80013ED0); INCLUDE_ASM("asm/nonmatchings/800", func_80013F3C); INCLUDE_ASM("asm/nonmatchings/800", func_80013F68); INCLUDE_ASM("asm/nonmatchings/800", func_80013F98); INCLUDE_ASM("asm/nonmatchings/800", func_80013FBC); INCLUDE_ASM("asm/nonmatchings/800", func_80013FE0); INCLUDE_ASM("asm/nonmatchings/800", func_80014004); INCLUDE_ASM("asm/nonmatchings/800", func_80014028); INCLUDE_ASM("asm/nonmatchings/800", func_8001404C); INCLUDE_ASM("asm/nonmatchings/800", func_80014070); INCLUDE_ASM("asm/nonmatchings/800", func_80014094); INCLUDE_ASM("asm/nonmatchings/800", func_800140B8); INCLUDE_ASM("asm/nonmatchings/800", func_80014128); INCLUDE_ASM("asm/nonmatchings/800", func_80014148); INCLUDE_ASM("asm/nonmatchings/800", func_80014168); INCLUDE_ASM("asm/nonmatchings/800", func_800141AC); INCLUDE_ASM("asm/nonmatchings/800", func_800141F0); INCLUDE_ASM("asm/nonmatchings/800", func_80014238); INCLUDE_ASM("asm/nonmatchings/800", func_800142C8); INCLUDE_ASM("asm/nonmatchings/800", func_80014338); INCLUDE_ASM("asm/nonmatchings/800", func_80014390); INCLUDE_ASM("asm/nonmatchings/800", func_800143AC); INCLUDE_ASM("asm/nonmatchings/800", func_80014444); INCLUDE_ASM("asm/nonmatchings/800", func_800144D4); void func_80014554(void) { } void func_8001455C(void) { } INCLUDE_ASM("asm/nonmatchings/800", func_80014564); INCLUDE_ASM("asm/nonmatchings/800", func_80014588); INCLUDE_ASM("asm/nonmatchings/800", func_800145EC); INCLUDE_ASM("asm/nonmatchings/800", func_800146B0); INCLUDE_ASM("asm/nonmatchings/800", func_80014774); INCLUDE_ASM("asm/nonmatchings/800", func_800147B8); INCLUDE_ASM("asm/nonmatchings/800", func_80014928); INCLUDE_ASM("asm/nonmatchings/800", func_80014960); INCLUDE_ASM("asm/nonmatchings/800", func_80014998); INCLUDE_ASM("asm/nonmatchings/800", func_800149E0); INCLUDE_ASM("asm/nonmatchings/800", func_80014B10); INCLUDE_ASM("asm/nonmatchings/800", func_80014BFC); INCLUDE_ASM("asm/nonmatchings/800", func_80014C28); INCLUDE_ASM("asm/nonmatchings/800", func_80014C54); INCLUDE_ASM("asm/nonmatchings/800", func_80014CAC); INCLUDE_ASM("asm/nonmatchings/800", func_80014CF8); INCLUDE_ASM("asm/nonmatchings/800", func_80014D30); INCLUDE_ASM("asm/nonmatchings/800", func_80014D68); INCLUDE_ASM("asm/nonmatchings/800", func_80014D94); INCLUDE_ASM("asm/nonmatchings/800", func_80014DC0); INCLUDE_ASM("asm/nonmatchings/800", func_80014DEC); INCLUDE_ASM("asm/nonmatchings/800", func_80014E24); INCLUDE_ASM("asm/nonmatchings/800", func_80014E80); INCLUDE_ASM("asm/nonmatchings/800", func_80014ED4); INCLUDE_ASM("asm/nonmatchings/800", func_80015018); INCLUDE_ASM("asm/nonmatchings/800", func_80015118); void func_8001513C(void) { } INCLUDE_ASM("asm/nonmatchings/800", func_80015144); INCLUDE_ASM("asm/nonmatchings/800", func_80015208); INCLUDE_ASM("asm/nonmatchings/800", func_800152F4); INCLUDE_ASM("asm/nonmatchings/800", func_80015310); INCLUDE_ASM("asm/nonmatchings/800", func_8001534C); INCLUDE_ASM("asm/nonmatchings/800", func_800153A4); INCLUDE_ASM("asm/nonmatchings/800", func_800153CC); INCLUDE_ASM("asm/nonmatchings/800", func_80015424); INCLUDE_ASM("asm/nonmatchings/800", func_8001544C); INCLUDE_ASM("asm/nonmatchings/800", func_80015498); INCLUDE_ASM("asm/nonmatchings/800", func_80015608); INCLUDE_ASM("asm/nonmatchings/800", func_80015760); INCLUDE_ASM("asm/nonmatchings/800", func_80015908); INCLUDE_ASM("asm/nonmatchings/800", func_80015954); INCLUDE_ASM("asm/nonmatchings/800", func_80015978); INCLUDE_ASM("asm/nonmatchings/800", func_8001599C); INCLUDE_ASM("asm/nonmatchings/800", func_800159C0); INCLUDE_ASM("asm/nonmatchings/800", func_800159E4); INCLUDE_ASM("asm/nonmatchings/800", func_80015A08); INCLUDE_ASM("asm/nonmatchings/800", func_80015A2C); INCLUDE_ASM("asm/nonmatchings/800", func_80015A50); #ifdef NON_MATCHING /* uint -> packed BCD (9 digits, ÷ powers of 10). All idioms match under the pinned * triple (divu+break div-by-zero via --expand-div, multu 0xCCCCCCCD + srl 3 for ÷10); * residual diff is a loop-setup instruction-scheduling permutation (li counter vs the * hoisted magic constant) — a decomp-permuter target. See docs/matching-cookbook.md. */ u32 func_80015A74(u32 param_1) { u32 result; s32 i; u32 divisor; divisor = 1000000000; result = 0; for (i = 9; i >= 0; i--) { result = (result << 4) | (param_1 / divisor); param_1 = param_1 % divisor; divisor = divisor / 10; } return result; } #else INCLUDE_ASM("asm/nonmatchings/800", func_80015A74); #endif INCLUDE_ASM("asm/nonmatchings/800", func_80015AD0); INCLUDE_ASM("asm/nonmatchings/800", func_80015B6C); INCLUDE_ASM("asm/nonmatchings/800", func_80015D4C); INCLUDE_ASM("asm/nonmatchings/800", func_80015F04); INCLUDE_ASM("asm/nonmatchings/800", func_80016110); INCLUDE_ASM("asm/nonmatchings/800", func_80016224); INCLUDE_ASM("asm/nonmatchings/800", func_80016450); INCLUDE_ASM("asm/nonmatchings/800", func_80016638); INCLUDE_ASM("asm/nonmatchings/800", func_800166E8); #ifdef NON_MATCHING /* bzero(p, n): n<4 byte path; else align-to-4 -> word-fill (sw) -> remainder bytes. * Logically correct and instruction-identical to the target EXCEPT gcc 2.7.2 emits a * phantom empty 16-byte stack frame here (target is frameless) — that one frame * prologue/epilogue is the entire residual. A decomp-permuter candidate (structural * permutation can flip frame allocation). See docs/matching-cookbook.md §4. */ void func_80016714(s8 *a0, s32 a1) { s32 v1; if (a1 < 4) { a1 = a1 - 1; if (a1 != -1) { do { *a0 = 0; a1 -= 1; a0 += 1; } while (a1 != -1); } } else { v1 = (s32)a0; if (((s32)a0 & 3) != 0) { do { *a0 = 0; a0 += 1; v1 += 1; a1 -= 1; } while ((v1 & 3) != 0); } v1 = (a1 >> 2) - 1; if (v1 != -1) { do { *(s32 *)a0 = 0; v1 -= 1; a0 += 4; } while (v1 != -1); } a1 = (a1 & 3) - 1; if (a1 != -1) { do { *a0 = 0; a1 -= 1; a0 += 1; } while (a1 != -1); } } } #else INCLUDE_ASM("asm/nonmatchings/800", func_80016714); #endif INCLUDE_ASM("asm/nonmatchings/800", func_800167B8); INCLUDE_ASM("asm/nonmatchings/800", func_800167F0); extern u16 D_800AF7CE; void func_800168B4(void) { D_800AF7CE = 0; } INCLUDE_ASM("asm/nonmatchings/800", func_800168C4); INCLUDE_ASM("asm/nonmatchings/800", func_80016940); INCLUDE_ASM("asm/nonmatchings/800", func_80016978); INCLUDE_ASM("asm/nonmatchings/800", func_80016A3C); INCLUDE_ASM("asm/nonmatchings/800", func_80016A5C); INCLUDE_ASM("asm/nonmatchings/800", func_80016A7C); INCLUDE_ASM("asm/nonmatchings/800", func_80016B60); INCLUDE_ASM("asm/nonmatchings/800", func_80016C28); INCLUDE_ASM("asm/nonmatchings/800", func_80016D78); INCLUDE_ASM("asm/nonmatchings/800", func_80016EB0); INCLUDE_ASM("asm/nonmatchings/800", func_80016ED4); INCLUDE_ASM("asm/nonmatchings/800", func_80016EF8); INCLUDE_ASM("asm/nonmatchings/800", func_80016F18); INCLUDE_ASM("asm/nonmatchings/800", func_80017168); INCLUDE_ASM("asm/nonmatchings/800", func_80017254); INCLUDE_ASM("asm/nonmatchings/800", func_80017274); INCLUDE_ASM("asm/nonmatchings/800", func_80017294); INCLUDE_ASM("asm/nonmatchings/800", func_8001739C); INCLUDE_ASM("asm/nonmatchings/800", func_800173BC); INCLUDE_ASM("asm/nonmatchings/800", func_800173DC); INCLUDE_ASM("asm/nonmatchings/800", func_800174DC); INCLUDE_ASM("asm/nonmatchings/800", func_800174FC); INCLUDE_ASM("asm/nonmatchings/800", func_8001751C); INCLUDE_ASM("asm/nonmatchings/800", func_800176F0); INCLUDE_ASM("asm/nonmatchings/800", func_80017714); INCLUDE_ASM("asm/nonmatchings/800", func_80017738); INCLUDE_ASM("asm/nonmatchings/800", func_80017758); INCLUDE_ASM("asm/nonmatchings/800", func_80017778); INCLUDE_ASM("asm/nonmatchings/800", func_800178C8); INCLUDE_ASM("asm/nonmatchings/800", func_800178EC); INCLUDE_ASM("asm/nonmatchings/800", func_80017910); INCLUDE_ASM("asm/nonmatchings/800", func_80017930); INCLUDE_ASM("asm/nonmatchings/800", func_80017B98); INCLUDE_ASM("asm/nonmatchings/800", func_80017D98); INCLUDE_ASM("asm/nonmatchings/800", func_80017DC4); INCLUDE_ASM("asm/nonmatchings/800", func_80017DF8); INCLUDE_ASM("asm/nonmatchings/800", func_80017E30); INCLUDE_ASM("asm/nonmatchings/800", func_80017E68); INCLUDE_ASM("asm/nonmatchings/800", func_80017E8C); INCLUDE_ASM("asm/nonmatchings/800", func_80017F14); INCLUDE_ASM("asm/nonmatchings/800", func_80018094); INCLUDE_ASM("asm/nonmatchings/800", func_80018194); INCLUDE_ASM("asm/nonmatchings/800", func_8001820C); INCLUDE_ASM("asm/nonmatchings/800", func_80018384); INCLUDE_ASM("asm/nonmatchings/800", func_800183E0); INCLUDE_ASM("asm/nonmatchings/800", func_80018450); INCLUDE_ASM("asm/nonmatchings/800", func_800184F0); INCLUDE_ASM("asm/nonmatchings/800", func_80018714); /* LZSS streaming sector decompressor (resumable coroutine state machine). * Decodes up to 0x800 input bytes per call out of an LZSS stream into a 0x400-byte * scratchpad ring (lzss_ringBuffer @ 0x1F800000) and to lzss_outPtr. lzss_state is the * resume point (0=idle/done, 1=fresh, 2=token loop, 3=have code low byte, 4=advance bit). * Returns 1 if the input sector was consumed mid-stream (resume next call), 0 at the * stream terminator (back-ref offset 0) or when idle. */ /* MATCHED — asm-differ score 0, full-binary SHA1 green (Phase 7, session F, 2026-06-15). * Five constructs below are LOAD-BEARING for the byte-for-byte match against gcc 2.7.2 -O2; a * future reader who "cleans them up" WILL break the match. Each is annotated inline and the * compiler-internal root cause is in docs/matching-cookbook.md §10 (+ §5a). All five were * ground-truthed against the pinned gcc-2.7.2 source (reorg.c, jump.c, local-alloc.c). */ extern u8 lzss_curMask; /* 0x800747A0 */ extern u8 lzss_curToken; /* 0x800747A4 */ extern u8 *lzss_outPtr; /* 0x800747AC */ extern u32 lzss_ringIndex; /* 0x800747B0 */ extern u16 lzss_partialCode; /* 0x800747B4 */ extern u32 lzss_state; /* 0x800C7D24 */ s32 LzssDecodeSector(u8 *src) { s32 count = 0x800; u32 ringIdx = lzss_ringIndex; u8 mask = lzss_curMask; u8 token = lzss_curToken; u8 *out = lzss_outPtr; u16 code = lzss_partialCode; u8 *ring = (u8 *)0x1F800000; /* scratchpad ring; original uses the literal (lui 0x1f80), not the symbol */ u32 readIdx; s32 len; u8 b; u8 nb; /* low-byte (state-3) source byte */ u8 cb; u8 nh; /* LOAD-BEARING #1 (residual A): a SEPARATE high-byte source var, NOT a reuse of `nb`. * `nb` is shared between the low- and high-byte paths; reusing it couples their * register allocation, so any high-byte reshaping shoves `nb` out of $v1. A distinct * `nh` decouples them. Cookbook §10/A. */ s32 newState; s32 result; /* return-1 value carried in $v0 from each save predecessor (state-3/state-4) */ /* LOAD-BEARING #2 (residual B3): NO `default:` case and NO statement after the switch. The * switch's own range check (`sltiu $v0,state,5; beqz $v0,`) is the ONLY state>=5 * guard; the `beqz` REUSES the sltiu result ($v0==0 when state>=5) as the return-0 value by * threading straight to `jr ra`. An explicit `if(state>=5)return 0;`, a `default:`, or a * trailing `return 0;` each makes gcc emit a separate `move $v0,$zero` (+1 insn / wrong branch * target). Falling off the end here is deliberate (and matches the original). Cookbook §10/B3. */ switch (lzss_state) { case 0: goto term_ret; case 1: ringIdx = 1; mask = 1; token = *src++; count--; case 2: for (;;) { if (token & mask) { b = *src++; ring[ringIdx] = b; ringIdx = (ringIdx + 1) & 0x3FF; count--; *out++ = b; } else { nb = *src++; count--; code = (code & 0xFF00) | nb; if (count != 0) { goto have_low; } /* LOAD-BEARING #3 (residual B): `result` is set in the state-3 PREDECESSOR (here, * before `goto save`), not inside the shared `save:` tail. This makes gcc emit a * distinct `li $v0,1` per return site instead of cross-jumping/sinking one copy into * the tail's branch delay slot (reorg.c fill_simple_delay_slots). Cookbook §10/B. */ result = 1; newState = 3; goto save; have_low: case 3: nh = *src++; count--; /* LOAD-BEARING #1 (residual A), cont.: operand order `(code & 0xFF) | (nh << 8)`, * NOT `(nh<<8)|(code&0xFF)`. gcc local-alloc.c combine_regs ties a commutative OR's * result to the FIRST RTL operand that dies; writing `code & 0xFF` first ties the * result to $v0 (the target reg) → `or $v0,$v0,$v1`. Cookbook §10/A. */ code = (code & 0xFF) | (nh << 8); readIdx = code & 0x3FF; if (readIdx == 0) { lzss_state = 0; term_ret: return 0; } len = (code >> 10) + 2; while (len != 0) { cb = ring[readIdx]; readIdx = (readIdx + 1) & 0x3FF; ring[ringIdx] = cb; ringIdx = (ringIdx + 1) & 0x3FF; *out++ = cb; len--; } } if (count != 0) { goto next_bit; } result = 1; /* state-4 save predecessor — see LOAD-BEARING #3 */ newState = 4; save: lzss_state = newState; lzss_ringIndex = ringIdx; lzss_curMask = mask; lzss_curToken = token; lzss_outPtr = out; lzss_partialCode = code; return result; next_bit: case 4: if (mask == 0x80) { mask = 1; token = *src++; count--; if (count == 0) { /* state-2 reload save. The original keeps this as a SEPARATE copy of the 6 * stores (not shared with `save:`). Two more load-bearing constructs: */ register s32 r __asm__("$2"); /* LOAD-BEARING #4 (residual B, state-2): an explicit $v0 local pinned early by a * read-only input-asm. This forces `li $v0,1` to materialise BEFORE the stores * (the target schedules the return value first; gcc otherwise, since `li $v0,1`'s * only use is the shared epilogue, defers it to just before `jr ra`). Cookbook §10/B. */ r = 1; __asm__ __volatile__("" : : "r"(r)); newState = 2; lzss_state = newState; lzss_ringIndex = ringIdx; lzss_curMask = mask; lzss_curToken = token; lzss_outPtr = out; lzss_partialCode = code; /* LOAD-BEARING #5 (the cross-jump barrier): a zero-byte volatile asm. gcc 2.7.2 * -O2 jump.c find_cross_jump would otherwise MERGE this save with the identical * `save:` tail (→111 insns); an ASM_INPUT node makes it bail (lose=1) so both * survive (→122, the correct count). No -fno-crossjumping before gcc 3.3. Cookbook §5a. */ __asm__ __volatile__("" ::: "memory"); return r; } } else { mask <<= 1; } } } } INCLUDE_ASM("asm/nonmatchings/800", func_80018918); INCLUDE_ASM("asm/nonmatchings/800", func_800189A8); INCLUDE_ASM("asm/nonmatchings/800", func_80018A20); INCLUDE_ASM("asm/nonmatchings/800", func_80018C64); INCLUDE_ASM("asm/nonmatchings/800", func_80018CE8); INCLUDE_ASM("asm/nonmatchings/800", func_80018E78); INCLUDE_ASM("asm/nonmatchings/800", func_80018E9C); void func_80018F20(s32 param_1) { u32 uVar3; s32 iVar2; u32 uVar1; uVar3 = 2; do { iVar2 = param_1 + uVar3; uVar1 = *(u8 *)(iVar2 + 0x32); if (uVar1 - 0x51 < 0x5f) { *(u8 *)(iVar2 + 0x32) = 0x80; } else if ((uVar1 & 0xff) < 8) { *(u8 *)(iVar2 + 0x32) = 0; } else if ((uVar1 & 0xff) >= 0xf8) { *(u8 *)(iVar2 + 0x32) = 0xff; } uVar3 = uVar3 + 1; } while (uVar3 < 8); } INCLUDE_ASM("asm/nonmatchings/800", func_80018F88); INCLUDE_ASM("asm/nonmatchings/800", func_80018FC8); extern s32 D_800747C8; void func_80019018(void) { D_800747C8 = 0; } INCLUDE_ASM("asm/nonmatchings/800", func_80019028); INCLUDE_ASM("asm/nonmatchings/800", func_8001903C); INCLUDE_ASM("asm/nonmatchings/800", func_80019064); INCLUDE_ASM("asm/nonmatchings/800", func_800190AC); extern s32 D_800747C0; s32 func_80019198(void) { return D_800747C0; } INCLUDE_ASM("asm/nonmatchings/800", func_800191A8); INCLUDE_ASM("asm/nonmatchings/800", func_800191BC); INCLUDE_ASM("asm/nonmatchings/800", func_800191D4); INCLUDE_ASM("asm/nonmatchings/800", func_8001923C); INCLUDE_ASM("asm/nonmatchings/800", func_8001931C); extern s32 debugBinPresent; s32 func_80019378(void) { return debugBinPresent; } extern s32 debugBinPresent; void func_80019388(s32 arg0) { debugBinPresent = arg0; } extern s32 D_800747D4; s32 func_80019398(void) { return D_800747D4; } extern s32 D_800747D4; void func_800193A8(s32 arg0) { D_800747D4 = arg0; } INCLUDE_ASM("asm/nonmatchings/800", func_800193B8); #ifdef NON_MATCHING extern void LoaderResetReadState(void); extern int VSync(int mode); extern CdlFILE D_80063058; extern char cdpath_DEBUG_BIN[]; extern u8 D_80062C38; /* path table entry[0].file (CdlFILE), entries stride 0x30; names at -0x14 */ extern u8 D_80062C68; /* path entry[1].file.pos (CdlLOC), the 8 .CD files, stride 0x30 */ extern s32 debugBinPresent; extern s32 D_800747D4; extern s32 D_80063074; extern s32 D_800747D8; extern u8 cdFileLocTable[]; /* out: {CdlLOC pos; u32 size} per sub-file, 8B stride */ extern u8 D_800AE834; /* cdFileLocTable + 4 (the size field) */ extern s32 listCdBuffer; /* LIST.CD content: 8B records {value; size} */ extern u8 D_80180004; /* listCdBuffer + 4 (the size field) */ /* file-loader directory resolver (boot @0x800101fc): probe \DEBUG.BIN;1, resolve the 21 * CdPathTable entries via CdSearchFile, read LIST.CD (0xE40 B) into listCdBuffer, then build * cdFileLocTable (CdlLOC+size per sub-file) over the 8 .CD files. Phase 3 T2. * NON_MATCHING: logically faithful, structurally close (138 vs 133 ins) but not byte-exact. * Residual is register allocation / loop-invariant hoisting — the target keeps &D_80063058, * &D_80062C38, &D_80062C68 in callee-saved regs and derives the name arg as (base - 0x14) * rather than a separate symbol; a multi-iteration / decomp-permuter target for a later pass. */ void LoaderInitFileTable(void) { CdlFILE *res; int tries; int pathOff; int pathN; int base; int n; int fileIdx; int bufIdx; int j; int outer; int locOff; int dstOff; int srcOff; int *pCount; int *pOff; CdlLOC *p; LoaderResetReadState(); tries = 0; do { res = CdSearchFile(&D_80063058, cdpath_DEBUG_BIN); tries++; if (res != (CdlFILE *)-1) { break; } } while (tries < 0x10); pathN = 0; pathOff = 0; debugBinPresent = (res != (CdlFILE *)0); D_800747D4 = 1; D_80063074 = 0; D_800747D8 = 0; do { do { res = CdSearchFile((CdlFILE *)(&D_80062C38 + pathOff), (char *)(&D_80062C38 - 0x14 + pathOff)); } while ((u32)((int)res + 1) < 2); pathN++; pathOff += 0x30; } while (pathN < 0x15); do { fileIdx = 0; n = CdReadRequest(&D_80062C38, &listCdBuffer, 0xE40, 0); if (n != 0) { break; } VSync(0); } while (1); bufIdx = 0; outer = 0; locOff = 0; pCount = &listCdBuffer; do { base = CdPosToInt((CdlLOC *)(&D_80062C68 + locOff)); n = *pCount; pCount += 2; bufIdx++; j = 0; if (n > 0) { dstOff = fileIdx * 8; p = (CdlLOC *)(cdFileLocTable + dstOff); srcOff = bufIdx * 8; pOff = &listCdBuffer + bufIdx * 2; do { if (*pOff != 0) { CdIntToPos(*pOff + base, p); *(s32 *)(&D_800AE834 + dstOff) = *(s32 *)(&D_80180004 + srcOff); } pOff += 2; srcOff += 8; pCount += 2; bufIdx++; p += 2; dstOff += 8; j++; fileIdx++; } while (j < n); } outer++; locOff += 0x30; } while (outer < 8); } #else INCLUDE_ASM("asm/nonmatchings/800", LoaderInitFileTable); #endif INCLUDE_ASM("asm/nonmatchings/800", func_80019930); extern s32 cdReq_sink; extern s32 cdReq_curSector; extern s32 D_800BA1B4; extern s32 D_800747F0; extern s32 D_800747F4; extern s32 cdReq_state; extern s32 D_800AE6F8; extern s32 D_800AE6FC; extern s32 D_800AE700; extern s32 cdReq_wordsRemaining; extern s32 cdReq_drainPhase; extern u8 D_800AE798; extern u8 D_800AE799; extern s32 D_800AE70C; void LoaderResetReadState(void) { cdReq_sink = 0x80010000; cdReq_curSector = 0; D_800BA1B4 = 0; D_800747F0 = 0; D_800747F4 = 0; cdReq_state = 0; D_800AE6F8 = 0; D_800AE6FC = 0; D_800AE700 = 0; cdReq_wordsRemaining = 1; cdReq_drainPhase = 0; D_800AE798 = 0; D_800AE799 = 0; D_800AE70C = 0; } INCLUDE_ASM("asm/nonmatchings/800", func_80019A10); extern s32 CdQueueBusy(void); extern void CdReadStateMachine(int); extern s32 cdReq_curSector; extern void *cdReq_dest; extern s32 cdReq_size; extern void *cdReq_cdlFile; extern s32 cdReq_result; extern s32 D_800AE720; extern s32 D_800AE724; /* Read-request dispatcher (Phase 3 T2). Refuse while CdQueueBusy(); dedup on the request's * start sector (*cdlFile) vs the in-flight cdReq_curSector; stash dest/size/cdlFile/mode into * the control block, set the "first read" flag D_800AE720 = (mode == 0), drive the state * machine, return cdReq_result. */ s32 CdReadRequest(int *cdlFile, void *dest, s32 size, s32 mode) { s32 sector; if (CdQueueBusy() != 0) { return 0; } if (cdReq_curSector == 0) { sector = *cdlFile; } else { sector = *cdlFile; if (sector != cdReq_curSector) { return 0; } } cdReq_dest = dest; cdReq_size = size; cdReq_cdlFile = cdlFile; D_800AE724 = mode; D_800AE720 = 0; cdReq_curSector = sector; if (mode == 0) { D_800AE720 = 1; } CdReadStateMachine(0); return cdReq_result; } #ifdef NON_MATCHING /* libcd low-level command API (the loader uses raw CdControl, NOT the PsyQ CdRead() wrapper; * not in psyq/libcd.h yet). */ extern int CdControl(u8 com, u8 *param, u8 *result); extern int CdSync(int mode, u8 *result); extern void CdFlush(void); extern void *CdReadyCallback(void *func); extern void CdReadSectorReadyCB(char); /* the CdlReadN data-ready callback @0x8001A338 */ extern void start(void); /* EXE entry — used as the idle "sink" sentinel */ extern int func_8002FD14(int buf, int len); /* per-sector consumer (drains the queued list) */ extern void func_8001A0FC(void); extern int func_8001A114(void); /* cdReq_* async-read control block (Phase 3 T2); the D_800AE* are its unnamed members. */ extern int cdReq_state; extern int cdReq_retry; extern int cdReq_result; /* return-by-global: 0 = still busy, 1 = done */ extern u8 cdReq_cdResult; /* CdControl status byte (bit 0x10 = error) */ extern void *cdReq_cdlFile; /* seek target (a CdlLOC*) */ extern int cdReq_posInt; extern int cdReq_timeout; extern int cdReq_size; /* bytes to read */ extern void *cdReq_dest; /* read destination */ extern s32 cdReq_sink; /* sector sink address (dest while reading, &start idle) */ extern int cdReq_wordsRemaining; extern int cdReq_drainPhase; /* 0 = reading, 1 = drained, 2 = finished */ extern void *cdReq_savedReadyCB; /* prior CdReadyCallback, restored on stop */ extern int cdReq_curSector; extern u8 D_800AE740; /* CdlSetmode mode-byte buffer (0xA0) */ extern int D_800AE6E8; /* CdSync result scratch */ extern int D_800AE6F8; extern s32 D_800AE70C; /* last/idle CdlLOC (held as a word) */ extern int D_800AE71C; /* count of queued sectors to drain (state 7) */ extern int D_800AE724; /* base of the queued {ptr,len} sector list */ extern int D_800AE6FC; extern int D_800AE700; extern u8 D_800AE798; extern u8 D_800AE799; /* Hand-rolled polled async CD reader: one state step per call, switch(cdReq_state). Sequence * SetMode(0xA0) -> SeekL(+CdPosToInt) -> ReadN(+CdReadSectorReadyCB sector drain) -> Pause/Flush. * Progress is returned via cdReq_result (0 busy / 1 done). The game does NOT use PsyQ CdRead()/ * CdReadSync(). pauseAfterSeek != 0 stops after the seek (state 8) instead of reading. * Provenance: static trace, Phase 3 T2 (verified). * NON_MATCHING: logically faithful to the Ghidra decompile; not byte-exact — a large switch state * machine whose register allocation + jump-table placement are a later byte-match pass. */ void CdReadStateMachine(int pauseAfterSeek) { int n; int i; int off; switch (cdReq_state) { case 0: cdReq_retry = 0; D_800AE71C = 0; D_800AE70C = 0; D_800AE740 = 0xA0; CdControl(0x0E, &D_800AE740, &cdReq_cdResult); /* CdlSetmode */ if ((cdReq_cdResult & 0x10) == 0) { cdReq_state++; goto state1; } break; case 1: state1: D_800AE6E8 = CdSync(1, &cdReq_cdResult); if (D_800AE6E8 == 0) { cdReq_result = 0; return; } if (D_800AE6E8 == 5) { cdReq_state = 0; cdReq_result = 0; return; } if (D_800AE6E8 != 2) { cdReq_result = 0; return; } cdReq_retry = 0; cdReq_state++; D_800AE6E8 = 2; state2: if (cdReq_retry + 1 < 3) { cdReq_retry++; cdReq_result = 0; return; } cdReq_state++; cdReq_retry = 0; cdReq_result = 0; return; case 2: goto state2; case 3: CdControl(0x15, (u8 *)cdReq_cdlFile, &cdReq_cdResult); /* CdlSeekL */ if ((cdReq_cdResult & 0x10) == 0) { cdReq_timeout = 0; cdReq_posInt = CdPosToInt((CdlLOC *)cdReq_cdlFile); cdReq_state++; goto state4; } break; case 4: state4: D_800AE6E8 = CdSync(1, &cdReq_cdResult); if (D_800AE6E8 == 5) { cdReq_retry++; flushRetry: CdFlush(); cdReq_state = 3; cdReq_result = 0; return; } if (D_800AE6E8 == 0) { cdReq_result = 0; return; } if (D_800AE6E8 != 2) { cdReq_result = 0; cdReq_timeout++; if (cdReq_timeout < 0xB5) { cdReq_result = 0; return; } goto flushRetry; } if (pauseAfterSeek == 0) { cdReq_state++; goto state5; } CdControl(0x09, (u8 *)0, &cdReq_cdResult); /* CdlPause */ if ((cdReq_cdResult & 0x10) == 0) { cdReq_state = 8; D_800AE70C = *(s32 *)cdReq_cdlFile; cdReq_result = 0; return; } break; case 5: state5: cdReq_drainPhase = 0; if (cdReq_size < 1) { D_800AE6F8 = 0; } else { int bytes = cdReq_size + 3; D_800AE6F8 = 3; if (bytes < 0) bytes = cdReq_size + 6; /* round-up word count, neg-safe */ cdReq_wordsRemaining = bytes >> 2; D_800AE798 = 1; cdReq_sink = (s32)cdReq_dest; } cdReq_savedReadyCB = CdReadyCallback(CdReadSectorReadyCB); CdControl(0x06, (u8 *)0, &cdReq_cdResult); /* CdlReadN */ if ((cdReq_cdResult & 0x10) == 0) { cdReq_retry = 0; cdReq_state++; goto state6; } break; case 6: state6: if (cdReq_drainPhase != 1) { if (cdReq_drainPhase == 2) { CdReadyCallback(cdReq_savedReadyCB); cdReq_state = 0; cdReq_result = 0; return; } cdReq_retry++; if (cdReq_retry > 299) { CdReadyCallback(cdReq_savedReadyCB); cdReq_state = 0; CdFlush(); cdReq_result = 0; return; } cdReq_result = 0; return; } CdReadyCallback(cdReq_savedReadyCB); CdControl(0x09, (u8 *)0, &cdReq_cdResult); /* CdlPause */ if ((cdReq_cdResult & 0x10) == 0) { cdReq_state += (D_800AE71C == 0) ? 2 : 1; /* -> 8 (no drain) or 7 (drain) */ cdReq_result = 0; return; } break; case 7: n = 0; if (D_800AE71C > 0) { off = 0; do { do { i = func_8002FD14(*(int *)(D_800AE724 + off), *(int *)(D_800AE724 + off + 4)); } while (i == 0); n++; off = n * 8; } while (n < D_800AE71C); } cdReq_state++; cdReq_result = 0; return; case 8: D_800AE6E8 = CdSync(1, &cdReq_cdResult); if (D_800AE6E8 == 2) { cdReq_sink = (s32)start; cdReq_state = 0; D_800AE6F8 = 0; D_800AE6FC = 0; D_800AE700 = 0; cdReq_curSector = 0; D_800AE70C = 0; cdReq_wordsRemaining = 1; cdReq_drainPhase = 0; D_800AE798 = 0; D_800AE799 = 0; cdReq_result = 1; return; } if (D_800AE6E8 != 5) { cdReq_result = 0; return; } CdFlush(); CdControl(0x09, (u8 *)0, &cdReq_cdResult); /* CdlPause */ if ((cdReq_cdResult & 0x10) == 0) { cdReq_result = 0; return; } break; case 9: func_8001A0FC(); cdReq_state++; /* fall through to state 10 */ case 10: D_800AE6E8 = func_8001A114(); if (D_800AE6E8 != 0) { cdReq_state = 0; cdReq_result = 0; return; } cdReq_result = 0; return; default: goto setDefault; } cdReq_state = 9; setDefault: cdReq_result = 0; return; } #else INCLUDE_ASM("asm/nonmatchings/800", CdReadStateMachine); #endif INCLUDE_ASM("asm/nonmatchings/800", func_8001A0FC); INCLUDE_ASM("asm/nonmatchings/800", func_8001A114); #ifdef NON_MATCHING typedef struct { short x, y, w, h; } RECT; /* libgpu RECT (VRAM rectangle) */ extern int CdGetSector(void *madr, int nsector); extern void LoadImage(RECT *rect, u32 *data); /* libgpu VRAM upload */ extern int func_8002FC64(int nbytes, u32 *src); /* stage/copy a payload run */ extern int func_8002FB08(int entry); /* kick off a queued list entry */ extern void func_8002FDC8(void); /* finalize the queued transfer */ extern void func_80018714(void); /* reset LZSS sector state */ /* shared cdReq_ control block (see CdReadStateMachine) + this callback's members */ extern int cdReq_posInt; extern int cdReq_size; extern int cdReq_wordsRemaining; extern int cdReq_drainPhase; extern void *cdReq_dest; extern s32 cdReq_sink; extern u32 lzss_sectorStagingBuf[]; /* 0x80079A70 — PAC header lands here ([0] = 'PAC' magic) */ extern u8 cdReq_sectorHdrBuf[]; /* sub-header scratch (3 words -> CdPosToInt) */ extern u8 D_80079A74; /* PAC type */ extern u8 D_80079A75; /* PAC flags -> D_800AE798 */ extern int D_80079A78; /* PAC sub-count (textures) */ extern int D_80079A7C; /* PAC payload size (bytes) */ extern int D_800AE6F8; /* load phase (PAC-type dispatcher state) */ extern u8 D_800AE798; /* saved PAC flags (nonzero = more sectors follow) */ extern int D_800AE704; /* texture sector index (0..3, round-robin) */ extern short D_800AE710, D_800AE712; /* VRAM dst x,y of the current tile (a RECT @0xAE710) */ extern short D_800AE714, D_800AE716; /* tile w,h (0x20 x 0x20) */ extern u8 D_800AE758[]; /* 64-byte present bitmask (which tiles are sent) */ extern u8 D_800AE79A, D_800AE79B; /* bit / byte cursor into the bitmask */ extern RECT *D_800AE718; /* current texture-rect pointer (PAC type 6) */ extern int D_800AE71C; /* queued-entry count */ extern int D_800AE720; /* "transfer already in progress" guard */ extern int D_800AE724; /* base of the queued {ptr,len} list */ extern void *D_80072C80; /* a fixed destination pointer (PAC type 7) */ extern u32 D_8007A280[]; /* texture RECT array (read from CD) */ extern u32 D_8007A310[]; /* texture pixel data (read from CD) */ /* CdReadyCallback for CdReadStateMachine (registered in its state 5). Per CD data-ready interrupt, * drain one sector and dispatch on the load phase D_800AE6F8: parse the PAC header, then per PAC * type either upload tiles to VRAM (LoadImage), copy raw sectors to cdReq_sink, or decompress via * LzssDecodeSector (this is its ONLY caller). reason: 1 = data-ready, 5 = end/error. * Provenance: static trace, Phase 3 T2/T4 (verified). * NON_MATCHING: faithful translation of the Ghidra decompile — logically faithful, not byte-verified * (large interrupt callback; register allocation + jump-table placement are a later byte-match pass). */ void CdReadSectorReadyCB(char reason) { void *dst; int pos; int i, n; if (reason != 1) goto endReason; CdGetSector(cdReq_sectorHdrBuf, 3); pos = CdPosToInt((CdlLOC *)cdReq_sectorHdrBuf); if (pos != cdReq_posInt) { /* sector out of order -> abort the drain */ if (D_800AE6F8 == 4) func_8002FDC8(); cdReq_drainPhase = 2; return; } cdReq_posInt = pos + 1; switch (D_800AE6F8) { case 0: /* expect a PAC header */ CdGetSector(lzss_sectorStagingBuf, 4); if (lzss_sectorStagingBuf[0] != 0x434150) goto abortDrain; /* "PAC" magic? */ D_800AE798 = D_80079A75; switch (D_80079A74) { /* PAC type */ case 0: case 5: /* tiled texture: scan the present-bitmask */ D_800AE704 = 0; CdGetSector(D_800AE758, 0x10); D_800AE716 = 0x20; D_800AE714 = 0x20; D_800AE712 = 0; D_800AE710 = 0; D_800AE79A = 1; D_800AE79B = 0; while (D_800AE79B < 0x40) { if ((D_800AE79A & D_800AE758[D_800AE79B]) != 0) goto tilePhase; if (D_800AE79A == 0x80) { D_800AE79A = 1; D_800AE79B++; } else D_800AE79A <<= 1; D_800AE710 += 0x20; if (D_800AE710 > 0x3FF) { D_800AE710 = 0; D_800AE712 += 0x20; } } D_800AE6F8 = (D_800AE798 == 0) ? 0 : 2; tilePhase: D_800AE6F8++; break; case 1: dst = cdReq_dest; goto setSink; case 2: if (D_800AE720 != 0) goto phaseDone; dst = *(void **)(D_800AE71C * 8 + D_800AE724 + 4); goto setSink; case 3: if (D_800AE720 != 0) goto phaseDone; do { i = func_8002FB08(*(int *)(D_800AE71C * 8 + D_800AE724)); } while (i == 0); D_800AE6F8 = 4; cdReq_wordsRemaining = D_80079A7C - 0x800; break; case 4: D_800AE6F8 = 5; cdReq_wordsRemaining = (D_80079A7C - 0x7FD) >> 2; cdReq_sink = (s32)cdReq_dest; func_80018714(); break; case 6: /* multiple TIMs: LoadImage each */ CdGetSector(D_8007A280, 0x1FC); n = D_80079A78; { u32 *p = D_8007A310; i = 0; D_800AE718 = (RECT *)D_8007A280; if (n > 0) { do { LoadImage(D_800AE718, p); i++; p += D_800AE718->w / 2; D_800AE718++; } while (i < n); } } goto sectorDone; case 7: dst = D_80072C80; if (cdReq_size < 0) goto phaseDone; setSink: D_800AE6F8 = 3; cdReq_wordsRemaining = (D_80079A7C - 0x7FD) >> 2; cdReq_sink = dst; break; case 8: D_800AE6F8 = 6; cdReq_wordsRemaining = (D_80079A7C - 0x7FD) >> 2; break; } break; case 1: /* stream tile pixels to VRAM */ i = D_800AE704 * 0x200; CdGetSector(&lzss_sectorStagingBuf[i], 0x200); LoadImage((RECT *)&D_800AE710, &lzss_sectorStagingBuf[i]); D_800AE704 = (D_800AE704 + 1) & 3; do { if (D_800AE79A == 0x80) { D_800AE79A = 1; D_800AE79B++; } else D_800AE79A <<= 1; if (D_800AE79B > 0x3F) goto sectorDone; D_800AE710 += 0x20; if (D_800AE710 > 0x3FF) { D_800AE710 = 0; D_800AE712 += 0x20; } } while ((D_800AE79A & D_800AE758[D_800AE79B]) == 0); break; case 3: /* raw copy to cdReq_sink */ if (cdReq_wordsRemaining < 0x201) { CdGetSector((void *)cdReq_sink, cdReq_wordsRemaining); sectorDone: D_800AE6F8 = (D_800AE798 == 0) ? 0 : 2; } else { CdGetSector((void *)cdReq_sink, 0x200); cdReq_wordsRemaining -= 0x200; cdReq_sink += 0x800; } break; case 4: /* staged copy via func_8002FC64 */ if (cdReq_wordsRemaining < 0x801) { n = cdReq_wordsRemaining + 3; if (n < 0) n = cdReq_wordsRemaining + 6; CdGetSector(lzss_sectorStagingBuf, n >> 2); if (func_8002FC64(cdReq_wordsRemaining, lzss_sectorStagingBuf) == 0) { stageFail: func_8002FDC8(); D_800AE6F8 = 7; } else { D_800AE71C++; if (D_800AE798 != 0) goto phaseDone; D_800AE6F8 = 0; } } else { CdGetSector(lzss_sectorStagingBuf, 0x200); i = func_8002FC64(0x800, lzss_sectorStagingBuf); cdReq_sink += 0x800; cdReq_wordsRemaining -= 0x800; if (i == 0) goto stageFail; } break; case 5: /* LZSS decompress one sector */ CdGetSector(lzss_sectorStagingBuf, 0x200); if (LzssDecodeSector(lzss_sectorStagingBuf) == 0) goto sectorDone; break; case 6: /* countdown the remaining words */ cdReq_wordsRemaining -= 0x200; if (cdReq_wordsRemaining < 1) { if (D_800AE798 != 0) goto phaseDone; D_800AE6F8 = 0; } break; } if (D_800AE6F8 == 2) { phaseDone: /* (reached by the switch above or by goto) */ D_800AE6F8 = 2; cdReq_drainPhase = 1; } else if (D_800AE6F8 == 7) { cdReq_drainPhase = 2; } endReason: if (reason == 5) { if (D_800AE6F8 == 4) func_8002FDC8(); abortDrain: cdReq_drainPhase = 2; } return; } #else INCLUDE_ASM("asm/nonmatchings/800", CdReadSectorReadyCB); #endif INCLUDE_ASM("asm/nonmatchings/800", func_8001A9D8); INCLUDE_ASM("asm/nonmatchings/800", func_8001A9F8); extern s32 cdReq_curSector; s32 func_8001AA78(void) { return cdReq_curSector; } extern s32 cdReq_curSector; void func_8001AA88(s32 arg0) { cdReq_curSector = arg0; } void func_8001AA98(void) { } INCLUDE_ASM("asm/nonmatchings/800", func_8001AAA0); INCLUDE_ASM("asm/nonmatchings/800", func_8001AAD0); void func_8001ABB4(void) { } INCLUDE_ASM("asm/nonmatchings/800", func_8001ABBC); INCLUDE_ASM("asm/nonmatchings/800", func_8001ACF0); INCLUDE_ASM("asm/nonmatchings/800", func_8001AE90); INCLUDE_ASM("asm/nonmatchings/800", func_8001AF04); INCLUDE_ASM("asm/nonmatchings/800", func_8001AF34); INCLUDE_ASM("asm/nonmatchings/800", func_8001B0D4); extern s32 D_800747E8; s32 func_8001B22C(void) { return D_800747E8; } INCLUDE_ASM("asm/nonmatchings/800", func_8001B23C); INCLUDE_ASM("asm/nonmatchings/800", func_8001B26C); INCLUDE_ASM("asm/nonmatchings/800", func_8001B324); INCLUDE_ASM("asm/nonmatchings/800", func_8001B34C); extern s32 resLoad_lastId; s32 func_8001B374(void) { return resLoad_lastId; } extern s32 resLoad_state; void func_8001B384(void) { resLoad_state = 0; } INCLUDE_ASM("asm/nonmatchings/800", func_8001B394); #ifdef NON_MATCHING extern int func_8001A114(void); extern void func_8001B710(void); extern void func_8002D4C8(int arg0, int arg1); extern void func_80036D58(int arg0); extern int StreamLoadStateMachine(int arg0, void *loc, int n); extern s32 CdQueueBusy(void); /* defined later in this file */ extern s32 ResourceGetCdLoc(s16 arg0); /* defined later in this file */ extern s32 resLoad_state; extern s32 resLoad_curId; extern s32 resLoad_lastId; extern s32 resLoad_loadedFileIdx; extern s32 resLoad_result; extern s32 cdReq_curSector; extern u8 resourceIdMap[]; /* 6B entries {s16 fileIdx; s16 D_8006313A; s16 D_8006313C} */ extern u8 D_8006313A; extern u8 D_8006313C; extern u8 cdFileLocTable[]; extern s32 D_800AE6F4; extern s32 D_800AE70C; /* loads a resource by resLoad_curId via resourceIdMap; load-once cache * (resLoad_lastId/resLoad_loadedFileIdx). field0<0 -> non-CD path func_80036D58; else * ResourceGetCdLoc -> StreamLoadStateMachine -> func_8002D4C8 post-process. Polled on * resLoad_state; done flag resLoad_result. Phase 3 T3. * NON_MATCHING: logically faithful (Ghidra-derived), body close but not byte-exact. Residuals: * (1) block placement — the target lays state blocks 0->1->2->3 in order under a top beq-chain * dispatch (order 1,0,2,3); this nested-if emits the state-2/3 block inline. (2) frame 0x38 vs * 0x28 (~16B reserved locals the original keeps). (3) func_8002D4C8 arg is field2 & 0xFFFF. * A switch() risks a rodata jump table (target has none). A later structural / permuter pass. */ void ResourceLoadStateMachine(void) { int result; result = 0; if (resLoad_state != 1) { if (resLoad_state != 0) { if (resLoad_state == 2) { D_800AE6F4 = 0; D_800AE70C = 0; resLoad_state = 3; } else if (resLoad_state != 3) { goto done; } if (func_8001A114() != 0) { resLoad_state = 0; } goto done; } if (resLoad_curId == resLoad_lastId) { resLoad_result = 1; return; } if (*(s16 *)(resourceIdMap + resLoad_curId * 6) == resLoad_loadedFileIdx && *(s16 *)(&D_8006313C + resLoad_curId * 6) != 0) { func_8002D4C8(*(s16 *)(&D_8006313C + resLoad_curId * 6), 0); resLoad_lastId = resLoad_curId; resLoad_result = 1; return; } if (CdQueueBusy() != 0) { goto done; } if (*(s16 *)(resourceIdMap + resLoad_curId * 6) < 0) { func_80036D58(*(s16 *)(&D_8006313A + resLoad_curId * 6)); resLoad_result = 1; return; } if (ResourceGetCdLoc((s16)resLoad_curId) == 0) { resLoad_result = 1; return; } if (cdReq_curSector != 0 && *(s32 *)(cdFileLocTable + *(s16 *)(resourceIdMap + resLoad_curId * 6) * 8) != cdReq_curSector) { goto done; } cdReq_curSector = *(s32 *)(cdFileLocTable + *(s16 *)(resourceIdMap + resLoad_curId * 6) * 8); resLoad_state++; } result = StreamLoadStateMachine(*(s16 *)(&D_8006313A + resLoad_curId * 6), cdFileLocTable + *(s16 *)(resourceIdMap + resLoad_curId * 6) * 8, 0x10); if (result == 2) { resLoad_state++; result = 0; } done: if (result != 0) { resLoad_loadedFileIdx = *(s16 *)(resourceIdMap + resLoad_curId * 6); if (*(s16 *)(&D_8006313C + resLoad_curId * 6) > 0) { func_8002D4C8(*(s16 *)(&D_8006313C + resLoad_curId * 6), 0); resLoad_lastId = resLoad_curId; if (resLoad_curId == 0x3D) { func_8001B710(); } } resLoad_state = 0; cdReq_curSector = 0; } resLoad_result = result; } #else INCLUDE_ASM("asm/nonmatchings/800", ResourceLoadStateMachine); #endif INCLUDE_ASM("asm/nonmatchings/800", func_8001B710); extern u8 resourceIdMap[]; extern u8 cdFileLocTable[]; s32 ResourceGetCdLoc(s16 arg0) { s32 idx = *(s16 *)(resourceIdMap + arg0 * 6); return *(s32 *)(cdFileLocTable + idx * 8); } INCLUDE_ASM("asm/nonmatchings/800", func_8001B7C4); extern s32 D_800747FC; void func_8001B85C(void) { D_800747FC = 0; } INCLUDE_ASM("asm/nonmatchings/800", func_8001B86C); INCLUDE_ASM("asm/nonmatchings/800", func_8001BA84); INCLUDE_ASM("asm/nonmatchings/800", func_8001BADC); INCLUDE_ASM("asm/nonmatchings/800", func_8001BB60); INCLUDE_ASM("asm/nonmatchings/800", func_8001BBBC); INCLUDE_ASM("asm/nonmatchings/800", func_8001BC6C); INCLUDE_ASM("asm/nonmatchings/800", SsGetMute); INCLUDE_ASM("asm/nonmatchings/800", func_8001BDA0); extern s32 D_800747EC; void func_8001BE20(void) { D_800747EC = 0; } INCLUDE_ASM("asm/nonmatchings/800", func_8001BE30); extern s32 D_80063074; s32 func_8001BFA0(void) { return D_80063074 & 0x1; } INCLUDE_ASM("asm/nonmatchings/800", func_8001BFB0); INCLUDE_ASM("asm/nonmatchings/800", func_8001BFD0); extern s32 D_800747D8; s32 func_8001BFE8(void) { return D_800747D8; } INCLUDE_ASM("asm/nonmatchings/800", func_8001BFF8); INCLUDE_ASM("asm/nonmatchings/800", func_8001C00C); INCLUDE_ASM("asm/nonmatchings/800", func_8001C044); INCLUDE_ASM("asm/nonmatchings/800", func_8001C0C8); INCLUDE_ASM("asm/nonmatchings/800", func_8001C14C); INCLUDE_ASM("asm/nonmatchings/800", func_8001C1E4); INCLUDE_ASM("asm/nonmatchings/800", func_8001C214); INCLUDE_ASM("asm/nonmatchings/800", func_8001C2C4); INCLUDE_ASM("asm/nonmatchings/800", func_8001C320); INCLUDE_ASM("asm/nonmatchings/800", func_8001C448); INCLUDE_ASM("asm/nonmatchings/800", func_8001C4A4); INCLUDE_ASM("asm/nonmatchings/800", func_8001C558); INCLUDE_ASM("asm/nonmatchings/800", func_8001C5B8); INCLUDE_ASM("asm/nonmatchings/800", func_8001C6E4); INCLUDE_ASM("asm/nonmatchings/800", func_8001C744); INCLUDE_ASM("asm/nonmatchings/800", func_8001C7B0); INCLUDE_ASM("asm/nonmatchings/800", func_8001C810); INCLUDE_ASM("asm/nonmatchings/800", func_8001C8C4); INCLUDE_ASM("asm/nonmatchings/800", func_8001C924); INCLUDE_ASM("asm/nonmatchings/800", func_8001C97C); INCLUDE_ASM("asm/nonmatchings/800", func_8001C9D0); INCLUDE_ASM("asm/nonmatchings/800", func_8001CA1C); INCLUDE_ASM("asm/nonmatchings/800", func_8001CA88); INCLUDE_ASM("asm/nonmatchings/800", func_8001CB00); INCLUDE_ASM("asm/nonmatchings/800", func_8001CB6C); INCLUDE_ASM("asm/nonmatchings/800", func_8001CBDC); INCLUDE_ASM("asm/nonmatchings/800", func_8001CC3C); INCLUDE_ASM("asm/nonmatchings/800", func_8001CCA0); INCLUDE_ASM("asm/nonmatchings/800", func_8001CD04); INCLUDE_ASM("asm/nonmatchings/800", func_8001CD50); INCLUDE_ASM("asm/nonmatchings/800", func_8001CD9C); INCLUDE_ASM("asm/nonmatchings/800", func_8001CDE8); INCLUDE_ASM("asm/nonmatchings/800", func_8001CE28); INCLUDE_ASM("asm/nonmatchings/800", func_8001CE68); INCLUDE_ASM("asm/nonmatchings/800", func_8001CEC0); INCLUDE_ASM("asm/nonmatchings/800", func_8001CF00); INCLUDE_ASM("asm/nonmatchings/800", func_8001CF30); INCLUDE_ASM("asm/nonmatchings/800", func_8001CF48); INCLUDE_ASM("asm/nonmatchings/800", func_8001CFB8); INCLUDE_ASM("asm/nonmatchings/800", func_8001CFDC); INCLUDE_ASM("asm/nonmatchings/800", func_8001D050); INCLUDE_ASM("asm/nonmatchings/800", func_8001D074); void func_8001D0E8(s32 arg0, s32 arg1, s32 arg2) { *(s16 *)(arg0 + 0x28) = arg1; *(s16 *)(arg0 + 0x2A) = arg2; } INCLUDE_ASM("asm/nonmatchings/800", func_8001D0F4); INCLUDE_ASM("asm/nonmatchings/800", func_8001D130); INCLUDE_ASM("asm/nonmatchings/800", func_8001D150); INCLUDE_ASM("asm/nonmatchings/800", func_8001D16C); INCLUDE_ASM("asm/nonmatchings/800", func_8001D1C4); INCLUDE_ASM("asm/nonmatchings/800", func_8001D388); INCLUDE_ASM("asm/nonmatchings/800", func_8001D3FC); INCLUDE_ASM("asm/nonmatchings/800", func_8001D70C); INCLUDE_ASM("asm/nonmatchings/800", func_8001D8C4); INCLUDE_ASM("asm/nonmatchings/800", func_8001DA34); INCLUDE_ASM("asm/nonmatchings/800", func_8001E094); INCLUDE_ASM("asm/nonmatchings/800", func_8001E378); INCLUDE_ASM("asm/nonmatchings/800", func_8001E668); INCLUDE_ASM("asm/nonmatchings/800", func_8001E7E0); INCLUDE_ASM("asm/nonmatchings/800", func_8001EA14); INCLUDE_ASM("asm/nonmatchings/800", func_8001EFE0); INCLUDE_ASM("asm/nonmatchings/800", func_8001F730); void func_8001F974(void) { } INCLUDE_ASM("asm/nonmatchings/800", func_8001F97C); INCLUDE_ASM("asm/nonmatchings/800", func_8001F9F8); INCLUDE_ASM("asm/nonmatchings/800", func_8001FB8C); INCLUDE_ASM("asm/nonmatchings/800", func_8001FC08); INCLUDE_ASM("asm/nonmatchings/800", func_80020248); INCLUDE_ASM("asm/nonmatchings/800", func_80020598); INCLUDE_ASM("asm/nonmatchings/800", func_80020A28); INCLUDE_ASM("asm/nonmatchings/800", func_80020DA4); INCLUDE_ASM("asm/nonmatchings/800", func_80020F34); INCLUDE_ASM("asm/nonmatchings/800", func_80021008); INCLUDE_ASM("asm/nonmatchings/800", func_80021050); INCLUDE_ASM("asm/nonmatchings/800", func_8002109C); INCLUDE_ASM("asm/nonmatchings/800", func_80021120); INCLUDE_ASM("asm/nonmatchings/800", func_80021174); INCLUDE_ASM("asm/nonmatchings/800", func_80021284); INCLUDE_ASM("asm/nonmatchings/800", func_800215F4); INCLUDE_ASM("asm/nonmatchings/800", func_80021D38); INCLUDE_ASM("asm/nonmatchings/800", func_800221A8); INCLUDE_ASM("asm/nonmatchings/800", func_800226C0); INCLUDE_ASM("asm/nonmatchings/800", func_80023138); INCLUDE_ASM("asm/nonmatchings/800", func_800233CC); INCLUDE_ASM("asm/nonmatchings/800", func_800234E4); INCLUDE_ASM("asm/nonmatchings/800", func_80023570); INCLUDE_ASM("asm/nonmatchings/800", func_8002374C); INCLUDE_ASM("asm/nonmatchings/800", func_80023BF0); INCLUDE_ASM("asm/nonmatchings/800", func_80024054); INCLUDE_ASM("asm/nonmatchings/800", func_800241C0); INCLUDE_ASM("asm/nonmatchings/800", func_800242D0); INCLUDE_ASM("asm/nonmatchings/800", func_800243EC); INCLUDE_ASM("asm/nonmatchings/800", func_80024448); INCLUDE_ASM("asm/nonmatchings/800", func_800249F0); INCLUDE_ASM("asm/nonmatchings/800", func_80024BC0); INCLUDE_ASM("asm/nonmatchings/800", func_80024DE8); INCLUDE_ASM("asm/nonmatchings/800", func_80025000); INCLUDE_ASM("asm/nonmatchings/800", func_8002528C); INCLUDE_ASM("asm/nonmatchings/800", func_80025504); INCLUDE_ASM("asm/nonmatchings/800", func_80025818); INCLUDE_ASM("asm/nonmatchings/800", func_80025A30); INCLUDE_ASM("asm/nonmatchings/800", func_80025CBC); INCLUDE_ASM("asm/nonmatchings/800", func_80025EB8); INCLUDE_ASM("asm/nonmatchings/800", func_80026128); INCLUDE_ASM("asm/nonmatchings/800", func_800262D8); INCLUDE_ASM("asm/nonmatchings/800", func_80026514); INCLUDE_ASM("asm/nonmatchings/800", func_800268D0); INCLUDE_ASM("asm/nonmatchings/800", func_80026D64); INCLUDE_ASM("asm/nonmatchings/800", func_80027058); INCLUDE_ASM("asm/nonmatchings/800", func_80027200); INCLUDE_ASM("asm/nonmatchings/800", func_800273F4); INCLUDE_ASM("asm/nonmatchings/800", func_800275BC); INCLUDE_ASM("asm/nonmatchings/800", func_800277DC); INCLUDE_ASM("asm/nonmatchings/800", func_800279AC); INCLUDE_ASM("asm/nonmatchings/800", func_80027BF0); INCLUDE_ASM("asm/nonmatchings/800", func_80027C10); INCLUDE_ASM("asm/nonmatchings/800", func_80027D20); INCLUDE_ASM("asm/nonmatchings/800", func_80027F4C); INCLUDE_ASM("asm/nonmatchings/800", func_80028200); void func_80028234(void) { } INCLUDE_ASM("asm/nonmatchings/800", func_8002823C); void func_800282FC(void) { } INCLUDE_ASM("asm/nonmatchings/800", func_80028304); INCLUDE_ASM("asm/nonmatchings/800", func_80028394); INCLUDE_ASM("asm/nonmatchings/800", func_80028428); INCLUDE_ASM("asm/nonmatchings/800", func_80028488); INCLUDE_ASM("asm/nonmatchings/800", func_8002850C); INCLUDE_ASM("asm/nonmatchings/800", func_80028558); INCLUDE_ASM("asm/nonmatchings/800", SsUtReverbOff); INCLUDE_ASM("asm/nonmatchings/800", func_800285CC); INCLUDE_ASM("asm/nonmatchings/800", func_80028620); INCLUDE_ASM("asm/nonmatchings/800", func_80028694); void func_80028A30(void) { } void func_80028A38(void) { } void func_80028A40(void) { } INCLUDE_ASM("asm/nonmatchings/800", func_80028A48); INCLUDE_ASM("asm/nonmatchings/800", func_80028C50); INCLUDE_ASM("asm/nonmatchings/800", func_80028D58); INCLUDE_ASM("asm/nonmatchings/800", func_80028D78); INCLUDE_ASM("asm/nonmatchings/800", func_80028D9C); INCLUDE_ASM("asm/nonmatchings/800", func_80028DBC); INCLUDE_ASM("asm/nonmatchings/800", func_80028DE0); INCLUDE_ASM("asm/nonmatchings/800", func_80028E00); INCLUDE_ASM("asm/nonmatchings/800", func_80028E24); INCLUDE_ASM("asm/nonmatchings/800", func_80028E44); INCLUDE_ASM("asm/nonmatchings/800", func_80028E68); INCLUDE_ASM("asm/nonmatchings/800", func_80028E88); INCLUDE_ASM("asm/nonmatchings/800", func_80028EAC); INCLUDE_ASM("asm/nonmatchings/800", func_80028ECC); INCLUDE_ASM("asm/nonmatchings/800", func_80028EF0); INCLUDE_ASM("asm/nonmatchings/800", func_80028F10); INCLUDE_ASM("asm/nonmatchings/800", func_80028F34); INCLUDE_ASM("asm/nonmatchings/800", func_80028F54); INCLUDE_ASM("asm/nonmatchings/800", func_80028F78); INCLUDE_ASM("asm/nonmatchings/800", func_80028F98); INCLUDE_ASM("asm/nonmatchings/800", func_80028FBC); INCLUDE_ASM("asm/nonmatchings/800", func_80028FDC); INCLUDE_ASM("asm/nonmatchings/800", func_80029000); INCLUDE_ASM("asm/nonmatchings/800", func_80029020); INCLUDE_ASM("asm/nonmatchings/800", func_80029044); INCLUDE_ASM("asm/nonmatchings/800", func_8002906C); INCLUDE_ASM("asm/nonmatchings/800", func_80029094); INCLUDE_ASM("asm/nonmatchings/800", func_800290BC); INCLUDE_ASM("asm/nonmatchings/800", func_800290E0); INCLUDE_ASM("asm/nonmatchings/800", func_80029104); INCLUDE_ASM("asm/nonmatchings/800", func_80029124); INCLUDE_ASM("asm/nonmatchings/800", func_80029178); INCLUDE_ASM("asm/nonmatchings/800", func_800291A0); INCLUDE_ASM("asm/nonmatchings/800", func_800291B4); INCLUDE_ASM("asm/nonmatchings/800", func_800291C8); INCLUDE_ASM("asm/nonmatchings/800", func_800291DC); INCLUDE_ASM("asm/nonmatchings/800", func_800291F0); INCLUDE_ASM("asm/nonmatchings/800", func_80029204); INCLUDE_ASM("asm/nonmatchings/800", func_80029218); INCLUDE_ASM("asm/nonmatchings/800", func_80029240); extern s32 D_80075838; void func_80029254(void) { D_80075838 = 0; } extern s32 D_80075838; s32 func_80029264(void) { return D_80075838; } INCLUDE_ASM("asm/nonmatchings/800", func_80029274); INCLUDE_ASM("asm/nonmatchings/800", func_8002931C); INCLUDE_ASM("asm/nonmatchings/800", func_80029344); INCLUDE_ASM("asm/nonmatchings/800", func_8002941C); INCLUDE_ASM("asm/nonmatchings/800", func_80029444); extern s32 D_80078E80; s32 func_80029504(void) { return D_80078E80; } extern s32 D_80078E80; void func_80029514(s32 arg0) { D_80078E80 = arg0; } INCLUDE_ASM("asm/nonmatchings/800", func_80029524); extern s32 D_80078E84; s32 func_8002953C(void) { return D_80078E84; } extern s32 D_80078E84; void func_8002954C(s32 arg0) { D_80078E84 = arg0; } INCLUDE_ASM("asm/nonmatchings/800", func_8002955C); extern s32 D_80078E88; s32 func_8002957C(void) { return D_80078E88; } extern s32 D_80078E88; void func_8002958C(s32 arg0) { D_80078E88 = arg0; } INCLUDE_ASM("asm/nonmatchings/800", func_8002959C); INCLUDE_ASM("asm/nonmatchings/800", func_800295D4); INCLUDE_ASM("asm/nonmatchings/800", func_80029664); INCLUDE_ASM("asm/nonmatchings/800", func_80029690); INCLUDE_ASM("asm/nonmatchings/800", func_800296F8); INCLUDE_ASM("asm/nonmatchings/800", func_80029774); INCLUDE_ASM("asm/nonmatchings/800", func_800298BC); INCLUDE_ASM("asm/nonmatchings/800", func_8002992C); INCLUDE_ASM("asm/nonmatchings/800", func_80029A58); INCLUDE_ASM("asm/nonmatchings/800", func_80029A94); INCLUDE_ASM("asm/nonmatchings/800", func_80029AAC); INCLUDE_ASM("asm/nonmatchings/800", func_80029AF4); INCLUDE_ASM("asm/nonmatchings/800", func_80029B4C); INCLUDE_ASM("asm/nonmatchings/800", func_80029BC8); INCLUDE_ASM("asm/nonmatchings/800", func_80029C44); INCLUDE_ASM("asm/nonmatchings/800", func_80029CD4); INCLUDE_ASM("asm/nonmatchings/800", func_80029D3C); INCLUDE_ASM("asm/nonmatchings/800", func_80029DB4); INCLUDE_ASM("asm/nonmatchings/800", func_80029E30); INCLUDE_ASM("asm/nonmatchings/800", func_80029E94); INCLUDE_ASM("asm/nonmatchings/800", func_80029EC0); INCLUDE_ASM("asm/nonmatchings/800", func_80029ED4); extern s32 D_80078F08; s32 func_80029FD4(void) { return D_80078F08; } INCLUDE_ASM("asm/nonmatchings/800", func_80029FE4); INCLUDE_ASM("asm/nonmatchings/800", func_8002A04C); INCLUDE_ASM("asm/nonmatchings/800", func_8002A088); INCLUDE_ASM("asm/nonmatchings/800", func_8002A108); INCLUDE_ASM("asm/nonmatchings/800", func_8002A1B4); INCLUDE_ASM("asm/nonmatchings/800", func_8002A200); INCLUDE_ASM("asm/nonmatchings/800", func_8002A234); extern s32 D_80078EE4; s32 func_8002A26C(void) { return D_80078EE4; } extern s32 D_80078EE8; s32 func_8002A27C(void) { return D_80078EE8; } INCLUDE_ASM("asm/nonmatchings/800", func_8002A28C); INCLUDE_ASM("asm/nonmatchings/800", func_8002A2B0); INCLUDE_ASM("asm/nonmatchings/800", func_8002A2D4); INCLUDE_ASM("asm/nonmatchings/800", func_8002A354); INCLUDE_ASM("asm/nonmatchings/800", func_8002A400); INCLUDE_ASM("asm/nonmatchings/800", func_8002A44C); INCLUDE_ASM("asm/nonmatchings/800", func_8002A480); extern s32 D_80078EEC; s32 func_8002A4B8(void) { return D_80078EEC; } extern s32 D_80078EF0; s32 func_8002A4C8(void) { return D_80078EF0; } INCLUDE_ASM("asm/nonmatchings/800", func_8002A4D8); INCLUDE_ASM("asm/nonmatchings/800", func_8002A4FC); INCLUDE_ASM("asm/nonmatchings/800", func_8002A520); INCLUDE_ASM("asm/nonmatchings/800", func_8002A544); INCLUDE_ASM("asm/nonmatchings/800", func_8002A5C4); INCLUDE_ASM("asm/nonmatchings/800", func_8002A670); INCLUDE_ASM("asm/nonmatchings/800", func_8002A6BC); INCLUDE_ASM("asm/nonmatchings/800", func_8002A6F0); extern s32 D_80078EFC; s32 func_8002A728(void) { return D_80078EFC; } extern s32 D_80078F00; s32 func_8002A738(void) { return D_80078F00; } INCLUDE_ASM("asm/nonmatchings/800", func_8002A748); INCLUDE_ASM("asm/nonmatchings/800", func_8002A76C); INCLUDE_ASM("asm/nonmatchings/800", func_8002A790); INCLUDE_ASM("asm/nonmatchings/800", func_8002A7B4); INCLUDE_ASM("asm/nonmatchings/800", func_8002A834); INCLUDE_ASM("asm/nonmatchings/800", func_8002A8E0); INCLUDE_ASM("asm/nonmatchings/800", func_8002A92C); INCLUDE_ASM("asm/nonmatchings/800", func_8002A960); extern s32 D_80078EF4; s32 func_8002A998(void) { return D_80078EF4; } extern s32 D_80078EF8; s32 func_8002A9A8(void) { return D_80078EF8; } INCLUDE_ASM("asm/nonmatchings/800", func_8002A9B8); INCLUDE_ASM("asm/nonmatchings/800", func_8002A9DC); INCLUDE_ASM("asm/nonmatchings/800", func_8002AA00); INCLUDE_ASM("asm/nonmatchings/800", func_8002AA3C); void func_8002AAAC(void) { } INCLUDE_ASM("asm/nonmatchings/800", func_8002AAB4); INCLUDE_ASM("asm/nonmatchings/800", func_8002AB64); INCLUDE_ASM("asm/nonmatchings/800", func_8002AC00); INCLUDE_ASM("asm/nonmatchings/800", func_8002AC98); INCLUDE_ASM("asm/nonmatchings/800", func_8002AE60); INCLUDE_ASM("asm/nonmatchings/800", func_8002AED0); INCLUDE_ASM("asm/nonmatchings/800", func_8002AEE4); extern s32 D_800760C8; void func_8002AEF8(void) { D_800760C8 = 0; } s32 func_8002AF08(void) { return D_800760C8; } INCLUDE_ASM("asm/nonmatchings/800", func_8002AF18); INCLUDE_ASM("asm/nonmatchings/800", func_8002AF48); extern s32 D_80075A40; s32 func_8002AF60(void) { return D_80075A40; } INCLUDE_ASM("asm/nonmatchings/800", func_8002AF70); INCLUDE_ASM("asm/nonmatchings/800", func_8002B00C); INCLUDE_ASM("asm/nonmatchings/800", func_8002B064); INCLUDE_ASM("asm/nonmatchings/800", func_8002B08C); INCLUDE_ASM("asm/nonmatchings/800", func_8002B0B4); /* DEFERRED: SaveLoadRoutine (0x8002B154) — Phase 7 (session G), per Drew, to Q#5. * Original intent: the save / PS1 memory-card handler. Referenced by saveHeaderTemplate * (0x80072DF0) via THREE entry-point pointers: 0x8002B154 / 0x8002B1AC / 0x8002BEA4. * Dispatch branches on (selector & 7) (case 0 -> +1 counter; 1 -> 7; 2 -> 0x1E; 3 -> 0x23). * Why deferred (NOT a clean state machine like the 3 CD loaders drafted this session): * - splat emits ONE 1139-instruction stub spanning 0x8002B154-0x8002C31C with a SINGLE `jr $ra` * => it is effectively one large MULTI-ENTRY function (the 3 saveHeaderTemplate entries share a * return; the caller passes args in $s0/$s3) — awkward to express in C at all. * - Ghidra mis-analyses it: get_code(0x8002B154) returns only a tiny fragment using unaff_s0/ * unaff_s3 (caller-set regs), so there is no faithful whole-function decompile to translate. * - It is the save-data/memcard format, explicitly Phase-3 Q#5 "format still TBD" — a different * subsystem from the file/overlay loader cluster (which IS drafted: CdReadStateMachine, * CdReadSectorReadyCB, StreamLoadStateMachine here + the matched CdReadRequest/CdQueueBusy/…). * - External helpers it calls (uncharacterised): func_800603BC (x20), func_80060614, func_8006023C, * func_80060D9C, func_80060AE0, func_8005FFB4, func_8005FD58, func_80061114/524, func_80016714(bzero). * Re-enable / revisit when Q#5 (save/memcard format) is studied: FIRST fix the Ghidra function * boundary (make 0x8002B154 span the whole 1139 ins, or model the 3 entry points), re-decompile, * characterise the func_80060xxx memcard helpers, THEN draft. A wrong faithful-looking draft here * would be worse than this honest stub (P9/G3). The default build is byte-identical via this stub. */ INCLUDE_ASM("asm/nonmatchings/800", SaveLoadRoutine); INCLUDE_ASM("asm/nonmatchings/800", func_8002C320); INCLUDE_ASM("asm/nonmatchings/800", func_8002C3B0); INCLUDE_ASM("asm/nonmatchings/800", func_8002C410); INCLUDE_ASM("asm/nonmatchings/800", func_8002C8BC); INCLUDE_ASM("asm/nonmatchings/800", func_8002C8F4); INCLUDE_ASM("asm/nonmatchings/800", func_8002CC4C); INCLUDE_ASM("asm/nonmatchings/800", func_8002CCB4); INCLUDE_ASM("asm/nonmatchings/800", func_8002CCD8); INCLUDE_ASM("asm/nonmatchings/800", func_8002CDD8); INCLUDE_ASM("asm/nonmatchings/800", func_8002CFE4); INCLUDE_ASM("asm/nonmatchings/800", func_8002D034); INCLUDE_ASM("asm/nonmatchings/800", func_8002D1F0); INCLUDE_ASM("asm/nonmatchings/800", func_8002D240); INCLUDE_ASM("asm/nonmatchings/800", func_8002D29C); INCLUDE_ASM("asm/nonmatchings/800", func_8002D320); extern u8 D_800A46BA; u8 func_8002D4B8(void) { return D_800A46BA; } INCLUDE_ASM("asm/nonmatchings/800", func_8002D4C8); INCLUDE_ASM("asm/nonmatchings/800", func_8002D59C); INCLUDE_ASM("asm/nonmatchings/800", func_8002D678); INCLUDE_ASM("asm/nonmatchings/800", func_8002D6D8); void func_8002D7F4(void) { } extern s32 D_800A4E7C; void func_8002D7FC(s32 arg0) { D_800A4E7C = arg0; } INCLUDE_ASM("asm/nonmatchings/800", func_8002D80C); extern s16 D_8006A990; void func_8002D834(void) { D_8006A990 = 0; } INCLUDE_ASM("asm/nonmatchings/800", func_8002D844); INCLUDE_ASM("asm/nonmatchings/800", func_8002D858); INCLUDE_ASM("asm/nonmatchings/800", func_8002D8A8); INCLUDE_ASM("asm/nonmatchings/800", func_8002D8D4); INCLUDE_ASM("asm/nonmatchings/800", func_8002D904); INCLUDE_ASM("asm/nonmatchings/800", func_8002DC68); INCLUDE_ASM("asm/nonmatchings/800", func_8002DF80); INCLUDE_ASM("asm/nonmatchings/800", func_8002E138); INCLUDE_ASM("asm/nonmatchings/800", func_8002E5BC); INCLUDE_ASM("asm/nonmatchings/800", func_8002E5F8); INCLUDE_ASM("asm/nonmatchings/800", func_8002E638); INCLUDE_ASM("asm/nonmatchings/800", func_8002E700); INCLUDE_ASM("asm/nonmatchings/800", func_8002E79C); INCLUDE_ASM("asm/nonmatchings/800", func_8002E818); INCLUDE_ASM("asm/nonmatchings/800", func_8002E8DC); INCLUDE_ASM("asm/nonmatchings/800", func_8002E94C); INCLUDE_ASM("asm/nonmatchings/800", func_8002EA10); INCLUDE_ASM("asm/nonmatchings/800", func_8002EAB0); INCLUDE_ASM("asm/nonmatchings/800", func_8002EB10); INCLUDE_ASM("asm/nonmatchings/800", func_8002EBAC); INCLUDE_ASM("asm/nonmatchings/800", func_8002EC10); INCLUDE_ASM("asm/nonmatchings/800", func_8002ED90); INCLUDE_ASM("asm/nonmatchings/800", func_8002EDE4); INCLUDE_ASM("asm/nonmatchings/800", func_8002EE64); INCLUDE_ASM("asm/nonmatchings/800", func_8002EE90); INCLUDE_ASM("asm/nonmatchings/800", func_8002EEB8); INCLUDE_ASM("asm/nonmatchings/800", func_8002EED8); INCLUDE_ASM("asm/nonmatchings/800", func_8002EFD0); INCLUDE_ASM("asm/nonmatchings/800", func_8002EFF8); INCLUDE_ASM("asm/nonmatchings/800", func_8002F064); INCLUDE_ASM("asm/nonmatchings/800", func_8002F0D0); INCLUDE_ASM("asm/nonmatchings/800", func_8002F0F4); INCLUDE_ASM("asm/nonmatchings/800", func_8002F12C); INCLUDE_ASM("asm/nonmatchings/800", func_8002F150); INCLUDE_ASM("asm/nonmatchings/800", func_8002F1CC); INCLUDE_ASM("asm/nonmatchings/800", func_8002F248); INCLUDE_ASM("asm/nonmatchings/800", func_8002F4E4); INCLUDE_ASM("asm/nonmatchings/800", func_8002F5C8); INCLUDE_ASM("asm/nonmatchings/800", func_8002F620); extern s16 D_800A4EF0; s16 func_8002F648(void) { return D_800A4EF0; } INCLUDE_ASM("asm/nonmatchings/800", func_8002F658); INCLUDE_ASM("asm/nonmatchings/800", func_8002F67C); INCLUDE_ASM("asm/nonmatchings/800", func_8002F714); INCLUDE_ASM("asm/nonmatchings/800", func_8002F80C); INCLUDE_ASM("asm/nonmatchings/800", func_8002FA3C); INCLUDE_ASM("asm/nonmatchings/800", func_8002FAE0); INCLUDE_ASM("asm/nonmatchings/800", func_8002FB08); INCLUDE_ASM("asm/nonmatchings/800", func_8002FC64); INCLUDE_ASM("asm/nonmatchings/800", func_8002FD14); INCLUDE_ASM("asm/nonmatchings/800", func_8002FDC8); INCLUDE_ASM("asm/nonmatchings/800", func_8002FDE8); INCLUDE_ASM("asm/nonmatchings/800", func_8002FF0C); INCLUDE_ASM("asm/nonmatchings/800", func_800301A4); INCLUDE_ASM("asm/nonmatchings/800", func_800301C8); INCLUDE_ASM("asm/nonmatchings/800", func_80030470); INCLUDE_ASM("asm/nonmatchings/800", func_800304C8); INCLUDE_ASM("asm/nonmatchings/800", func_80030538); INCLUDE_ASM("asm/nonmatchings/800", func_80030634); INCLUDE_ASM("asm/nonmatchings/800", func_80030730); INCLUDE_ASM("asm/nonmatchings/800", func_80030A14); INCLUDE_ASM("asm/nonmatchings/800", func_80030CA4); INCLUDE_ASM("asm/nonmatchings/800", func_80030D80); INCLUDE_ASM("asm/nonmatchings/800", func_80030F80); INCLUDE_ASM("asm/nonmatchings/800", func_800314DC); INCLUDE_ASM("asm/nonmatchings/800", func_800316F8); INCLUDE_ASM("asm/nonmatchings/800", func_80031988); INCLUDE_ASM("asm/nonmatchings/800", func_80031A98); INCLUDE_ASM("asm/nonmatchings/800", func_80031B7C); INCLUDE_ASM("asm/nonmatchings/800", func_80031BE0); INCLUDE_ASM("asm/nonmatchings/800", func_80031CC8); INCLUDE_ASM("asm/nonmatchings/800", func_80031D70); INCLUDE_ASM("asm/nonmatchings/800", func_80031DEC); INCLUDE_ASM("asm/nonmatchings/800", func_80031E94); INCLUDE_ASM("asm/nonmatchings/800", func_80031F14); INCLUDE_ASM("asm/nonmatchings/800", func_80031FC8); INCLUDE_ASM("asm/nonmatchings/800", func_80032048); INCLUDE_ASM("asm/nonmatchings/800", func_800322A8); INCLUDE_ASM("asm/nonmatchings/800", func_800324A4); INCLUDE_ASM("asm/nonmatchings/800", func_80032774); INCLUDE_ASM("asm/nonmatchings/800", func_80032A74); INCLUDE_ASM("asm/nonmatchings/800", func_8003310C); INCLUDE_ASM("asm/nonmatchings/800", func_800331D4); INCLUDE_ASM("asm/nonmatchings/800", func_8003324C); INCLUDE_ASM("asm/nonmatchings/800", func_80033324); INCLUDE_ASM("asm/nonmatchings/800", func_80033398); INCLUDE_ASM("asm/nonmatchings/800", func_8003350C); INCLUDE_ASM("asm/nonmatchings/800", func_800335B8); INCLUDE_ASM("asm/nonmatchings/800", func_800336A8); INCLUDE_ASM("asm/nonmatchings/800", func_8003388C); INCLUDE_ASM("asm/nonmatchings/800", func_800342E8); INCLUDE_ASM("asm/nonmatchings/800", func_80034314); INCLUDE_ASM("asm/nonmatchings/800", func_80034650); INCLUDE_ASM("asm/nonmatchings/800", func_800346D0); INCLUDE_ASM("asm/nonmatchings/800", func_800347C8); INCLUDE_ASM("asm/nonmatchings/800", func_80034844); INCLUDE_ASM("asm/nonmatchings/800", func_800348A8); INCLUDE_ASM("asm/nonmatchings/800", func_8003491C); INCLUDE_ASM("asm/nonmatchings/800", func_80034A54); INCLUDE_ASM("asm/nonmatchings/800", func_80034A9C); INCLUDE_ASM("asm/nonmatchings/800", func_80034AE0); INCLUDE_ASM("asm/nonmatchings/800", func_80034B0C); INCLUDE_ASM("asm/nonmatchings/800", func_80034B3C); extern s32 D_8006AEF8; extern s32 D_8006AEFC; extern u8 D_80076214; extern u8 D_8007620C; /* CD read-queue status: head==tail (D_8006AEF8/FC equal) => idle; flags D_80076214 (a * pending/error byte) and D_8007620C (bit7/bit5) classify the busy/result state. * Returns 0=idle done, 8=had pending, 2/4/1=busy variants. */ s32 CdQueueBusy(void) { if (D_8006AEF8 != D_8006AEFC) { if (D_80076214 == 0) { if (D_8007620C & 0x80) { return 2; } if (D_8007620C & 0x20) { return 4; } return 1; } } else { D_8007620C = 0; if (D_80076214 == 0) { return 0; } } D_80076214 = 0; return 8; } INCLUDE_ASM("asm/nonmatchings/800", func_80034C24); INCLUDE_ASM("asm/nonmatchings/800", func_80034CF0); INCLUDE_ASM("asm/nonmatchings/800", func_80034DFC); INCLUDE_ASM("asm/nonmatchings/800", func_8003500C); INCLUDE_ASM("asm/nonmatchings/800", func_800351E8); INCLUDE_ASM("asm/nonmatchings/800", func_80035210); INCLUDE_ASM("asm/nonmatchings/800", func_80035270); INCLUDE_ASM("asm/nonmatchings/800", func_800359B0); INCLUDE_ASM("asm/nonmatchings/800", func_80035C4C); INCLUDE_ASM("asm/nonmatchings/800", func_8003602C); INCLUDE_ASM("asm/nonmatchings/800", func_80036130); INCLUDE_ASM("asm/nonmatchings/800", func_800361CC); INCLUDE_ASM("asm/nonmatchings/800", func_8003621C); INCLUDE_ASM("asm/nonmatchings/800", func_80036260); #ifdef NON_MATCHING extern int CdControl(u8 com, u8 *param, u8 *result); extern int CdSync(int mode, u8 *result); extern u32 CdMode(void); extern void CdFlush(void); extern void *CdReadyCallback(void *func); extern void func_800377D8(void); /* this loader's CdlReadN ready-callback */ extern void func_80036260(void); /* sub-handler passed to func_80037CD8 */ extern void func_8002EC10(void); extern void func_80037334(void); extern void func_80037358(int posInt); extern void func_80037144(int idx); extern int func_80037CD8(void *arg); extern int func_8003750C(void); extern int func_800374CC(int *out); extern int func_8003775C(void); extern void func_80037D74(void); extern void *func_80037368(int *out); extern int streamLoad_state; /* 0x8006AF00 */ extern void *streamLoad_savedReadyCB; extern u8 streamLoad_cbActive; extern int D_800A4F28; /* tick / timeout counter */ extern int D_800A4F2C; /* CdMode-derived retry budget */ extern int D_800A4F30; /* remaining sub-stream repeat count (from param_3) */ extern int D_800A4F34; /* last sector position (stall detection) */ extern int D_800A4F38; /* end/abort flag */ extern int D_800A6544; extern u16 D_800A4E8E; /* 16-bit status flags */ extern u8 D_8006AEF4; /* 8-bit status flags */ extern u8 D_80068B60[]; /* per-resource descriptor table (0x10 stride) */ /* Second CD loader, DISTINCT from CdReadStateMachine: an 18-state machine (streamLoad_state) with * its OWN ready-callback (func_800377D8). Runs SetMode(0xA0)/SeekL/ReadN with retry + CdMode * handling, looping param_3 (D_800A4F30) times over sub-streams. Returns 0 = busy, 1 = done, * 2 = error/abort. Driven by ResourceLoadStateMachine. Provenance: static trace, Phase 3 T4 (fn id * verified; full semantics partial). * NON_MATCHING: faithful translation of the Ghidra decompile — logically faithful, not byte-verified. */ int StreamLoadStateMachine(int param_1, void *param_2, int param_3) { /* param_2 is a CdlLOC* */ short sVar1; int iVar4; u32 uVar2; char *pcVar3; u8 local_28[8]; u8 local_20[8]; int local_18; int local_14; sVar1 = *(short *)(D_80068B60 + (param_1 - 0x100) * 0x10); D_800A4F28++; switch (streamLoad_state) { case 0: D_800A4F38 = 0; D_800A6544 = 0; D_800A4F30 = param_3; func_8002EC10(); streamLoad_state++; D_800A4E8E &= 0xFFDF; return 0; case 1: func_80037334(); iVar4 = CdPosToInt((CdlLOC *)param_2); func_80037358(iVar4); func_80037144(sVar1); streamLoad_state++; /* fall through */ case 2: local_14 = CdSync(1, local_20); if (local_14 != 5 && local_14 != 2) return 0; uVar2 = CdMode(); D_800A4F2C = ((uVar2 & 0x80) == 0) ? 3 : 0; streamLoad_state++; /* fall through */ case 3: local_28[0] = 0xA0; iVar4 = CdControl(0x0E, local_28, local_20); /* CdlSetmode */ if (iVar4 == 0) { if ((local_20[0] & 0x10) != 0) { func_80037334(); streamLoad_state = 0; return 2; } return 0; } D_800A4F28 = 0; streamLoad_state++; /* fall through */ case 4: iVar4 = CdSync(1, local_20); if (iVar4 != 5) { if (iVar4 == 2) { streamLoad_state++; local_14 = 2; modeWait: if (D_800A4F2C != 0) { D_800A4F2C--; return 0; } streamLoad_state++; goto issueSeek; } if (D_800A4F28 < 0x3D) return 0; } streamLoad_state = 3; return 0; case 5: goto modeWait; case 6: issueSeek: iVar4 = func_80037CD8((void *)func_80036260); if (iVar4 == 0) return 0; streamLoad_state = 7; /* fall through */ case 7: iVar4 = func_8003750C(); if (iVar4 == 0) return 0; streamLoad_state++; /* fall through */ case 8: local_14 = CdSync(1, local_20); if (local_14 != 5 && local_14 != 2) return 0; streamLoad_state++; /* fall through */ case 9: D_800A4F28 = 0; iVar4 = CdControl(0x15, (u8 *)param_2, local_20); /* CdlSeekL */ if (iVar4 == 0) return 0; streamLoad_state++; /* fall through */ case 10: local_14 = CdSync(1, local_20); if (local_14 == 5) { iVar4 = CdControl(0x01, (u8 *)0, local_20); /* CdlNop */ if (iVar4 == 0) { streamLoad_state = 9; return 0; } if ((local_20[0] & 0x10) != 0) { func_80037334(); D_8006AEF4 &= 0xFD; streamLoad_state = 0; return 2; } streamLoad_state = 9; return 0; } if (local_14 != 2) { if (D_800A4F28 < 0x12D) return 0; CdFlush(); streamLoad_state = 9; return 2; } streamLoad_state++; local_14 = 2; /* fall through */ case 0xB: D_800A4F28 = 0; iVar4 = CdControl(0x06, (u8 *)param_2, local_20); /* CdlReadN */ if (iVar4 != 0) { if (streamLoad_cbActive == 0) streamLoad_savedReadyCB = CdReadyCallback((void *)func_800377D8); else CdReadyCallback((void *)func_800377D8); streamLoad_state++; streamLoad_cbActive = 1; return 0; } if ((local_20[0] & 0x10) == 0) return 0; D_8006AEF4 &= 0xFD; func_80037334(); streamLoad_state = 0; return 2; case 0xC: iVar4 = func_800374CC(&local_18); if (iVar4 == 0) { if (local_18 != D_800A4F34) { D_800A4F34 = local_18; D_800A4F28 = 0; } if (D_800A4F28 > 300) { if (streamLoad_cbActive != 0) { CdReadyCallback(streamLoad_savedReadyCB); streamLoad_savedReadyCB = 0; streamLoad_cbActive = 0; } streamLoad_state++; } return 0; } if (streamLoad_cbActive != 0) { CdReadyCallback(streamLoad_savedReadyCB); streamLoad_savedReadyCB = 0; streamLoad_cbActive = 0; } streamLoad_state++; /* fall through */ case 0xD: iVar4 = func_8003775C(); if (iVar4 == 0) return 0; func_80037D74(); streamLoad_state++; return 0; case 0xE: pcVar3 = (char *)func_80037368(&local_14); if (local_14 != 1) { streamLoad_state = 0x11; return 0; } if (*pcVar3 != 1) { if (*pcVar3 == 2) { streamLoad_state = 0x11; D_800A4F38 = 1; return 0; } if (D_800A4F30 != 0) { if (D_800A4F30 - 1 == 0) { streamLoad_state = 0x11; D_800A4F30 = 0; return 0; } streamLoad_state = 1; D_800A4F30--; return 0; } streamLoad_state = 1; return 0; } streamLoad_state++; break; /* -> CdlPause (post-switch) */ case 0xF: break; /* -> CdlPause (post-switch) */ case 0x10: iVar4 = CdSync(1, local_20); if (iVar4 != 5 && iVar4 != 2) return 0; if (D_800A4F38 == 0) { streamLoad_state = 0; return 1; } streamLoad_state = 0; D_800A4F38 = 0; return 2; case 0x11: iVar4 = CdControl(0x09, (u8 *)0, local_20); /* CdlPause */ if (iVar4 != 0) { streamLoad_state = 0x10; return 0; } return 0; default: return 0; } /* shared tail for states 0xE (advance) and 0xF: pause, then wait for it */ iVar4 = CdControl(0x09, (u8 *)0, local_20); /* CdlPause */ if (iVar4 != 0) { streamLoad_state++; return 0; } if ((local_20[0] & 0x10) != 0) { streamLoad_state = 0; return 1; } return 0; } #else INCLUDE_ASM("asm/nonmatchings/800", StreamLoadStateMachine); #endif INCLUDE_ASM("asm/nonmatchings/800", func_80036AF8); INCLUDE_ASM("asm/nonmatchings/800", func_80036D24); INCLUDE_ASM("asm/nonmatchings/800", func_80036D58); INCLUDE_ASM("asm/nonmatchings/800", func_80036EB4); INCLUDE_ASM("asm/nonmatchings/800", func_80036EE8); INCLUDE_ASM("asm/nonmatchings/800", func_80036F18); INCLUDE_ASM("asm/nonmatchings/800", func_80036F98); INCLUDE_ASM("asm/nonmatchings/800", func_80036FB0); CLEAR_TBL40(func_80037004) /* dedup I0: shared body (src/shared/clearTbl40.h) */ INCLUDE_ASM("asm/nonmatchings/800", func_80037028); INCLUDE_ASM("asm/nonmatchings/800", func_80037144); CLEAR_TBL40(func_80037334) /* dedup I0: shared body (src/shared/clearTbl40.h) */ extern s32 D_8007623C; void func_80037358(int posInt) { D_8007623C = posInt; } INCLUDE_ASM("asm/nonmatchings/800", func_80037368); INCLUDE_ASM("asm/nonmatchings/800", func_800373D0); INCLUDE_ASM("asm/nonmatchings/800", func_800374CC); INCLUDE_ASM("asm/nonmatchings/800", func_8003750C); INCLUDE_ASM("asm/nonmatchings/800", func_8003775C); INCLUDE_ASM("asm/nonmatchings/800", func_800377D8); extern s32 D_800BA0F8; void func_80037CC8(void) { D_800BA0F8 = 0; } INCLUDE_ASM("asm/nonmatchings/800", func_80037CD8); INCLUDE_ASM("asm/nonmatchings/800", func_80037D74); INCLUDE_ASM("asm/nonmatchings/800", func_80037D98); INCLUDE_ASM("asm/nonmatchings/800", func_80037EA0); INCLUDE_ASM("asm/nonmatchings/800", func_80037F3C); INCLUDE_ASM("asm/nonmatchings/800", func_80037FC4); INCLUDE_ASM("asm/nonmatchings/800", func_8003819C); INCLUDE_ASM("asm/nonmatchings/800", func_800381E4); INCLUDE_ASM("asm/nonmatchings/800", func_80038210); INCLUDE_ASM("asm/nonmatchings/800", func_80038308); INCLUDE_ASM("asm/nonmatchings/800", func_8003834C); INCLUDE_ASM("asm/nonmatchings/800", func_8003836C); INCLUDE_ASM("asm/nonmatchings/800", func_800383A4); INCLUDE_ASM("asm/nonmatchings/800", func_800384A8); INCLUDE_ASM("asm/nonmatchings/800", func_800385C0); INCLUDE_ASM("asm/nonmatchings/800", func_80038638); INCLUDE_ASM("asm/nonmatchings/800", func_80038668); INCLUDE_ASM("asm/nonmatchings/800", func_80038698); INCLUDE_ASM("asm/nonmatchings/800", func_800387C0); INCLUDE_ASM("asm/nonmatchings/800", func_80038838); INCLUDE_ASM("asm/nonmatchings/800", func_800388E8); INCLUDE_ASM("asm/nonmatchings/800", func_80038908); INCLUDE_ASM("asm/nonmatchings/800", func_80038958); INCLUDE_ASM("asm/nonmatchings/800", func_80038A00); INCLUDE_ASM("asm/nonmatchings/800", func_80038A58); INCLUDE_ASM("asm/nonmatchings/800", func_80038FC4); INCLUDE_ASM("asm/nonmatchings/800", func_80038FFC); INCLUDE_ASM("asm/nonmatchings/800", func_8003916C); INCLUDE_ASM("asm/nonmatchings/800", func_800391D4); void func_80039300(void) { } INCLUDE_ASM("asm/nonmatchings/800", func_80039308); INCLUDE_ASM("asm/nonmatchings/800", func_80039B20); INCLUDE_ASM("asm/nonmatchings/800", func_80039C5C); INCLUDE_ASM("asm/nonmatchings/800", func_80039C70); INCLUDE_ASM("asm/nonmatchings/800", func_80039DEC); INCLUDE_ASM("asm/nonmatchings/800", func_80039F14); INCLUDE_ASM("asm/nonmatchings/800", func_80039F50); INCLUDE_ASM("asm/nonmatchings/800", func_8003A098); INCLUDE_ASM("asm/nonmatchings/800", func_8003A0D0); INCLUDE_ASM("asm/nonmatchings/800", func_8003A0E4); INCLUDE_ASM("asm/nonmatchings/800", func_8003A234); INCLUDE_ASM("asm/nonmatchings/800", func_8003A3D8); INCLUDE_ASM("asm/nonmatchings/800", func_8003A404); INCLUDE_ASM("asm/nonmatchings/800", func_8003A424);