diff --git a/Makefile b/Makefile index cf33f5431..90dd69b3a 100644 --- a/Makefile +++ b/Makefile @@ -549,11 +549,12 @@ LIBCD_ELF := .run/obj40/libcd LIBCD_OBJDIR := build/psyq/libcd LIBCD_SYMS := build/psyq/libcd_externals.ld -# libgs (Phase 7 Task #9, FULL integration): 31 libgs objects in 6 contiguous blocks linked in place -# of the libgs1..libgs6 block stubs (the 5 non-libgs gaps stay gsgapN asm stubs). Same conditional/ +# libgs (Phase 7 Task #9, FULL integration; S78 #3/#4): 34 libgs objects in 8 blocks linked in place +# of the libgs1..libgs8 block stubs (libgs7 = 2D_BG0/2D_BG1, S78 #3; libgs8 = GS_001 via the link-prepare +# .bss split, S78 #4; the 4 remaining gaps are libgte objects, libgte27-30). Same conditional/ # idempotent model as libcd. The curated object dir is SDK-derived (gitignored), regenerated by # tools/make_libgs.sh (needs the LIBGS ELF from psyq_build_libs.sh LIBGS). GS_106 (block 4) anchors -# uniquely only within the libgs window, so the integrate call passes 0x80051804 0x80057928. +# uniquely only within the libgs window, so the integrate call passes 0x8005080C 0x80057928. LIBGS_ELF := .run/obj40/libgs_used LIBGS_OBJDIR := build/psyq/libgs LIBGS_SYMS := build/psyq/libgs_externals.ld @@ -565,10 +566,12 @@ LIBETC_ELF := .run/obj40/libetc LIBETC_OBJDIR := build/psyq/libetc LIBETC_SYMS := build/psyq/libetc_externals.ld -# libgpu (Phase 8): EXT+PRIM only — SYS.o EXCLUDED (scattered-.bss, cookbook §9.1, GS_001 class; stays a -# stub in 800c). Curated dir libgpu_used = {EXT,PRIM}; regenerate: tools/psyq_build_libs.sh LIBGPU then -# `mkdir -p .run/obj40/libgpu_used && cp .run/obj40/libgpu/{EXT,PRIM}.o .run/obj40/libgpu_used/`. -LIBGPU_ELF := .run/obj40/libgpu_used +# libgpu (Phase 8; S78 #4): EXT+PRIM (block `libgpu`) + SYS.o (block `libgpu2`, 3109 ins). SYS.o was +# EXCLUDED from Phase 8 to P31 S78 as scattered-.bss (cookbook §9.1, the GS_001 class) and lived in 800c +# as hand-matched SDK C + verbatim frags; psyq_integrate now splits such a .bss into per-base NOLOAD +# pieces at link-prepare (tools/psyq_bss_split.py, cookbook §489), so the raw psyq_build_libs.sh LIBGPU +# output links directly — no curated dir (psyq_identify drops the 8 objects the EXE does not link). +LIBGPU_ELF := .run/obj40/libgpu LIBGPU_OBJDIR := build/psyq/libgpu LIBGPU_SYMS := build/psyq/libgpu_externals.ld @@ -595,13 +598,14 @@ LIBGTE_OBJDIR := build/psyq/libgte LIBGTE_SYMS := build/psyq/libgte_externals.ld LIBGTE_STUBS := libgte1,libgte2,libgte3,libgte4,libgte5,libgte6,libgte7,libgte8,libgte9,libgte10,libgte11,libgte12,libgte13,libgte14,libgte15,libgte16,libgte17,libgte18,libgte19,libgte20,libgte21,libgte22,libgte23,libgte24,libgte25,libgte26,libgte27,libgte28,libgte29,libgte30 -# Combined libspu+libsnd sound region (Phase 8): the two SDK sound libs interleave in 0x3A444..0x4239C -# so they link as one 60-object region (snd1..snd9). Curated dir .run/obj40/snd_used built by -# tools/make_snd_used.py (4 addresses excluded as scattered-.bss/false-positive stubs). Window arg below. +# Combined libspu+libsnd sound region (Phase 8; S78 #3/#4): the two SDK sound libs interleave in +# 0x3A444..0x4239C so they link as one 63-object region (snd1..snd12). Curated dir .run/obj40/snd_used +# built by tools/make_snd_used.py (3 addresses excluded as cross-object-common/false-positive stubs; +# VM_F rejoined in S78 #4 via the link-prepare .bss split, cookbook §489). Window arg below. SND_ELF := .run/obj40/snd_used SND_OBJDIR := build/psyq/snd SND_SYMS := build/psyq/snd_externals.ld -SND_STUBS := snd1,snd2,snd3,snd4,snd5,snd6,snd7,snd8,snd9,snd10,snd11 +SND_STUBS := snd1,snd2,snd3,snd4,snd5,snd6,snd7,snd8,snd9,snd10,snd11,snd12 # Combined libapi+libcard 800c2 region (Phase 8): 22 objects in 4 blocks (apicard1..4). Curated dir # .run/obj40/apicard_used (tools/make_apicard_used.py). Window 0x61F38..0x62888. (libapi's ~22 objects @@ -839,7 +843,7 @@ ifeq ($(BINARY),main) echo " (no $(LIBCD_ELF) — libcd region stays asm stubs; run tools/psyq_build_libs.sh LIBCD)" fi if [ -d "$(LIBGS_ELF)" ]; then - $(PYTHON) tools/psyq_integrate.py --vram-base $(main_VRAM_BASE) --exe $(main_EXE) --symbols $(main_SYMBOLS) --yaml $(main_SPLAT_YAML) $(LIBGS_ELF) $(LD_SCRIPT) $(LIBGS_OBJDIR) $(LIBGS_SYMS) libgs1,libgs2,libgs3,libgs4,libgs5,libgs6,libgs7 0x8005080C 0x80057928 + $(PYTHON) tools/psyq_integrate.py --vram-base $(main_VRAM_BASE) --exe $(main_EXE) --symbols $(main_SYMBOLS) --yaml $(main_SPLAT_YAML) $(LIBGS_ELF) $(LD_SCRIPT) $(LIBGS_OBJDIR) $(LIBGS_SYMS) libgs1,libgs2,libgs3,libgs4,libgs5,libgs6,libgs7,libgs8 0x8005080C 0x80057928 else echo " (no $(LIBGS_ELF) — libgs region stays asm stubs; run tools/make_libgs.sh)" fi @@ -849,9 +853,9 @@ ifeq ($(BINARY),main) echo " (no $(LIBETC_ELF) — libetc region stays asm stubs; run tools/psyq_build_libs.sh LIBETC)" fi if [ -d "$(LIBGPU_ELF)" ]; then - $(PYTHON) tools/psyq_integrate.py --vram-base $(main_VRAM_BASE) --exe $(main_EXE) --symbols $(main_SYMBOLS) --yaml $(main_SPLAT_YAML) $(LIBGPU_ELF) $(LD_SCRIPT) $(LIBGPU_OBJDIR) $(LIBGPU_SYMS) libgpu + $(PYTHON) tools/psyq_integrate.py --vram-base $(main_VRAM_BASE) --exe $(main_EXE) --symbols $(main_SYMBOLS) --yaml $(main_SPLAT_YAML) $(LIBGPU_ELF) $(LD_SCRIPT) $(LIBGPU_OBJDIR) $(LIBGPU_SYMS) libgpu,libgpu2 else - echo " (no $(LIBGPU_ELF) — libgpu region stays asm stubs; run tools/psyq_build_libs.sh LIBGPU + curate libgpu_used)" + echo " (no $(LIBGPU_ELF) — libgpu region stays asm stubs; run tools/psyq_build_libs.sh LIBGPU)" fi if [ -d "$(LIBMCRD_ELF)" ]; then $(PYTHON) tools/psyq_integrate.py --vram-base $(main_VRAM_BASE) --exe $(main_EXE) --symbols $(main_SYMBOLS) --yaml $(main_SPLAT_YAML) $(LIBMCRD_ELF) $(LD_SCRIPT) $(LIBMCRD_OBJDIR) $(LIBMCRD_SYMS) libmcrd1,libmcrd2 diff --git a/config/splat.us.exe.yaml b/config/splat.us.exe.yaml index ef49b49ce..8339e0439 100644 --- a/config/splat.us.exe.yaml +++ b/config/splat.us.exe.yaml @@ -92,10 +92,12 @@ segments: - [0x1D0BC, c, 800_b_2] # -O2 -> src/800_b_2.c (vram 0x8002C8BC-0x80035270); owns .rodata span B (tail) - [0x25A70, c, 800_c] # -O2 game code -> src/800_c.c (vram 0x80035270-0x8003A444); owns .rodata span C # PsyQ libspu+libsnd COMBINED sound region (Phase 8): the two SDK sound libs are interleaved here, - # so they link as one 60-object region (curated by tools/make_snd_used.py; 4 addresses excluded as - # scattered-.bss/false-positive stubs: S_R/S_W 0x3C438, S_GRMDT* 0x3D424, S_IH/UT_RON 0x3D94C, - # VM_F 0x3FA64). Subsegs via gen_lib_subsegs.py; integrate window 0x3A444..0x4239C. snd1..snd9 link; - # sgap* = game code + the 4 excluded stubs. (libsnd SSGM.o @0x1BD80 stays a stub in 800.) + # so they link as one 63-object region (curated by tools/make_snd_used.py; 3 addresses excluded as + # cross-object-common/false-positive stubs: S_R/S_W 0x3C438, S_GRMDT* 0x3D424, S_IH/UT_RON 0x3D94C). + # VM_F 0x3FA64 was the 4th exclusion (scattered-.bss) until P31 S78 #4: psyq_integrate now splits + # such a .bss into per-base NOLOAD pieces at link-prepare (psyq_bss_split, cookbook §489) and it + # links as snd12. Subsegs via gen_lib_subsegs.py; integrate window 0x3A444..0x4239C. snd1..snd12 + # link; sgap* = game code + the 3 excluded stubs. (libsnd SSGM.o @0x1BD80 stays a stub in 800.) - [0x2AC44, c, snd1] # snd block 1: 15 obj (S_INI.o..S_SK.o) vram 0x8003A444-0x8003C438 - [0x2CC38, c, sgap] # game code (vram 0x8003C438-0x8003C498) - [0x2CC98, c, snd2] # snd block 2: 8 obj (S_STSA.o..S_SRMD.o) vram 0x8003C498-0x8003D424 @@ -107,7 +109,8 @@ segments: - [0x2EA48, c, snd5] # snd block 5: 1 obj (PAUSE.o) vram 0x8003E248-0x8003E2E4 - [0x2EAE4, c, sgap_5] # game code (vram 0x8003E2E4-0x8003E310) - [0x2EB10, c, snd6] # snd block 6: 12 obj (MIDIREAD.o..VM_ALOC2.o) vram 0x8003E310-0x8003FA54 - - [0x30254, c, sgap_6] # game code + excluded VM_F stub (vram 0x8003FA54-0x8003FE18) + - [0x30254, c, sgap_6] # game code: func_8003FA54, 4 ins (vram 0x8003FA54-0x8003FA64) + - [0x30264, c, snd12] # snd block 12 (S78 #4): VM_F.o (237 ins, exact tile; .bss split ×2 at link-prepare, §489) vram 0x8003FA64-0x8003FE18 — carved off sgap_6 - [0x30618, c, snd7] # snd block 7: 5 obj (S_SNV.o..VM_N2P.o) vram 0x8003FE18-0x800403A4 - [0x30BA4, c, snd10] # snd block 10 (S78): VM_NO1.o (305 ins, exact tile) vram 0x800403A4-0x80040868 — was 'sgap_7' game code (§485) - [0x31068, c, snd8] # snd block 8: 1 obj (VM_NOWOF.o) vram 0x80040868-0x80040938 @@ -124,13 +127,16 @@ segments: - [0x33888, c, libcd1] # libcd block 1 -> src/libcd1.c (vram 0x80043088-0x80046980, 11 objs) - [0x37180, c, gap] # non-libcd gap -> src/gap.c (vram 0x80046980-0x800469CC, stub) - [0x371CC, c, libcd2] # libcd block 2 -> src/libcd2.c (vram 0x800469CC-0x8004787C, 7 objs) - # PsyQ libgs (Phase 7 Task #9, FULL integration): 31 libgs objects in 6 contiguous blocks - # across vram 0x80051804-0x80057928, separated by 5 non-libgs gaps. psyq_integrate swaps each - # block stub's build/src/libgsN.o(.text) for the real objects + NOLOAD data (same mechanism as - # libcd). The 5 gaps stay asm stubs (gsgapN): 80 / 48 / 1536[GS_001] / 48 / 304 B. GS_001 is - # EXCLUDED (scattered-.bss hard case, cookbook §9.1) and stays a stub (gsgap3). GS_106 (block 4) - # is an 8-ins object that only anchors uniquely within the libgs window, so make extract passes - # 0x80051804 0x80057928 to psyq_integrate. Object lists + disambiguation: tools/make_libgs.sh. + # PsyQ libgs (Phase 7 Task #9, FULL integration; S78 #3/#4): 34 libgs objects in 8 blocks + # across vram 0x8005080C-0x80057928. psyq_integrate swaps each block stub's + # build/src/libgsN.o(.text) for the real objects + NOLOAD data (same mechanism as libcd). + # The 4 remaining gaps (gsgap1/2/4/5: 80 / 48 / 48 / 304 B) are libgte objects, wired as + # libgte27-30 (S78 #3). The 1536 B gap gsgap3 was GS_001, EXCLUDED from Phase 7 to P31 S78 as the + # scattered-.bss "hard case" (cookbook §9.1; six bases): psyq_integrate now splits such a .bss + # into per-base NOLOAD pieces at link-prepare (psyq_bss_split, cookbook §489), so it links as + # libgs8 (S78 #4). GS_106 (block 4) is an 8-ins object that only anchors uniquely within the + # libgs window, so make extract passes 0x8005080C 0x80057928 to psyq_integrate. Object lists + + # disambiguation: tools/make_libgs.sh. # PsyQ libgte (Phase 8): GTE matrix/vector math, 53 objects in 22 blocks across the old 800b region, # interleaved with game code (800b/800b_2..800b_7). Subseg lines generated by gen_lib_subsegs.py # (section-size-correct boundaries). integrate window 0x4787C..0x51804. The 5 libgs-gap libgte @@ -167,26 +173,29 @@ segments: - [0x425C8, c, libgs2] # libgs block 2: 2D_LIN0/COM1/SP0 -> src/libgs2.c (vram 0x80051DC8-0x80052430, 3 objs) - [0x42C30, c, libgte28] # libgte block 28 (S78): MTX_07.o (12 ins, exact tile) vram 0x80052430-0x80052460 — was gsgap2 - [0x42C60, c, libgs3] # libgs block 3: 2D_SP1 -> src/libgs3.c (vram 0x80052460-0x800525DC, 1 obj) - - [0x42DDC, c, gsgap3] # gap 1536 B: GS_001 excluded -> src/gsgap3.c (vram 0x800525DC-0x80052BDC) + - [0x42DDC, c, libgs8] # libgs block 8 (S78 #4): GS_001.o (384 ins, exact tile; .bss split ×6 at link-prepare, §489) -> src/libgs8.c (vram 0x800525DC-0x80052BDC) — was the 'gsgap3' stub (hand-matched as game C) - [0x433DC, c, libgs4] # libgs block 4: GS_002/003/MATRIX/103/104/105/106/107 -> src/libgs4.c (vram 0x80052BDC-0x800538BC, 8 objs) - [0x440BC, c, libgte29] # libgte block 29 (S78): MTX_11.o (12 ins, exact tile) vram 0x800538BC-0x800538EC — was gsgap4 - [0x440EC, c, libgs5] # libgs block 5: GS_108/109 -> src/libgs5.c (vram 0x800538EC-0x800539C8, 2 objs) - [0x441C8, c, libgte30] # libgte block 30 (S78): REG03.o + REG11.o (76 ins, exact tile) vram 0x800539C8-0x80053AF8 — was gsgap5 - [0x442F8, c, libgs6] # libgs block 6 (16 objs) -> src/libgs6.c (vram 0x80053AF8-0x80057928) - [0x48128, c, 800b2] # -O2 game code (post-libgs, pre-libgpu) -> src/800b2.c (vram 0x80057928-0x80058890) - # PsyQ libgpu (Phase 8): EXT/PRIM linked; SYS.o EXCLUDED — scattered-.bss commons (cookbook §9.1, - # the GS_001 class: SYS references .bss by section+offset but the original linker scattered the - # commons across 0x80078xxx/0x800c5xxx, so no single NOLOAD base reproduces it). SYS stays a stub - # in 800c. Curated dir .run/obj40/libgpu_used = {EXT,PRIM}. - # ⚠ P31 S77 — "no single base" is TRUE; "therefore unlinkable" is NOT (cookbook §484). - # tools/psyq_bss_probe.py derives SYS.o's bases from the bytes: exactly TWO, and their .bss - # offset ranges are DISJOINT (0x0000-0x0044 @ 0x80078830, 0x0148-0x0150 @ 0x800c53cc), so a - # split at 0x148 places each half NOLOAD. Only .text references .bss (.data: zero), so the - # split is complete. GS_001.o is the genuine wall (5 interleaved bases); 2D_BG0.o and VM_NO1.o - # have NO .bss at all and are excluded for some other, unrecorded reason. - # src/800c.c is 100% SYS.o — its span is exactly the object's .text size, not "game code". - - [0x49090, c, libgpu] # libgpu block -> src/libgpu.c (vram 0x80058890-0x80059234, EXT+PRIM) - - [0x49A34, c, 800c] # -O2 game code (incl. excluded libgpu SYS stub) -> src/800c.c (vram 0x80059234-0x8005C2C8) + # PsyQ libgpu (Phase 8; S78 #4): EXT/PRIM linked as `libgpu`; SYS.o (3109 ins) was EXCLUDED from + # Phase 8 to P31 S78 as scattered-.bss commons (cookbook §9.1, the GS_001 class: SYS references + # .bss by section+offset but the original linker scattered the commons across 0x80078xxx/ + # 0x800c5xxx, so no single NOLOAD base reproduces it) and sat in `800c` as 56 hand-matched SDK + # functions + 62 verbatim frags — 100% SYS.o, the span IS the object's .text size. + # P31 S77 (cookbook §484): "no single base" is TRUE; "therefore unlinkable" is NOT — + # tools/psyq_bss_probe.py derived exactly TWO bases from the bytes with DISJOINT offset ranges + # (0x0000-0x0044 @ 0x80078830, 0x0148-0x0150 @ 0x800c53cc). + # P31 S78 #4 (cookbook §489): psyq_integrate now SPLITS such a section into per-base NOLOAD + # pieces at link-prepare (tools/psyq_bss_split.py: .bss [0,0x144) @0x80078830 + .bss2 = `_que` + # @0x800C5510), so SYS.o links byte-identical as `libgpu2`. No curated dir any more: LIBGPU_ELF is + # the raw .run/obj40/libgpu (psyq_identify drops the 8 objects the EXE does not link). The same + # split takes GS_001.o (libgs8, six pieces) and VM_F.o (snd12). 2D_BG0.o / VM_NO1.o have NO .bss + # and were wired in S78 #3. + - [0x49090, c, libgpu] # libgpu block 1 -> src/libgpu.c (vram 0x80058890-0x80059234, EXT+PRIM) + - [0x49A34, c, libgpu2] # libgpu block 2 (S78 #4): SYS.o (3109 ins, exact tile; .bss split ×2 at link-prepare, §489) -> src/libgpu2.c (vram 0x80059234-0x8005C2C8) — was '800c' # PsyQ libc2 (Phase 8): C stdlib. Main block = 16 objs (BZERO/MEMCPY/STRCMP/PRINTF/PRNT[jtbl ok]/ # …/SETJMP); STRCAT.o is a 2nd block at 0x80061E90 (start of the old 800c2). integrate libc2_1,libc2_2. - [0x4CAC8, c, libc2_1] # libc2 main block (16 objs) -> src/libc2_1.c (vram 0x8005C2C8-0x8005CE18); diff --git a/config/verbatim_manifest.json b/config/verbatim_manifest.json index a0e7e4f20..9bcfa31a4 100644 --- a/config/verbatim_manifest.json +++ b/config/verbatim_manifest.json @@ -12,30 +12,6 @@ ], "generated": "P31 S75 from .run/S75/triage/taxonomy.json", "rows": [ - { - "binary": "main", - "fn": "ApplyMatrix", - "addr": "0x80051d78", - "nins": 20, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "ApplyMatrix", - "unit_nins": 20, - "path": "src/gsgap1.c", - "why": "libgte MTX_05.o hand asm: cop2=11, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "AverageZ4", - "addr": "0x8004936c", - "nins": 9, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "AverageZ4", - "unit_nins": 9, - "path": "src/800b_2.c", - "why": "libgte hand asm: cop2=6, multi-entry shared tails, $at/k0 use, hazard nops" - }, { "binary": "main", "fn": "ChangeClearPAD", @@ -96,6 +72,18 @@ "path": "src/800c3.c", "why": "BIOS A/B/C-table trampoline: li $t2,0xA0/B0/C0; jr $t2; li $t1,N; pad nop (or li $a0; syscall)" }, + { + "binary": "main", + "fn": "DisablePAD", + "addr": "0x800626dc", + "nins": 5, + "cls": "SDK-ASM", + "disposition": "PERMANENT-VERBATIM", + "unit_entry": "func_800626dc", + "unit_nins": 5, + "path": "src/800c2_3.c", + "why": "lui/lw/nop/jr $t1 through jtbl_80078D24 \u2014 vector hook" + }, { "binary": "main", "fn": "EnableEvent", @@ -110,147 +98,15 @@ }, { "binary": "main", - "fn": "FGO_01_OBJ_160", - "addr": "0x800498ec", - "nins": 76, + "fn": "EnablePAD", + "addr": "0x800626c8", + "nins": 5, "cls": "SDK-ASM", "disposition": "PERMANENT-VERBATIM", - "unit_entry": "func_8004978c", - "unit_nins": 164, - "path": "src/800b_5.c", - "why": "libgte FGO_01.o RotMatrix hand asm: cop2=0, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "FGO_01_OBJ_64", - "addr": "0x800497f0", - "nins": 26, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "func_8004978c", - "unit_nins": 164, - "path": "src/800b_5.c", - "why": "libgte FGO_01.o RotMatrix hand asm: cop2=0, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "FGO_01_OBJ_CC", - "addr": "0x80049858", - "nins": 37, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "func_8004978c", - "unit_nins": 164, - "path": "src/800b_5.c", - "why": "libgte FGO_01.o RotMatrix hand asm: cop2=0, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "FGO_02_OBJ_160", - "addr": "0x80049b7c", - "nins": 76, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "RotMatrixYXZ", - "unit_nins": 164, - "path": "src/800b_5.c", - "why": "libgte FGO_02.o hand asm: cop2=0, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "FGO_02_OBJ_68", - "addr": "0x80049a84", - "nins": 25, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "RotMatrixYXZ", - "unit_nins": 164, - "path": "src/800b_5.c", - "why": "libgte FGO_02.o hand asm: cop2=0, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "FGO_02_OBJ_CC", - "addr": "0x80049ae8", - "nins": 37, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "RotMatrixYXZ", - "unit_nins": 164, - "path": "src/800b_5.c", - "why": "libgte FGO_02.o hand asm: cop2=0, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "FGO_03_OBJ_160", - "addr": "0x80049e0c", - "nins": 76, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "func_80049cac", - "unit_nins": 164, - "path": "src/800b_5.c", - "why": "libgte FGO_03.o hand asm: cop2=0, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "FGO_03_OBJ_64", - "addr": "0x80049d10", - "nins": 26, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "func_80049cac", - "unit_nins": 164, - "path": "src/800b_5.c", - "why": "libgte FGO_03.o hand asm: cop2=0, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "FGO_03_OBJ_CC", - "addr": "0x80049d78", - "nins": 37, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "func_80049cac", - "unit_nins": 164, - "path": "src/800b_5.c", - "why": "libgte FGO_03.o hand asm: cop2=0, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "FGO_04_OBJ_64", - "addr": "0x80049fa0", - "nins": 79, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "RotMatrixX", - "unit_nins": 104, - "path": "src/800b_5.c", - "why": "libgte FGO_04.o hand asm: cop2=0, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "FGO_05_OBJ_64", - "addr": "0x8004a140", - "nins": 79, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "RotMatrixY", - "unit_nins": 104, - "path": "src/800b_5.c", - "why": "libgte FGO_05.o hand asm: cop2=0, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "FGO_06_OBJ_64", - "addr": "0x8004a2e0", - "nins": 79, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "RotMatrixZ", - "unit_nins": 104, - "path": "src/800b_5.c", - "why": "libgte FGO_06.o hand asm: cop2=0, multi-entry shared tails, $at/k0 use, hazard nops" + "unit_entry": "func_800626c8", + "unit_nins": 5, + "path": "src/800c2_3.c", + "why": "lui/lw/nop/jr $t1 through jtbl_80078D20 \u2014 vector hook" }, { "binary": "main", @@ -264,54 +120,6 @@ "path": "src/800c3.c", "why": "BIOS A/B/C-table trampoline: li $t2,0xA0/B0/C0; jr $t2; li $t1,N; pad nop (or li $a0; syscall)" }, - { - "binary": "main", - "fn": "GS_001_OBJ_5D0", - "addr": "0x80052bac", - "nins": 12, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "GsSortClear", - "unit_nins": 79, - "path": "src/gsgap3.c", - "why": "libgs GS_001.o (archive text byte-identical, EXCLUDED for scattered .bss); GsSortClear @0x4C4 owns GS_001_OBJ_5D0" - }, - { - "binary": "main", - "fn": "GsSortBg", - "addr": "0x8005080c", - "nins": 109, - "cls": "SDK-C-VERSION", - "disposition": "DECOMPILE-LOW-VALUE", - "unit_entry": "GsSortBg", - "unit_nins": 526, - "path": "src/800b_7.c", - "why": "libgs GS_001.o (archive text byte-identical, EXCLUDED for scattered .bss); GsSortClear @0x4C4 owns GS_001_OBJ_5D0" - }, - { - "binary": "main", - "fn": "GsSortClear", - "addr": "0x80052aa0", - "nins": 67, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "GsSortClear", - "unit_nins": 79, - "path": "src/gsgap3.c", - "why": "libgs GS_001.o (archive text byte-identical, EXCLUDED for scattered .bss); GsSortClear @0x4C4 owns GS_001_OBJ_5D0" - }, - { - "binary": "main", - "fn": "GsSortFastBg", - "addr": "0x80051044", - "nins": 402, - "cls": "SDK-C-VERSION", - "disposition": "DECOMPILE-LOW-VALUE", - "unit_entry": "GsSortFastBg", - "unit_nins": 496, - "path": "src/800b_7.c", - "why": "libgs GS_001.o (archive text byte-identical, EXCLUDED for scattered .bss); GsSortClear @0x4C4 owns GS_001_OBJ_5D0" - }, { "binary": "main", "fn": "HookEntryInt", @@ -336,30 +144,6 @@ "path": "src/800c3.c", "why": "BIOS A/B/C-table trampoline: li $t2,0xA0/B0/C0; jr $t2; li $t1,N; pad nop (or li $a0; syscall)" }, - { - "binary": "main", - "fn": "InvSquareRoot", - "addr": "0x80047dcc", - "nins": 35, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "InvSquareRoot", - "unit_nins": 35, - "path": "src/800b.c", - "why": "libgte hand asm: cop2=2, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "MatrixNormal", - "addr": "0x80047f84", - "nins": 58, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "MatrixNormal", - "unit_nins": 58, - "path": "src/800b.c", - "why": "libgte hand asm: cop2=29, multi-entry shared tails, $at/k0 use, hazard nops" - }, { "binary": "main", "fn": "OpenEvent", @@ -372,30 +156,6 @@ "path": "src/800c3.c", "why": "BIOS A/B/C-table trampoline: li $t2,0xA0/B0/C0; jr $t2; li $t1,N; pad nop (or li $a0; syscall)" }, - { - "binary": "main", - "fn": "OuterProduct0", - "addr": "0x800493e8", - "nins": 22, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "OuterProduct0", - "unit_nins": 22, - "path": "src/800b_2.c", - "why": "libgte hand asm: cop2=16, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "OuterProduct12", - "addr": "0x80049390", - "nins": 22, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "OuterProduct12", - "unit_nins": 22, - "path": "src/800b_2.c", - "why": "libgte hand asm: cop2=16, multi-entry shared tails, $at/k0 use, hazard nops" - }, { "binary": "main", "fn": "ResetEntryInt", @@ -422,555 +182,15 @@ }, { "binary": "main", - "fn": "RotMatrixX", - "addr": "0x80049f3c", - "nins": 25, + "fn": "SetInitPadFlag", + "addr": "0x80062388", + "nins": 3, "cls": "SDK-ASM", "disposition": "PERMANENT-VERBATIM", - "unit_entry": "RotMatrixX", - "unit_nins": 104, - "path": "src/800b_5.c", - "why": "libgte FGO_04.o hand asm: cop2=0, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "RotMatrixY", - "addr": "0x8004a0dc", - "nins": 25, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "RotMatrixY", - "unit_nins": 104, - "path": "src/800b_5.c", - "why": "libgte FGO_05.o hand asm: cop2=0, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "RotMatrixYXZ", - "addr": "0x80049a1c", - "nins": 26, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "RotMatrixYXZ", - "unit_nins": 164, - "path": "src/800b_5.c", - "why": "libgte FGO_02.o hand asm: cop2=0, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "RotMatrixZ", - "addr": "0x8004a27c", - "nins": 25, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "RotMatrixZ", - "unit_nins": 104, - "path": "src/800b_5.c", - "why": "libgte FGO_06.o hand asm: cop2=0, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "SYS_OBJ_1034", - "addr": "0x8005a268", - "nins": 99, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_80059fc0", - "unit_nins": 298, - "path": "src/800c.c", - "why": "inside archived SYS.o function `PutDispEnv` (+0xd8c); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_11C", - "addr": "0x80059350", - "nins": 20, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_80059234", - "unit_nins": 97, - "path": "src/800c.c", - "why": "inside archived SYS.o function `ResetGraph` (+0x0); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_11C0", - "addr": "0x8005a3f4", - "nins": 29, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_80059fc0", - "unit_nins": 298, - "path": "src/800c.c", - "why": "inside archived SYS.o function `PutDispEnv` (+0xd8c); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_1578", - "addr": "0x8005a7ac", - "nins": 49, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "SetDrawEnv", - "unit_nins": 134, - "path": "src/800c.c", - "why": "inside archived SYS.o function `SetDrawEnv` (+0x1424); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_16C", - "addr": "0x800593a0", - "nins": 6, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_80059234", - "unit_nins": 97, - "path": "src/800c.c", - "why": "inside archived SYS.o function `ResetGraph` (+0x0); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_1790", - "addr": "0x8005a9c4", - "nins": 71, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_8005a870", - "unit_nins": 164, - "path": "src/800c.c", - "why": "inside archived SYS.o function `SetDrawEnv2` (+0x163c); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_18AC", - "addr": "0x8005aae0", - "nins": 8, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_8005a870", - "unit_nins": 164, - "path": "src/800c.c", - "why": "inside archived SYS.o function `SetDrawEnv2` (+0x163c); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_1964", - "addr": "0x8005ab98", - "nins": 16, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_8005ab58", - "unit_nins": 51, - "path": "src/800c.c", - "why": "inside archived SYS.o function `get_cs` (+0x1924); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_19A4", - "addr": "0x8005abd8", - "nins": 13, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_8005ab58", - "unit_nins": 51, - "path": "src/800c.c", - "why": "inside archived SYS.o function `get_cs` (+0x1924); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_1A30", - "addr": "0x8005ac64", - "nins": 16, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_8005ac24", - "unit_nins": 51, - "path": "src/800c.c", - "why": "inside archived SYS.o function `get_ce` (+0x19f0); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_1A70", - "addr": "0x8005aca4", - "nins": 13, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_8005ac24", - "unit_nins": 51, - "path": "src/800c.c", - "why": "inside archived SYS.o function `get_ce` (+0x19f0); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_1BC4", - "addr": "0x8005adf8", - "nins": 25, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_8005adb8", - "unit_nins": 42, - "path": "src/800c.c", - "why": "inside archived SYS.o function `get_dx` (+0x1b84); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_1C28", - "addr": "0x8005ae5c", - "nins": 1, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_8005adb8", - "unit_nins": 42, - "path": "src/800c.c", - "why": "inside archived SYS.o function `get_dx` (+0x1b84); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_1D84", - "addr": "0x8005afb8", - "nins": 15, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "_clr", - "unit_nins": 151, - "path": "src/800c.c", - "why": "inside archived SYS.o function `_clr` (+0x1d34); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_1DC0", - "addr": "0x8005aff4", - "nins": 105, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "_clr", - "unit_nins": 151, - "path": "src/800c.c", - "why": "inside archived SYS.o function `_clr` (+0x1d34); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_1F64", - "addr": "0x8005b198", - "nins": 11, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "_clr", - "unit_nins": 151, - "path": "src/800c.c", - "why": "inside archived SYS.o function `_clr` (+0x1d34); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_1FF4", - "addr": "0x8005b228", - "nins": 14, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "_dws", - "unit_nins": 143, - "path": "src/800c.c", - "why": "inside archived SYS.o function `_dws` (+0x1f90); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_202C", - "addr": "0x8005b260", - "nins": 94, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "_dws", - "unit_nins": 143, - "path": "src/800c.c", - "why": "inside archived SYS.o function `_dws` (+0x1f90); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_210", - "addr": "0x80059444", - "nins": 34, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "SetGraphReverse", - "unit_nins": 69, - "path": "src/800c.c", - "why": "inside archived SYS.o function `SetGraphReverse` (+0x184); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_21A4", - "addr": "0x8005b3d8", - "nins": 10, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "_dws", - "unit_nins": 143, - "path": "src/800c.c", - "why": "inside archived SYS.o function `_dws` (+0x1f90); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_222C", - "addr": "0x8005b460", - "nins": 14, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "_drs", - "unit_nins": 161, - "path": "src/800c.c", - "why": "inside archived SYS.o function `_drs` (+0x21cc); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_2264", - "addr": "0x8005b498", - "nins": 114, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "_drs", - "unit_nins": 161, - "path": "src/800c.c", - "why": "inside archived SYS.o function `_drs` (+0x21cc); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_242C", - "addr": "0x8005b660", - "nins": 9, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "_drs", - "unit_nins": 161, - "path": "src/800c.c", - "why": "inside archived SYS.o function `_drs` (+0x21cc); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_2C6C", - "addr": "0x8005bea0", - "nins": 14, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_8005bd7c", - "unit_nins": 87, - "path": "src/800c.c", - "why": "inside archived SYS.o function `_reset` (+0x2b48); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_2CC4", - "addr": "0x8005bef8", - "nins": 6, - "cls": "SDK-C-FRAG", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "SYS_OBJ_2CC4", - "unit_nins": 6, - "path": "src/800c.c", - "why": "inside archived SYS.o function `_sync` (+0x2ca4); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler | S76 CORRECTION: \u00a7179-C \u2014 no `jr $ra` of its own, falls into a sibling shared epilogue; gcc-2.7.2 appends an epilogue to every C function, so no C spelling exists. Verified by the mechanical no-jr-$ra detector AND independently by three drafting agents." - }, - { - "binary": "main", - "fn": "SYS_OBJ_2CDC", - "addr": "0x8005bf10", - "nins": 63, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "SYS_OBJ_2CDC", - "unit_nins": 68, - "path": "src/800c.c", - "why": "inside archived SYS.o function `_sync` (+0x2ca4); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_2DD8", - "addr": "0x8005c00c", - "nins": 5, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "SYS_OBJ_2CDC", - "unit_nins": 68, - "path": "src/800c.c", - "why": "inside archived SYS.o function `_sync` (+0x2ca4); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_2F7C", - "addr": "0x8005c1b0", - "nins": 4, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_8005c054", - "unit_nins": 91, - "path": "src/800c.c", - "why": "inside archived SYS.o function `get_alarm` (+0x2e20); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_604", - "addr": "0x80059838", - "nins": 15, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_80059760", - "unit_nins": 74, - "path": "src/800c.c", - "why": "inside archived SYS.o function `checkRECT` (+0x52c); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_640", - "addr": "0x80059874", - "nins": 5, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_80059760", - "unit_nins": 74, - "path": "src/800c.c", - "why": "inside archived SYS.o function `checkRECT` (+0x52c); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_E34", - "addr": "0x8005a068", - "nins": 51, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_80059fc0", - "unit_nins": 298, - "path": "src/800c.c", - "why": "inside archived SYS.o function `PutDispEnv` (+0xd8c); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_F00", - "addr": "0x8005a134", - "nins": 9, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_80059fc0", - "unit_nins": 298, - "path": "src/800c.c", - "why": "inside archived SYS.o function `PutDispEnv` (+0xd8c); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_F24", - "addr": "0x8005a158", - "nins": 13, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_80059fc0", - "unit_nins": 298, - "path": "src/800c.c", - "why": "inside archived SYS.o function `PutDispEnv` (+0xd8c); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_F58", - "addr": "0x8005a18c", - "nins": 32, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_80059fc0", - "unit_nins": 298, - "path": "src/800c.c", - "why": "inside archived SYS.o function `PutDispEnv` (+0xd8c); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SYS_OBJ_FD8", - "addr": "0x8005a20c", - "nins": 23, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_80059fc0", - "unit_nins": 298, - "path": "src/800c.c", - "why": "inside archived SYS.o function `PutDispEnv` (+0xd8c); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SaveLoadRoutine", - "addr": "0x8002b154", - "nins": 1139, - "cls": "GAME-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "SaveLoadRoutine", - "unit_nins": 1139, - "path": "src/800_b.c", - "why": "no prologue, owns the 0x40-frame epilogue; = jtbl_80072E44 entry 0 of func_8002B0B4 (prologue, jr $v0 dispatch, 3 jumps into this body); unit = 40+1139 = 1179 ins" - }, - { - "binary": "main", - "fn": "SetDrawEnv", - "addr": "0x8005a658", - "nins": 85, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "SetDrawEnv", - "unit_nins": 134, - "path": "src/800c.c", - "why": "inside archived SYS.o function `SetDrawEnv` (+0x1424); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SetGraphReverse", - "addr": "0x800593b8", - "nins": 35, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "SetGraphReverse", - "unit_nins": 69, - "path": "src/800c.c", - "why": "inside archived SYS.o function `SetGraphReverse` (+0x184); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "SetSZfifo3", - "addr": "0x80053a4c", - "nins": 5, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "SetSZfifo3", - "unit_nins": 5, - "path": "src/gsgap5.c", - "why": "libgte REG03.o hand asm: cop2=3, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "SetSZfifo4", - "addr": "0x80053a60", - "nins": 6, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "SetSZfifo4", - "unit_nins": 6, - "path": "src/gsgap5.c", - "why": "libgte REG03.o hand asm: cop2=4, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "SquareRoot12", - "addr": "0x800480ec", - "nins": 40, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "SquareRoot12", - "unit_nins": 40, - "path": "src/800b.c", - "why": "libgte hand asm: cop2=2, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "StopRCnt", - "addr": "0x8005d06c", - "nins": 13, - "cls": "SDK-C-PLAIN", - "disposition": "DECOMPILE-NOW", - "unit_entry": "StopRCnt", - "unit_nins": 13, - "path": "src/800c3.c", - "why": "libapi C leaf (siblings SetRCnt/GetRCnt/StartRCnt/ResetRCnt are REAL); no wall recorded; 7 drafts" + "unit_entry": "SetInitPadFlag", + "unit_nins": 3, + "path": "src/800c2_2.c", + "why": "lui $at; jr $ra; sw $a0,lo($at) \u2014 hand-written setter (libcard region, 800c2 reorder island)" }, { "binary": "main", @@ -1008,150 +228,6 @@ "path": "src/800c3.c", "why": "BIOS A/B/C-table trampoline: li $t2,0xA0/B0/C0; jr $t2; li $t1,N; pad nop (or li $a0; syscall)" }, - { - "binary": "main", - "fn": "VM_NO1_OBJ_184", - "addr": "0x80040528", - "nins": 28, - "cls": "SDK-C-VERSION", - "disposition": "DECOMPILE-LOW-VALUE", - "unit_entry": "vmNoiseOn", - "unit_nins": 305, - "path": "src/sgap_7.c", - "why": "libsnd VM_NO1.o / VM_NOWON.o (archive exports one function each; game copy differs from lib 4.0); fragment chain j+fallthrough" - }, - { - "binary": "main", - "fn": "VM_NO1_OBJ_1F4", - "addr": "0x80040598", - "nins": 28, - "cls": "SDK-C-VERSION", - "disposition": "DECOMPILE-LOW-VALUE", - "unit_entry": "vmNoiseOn", - "unit_nins": 305, - "path": "src/sgap_7.c", - "why": "libsnd VM_NO1.o / VM_NOWON.o (archive exports one function each; game copy differs from lib 4.0); fragment chain j+fallthrough" - }, - { - "binary": "main", - "fn": "VM_NO1_OBJ_264", - "addr": "0x80040608", - "nins": 10, - "cls": "SDK-C-VERSION", - "disposition": "DECOMPILE-LOW-VALUE", - "unit_entry": "vmNoiseOn", - "unit_nins": 305, - "path": "src/sgap_7.c", - "why": "libsnd VM_NO1.o / VM_NOWON.o (archive exports one function each; game copy differs from lib 4.0); fragment chain j+fallthrough" - }, - { - "binary": "main", - "fn": "VM_NO1_OBJ_28C", - "addr": "0x80040630", - "nins": 36, - "cls": "SDK-C-VERSION", - "disposition": "DECOMPILE-LOW-VALUE", - "unit_entry": "vmNoiseOn", - "unit_nins": 305, - "path": "src/sgap_7.c", - "why": "libsnd VM_NO1.o / VM_NOWON.o (archive exports one function each; game copy differs from lib 4.0); fragment chain j+fallthrough" - }, - { - "binary": "main", - "fn": "VM_NO1_OBJ_31C", - "addr": "0x800406c0", - "nins": 98, - "cls": "SDK-C-VERSION", - "disposition": "DECOMPILE-LOW-VALUE", - "unit_entry": "vmNoiseOn", - "unit_nins": 305, - "path": "src/sgap_7.c", - "why": "libsnd VM_NO1.o / VM_NOWON.o (archive exports one function each; game copy differs from lib 4.0); fragment chain j+fallthrough" - }, - { - "binary": "main", - "fn": "VM_NOWON_OBJ_1C0", - "addr": "0x80040af8", - "nins": 28, - "cls": "SDK-C-VERSION", - "disposition": "DECOMPILE-LOW-VALUE", - "unit_entry": "_SsVmKeyOnNow", - "unit_nins": 300, - "path": "src/sgap_8.c", - "why": "libsnd VM_NO1.o / VM_NOWON.o (archive exports one function each; game copy differs from lib 4.0); fragment chain j+fallthrough" - }, - { - "binary": "main", - "fn": "VM_NOWON_OBJ_230", - "addr": "0x80040b68", - "nins": 28, - "cls": "SDK-C-VERSION", - "disposition": "DECOMPILE-LOW-VALUE", - "unit_entry": "_SsVmKeyOnNow", - "unit_nins": 300, - "path": "src/sgap_8.c", - "why": "libsnd VM_NO1.o / VM_NOWON.o (archive exports one function each; game copy differs from lib 4.0); fragment chain j+fallthrough" - }, - { - "binary": "main", - "fn": "VM_NOWON_OBJ_2A0", - "addr": "0x80040bd8", - "nins": 10, - "cls": "SDK-C-VERSION", - "disposition": "DECOMPILE-LOW-VALUE", - "unit_entry": "_SsVmKeyOnNow", - "unit_nins": 300, - "path": "src/sgap_8.c", - "why": "libsnd VM_NO1.o / VM_NOWON.o (archive exports one function each; game copy differs from lib 4.0); fragment chain j+fallthrough" - }, - { - "binary": "main", - "fn": "VM_NOWON_OBJ_2C8", - "addr": "0x80040c00", - "nins": 67, - "cls": "SDK-C-VERSION", - "disposition": "DECOMPILE-LOW-VALUE", - "unit_entry": "_SsVmKeyOnNow", - "unit_nins": 300, - "path": "src/sgap_8.c", - "why": "libsnd VM_NO1.o / VM_NOWON.o (archive exports one function each; game copy differs from lib 4.0); fragment chain j+fallthrough" - }, - { - "binary": "main", - "fn": "VM_NOWON_OBJ_3D4", - "addr": "0x80040d0c", - "nins": 30, - "cls": "SDK-C-VERSION", - "disposition": "DECOMPILE-LOW-VALUE", - "unit_entry": "_SsVmKeyOnNow", - "unit_nins": 300, - "path": "src/sgap_8.c", - "why": "libsnd VM_NO1.o / VM_NOWON.o (archive exports one function each; game copy differs from lib 4.0); fragment chain j+fallthrough" - }, - { - "binary": "main", - "fn": "VectorNormal", - "addr": "0x80047e6c", - "nins": 11, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "VectorNormal", - "unit_nins": 11, - "path": "src/800b.c", - "why": "libgte hand asm: cop2=0, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "VectorNormalSS", - "addr": "0x80047e98", - "nins": 12, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "VectorNormalSS", - "unit_nins": 12, - "path": "src/800b.c", - "why": "libgte hand asm: cop2=0, multi-entry shared tails, $at/k0 use, hazard nops" - }, { "binary": "main", "fn": "WaitEvent", @@ -1176,18 +252,6 @@ "path": "src/800c3.c", "why": "BIOS A/B/C-table trampoline: li $t2,0xA0/B0/C0; jr $t2; li $t1,N; pad nop (or li $a0; syscall)" }, - { - "binary": "main", - "fn": "_SsVmKeyOnNow", - "addr": "0x80040938", - "nins": 112, - "cls": "SDK-C-VERSION", - "disposition": "DECOMPILE-LOW-VALUE", - "unit_entry": "_SsVmKeyOnNow", - "unit_nins": 300, - "path": "src/sgap_8.c", - "why": "libsnd VM_NO1.o / VM_NOWON.o (archive exports one function each; game copy differs from lib 4.0); fragment chain j+fallthrough" - }, { "binary": "main", "fn": "__do_global_dtors", @@ -1212,606 +276,6 @@ "path": "src/boot.c", "why": "libgcc2.c C compiled -O2 inside the -O0 boot TU (per src comment); gcc-2.7.2 has no per-function opt level" }, - { - "binary": "main", - "fn": "_clr", - "addr": "0x8005af68", - "nins": 20, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "_clr", - "unit_nins": 151, - "path": "src/800c.c", - "why": "inside archived SYS.o function `_clr` (+0x1d34); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "_drs", - "addr": "0x8005b400", - "nins": 24, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "_drs", - "unit_nins": 161, - "path": "src/800c.c", - "why": "inside archived SYS.o function `_drs` (+0x21cc); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "_dws", - "addr": "0x8005b1c4", - "nins": 25, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "_dws", - "unit_nins": 143, - "path": "src/800c.c", - "why": "inside archived SYS.o function `_dws` (+0x1f90); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "func_80013154", - "addr": "0x80013154", - "nins": 43, - "cls": "GAME-C", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_80013154", - "unit_nins": 43, - "path": "src/800.c", - "why": "-O2 leaf, ordinary shape; journal: NEAR closeness 5 (regalloc-local); banked verbatim by asm_verbatim.py with no reason" - }, - { - "binary": "main", - "fn": "func_80047D3C", - "addr": "0x80047d3c", - "nins": 36, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "func_80047d3c", - "unit_nins": 36, - "path": "src/800b.c", - "why": "libgte hand asm: cop2=2, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "func_80047E58", - "addr": "0x80047e58", - "nins": 5, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "func_80047e58", - "unit_nins": 5, - "path": "src/800b.c", - "why": "libgte hand asm: cop2=0, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "func_80047EC8", - "addr": "0x80047ec8", - "nins": 47, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "func_80047ec8", - "unit_nins": 47, - "path": "src/800b.c", - "why": "libgte hand asm: cop2=17, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "func_80049440", - "addr": "0x80049440", - "nins": 7, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "func_80049440", - "unit_nins": 7, - "path": "src/800b_2.c", - "why": "libgte Lzc (lzcs/lzcr) hand asm: cop2=2, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "func_800495EC", - "addr": "0x800495ec", - "nins": 5, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "func_800495ec", - "unit_nins": 9, - "path": "src/800b_3.c", - "why": "libgte SMP_05.o NormalClip (head; tail is the linked SMP_06 4-ins pattern) hand asm: cop2=3, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "func_80049610", - "addr": "0x80049610", - "nins": 3, - "cls": "NOTCODE-PAD", - "disposition": "NOT-CODE", - "unit_entry": "func_80049610", - "unit_nins": 3, - "path": "src/800b_4.c", - "why": "3 x 0x00000000 between SMP_06.o (ends 0x80049610) and CMB_00.o (0x8004961C); no callers, no refs" - }, - { - "binary": "main", - "fn": "func_8004978C", - "addr": "0x8004978c", - "nins": 25, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "func_8004978c", - "unit_nins": 164, - "path": "src/800b_5.c", - "why": "libgte FGO_01.o RotMatrix hand asm: cop2=0, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "func_80049CAC", - "addr": "0x80049cac", - "nins": 25, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "func_80049cac", - "unit_nins": 164, - "path": "src/800b_5.c", - "why": "libgte FGO_03.o hand asm: cop2=0, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "func_8004D16C", - "addr": "0x8004d16c", - "nins": 28, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "func_8004d16c", - "unit_nins": 28, - "path": "src/800b_6.c", - "why": "libgte exception-handler head falling into TRR.o hand asm: cop2=0, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "func_8004D1DC", - "addr": "0x8004d1dc", - "nins": 12, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "func_8004d1dc", - "unit_nins": 116, - "path": "src/800b_6.c", - "why": "libgte exception-handler head falling into TRR.o hand asm: cop2=0, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "func_80052430", - "addr": "0x80052430", - "nins": 12, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "func_80052430", - "unit_nins": 12, - "path": "src/gsgap2.c", - "why": "libgte MTX_07.o TransMatrix hand asm: cop2=0, multi-entry shared tails, $at/k0 use, hazard nops" - }, - { - "binary": "main", - "fn": "func_80059234", - "addr": "0x80059234", - "nins": 71, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_80059234", - "unit_nins": 97, - "path": "src/800c.c", - "why": "inside archived SYS.o function `ResetGraph` (+0x0); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "func_80059760", - "addr": "0x80059760", - "nins": 54, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_80059760", - "unit_nins": 74, - "path": "src/800c.c", - "why": "inside archived SYS.o function `checkRECT` (+0x52c); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "func_80059FC0", - "addr": "0x80059fc0", - "nins": 42, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_80059fc0", - "unit_nins": 298, - "path": "src/800c.c", - "why": "inside archived SYS.o function `PutDispEnv` (+0xd8c); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "func_8005A870", - "addr": "0x8005a870", - "nins": 85, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_8005a870", - "unit_nins": 164, - "path": "src/800c.c", - "why": "inside archived SYS.o function `SetDrawEnv2` (+0x163c); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "func_8005AB00", - "addr": "0x8005ab00", - "nins": 20, - "cls": "SDK-C-FRAG", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "func_8005ab00", - "unit_nins": 22, - "path": "src/800c.c", - "why": "inside archived SYS.o function `get_mode` (+0x18cc); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler | S76 CORRECTION: \u00a7179-C \u2014 no `jr $ra` of its own, falls into a sibling shared epilogue; gcc-2.7.2 appends an epilogue to every C function, so no C spelling exists. Verified by the mechanical no-jr-$ra detector AND independently by three drafting agents." - }, - { - "binary": "main", - "fn": "func_8005AB58", - "addr": "0x8005ab58", - "nins": 16, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_8005ab58", - "unit_nins": 51, - "path": "src/800c.c", - "why": "inside archived SYS.o function `get_cs` (+0x1924); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "func_8005AC24", - "addr": "0x8005ac24", - "nins": 16, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_8005ac24", - "unit_nins": 51, - "path": "src/800c.c", - "why": "inside archived SYS.o function `get_ce` (+0x19f0); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "func_8005ACF0", - "addr": "0x8005acf0", - "nins": 13, - "cls": "SDK-C-FRAG", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "func_8005acf0", - "unit_nins": 17, - "path": "src/800c.c", - "why": "inside archived SYS.o function `get_ofs` (+0x1abc); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler | S76 CORRECTION: \u00a7179-C \u2014 no `jr $ra` of its own, falls into a sibling shared epilogue; gcc-2.7.2 appends an epilogue to every C function, so no C spelling exists. Verified by the mechanical no-jr-$ra detector AND independently by three drafting agents." - }, - { - "binary": "main", - "fn": "func_8005AD34", - "addr": "0x8005ad34", - "nins": 30, - "cls": "SDK-C-FRAG", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "func_8005ad34", - "unit_nins": 33, - "path": "src/800c.c", - "why": "inside archived SYS.o function `get_tw` (+0x1b00); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler | S76 CORRECTION: \u00a7179-C \u2014 no `jr $ra` of its own, falls into a sibling shared epilogue; gcc-2.7.2 appends an epilogue to every C function, so no C spelling exists. Verified by the mechanical no-jr-$ra detector AND independently by three drafting agents." - }, - { - "binary": "main", - "fn": "func_8005ADB8", - "addr": "0x8005adb8", - "nins": 16, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_8005adb8", - "unit_nins": 42, - "path": "src/800c.c", - "why": "inside archived SYS.o function `get_dx` (+0x1b84); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "func_8005BD7C", - "addr": "0x8005bd7c", - "nins": 73, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_8005bd7c", - "unit_nins": 87, - "path": "src/800c.c", - "why": "inside archived SYS.o function `_reset` (+0x2b48); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "func_8005BED8", - "addr": "0x8005bed8", - "nins": 8, - "cls": "SDK-C-FRAG", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "func_8005bed8", - "unit_nins": 8, - "path": "src/800c.c", - "why": "inside archived SYS.o function `_sync` (+0x2ca4); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler | S76 CORRECTION: \u00a7179-C \u2014 no `jr $ra` of its own, falls into a sibling shared epilogue; gcc-2.7.2 appends an epilogue to every C function, so no C spelling exists. Verified by the mechanical no-jr-$ra detector AND independently by three drafting agents." - }, - { - "binary": "main", - "fn": "func_8005C054", - "addr": "0x8005c054", - "nins": 87, - "cls": "SDK-C-FRAG", - "disposition": "DECOMPILE-AS-PARENT", - "unit_entry": "func_8005c054", - "unit_nins": 91, - "path": "src/800c.c", - "why": "inside archived SYS.o function `get_alarm` (+0x2e20); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler" - }, - { - "binary": "main", - "fn": "func_8005C1C0", - "addr": "0x8005c1c0", - "nins": 53, - "cls": "SDK-C-FRAG", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "func_8005c1c0", - "unit_nins": 53, - "path": "src/800c.c", - "why": "inside archived SYS.o function `_version` (+0x2f8c); archive .text byte-identical to the game (psyq_identify 3109 ins); siblings REAL with the pinned compiler | S76 CORRECTION: \u00a7179-C \u2014 no `jr $ra` of its own, falls into a sibling shared epilogue; gcc-2.7.2 appends an epilogue to every C function, so no C spelling exists. Verified by the mechanical no-jr-$ra detector AND independently by three drafting agents." - }, - { - "binary": "main", - "fn": "func_8005CE38", - "addr": "0x8005ce38", - "nins": 0, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "func_8005ce38", - "unit_nins": 0, - "path": "src/800c3.c", - "why": "BIOS A/B/C-table trampoline: li $t2,0xA0/B0/C0; jr $t2; li $t1,N; pad nop (or li $a0; syscall)" - }, - { - "binary": "main", - "fn": "PadInfoAct", - "addr": "0x8005d33c", - "nins": 53, - "cls": "SDK-C-REORDER", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_8005d33c", - "unit_nins": 53, - "path": "src/800c3.c", - "why": "\u00a7188 shape (jr $ra + addiu $sp in slot, 3 restores) \u2014 produced by the as -O2 REORDER island (Makefile REORDER_TUS, landed 2026-09-01, commit:3557); REAL PadInfoMode/_padSioRW/firstfile carry t" - }, - { - "binary": "main", - "fn": "PadInfoComb", - "addr": "0x8005d410", - "nins": 42, - "cls": "SDK-C-REORDER", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_8005d410", - "unit_nins": 42, - "path": "src/800c3.c", - "why": "\u00a7188 shape (jr $ra + addiu $sp in slot, 3 restores) \u2014 produced by the as -O2 REORDER island (Makefile REORDER_TUS, landed 2026-09-01, commit:3557); REAL PadInfoMode/_padSioRW/firstfile carry t" - }, - { - "binary": "main", - "fn": "PadSetActAlign", - "addr": "0x8005d4b8", - "nins": 14, - "cls": "SDK-C-REORDER", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_8005d4b8", - "unit_nins": 14, - "path": "src/800c3.c", - "why": "\u00a7188 shape (jr $ra + addiu $sp in slot, 2 restores) \u2014 produced by the as -O2 REORDER island (Makefile REORDER_TUS, landed 2026-09-01, commit:3557); REAL PadInfoMode/_padSioRW/firstfile carry t" - }, - { - "binary": "main", - "fn": "PadSetMainMode", - "addr": "0x8005d4f0", - "nins": 18, - "cls": "SDK-C-REORDER", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_8005d4f0", - "unit_nins": 18, - "path": "src/800c3.c", - "why": "\u00a7188 shape (jr $ra + addiu $sp in slot, 3 restores) \u2014 produced by the as -O2 REORDER island (Makefile REORDER_TUS, landed 2026-09-01, commit:3557); REAL PadInfoMode/_padSioRW/firstfile carry t" - }, - { - "binary": "main", - "fn": "PadSetAct", - "addr": "0x8005d538", - "nins": 20, - "cls": "SDK-C-REORDER", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_8005d538", - "unit_nins": 20, - "path": "src/800c3.c", - "why": "\u00a7188 shape (jr $ra + addiu $sp in slot, 3 restores) \u2014 produced by the as -O2 REORDER island (Makefile REORDER_TUS, landed 2026-09-01, commit:3557); REAL PadInfoMode/_padSioRW/firstfile carry t" - }, - { - "binary": "main", - "fn": "PadEnableCom", - "addr": "0x8005d588", - "nins": 70, - "cls": "SDK-C-REORDER", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_8005d588", - "unit_nins": 70, - "path": "src/800c3.c", - "why": "\u00a7188 shape (jr $ra + addiu $sp in slot, 4 restores) \u2014 produced by the as -O2 REORDER island (Makefile REORDER_TUS, landed 2026-09-01, commit:3557); REAL PadInfoMode/_padSioRW/firstfile carry t" - }, - { - "binary": "main", - "fn": "func_8005D734", - "addr": "0x8005d734", - "nins": 91, - "cls": "SDK-C-REORDER", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_8005d734", - "unit_nins": 91, - "path": "src/800c3.c", - "why": "reorder-island TU; ordinary C shape; no wall recorded" - }, - { - "binary": "main", - "fn": "_padChkVsync", - "addr": "0x8005d8a0", - "nins": 5, - "cls": "SDK-C-REORDER", - "disposition": "DECOMPILE-NOW", - "unit_entry": "_padChkVsync", - "unit_nins": 5, - "path": "src/800c3.c", - "why": "label-only `asm(\".section .text ... \"_padChkVsync:\")` block MISSED by all three detectors; 5-ins leaf" - }, - { - "binary": "main", - "fn": "_padStartCom", - "addr": "0x8005d8b4", - "nins": 51, - "cls": "SDK-C-REORDER", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_8005d8b4", - "unit_nins": 51, - "path": "src/800c3.c", - "why": "\u00a7188 shape (jr $ra + addiu $sp in slot, 2 restores) \u2014 produced by the as -O2 REORDER island (Makefile REORDER_TUS, landed 2026-09-01, commit:3557); REAL PadInfoMode/_padSioRW/firstfile carry t" - }, - { - "binary": "main", - "fn": "_padWaitRXready", - "addr": "0x8005e13c", - "nins": 11, - "cls": "SDK-C-REORDER", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_8005e13c", - "unit_nins": 11, - "path": "src/800c3.c", - "why": "reorder-island TU; ordinary C shape; no wall recorded" - }, - { - "binary": "main", - "fn": "_padRecvAtLoadInfo", - "addr": "0x8005e228", - "nins": 83, - "cls": "SDK-C-REORDER", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_8005e228", - "unit_nins": 83, - "path": "src/800c3.c", - "why": "\u00a7188 shape (jr $ra + addiu $sp in slot, 2 restores) \u2014 produced by the as -O2 REORDER island (Makefile REORDER_TUS, landed 2026-09-01, commit:3557); REAL PadInfoMode/_padSioRW/firstfile carry t" - }, - { - "binary": "main", - "fn": "_padLoadActInfo", - "addr": "0x8005e3ac", - "nins": 53, - "cls": "SDK-C-REORDER", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_8005e3ac", - "unit_nins": 53, - "path": "src/800c3.c", - "why": "\u00a7188 shape (jr $ra + addiu $sp in slot, 3 restores) \u2014 produced by the as -O2 REORDER island (Makefile REORDER_TUS, landed 2026-09-01, commit:3557); REAL PadInfoMode/_padSioRW/firstfile carry t" - }, - { - "binary": "main", - "fn": "_padSetActAlign", - "addr": "0x8005e79c", - "nins": 26, - "cls": "SDK-C-REORDER", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_8005e79c", - "unit_nins": 26, - "path": "src/800c3.c", - "why": "\u00a7188 shape (jr $ra + addiu $sp in slot, 3 restores) \u2014 produced by the as -O2 REORDER island (Makefile REORDER_TUS, landed 2026-09-01, commit:3557); REAL PadInfoMode/_padSioRW/firstfile carry t" - }, - { - "binary": "main", - "fn": "_padSetMainMode", - "addr": "0x8005e8e8", - "nins": 38, - "cls": "SDK-C-REORDER", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_8005e8e8", - "unit_nins": 38, - "path": "src/800c3.c", - "why": "\u00a7188 shape (jr $ra + addiu $sp in slot, 5 restores) \u2014 produced by the as -O2 REORDER island (Makefile REORDER_TUS, landed 2026-09-01, commit:3557); REAL PadInfoMode/_padSioRW/firstfile carry t" - }, - { - "binary": "main", - "fn": "func_8005EAC8", - "addr": "0x8005eac8", - "nins": 8, - "cls": "SDK-C-REORDER", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_8005eac8", - "unit_nins": 8, - "path": "src/800c3.c", - "why": "reorder-island TU; ordinary C shape; no wall recorded" - }, - { - "binary": "main", - "fn": "func_8005EAE8", - "addr": "0x8005eae8", - "nins": 16, - "cls": "SDK-C-REORDER", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_8005eae8", - "unit_nins": 16, - "path": "src/800c3.c", - "why": "\u00a7188 shape (jr $ra + addiu $sp in slot, 2 restores) \u2014 produced by the as -O2 REORDER island (Makefile REORDER_TUS, landed 2026-09-01, commit:3557); REAL PadInfoMode/_padSioRW/firstfile carry t" - }, - { - "binary": "main", - "fn": "func_8005EB28", - "addr": "0x8005eb28", - "nins": 54, - "cls": "SDK-C-REORDER", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_8005eb28", - "unit_nins": 54, - "path": "src/800c3.c", - "why": "\u00a7188 shape (jr $ra + addiu $sp in slot, 2 restores) \u2014 produced by the as -O2 REORDER island (Makefile REORDER_TUS, landed 2026-09-01, commit:3557); REAL PadInfoMode/_padSioRW/firstfile carry t" - }, - { - "binary": "main", - "fn": "func_8005EC00", - "addr": "0x8005ec00", - "nins": 48, - "cls": "SDK-C-REORDER", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_8005ec00", - "unit_nins": 48, - "path": "src/800c3.c", - "why": "\u00a7188 shape (jr $ra + addiu $sp in slot, 2 restores) \u2014 produced by the as -O2 REORDER island (Makefile REORDER_TUS, landed 2026-09-01, commit:3557); REAL PadInfoMode/_padSioRW/firstfile carry t" - }, - { - "binary": "main", - "fn": "func_8005ED4C", - "addr": "0x8005ed4c", - "nins": 223, - "cls": "SDK-C-REORDER", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_8005ed4c", - "unit_nins": 223, - "path": "src/800c3.c", - "why": "\u00a7188 shape (jr $ra + addiu $sp in slot, 7 restores) \u2014 produced by the as -O2 REORDER island (Makefile REORDER_TUS, landed 2026-09-01, commit:3557); REAL PadInfoMode/_padSioRW/firstfile carry t" - }, - { - "binary": "main", - "fn": "func_8005F450", - "addr": "0x8005f450", - "nins": 159, - "cls": "SDK-C-REORDER", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_8005f450", - "unit_nins": 159, - "path": "src/800c3.c", - "why": "\u00a7188 shape (jr $ra + addiu $sp in slot, 2 restores) \u2014 produced by the as -O2 REORDER island (Makefile REORDER_TUS, landed 2026-09-01, commit:3557); REAL PadInfoMode/_padSioRW/firstfile carry t" - }, { "binary": "main", "fn": "_padInitDirSeq", @@ -1824,102 +288,6 @@ "path": "src/800c3.c", "why": "jr-slot symbolic store shape (as -O2 reorder island form)" }, - { - "binary": "main", - "fn": "_dirFailAuto", - "addr": "0x8005fa94", - "nins": 55, - "cls": "SDK-C-REORDER", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_8005fa94", - "unit_nins": 55, - "path": "src/800c3.c", - "why": "\u00a7188 shape (jr $ra + addiu $sp in slot, 2 restores) \u2014 produced by the as -O2 REORDER island (Makefile REORDER_TUS, landed 2026-09-01, commit:3557); REAL PadInfoMode/_padSioRW/firstfile carry t" - }, - { - "binary": "main", - "fn": "setRC2wait", - "addr": "0x8005fba8", - "nins": 8, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "func_8005fba8", - "unit_nins": 8, - "path": "src/800c3.c", - "why": "jr-slot symbolic store; reads 0x1F801120 (RCNT) \u2014 hand-written" - }, - { - "binary": "main", - "fn": "SetInitPadFlag", - "addr": "0x80062388", - "nins": 3, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "SetInitPadFlag", - "unit_nins": 3, - "path": "src/800c2_2.c", - "why": "lui $at; jr $ra; sw $a0,lo($at) \u2014 hand-written setter (libcard region, 800c2 reorder island)" - }, - { - "binary": "main", - "fn": "PAD_init", - "addr": "0x800623a4", - "nins": 36, - "cls": "SDK-C-REORDER", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_800623a4", - "unit_nins": 36, - "path": "src/800c2_2.c", - "why": "\u00a7188 shape (jr $ra + addiu $sp in slot, 5 restores) \u2014 produced by the as -O2 REORDER island (Makefile REORDER_TUS, landed 2026-09-01, commit:3557); REAL PadInfoMode/_padSioRW/firstfile carry t" - }, - { - "binary": "main", - "fn": "InitPAD", - "addr": "0x80062434", - "nins": 36, - "cls": "SDK-C-REORDER", - "disposition": "DECOMPILE-NOW", - "unit_entry": "InitPAD", - "unit_nins": 36, - "path": "src/800c2_2.c", - "why": "\u00a7188 shape (jr $ra + addiu $sp in slot, 5 restores) \u2014 produced by the as -O2 REORDER island (Makefile REORDER_TUS, landed 2026-09-01, commit:3557); REAL PadInfoMode/_padSioRW/firstfile carry t" - }, - { - "binary": "main", - "fn": "func_8006252C", - "addr": "0x8006252c", - "nins": 30, - "cls": "SDK-C-REORDER", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_8006252c", - "unit_nins": 30, - "path": "src/800c2_2.c", - "why": "\u00a7188 shape (jr $ra + addiu $sp in slot, 2 restores) \u2014 produced by the as -O2 REORDER island (Makefile REORDER_TUS, landed 2026-09-01, commit:3557); REAL PadInfoMode/_padSioRW/firstfile carry t" - }, - { - "binary": "main", - "fn": "EnablePAD", - "addr": "0x800626c8", - "nins": 5, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "func_800626c8", - "unit_nins": 5, - "path": "src/800c2_3.c", - "why": "lui/lw/nop/jr $t1 through jtbl_80078D20 \u2014 vector hook" - }, - { - "binary": "main", - "fn": "DisablePAD", - "addr": "0x800626dc", - "nins": 5, - "cls": "SDK-ASM", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "func_800626dc", - "unit_nins": 5, - "path": "src/800c2_3.c", - "why": "lui/lw/nop/jr $t1 through jtbl_80078D24 \u2014 vector hook" - }, { "binary": "main", "fn": "_patch_pad", @@ -1946,87 +314,15 @@ }, { "binary": "main", - "fn": "gfx2D_BG0_OBJ_1B4", - "addr": "0x800509c0", - "nins": 187, - "cls": "SDK-C-VERSION", - "disposition": "DECOMPILE-LOW-VALUE", - "unit_entry": "GsSortBg", - "unit_nins": 526, - "path": "src/800b_7.c", - "why": "libgs 2D_BG0.o/2D_BG1.o (archive exports one function each; game copy differs); `break 7` div traps = gcc" - }, - { - "binary": "main", - "fn": "gfx2D_BG0_OBJ_4A0", - "addr": "0x80050cac", - "nins": 14, - "cls": "SDK-C-VERSION", - "disposition": "DECOMPILE-LOW-VALUE", - "unit_entry": "GsSortBg", - "unit_nins": 526, - "path": "src/800b_7.c", - "why": "libgs 2D_BG0.o/2D_BG1.o (archive exports one function each; game copy differs); `break 7` div traps = gcc" - }, - { - "binary": "main", - "fn": "gfx2D_BG0_OBJ_4D8", - "addr": "0x80050ce4", - "nins": 96, - "cls": "SDK-C-VERSION", - "disposition": "DECOMPILE-LOW-VALUE", - "unit_entry": "GsSortBg", - "unit_nins": 526, - "path": "src/800b_7.c", - "why": "libgs 2D_BG0.o/2D_BG1.o (archive exports one function each; game copy differs); `break 7` div traps = gcc" - }, - { - "binary": "main", - "fn": "gfx2D_BG0_OBJ_658", - "addr": "0x80050e64", - "nins": 16, - "cls": "SDK-C-VERSION", - "disposition": "DECOMPILE-LOW-VALUE", - "unit_entry": "GsSortBg", - "unit_nins": 526, - "path": "src/800b_7.c", - "why": "libgs 2D_BG0.o/2D_BG1.o (archive exports one function each; game copy differs); `break 7` div traps = gcc" - }, - { - "binary": "main", - "fn": "gfx2D_BG0_OBJ_698", - "addr": "0x80050ea4", - "nins": 104, - "cls": "SDK-C-VERSION", - "disposition": "DECOMPILE-LOW-VALUE", - "unit_entry": "GsSortBg", - "unit_nins": 526, - "path": "src/800b_7.c", - "why": "libgs 2D_BG0.o/2D_BG1.o (archive exports one function each; game copy differs); `break 7` div traps = gcc" - }, - { - "binary": "main", - "fn": "gfx2D_BG1_OBJ_648", - "addr": "0x8005168c", - "nins": 94, - "cls": "SDK-C-VERSION", - "disposition": "DECOMPILE-LOW-VALUE", - "unit_entry": "GsSortFastBg", - "unit_nins": 496, - "path": "src/800b_7.c", - "why": "libgs 2D_BG0.o/2D_BG1.o (archive exports one function each; game copy differs); `break 7` div traps = gcc" - }, - { - "binary": "main", - "fn": "main", - "addr": "0x80010178", - "nins": 509, - "cls": "GAME-C", - "disposition": "DECOMPILE-NOW", - "unit_entry": "main", - "unit_nins": 509, - "path": "src/boot.c", - "why": "-O0 body (addu $fp,$sp) in the -O0 boot TU; prologue/epilogue/jr ra; NO wall recorded (commit commit:3066); 1 stored draft" + "fn": "func_8005CE38", + "addr": "0x8005ce38", + "nins": 0, + "cls": "SDK-ASM", + "disposition": "PERMANENT-VERBATIM", + "unit_entry": "func_8005ce38", + "unit_nins": 0, + "path": "src/800c3.c", + "why": "BIOS A/B/C-table trampoline: li $t2,0xA0/B0/C0; jr $t2; li $t1,N; pad nop (or li $a0; syscall)" }, { "binary": "main", @@ -2040,6 +336,18 @@ "path": "src/800c3.c", "why": "BIOS A/B/C-table trampoline: li $t2,0xA0/B0/C0; jr $t2; li $t1,N; pad nop (or li $a0; syscall)" }, + { + "binary": "main", + "fn": "setRC2wait", + "addr": "0x8005fba8", + "nins": 8, + "cls": "SDK-ASM", + "disposition": "PERMANENT-VERBATIM", + "unit_entry": "func_8005fba8", + "unit_nins": 8, + "path": "src/800c3.c", + "why": "jr-slot symbolic store; reads 0x1F801120 (RCNT) \u2014 hand-written" + }, { "binary": "main", "fn": "start", @@ -2052,18 +360,6 @@ "path": "src/boot.c", "why": "crt0: `addi` (trapping add), break 1, $gp load; splat Handwritten" }, - { - "binary": "main", - "fn": "vmNoiseOn", - "addr": "0x800403a4", - "nins": 97, - "cls": "SDK-C-VERSION", - "disposition": "DECOMPILE-LOW-VALUE", - "unit_entry": "vmNoiseOn", - "unit_nins": 305, - "path": "src/sgap_7.c", - "why": "libsnd VM_NO1.o / VM_NOWON.o (archive exports one function each; game copy differs from lib 4.0); fragment chain j+fallthrough" - }, { "binary": "main", "fn": "write", @@ -2076,138 +372,6 @@ "path": "src/800c3.c", "why": "BIOS A/B/C-table trampoline: li $t2,0xA0/B0/C0; jr $t2; li $t1,N; pad nop (or li $a0; syscall)" }, - { - "binary": "md_MAIN_003", - "fn": "func_800D0100", - "addr": "0x800d0100", - "nins": 29, - "cls": "GAME-O0-CARVED", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_800D0100", - "unit_nins": 29, - "path": "src/md_MAIN_003/md_MAIN_003_o0e.c", - "why": "-O0 body (addu $fp,$sp) now living in md_MAIN_003_o0e.c \u2014 an _o0? TU the Makefile compiles -O0 (S68 glob); prior MATCH drafts recorded in the block comments" - }, - { - "binary": "md_MAIN_003", - "fn": "func_800D0174", - "addr": "0x800d0174", - "nins": 36, - "cls": "GAME-O0-CARVED", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_800D0174", - "unit_nins": 36, - "path": "src/md_MAIN_003/md_MAIN_003_o0e.c", - "why": "-O0 body (addu $fp,$sp) now living in md_MAIN_003_o0e.c \u2014 an _o0? TU the Makefile compiles -O0 (S68 glob); prior MATCH drafts recorded in the block comments" - }, - { - "binary": "md_MAIN_003", - "fn": "func_800D0204", - "addr": "0x800d0204", - "nins": 25, - "cls": "GAME-O0-CARVED", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_800D0204", - "unit_nins": 25, - "path": "src/md_MAIN_003/md_MAIN_003_o0e.c", - "why": "-O0 body (addu $fp,$sp) now living in md_MAIN_003_o0e.c \u2014 an _o0? TU the Makefile compiles -O0 (S68 glob); prior MATCH drafts recorded in the block comments" - }, - { - "binary": "md_MAIN_003", - "fn": "func_800D0440", - "addr": "0x800d0440", - "nins": 93, - "cls": "GAME-O0-CARVED", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_800D0440", - "unit_nins": 93, - "path": "src/md_MAIN_003/md_MAIN_003_o0e.c", - "why": "-O0 body (addu $fp,$sp) now living in md_MAIN_003_o0e.c \u2014 an _o0? TU the Makefile compiles -O0 (S68 glob); prior MATCH drafts recorded in the block comments" - }, - { - "binary": "md_MAIN_003", - "fn": "func_800D05B4", - "addr": "0x800d05b4", - "nins": 44, - "cls": "GAME-O0-CARVED", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_800D05B4", - "unit_nins": 44, - "path": "src/md_MAIN_003/md_MAIN_003_o0e.c", - "why": "-O0 body (addu $fp,$sp) now living in md_MAIN_003_o0e.c \u2014 an _o0? TU the Makefile compiles -O0 (S68 glob); prior MATCH drafts recorded in the block comments" - }, - { - "binary": "md_MAIN_003", - "fn": "func_800D0664", - "addr": "0x800d0664", - "nins": 22, - "cls": "GAME-O0-CARVED", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_800D0664", - "unit_nins": 22, - "path": "src/md_MAIN_003/md_MAIN_003_o0e.c", - "why": "-O0 body (addu $fp,$sp) now living in md_MAIN_003_o0e.c \u2014 an _o0? TU the Makefile compiles -O0 (S68 glob); prior MATCH drafts recorded in the block comments" - }, - { - "binary": "md_MAIN_003", - "fn": "func_800D06BC", - "addr": "0x800d06bc", - "nins": 33, - "cls": "GAME-O0-CARVED", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_800D06BC", - "unit_nins": 33, - "path": "src/md_MAIN_003/md_MAIN_003_o0e.c", - "why": "-O0 body (addu $fp,$sp) now living in md_MAIN_003_o0e.c \u2014 an _o0? TU the Makefile compiles -O0 (S68 glob); prior MATCH drafts recorded in the block comments" - }, - { - "binary": "md_MAIN_003", - "fn": "func_800D09A0", - "addr": "0x800d09a0", - "nins": 55, - "cls": "GAME-O0-CARVED", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_800D09A0", - "unit_nins": 55, - "path": "src/md_MAIN_003/md_MAIN_003_o0e.c", - "why": "-O0 body (addu $fp,$sp) now living in md_MAIN_003_o0e.c \u2014 an _o0? TU the Makefile compiles -O0 (S68 glob); prior MATCH drafts recorded in the block comments" - }, - { - "binary": "md_MAIN_003", - "fn": "func_800D0A7C", - "addr": "0x800d0a7c", - "nins": 40, - "cls": "GAME-O0-CARVED", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_800D0A7C", - "unit_nins": 40, - "path": "src/md_MAIN_003/md_MAIN_003_o0e.c", - "why": "-O0 body (addu $fp,$sp) now living in md_MAIN_003_o0e.c \u2014 an _o0? TU the Makefile compiles -O0 (S68 glob); prior MATCH drafts recorded in the block comments" - }, - { - "binary": "md_MAIN_003", - "fn": "func_800D0B1C", - "addr": "0x800d0b1c", - "nins": 77, - "cls": "GAME-O0-CARVED", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_800D0B1C", - "unit_nins": 77, - "path": "src/md_MAIN_003/md_MAIN_003_o0e.c", - "why": "-O0 body (addu $fp,$sp) now living in md_MAIN_003_o0e.c \u2014 an _o0? TU the Makefile compiles -O0 (S68 glob); prior MATCH drafts recorded in the block comments" - }, - { - "binary": "md_MAIN_003", - "fn": "func_800D1D14", - "addr": "0x800d1d14", - "nins": 65, - "cls": "GAME-O0-CARVED", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_800D1D14", - "unit_nins": 65, - "path": "src/md_MAIN_003/md_MAIN_003_o0d.c", - "why": "-O0 body (addu $fp,$sp) now living in md_MAIN_003_o0d.c \u2014 an _o0? TU the Makefile compiles -O0 (S68 glob); prior MATCH drafts recorded in the block comments" - }, { "binary": "md_MAIN_003", "fn": "func_800D3204", @@ -2232,114 +396,6 @@ "path": "src/md_MAIN_003/md_MAIN_003_jr_800D1E18.c", "why": "`add`/`addi` (trapping) arithmetic throughout, no frame, $at use \u2014 hand-written (MDEC-side)" }, - { - "binary": "md_MAIN_020", - "fn": "func_800CB17C", - "addr": "0x800cb17c", - "nins": 30, - "cls": "GAME-C", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_800CB17C", - "unit_nins": 30, - "path": "src/md_MAIN_020/md_MAIN_020.c", - "why": "ordinary -O2 shape (prologue, 7 jal, epilogue); no reason recorded; 69 stored drafts, no journal note" - }, - { - "binary": "ov_MAIN_012", - "fn": "func_80163408", - "addr": "0x80163408", - "nins": 21, - "cls": "FALSE-POSITIVE", - "disposition": "NOT-VERBATIM", - "unit_entry": "func_80163408", - "unit_nins": 21, - "path": "src/ov_MAIN_012/ov_MAIN_012_jr_8015A3C8.c", - "why": "real C body (memcpy + call / register pin + call); asm_in_c class-B misread an `__asm__(\"sym\")` label or register pin as an asm body" - }, - { - "binary": "ov_MAIN_012", - "fn": "func_801634D8", - "addr": "0x801634d8", - "nins": 23, - "cls": "FALSE-POSITIVE", - "disposition": "NOT-VERBATIM", - "unit_entry": "func_801634D8", - "unit_nins": 23, - "path": "src/ov_MAIN_012/ov_MAIN_012_jr_8015A3C8.c", - "why": "real C body (memcpy + call / register pin + call); asm_in_c class-B misread an `__asm__(\"sym\")` label or register pin as an asm body" - }, - { - "binary": "ov_SC01_001", - "fn": "func_80181E04", - "addr": "0x80181e04", - "nins": 269, - "cls": "GAME-GTE", - "disposition": "UNCERTAIN", - "unit_entry": "func_80181E04", - "unit_nins": 269, - "path": "src/ov_SC01_001/ov_SC01_001_jr_8017D2DC.c", - "why": "cop2=13 of 269 ins; no reason recorded" - }, - { - "binary": "ov_SC02_037", - "fn": "func_80163408", - "addr": "0x80163408", - "nins": 21, - "cls": "FALSE-POSITIVE", - "disposition": "NOT-VERBATIM", - "unit_entry": "func_80163408", - "unit_nins": 21, - "path": "src/ov_SC02_037/ov_SC02_037_jr_8015A3C8.c", - "why": "real C body (memcpy + call / register pin + call); asm_in_c class-B misread an `__asm__(\"sym\")` label or register pin as an asm body" - }, - { - "binary": "ov_SC02_037", - "fn": "func_801634D8", - "addr": "0x801634d8", - "nins": 23, - "cls": "FALSE-POSITIVE", - "disposition": "NOT-VERBATIM", - "unit_entry": "func_801634D8", - "unit_nins": 23, - "path": "src/ov_SC02_037/ov_SC02_037_jr_8015A3C8.c", - "why": "real C body (memcpy + call / register pin + call); asm_in_c class-B misread an `__asm__(\"sym\")` label or register pin as an asm body" - }, - { - "binary": "ov_SC03_105", - "fn": "func_80185810", - "addr": "0x80185810", - "nins": 489, - "cls": "GAME-GTE", - "disposition": "UNCERTAIN", - "unit_entry": "func_80185810", - "unit_nins": 489, - "path": "src/ov_SC03_105/ov_SC03_105_jr_80181C84.c", - "why": "cop2=110 of 489 ins; \u00a7265 precedent; 110 cop2 ops" - }, - { - "binary": "ov_SC03_107", - "fn": "func_80163408", - "addr": "0x80163408", - "nins": 21, - "cls": "FALSE-POSITIVE", - "disposition": "NOT-VERBATIM", - "unit_entry": "func_80163408", - "unit_nins": 21, - "path": "src/ov_SC03_107/ov_SC03_107_jr_8015A3C8.c", - "why": "real C body (memcpy + call / register pin + call); asm_in_c class-B misread an `__asm__(\"sym\")` label or register pin as an asm body" - }, - { - "binary": "ov_SC03_107", - "fn": "func_801634D8", - "addr": "0x801634d8", - "nins": 23, - "cls": "FALSE-POSITIVE", - "disposition": "NOT-VERBATIM", - "unit_entry": "func_801634D8", - "unit_nins": 23, - "path": "src/ov_SC03_107/ov_SC03_107_jr_8015A3C8.c", - "why": "real C body (memcpy + call / register pin + call); asm_in_c class-B misread an `__asm__(\"sym\")` label or register pin as an asm body" - }, { "binary": "ov_SC03_107", "fn": "func_8017D878", @@ -2351,66 +407,6 @@ "unit_nins": 45, "path": "src/ov_SC03_107/ov_SC03_107_jr_801789AC.c", "why": "ordinary -O2 shape; block comment gives semantics but no wall; 37 stored drafts" - }, - { - "binary": "ov_SC05_005", - "fn": "func_80181828", - "addr": "0x80181828", - "nins": 87, - "cls": "GAME-GTE", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "func_80181828", - "unit_nins": 87, - "path": "src/ov_SC05_005/ov_SC05_005_jr_8017D898.c", - "why": "cop2=7 of 87 ins; splat Handwritten tag (heuristic); mult/GTE | S76 CORRECTION: handwritten GTE (SQR lane); the drafting agent transcribed the .s 1:1 and reported the target as hand-written, not compiler output." - }, - { - "binary": "ov_SC06_010", - "fn": "func_801809E4", - "addr": "0x801809e4", - "nins": 33, - "cls": "GAME-C", - "disposition": "DECOMPILE-NOW", - "unit_entry": "func_801809E4", - "unit_nins": 33, - "path": "src/ov_SC06_010/ov_SC06_010_jr_8017A4AC.c", - "why": "journal: 2 attempts MATCH closeness 0 (\u00a717 pin `register s16 mask __asm__(\"$19\")`) \u2014 a matching C body exists; banked verbatim anyway (C-PLUMBING per \u00a7451)" - }, - { - "binary": "ov_SC06_032", - "fn": "func_8017D810", - "addr": "0x8017d810", - "nins": 33, - "cls": "GAME-GTE", - "disposition": "PERMANENT-VERBATIM", - "unit_entry": "func_8017D810", - "unit_nins": 33, - "path": "src/ov_SC06_032/ov_SC06_032_jr_8017C24C.c", - "why": "cop2=7 of 33 ins; GTE SQR distance check, 7 cop2 | S76 CORRECTION: handwritten GTE (SQR lane); the drafting agent transcribed the .s 1:1 and reported the target as hand-written, not compiler output." - }, - { - "binary": "ov_SC07_000", - "fn": "func_8017EEC0", - "addr": "0x8017eec0", - "nins": 8, - "cls": "FALSE-POSITIVE", - "disposition": "NOT-VERBATIM", - "unit_entry": "func_8017EEC0", - "unit_nins": 8, - "path": "src/ov_SC07_000/ov_SC07_000_jr_8017ECB4.c", - "why": "real C body (memcpy + call / register pin + call); asm_in_c class-B misread an `__asm__(\"sym\")` label or register pin as an asm body" - }, - { - "binary": "ov_SC07_002", - "fn": "func_8017DC80", - "addr": "0x8017dc80", - "nins": 346, - "cls": "GAME-GTE", - "disposition": "UNCERTAIN", - "unit_entry": "func_8017DC80", - "unit_nins": 346, - "path": "src/ov_SC07_002/ov_SC07_002_jr_8017C8D0.c", - "why": "cop2=29 of 346 ins; splat Handwritten; ~20 drafts plateaued LENGTH-DRIFT" } ] } \ No newline at end of file diff --git a/docs/SETUP.md b/docs/SETUP.md index 08f794472..355114e99 100644 --- a/docs/SETUP.md +++ b/docs/SETUP.md @@ -729,14 +729,15 @@ Every script under `tools/` (plus the two report make-targets), grouped by purpo | **PsyQ library linking** (cookbook §8/§9) | `tools/psyq_lib_split.py` | Split a PsyQ `.LIB` into per-object members. | | | `tools/psyq_build_libs.sh` | Build the PsyQ libs from split members. | | | `tools/psyq_identify.py` | Identify which SDK objects a region's functions belong to. | -| | `tools/psyq_link.py` | Link identified PsyQ objects into the build. | +| | `tools/psyq_link.py` | Link identified PsyQ objects into the build. **P31 S78 #4:** `link_object` first runs `psyq_bss_split.prepare_object` (the same prepare step the region verify and the build use), so its PASS/FAIL is the build's verdict for scattered-`.bss` objects; links with `--no-check-sections` like the build. | +| | `tools/psyq_bss_split.py` | **(P31 S78 #4, cookbook §489)** Splits a PsyQ object's scattered `.bss` into per-base NOBITS pieces (`.bss`, `.bss2`, …) — a pure-Python ELF32 REL rewrite: bases derived from the game bytes per HI16/LO16 pair, runs in offset order, cuts snapped to symbol starts, relocs retargeted with the addend rewritten in place, self-checked. Refuses (loud, R43) a sized symbol straddling a cut or a HI16 shared across pieces. Runs automatically inside `psyq_link` / `psyq_link_region` / `psyq_integrate` (`prepare_object`); the CLI reports a plan (`--vram --exe --vram-base`, `-o` to write). Takes SYS.o (2 pieces), VM_F.o (2), GS_001.o (6). | | | `tools/psyq_link_lib.py` | Per-library link driver. | | | `tools/psyq_link_region.py` | Link a specific address region from PsyQ libs. | | | `tools/progress.py` (weighted main) | **(P31 S78)** `MAIN game-code weighted` now excludes LINKED subsegs LIVE (`_main_linked_ranges`: Makefile `psyq_integrate` stub lists → yaml ranges, R33); the 2026-08-05 sig had carried all linked-SDK instructions, under-reporting main by ~32 points (59.8% → 91.8%). | | | `tools/psyq_integrate.py` | Integrate linked PsyQ results back into the source tree. **P31 S78:** `--yaml ` (every main call passes `$(main_SPLAT_YAML)`) maps stub↔objects by SUBSEG RANGE with an exact-tiling check and PRINTS the located-but-unwired objects (`~~ N located object(s) / M ins OUTSIDE the stub subsegs`) — the completion contract's SDK-residue line; and a library object's DEFINED symbol whose recovered address the curated symbol file names differently is `--redefine-sym`'d to the curated name (R15; e.g. libapi 4.0 `A66.o` `firstfile`→`firstfile2`). Without `--yaml` the old contiguity mapping runs (overlay-free libraries only). | | | `tools/make_libgs.sh` | Build/link the `libgs` block (cookbook §9). | | | `tools/gen_lib_subsegs.py` | **(Phase 8)** Generate splat subseg lines + integrate stub list for a multi-block library (section-size-correct boundaries; cookbook §9.6). | -| | `tools/make_snd_used.py` | **(Phase 8)** Build the combined libspu+libsnd curated dir (alias dedup by byte-match, scattered-`.bss` exclusions; §9.6). | +| | `tools/make_snd_used.py` | **(Phase 8)** Build the combined libspu+libsnd curated dir (alias dedup by byte-match; 3 address exclusions since S78 #4 — VM_F rejoined via the `.bss` split; §9.6). | | | `tools/make_apicard_used.py` | **(Phase 8)** Build the combined libapi+libcard curated dir (§9.6). | | | `tools/ld_interleave.py` | Interleave linker inputs to match the original section ordering. Three forms: `--front/--tail` (the original data->rodata->data sandwich), **`--order`** (P31 S72 — an address-ordered leaf list, needed once a binary owns SEVERAL `.rodata` carves: a `*.data.o` leaf contributes its `(.data)`, a code-object leaf its `(.rodata)`; main's island is a 7-piece sandwich `--front/--tail` cannot express), and **`--pre`** (P31 S74, cookbook §440 — a piece that must land BEFORE the text). `--pre` exists for the **resident**, which opens with `- [0x0, rodata, hdr]`, a 1-word `.rodata` header ahead of its code: every `--order` piece is emitted after TEXT_START, so `hdr.rodata.o(.rodata)` would fall into the unchecked `empties` bucket, be parked after the text, and move every byte in the binary. | | | `tools/jtbl_rodata_pads.py` | **(Phase 29, cookbook §8e)** Post-maspsx filter for multi-table `.rodata` carve spans: REPLACES each cc1 `.align 3` (which is section-relative and would mis-pad a merged/4-mod-8 span) with the ORIGINAL's exact pad bytes per the object's `JTBL_PADS` spec (written by `jtbl_carve` into `config/overlays.mk`; armed via `$(if $(JTBL_PADS),…)` in the Makefile `build/src/%.o` recipe). Fail-loud on table-count drift / non-`.align 3` / non-jtbl rodata content. Unset var ⇒ pipeline byte-identical. | @@ -983,11 +984,21 @@ fills fast). Nothing is leaking — but the host does not get the memory back on |---|---|---| | `tools/gate_main_parallel.py` **(NEW)** | runs the REAL `gate_main` inside N git worktrees to discover which drafts pass, then hands the union to ONE authoritative `gate_main` in the real tree. Workers discover; only the final serial pass banks | a main slate large enough that serial bisection hurts. **Measured: one gate cycle is 16 s**, so MAX_STEPS=24 is ~6.4 min serial and ~90 s across four workers. Run `--negative-control` once per environment first | | `tools/permuter_sweep.py` **(NEW)** | selects a wave's NEARs the permuter can actually search (small residual + SCHEDULE/DELAY-SLOT/REGALLOC class) and runs `permuter_ils` on them; journals are scoped to the wave so an older run's row cannot win on a bare fn name (R48) | after every wave gate — agents are briefed to STOP at permuter-class residuals, so these arrive unattempted and cost no tokens. Measured yield ~3 in 8; there is NO validated predictor of which 3 | -| `tools/psyq_bss_probe.py` **(NEW)** | derives a PsyQ object's `.bss` bases FROM THE BYTES (base = resolved − addend over each HI16/LO16 pair) and reports whether the offset ranges are DISJOINT, i.e. whether the section can be split and placed | before accepting any "scattered .bss, unlinkable" exclusion. Measured: SYS.o splits at 0x148 (2 bases), GS_001.o does not (5 interleaved), 2D_BG0.o/VM_NO1.o have no `.bss` at all. Locates the object itself by masked search, so a wrong `--vram` cannot fake a clean answer (cookbook §484) | +| `tools/psyq_bss_probe.py` **(NEW)** | derives a PsyQ object's `.bss` bases FROM THE BYTES (base = resolved − addend over each HI16/LO16 pair) and reports whether the section can be cut into single-base pieces | before accepting any "scattered .bss, unlinkable" exclusion. Measured S76: SYS.o splits at 0x148 (2 bases), 2D_BG0.o/VM_NO1.o have no `.bss` at all. **S78 #4 correction:** its "GS_001.o: 5 interleaved bases, NOT splittable" grouped by BASE; grouped by RUN in offset order GS_001 is six pieces, every cut on a symbol start — it now reports over `psyq_bss_split.analyze` (one implementation, R33). Locates the object itself by masked search, so a wrong `--vram` cannot fake a clean answer (cookbook §484/§489) | | `make sig-main-oracle` **(NEW)** | main's INDEPENDENT second boundary oracle (roadmap contract §1.3): signs the ORIGINAL EXE bytes over 28 game-code ranges derived from the splat yaml's SEGMENT TYPES, never its function boundaries | run by `tools-health`; needed before any 100% claim on main. Distinct from `make sig-main`, which is splat-SEEDED on purpose — `corpus.ORACLE_SIG` keeps the audit off that one. Result: 986 fns, 0 phantom / 0 truncated / 1 pad-tail (docs/second-oracle.md) | | `tools/recover_route.py` **(NEW)** | reads a gate's DROP ledger and names the tool that actually applies — SELF / CALLEE / DATA, each with its ordered ladder; refuses a verbatim draft up front. Wired into `gate_main`'s dropped report | after any gate that drops a draft. Replaces the single hardcoded chain gate_main used to print for every drop, which was the SELF chain and measured RED on a callee (S69) and inert on data. Negative-controlled against all 7 S77 drops whose winning tool was already known | | `tools/sync_tu_decls.py` **(NEW)** | banks a draft the gate refuses by copying the TU's OWN `extern` line for whatever symbol the gate names, re-gating, and repeating | a draft that is byte-correct but rejected on a declaration conflict. Refuses `self_decl_tu` (use `cast_self_callers --sync-decls`) and refuses a NEAR up front, since syncing declarations makes a body COMPILE, never MATCH | +### Tools added / changed 2026-09-04 (S79, task #4) — R21 record + +| tool | what it does | when you need it | +|---|---|---| +| `tools/psyq_bss_split.py` **(NEW)** | rewrites a PsyQ ELF object whose `.bss` is referenced through the SECTION symbol at several bases into per-base NOBITS pieces (`.bss`/`.bss2`/…): bases from the game bytes, runs in offset order, cuts snapped to symbol starts, symbols moved, a LOCAL section symbol per piece inserted (REL symbol indices bumped), relocs retargeted with the addend rewritten in the instruction immediates, then self-diffed. No pyelftools — its own 60-line ELF32 reader/writer | never by hand: `psyq_link.link_object`, `psyq_link_region.build_region` and `psyq_integrate.integrate` all call `prepare_object()` before `classify()`, so every library build splits what needs splitting and passes the rest through untouched (R39: 235 placed objects, 0 refusals, exactly 3 splits). CLI = the plan report (` --vram --exe --vram-base [-o out.o]`) | +| `tools/psyq_bss_probe.py` | now a thin reporter over `psyq_bss_split.analyze` (its own pairing code deleted, R33); "SPLITTABLE" means "tiles into single-base runs at symbol boundaries", which is what the build does | as before — before believing any scattered-`.bss` exclusion | +| `tools/psyq_link.py` / `psyq_link_region.py` / `psyq_integrate.py` | the NOBITS predicate is `^\.s?bss\d*$` (was the literal pair `.bss`/`.sbss`), so split pieces are NOLOAD-placed from their own section symbols; `link_object` links with `--no-check-sections` like the build (piece extents tile the PACKED section, so unreferenced commons overlap other pieces harmlessly) | automatic | +| `LIBGPU_ELF := .run/obj40/libgpu` | the `libgpu_used` curated dir is retired (it existed only to exclude SYS.o); `psyq_identify` drops the 8 objects the EXE never links | fresh clone: `tools/psyq_build_libs.sh LIBGPU` is now the whole libgpu step | +| `tools/make_libgs.sh` (+GS_001) / `tools/make_snd_used.py` (VM_F rejoined) | curated dirs now carry the two objects the split unlocked: libgs 34 objects / 8 blocks (`libgs8`), sound 63 / 12 (`snd12`) | re-run after `psyq_build_libs.sh` on a fresh clone | + **Oracle corrections — re-read any verdict recorded before these:** * `match_one` and `rtu_match` now route the Makefile's `REORDER_TUS` (`800c2 800c2_2 800c2_3 800c3`) through `reorder_passthrough.py + as -O2`, the real build path. They previously modelled diff --git a/docs/accelerators.md b/docs/accelerators.md index baf9ddec4..695d4a7ee 100644 --- a/docs/accelerators.md +++ b/docs/accelerators.md @@ -663,3 +663,17 @@ frontier's own stub sum (~4,000 ins), and nobody subtracted the two. One subtrac the denominator was carrying the 31,000 linked-SDK instructions. Accelerator: **every headline % ships with its remainder, and the remainder is reconciled against an independently-derived list of what is actually open.** + +## S79 — "no single base" means "partition it", and partition along the producer's structure + +Three SDK objects sat excluded for twenty-three phases as "scattered `.bss`, no single NOLOAD base". +The general fix (cut the section into per-base NOBITS pieces at link-prepare, ~400 lines of ELF +surgery, `tools/psyq_bss_split.py`) took one afternoon and closed the class 3/3 — including the object +the previous session's probe had certified as a genuine wall, because that probe grouped by base while +the original linker had scattered SYMBOLS. Accelerators: **(1)** a "no single X" verdict is a +partition problem, not a wall — build the partition the day the exclusion is written; **(2)** partition +along the structure the original producer used (the symbol table), and confirm every cut against an +independent oracle (here the other objects' by-name recoveries agreed on all seven cuts); **(3)** put +the transformation in the shared prepare path, not in a curated artifact, so it is re-derived from the +bytes on every build and negative-controlled over the whole placed population for free. + diff --git a/docs/cookbook-index.md b/docs/cookbook-index.md index 0be8d45b6..05032e735 100644 --- a/docs/cookbook-index.md +++ b/docs/cookbook-index.md @@ -2,7 +2,7 @@ > **Generated by `tools/cookbook_index.py` — do not hand-edit** (R33). Regenerate after adding a cookbook section. > -> `docs/matching-cookbook.md` is ~716 KB / 1156 sections. Grepping it blind is how three P30 wave-1 agents each "discovered" an idiom that was already written down. **Start here, then read the section.** A section appears under every symptom it addresses. +> `docs/matching-cookbook.md` is ~716 KB / 1157 sections. Grepping it blind is how three P30 wave-1 agents each "discovered" an idiom that was already written down. **Start here, then read the section.** A section appears under every symptom it addresses. **How to use:** name what you SEE in the diff (a stolen delay slot, an extra `la`, a swapped register pair, a `conflicting types` error), find that symptom below, read those sections first. If nothing fits, THEN grind — and add a section when you win. @@ -1080,7 +1080,7 @@ - **§442** — ★★★ — A RECOVERY RUNG THAT REWRITES A LEGAL CONSTRUCT INTO AN ILLEGAL ONE READS EXACTLY LIKE A CODEGEN WALL (P31 S75; `reconcile_tu`, 344 ins unblocked) L34647 - **§477** — ★★★ — THE `self_decl_tu` CLASS IS A SOLVED, MECHANICAL LANE: 16 DRAFTS, 16 BANKS (P31 S77) L35713 -### build graph, splat & the harness (208) +### build graph, splat & the harness (209) - **§4** — Flag/toolchain gotchas L190 - **Build** — mechanism — per-file opt override (splat resegmentation) L307 @@ -1290,6 +1290,7 @@ - **§485** — ★★★ — THE PLACEMENT MAP WAS PARSING A PRETTY-PRINTER: 25 PsyQ OBJECTS WERE INVISIBLE, NOT ABSENT (P31 S77) L36069 - **§487** — ★★★ — THE PSX LOADER'S PER-VERSION SIGNATURE SETS ARE A FREE PROVENANCE ORACLE: main's "WALL" BAND IS LIBPAD 4.2.1 (P31 S78) L36150 - **§488** — ★★ — THE "GAME CODE" GAPS BETWEEN LIBRARY BLOCKS WERE LIBRARY OBJECTS: 13 SUBSEGS → LINKED, EXACT-TILED, ZERO TOKENS (P31 S78) L36202 +- **§489** — ★★★ — SCATTERED `.bss` IS A PARTITION PROBLEM: SPLIT THE SECTION INTO PER-BASE PIECES AT LINK-PREPARE (P31 S78 #4; closes the §9.1 exclusion class 3/3) L36242 ### process, measurement & doctrine (141) @@ -2934,6 +2935,7 @@ - **§486** — ★★★ — CARVING AN `-O0` ISLAND IN **main**: FIVE COUPLED PIECES, AND THE TWO THAT ANNOUNCE THEMSELVES (P31 S77) L36105 - **§487** — ★★★ — THE PSX LOADER'S PER-VERSION SIGNATURE SETS ARE A FREE PROVENANCE ORACLE: main's "WALL" BAND IS LIBPAD 4.2.1 (P31 S78) L36150 - **§488** — ★★ — THE "GAME CODE" GAPS BETWEEN LIBRARY BLOCKS WERE LIBRARY OBJECTS: 13 SUBSEGS → LINKED, EXACT-TILED, ZERO TOKENS (P31 S78) L36202 +- **§489** — ★★★ — SCATTERED `.bss` IS A PARTITION PROBLEM: SPLIT THE SECTION INTO PER-BASE PIECES AT LINK-PREPARE (P31 S78 #4; closes the §9.1 exclusion class 3/3) L36242 --- @@ -4102,3 +4104,4 @@ Notes routinely quote that as a section id. This table resolves it. Grep bait: ` | L36105 | §486 | ★★★ — CARVING AN `-O0` ISLAND IN **main**: FIVE COUPLED PIECES, AND THE TWO THAT ANNOUNCE | | L36150 | §487 | ★★★ — THE PSX LOADER'S PER-VERSION SIGNATURE SETS ARE A FREE PROVENANCE ORACLE: main's "WA | | L36202 | §488 | ★★ — THE "GAME CODE" GAPS BETWEEN LIBRARY BLOCKS WERE LIBRARY OBJECTS: 13 SUBSEGS → LINKED | +| L36242 | §489 | ★★★ — SCATTERED `.bss` IS A PARTITION PROBLEM: SPLIT THE SECTION INTO PER-BASE PIECES AT L | diff --git a/docs/decision-log.md b/docs/decision-log.md index aa59e1a50..78517f031 100644 --- a/docs/decision-log.md +++ b/docs/decision-log.md @@ -3111,3 +3111,33 @@ exclusion derived live (Makefile stub lists → yaml ranges), main reads **91.8% the remainder equals the open-stub instruction sum to the instruction. Hindsight: a metric whose denominator is a snapshot will drift the first time the thing it snapshots changes; derive it (R33), and check it against a case whose answer you already know (the 28 stubs' size). + +### S79 addendum (2026-09-04, task #4) — the "scattered-`.bss`" wall class is closed, and the probe that measured it was too strict + +**Belief.** From Phase 8 to P31 S77 three SDK objects were excluded from the LINKED build as "scattered +`.bss` commons — no single NOLOAD base reproduces them": SYS.o (3,109 ins, kept as 56 hand-matched +Sony functions + 62 verbatim frags in `src/800c.c`), VM_F.o (237, hand-matched as game code in +`sgap_6`), GS_001.o (384, hand-matched as game code in `gsgap3`). S77's probe reframed two of them as +"disjoint ranges → splittable" and confirmed GS_001 as the genuine wall ("5 interleaved bases"). + +**What happened.** Task #4 built the split as a link-time ELF rewrite (`psyq_bss_split.py`, §489) +instead of a curated-dir artifact, and modelled the section as RUNS of one base in offset order with +cuts snapped to symbol starts — because the original linker scattered *symbols*, not offset ranges. +Under that model GS_001 is six symbol-aligned pieces, and the five cut symbols recover by name from +the other libgs objects at exactly the piece bases. All three link byte-identical; main is `143dbb89` +with and without the SDK objects; 235 placed objects across nine curated dirs pass through with zero +refusals. + +**Why the probe was wrong.** It grouped references BY BASE and asked whether the per-base offset ranges +were disjoint. A common that the linker placed between two others (PSDBASEY at +0x38 sits between +PSDBASEX at +0x28 and CLIP2 at +0x30 in the packed section, but in the game X and Y are adjacent) +makes two ranges interleave while every run is still single-base. The right unit was the run; the +right tie-breaker was the symbol table. + +**Hindsight.** The worklist's own italic note from Phase 8 said "escalate to a Max general fix (split +each object's `.bss` into per-common NOLOAD sections)". That fix is ~400 lines and one afternoon; it +waited twenty-three phases because three exclusions never looked worth a general mechanism, and the +probe's stricter test then ratified one of them as a wall. General form: when a tool says "no single +X reproduces it", the next question is "can X be partitioned", and the partition should follow the +structure the ORIGINAL producer used (here: symbols), not the structure the measurement happened to +group by. diff --git a/docs/difficulty.md b/docs/difficulty.md index 85874d08a..de57d7bcc 100644 --- a/docs/difficulty.md +++ b/docs/difficulty.md @@ -1,8 +1,8 @@ # Unmatched difficulty inventory (generated by tools/difficulty.py — harvest queue) -unmatched functions : 1069 -trivial (<=5 ins) : 228 -non-jtbl leaves : 734 (best harvest targets) +unmatched functions : 1179 +trivial (<=5 ins) : 238 +non-jtbl leaves : 797 (best harvest targets) jump-table funcs : 36 (deferred — need the rodata-island workflow, Task 2') ## Easiest 120 unmatched (score asc) — the work queue @@ -30,6 +30,7 @@ jump-table funcs : 36 (deferred — need the rodata-island workflow, Task | 1 | PRNT_OBJ_2A0 | 1 | 0 | 0 | - | Y | | 1 | PRNT_OBJ_348 | 1 | 0 | 0 | - | Y | | 1 | PRNT_OBJ_3D0 | 1 | 0 | 0 | - | Y | +| 1 | SYS_OBJ_1C28 | 1 | 0 | 0 | - | Y | | 1 | S_SR_OBJ_B0 | 1 | 0 | 0 | - | Y | | 2 | INTR_DMA_OBJ_274 | 2 | 0 | 0 | - | Y | | 2 | LIBMCRD_OBJ_1A60 | 2 | 0 | 0 | - | Y | @@ -39,6 +40,7 @@ jump-table funcs : 36 (deferred — need the rodata-island workflow, Task | 2 | PRIM_OBJ_228 | 2 | 0 | 0 | - | Y | | 2 | SR_SV_OBJ_224 | 2 | 0 | 0 | - | Y | | 2 | SR_SV_OBJ_2F4 | 2 | 0 | 0 | - | Y | +| 2 | SYS_OBJ_191C | 2 | 0 | 0 | - | Y | | 2 | S_ITC_OBJ_88 | 2 | 0 | 0 | - | Y | | 2 | S_SCA_OBJ_15C | 2 | 0 | 0 | - | Y | | 2 | S_SCA_OBJ_94 | 2 | 0 | 0 | - | Y | @@ -49,6 +51,7 @@ jump-table funcs : 36 (deferred — need the rodata-island workflow, Task | 3 | MIDIREAD_OBJ_6C0 | 3 | 0 | 0 | - | Y | | 3 | PRESET2_OBJ_A88 | 3 | 0 | 0 | - | Y | | 3 | PRNT_OBJ_380 | 3 | 0 | 0 | - | Y | +| 3 | SYS_OBJ_1B78 | 3 | 0 | 0 | - | Y | | 3 | SetDQA | 3 | 0 | 0 | - | Y | | 3 | SetDQB | 3 | 0 | 0 | - | Y | | 3 | SetData32 | 3 | 0 | 0 | - | Y | @@ -59,6 +62,8 @@ jump-table funcs : 36 (deferred — need the rodata-island workflow, Task | 4 | CdLastCom | 4 | 0 | 0 | - | Y | | 4 | GEO_00_OBJ_2C | 4 | 0 | 0 | - | Y | | 4 | GS_108_OBJ_7C | 4 | 0 | 0 | - | Y | +| 4 | GetGraphDebug | 4 | 0 | 0 | - | Y | +| 4 | GetGraphType | 4 | 0 | 0 | - | Y | | 4 | GsGetActiveBuff | 4 | 0 | 0 | - | Y | | 4 | LIBMCRD_OBJ_15C | 4 | 0 | 0 | - | Y | | 4 | LIBMCRD_OBJ_1944 | 4 | 0 | 0 | - | Y | @@ -71,6 +76,8 @@ jump-table funcs : 36 (deferred — need the rodata-island workflow, Task | 4 | SSSTART_OBJ_240 | 2 | 0 | 1 | - | - | | 4 | SSSTART_OBJ_248 | 2 | 0 | 1 | - | - | | 4 | SSSTART_OBJ_328 | 4 | 0 | 0 | - | Y | +| 4 | SYS_OBJ_1AF0 | 4 | 0 | 0 | - | Y | +| 4 | SYS_OBJ_2F7C | 4 | 0 | 0 | - | Y | | 4 | S_RRWA_OBJ_40 | 4 | 0 | 0 | - | Y | | 4 | S_SAV_OBJ_1E8 | 4 | 0 | 0 | - | Y | | 4 | S_SAV_OBJ_1F8 | 4 | 0 | 0 | - | Y | @@ -121,10 +128,3 @@ jump-table funcs : 36 (deferred — need the rodata-island workflow, Task | 5 | PRNT_OBJ_F4 | 2 | 1 | 0 | - | Y | | 5 | RATAN_OBJ_148 | 5 | 0 | 0 | - | Y | | 5 | SPU_OBJ_848 | 5 | 0 | 0 | - | Y | -| 5 | SR_SV_OBJ_1EC | 2 | 1 | 0 | - | Y | -| 5 | SR_SV_OBJ_1F4 | 2 | 1 | 0 | - | Y | -| 5 | SR_SV_OBJ_1FC | 2 | 1 | 0 | - | Y | -| 5 | SR_SV_OBJ_204 | 2 | 1 | 0 | - | Y | -| 5 | SR_SV_OBJ_20C | 2 | 1 | 0 | - | Y | -| 5 | SR_SV_OBJ_214 | 2 | 1 | 0 | - | Y | -| 5 | SR_SV_OBJ_21C | 2 | 1 | 0 | - | Y | diff --git a/docs/matching-cookbook.md b/docs/matching-cookbook.md index 06b0b99e1..c7337a25f 100644 --- a/docs/matching-cookbook.md +++ b/docs/matching-cookbook.md @@ -36238,3 +36238,62 @@ the fresh-clone fallback: move `.run/obj40` aside, **re-extract**, build, restor deleted, REAL −4 (inline-asm wrappers), 0 agent tokens. Remaining LINKED residue: `SYS.o` (3,109), `VM_F` (237), the libpad/libapi band pieces (task #5), `SSGM.o` (8 ins amid matched C), and the GS_001 / S_R / S_GRMDT scattered-`.bss` genuine walls. + +#### §489 ★★★ — SCATTERED `.bss` IS A PARTITION PROBLEM: SPLIT THE SECTION INTO PER-BASE PIECES AT LINK-PREPARE (P31 S78 #4; closes the §9.1 exclusion class 3/3) + +**The wall (§9.1, Phase 8).** psyq-obj-parser packs an object's common-style globals into ONE `.bss` with +sequential offsets; the original linker allocated those commons individually, so the game has them at +unrelated addresses. A common referenced BY NAME is weakened and `--defsym`'d (§9.2). But the compiler +references the object's own statics through the `.bss` SECTION SYMBOL + offset — no name to defsym — and +one section can be NOLOAD-placed at only one base. SYS.o (2 bases), VM_F.o (2) and GS_001.o (6) were +excluded on that reason for twenty-three phases; §484 (S77) asked whether the bases' offset ranges were +disjoint and said yes for two of them, "no, interleaved" for GS_001. + +**The model that is actually right: RUNS, cut at SYMBOL starts.** Walk the section-symbol references in +offset order; each maximal run with one base is a piece. The cut between two runs snaps to the largest +symbol start between them, because the linker scattered *symbols*: SYS.o's second run begins inside `_que` +(+0x148) and the piece begins at `_que` (+0x144) — and `_que`, recovered BY NAME from SYS.o's own four +named references, is 0x800C5510 = base2 + 0x144; VM_F.o's second run begins at `_svm_sreg_buf` (+0x508), +which 62 other sound objects recover to 0x800B9B58 = base2 + 0x508; GS_001.o's five cuts land on +PSDBASEX / CLIP2 / PSDBASEY / POSITION / GsDRAWENV, all five recovered by the other libgs objects at exactly +the piece bases. Two unrelated oracles agree on all seven cuts (R34). §484's "interleaved" verdict came +from grouping by BASE: PSDBASEY (+0x38) sits between PSDBASEX (+0x28) and CLIP2 (+0x30) in the packed +section while X and Y are adjacent in the game — two base-ranges interleave, every run is single-base. +Refuse (R43) only what the run model cannot tile: a SIZED symbol straddling a cut (one common at two +bases), a HI16 whose LO16s need different pieces or high halves, an orphan LO16, a far-out addend. + +**The rewrite** (`tools/psyq_bss_split.py`, its own 60-line ELF32 REL reader/writer — no pyelftools): +new NOBITS sections `.bss2…` sized [s_k, s_k+1); the original shrunk to [0, s_2); symbols at/after a cut +moved (value −= piece start); one LOCAL section symbol per piece inserted with the existing section +symbols and every later symbol index in every REL entry bumped; each reference retargeted to its piece's +symbol with the addend rewritten in place — HI16/LO16 immediates in `.text` (`hi' = (A'+0x8000)>>16`, +`lo' = A' & 0xFFFF`, `A' = A − s_k`; a shared `lui` is one cluster and all its LO16s must agree), or the +R_MIPS_32 word in data. `classify()` then recovers one base per piece from the piece's own section symbol +(base = resolved − addend, tautologically the game's address) and NOLOAD-places each; the NOBITS predicate +in `psyq_link` / `psyq_link_region` / `psyq_integrate` is `^\.s?bss\d*$`. Self-check: the code/data +sections differ from the original at exactly the retargeted sites whose value changed (R37, the tool +diffs its own artifact). + +**Where it runs, and why there.** Not in the curated dirs — inside the ONE prepare step that +`psyq_link.link_object` (per-object verify), `psyq_link_region.build_region` (region verify) and +`psyq_integrate.integrate` (the build) share (`prepare_object()`, before `classify()`). The split is +re-derived from the bytes on every build — no recorded offset to go stale (R51) — and the same call is the +negative control: 235 placed objects across the 9 curated dirs, 0 refusals, exactly 3 splits (R39). The +first build DID refuse: a libcd object references `.bss + size` (an end-of-buffer pointer) and the strict +`addend < size` bound fired on an object one base already served. Law that fell out: **problems found +while classifying references are fatal only when a split is actually needed** — an object that passed +before this tool existed must pass through it untouched. + +**Two things the extents are NOT.** A piece's extent tiles the PACKED section, so an unreferenced common +inside piece k may in truth live inside piece j's game range (GS_001's PSDBASEX/PSDBASEY: adjacent in the +game, 16 bytes apart in the object) — NOLOAD pieces therefore overlap, harmlessly (zero bytes), and the +verifiers link with `--no-check-sections` exactly like the build. And a named common whose recovered +address disagrees with its piece is still handled by §9.2's weaken+defsym — the split only serves the +section-symbol references; the two mechanisms compose. + +**Yield.** `800c` (56 hand-matched Sony functions + 62 verbatim frags, 100% SYS.o) → `libgpu2`; +`gsgap3` (hand-matched as game C) → `libgs8`; `_SsVmFlush` out of `sgap_6` → `snd12`. `libgpu_used` +retired (`LIBGPU_ELF` = the raw dir; identify drops the 8 objects the EXE never links). Main `143dbb89` +with and without the SDK objects. The class that remains in the sound region — `S_R`/`S_W`, `S_GRMDT*` — +has NO `.bss` of its own (cross-object commons at a minority address): a different wall, not this one. + diff --git a/docs/progress.fleet.md b/docs/progress.fleet.md index 874844a82..2eeaf485a 100644 --- a/docs/progress.fleet.md +++ b/docs/progress.fleet.md @@ -4,21 +4,21 @@ # cross-binary collapsible-byte leverage: docs/duplicates.cross.md. # THREE progress metrics (all matter — see the labels): -FLEET fn-count byte-ident: 363098 / 363149 = 99.99% (REAL+LINKED+empties; FUNCTION-count, ×134-inflated — one crack counts per overlay) -FLEET instr-weighted : 13485298 / 13492892 = 99.9% (shipped .text across main + resident + 211 overlays; the decomp.dev-DISPLAY number) -FLEET distinct-code(uniq): 5813544 / 5820999 = 99.9% (90909/90929 unique fns; the DISTINCT-RE number) -MAIN game-code weighted : 44562 / 48537 = 91.8% (INCLUDED in the fleet numbers above since 2026-07-22 — roadmap §1 metrics contract; LINKED-excluding Ghidra sig dated 2026-08-05; boundaries INDEPENDENTLY VERIFIED since P31 S77 — `make sig-main-oracle` + `make audit-corpus`: 0 phantom, 0 truncated, 1 explained pad-tail) +FLEET fn-count byte-ident: 363105 / 363156 = 99.99% (REAL+LINKED+empties; FUNCTION-count, ×134-inflated — one crack counts per overlay) +FLEET instr-weighted : 13481631 / 13489225 = 99.9% (shipped .text across main + resident + 211 overlays; the decomp.dev-DISPLAY number) +FLEET distinct-code(uniq): 5809877 / 5817332 = 99.9% (90909/90929 unique fns; the DISTINCT-RE number) +MAIN game-code weighted : 40895 / 44870 = 91.1% (INCLUDED in the fleet numbers above since 2026-07-22 — roadmap §1 metrics contract; LINKED-excluding Ghidra sig dated 2026-08-05; boundaries INDEPENDENTLY VERIFIED since P31 S77 — `make sig-main-oracle` + `make audit-corpus`: 0 phantom, 0 truncated, 1 explained pad-tail) (fleet EXCLUDING main, for continuity with pre-2026-07-22 readings: 13440736 / 13444355 = 100.0%) -FLEET REAL substantive : 360755 (of which dedup-shared 255632 via 2220 groups / 255708 instances) -FLEET LINKED PsyQ objs : 1040 +FLEET REAL substantive : 360708 (of which dedup-shared 255632 via 2220 groups / 255708 instances) +FLEET LINKED PsyQ objs : 1150 FLEET NON_MATCHING : 0 (0 in any default build — G4) FLEET INCLUDE_ASM stubs : 51 -FLEET matchable : 363149 +FLEET matchable : 363156 | binary | REAL | shared | LINKED | byte-ident | matchable | byte-ident % | |---|---:|---:|---:|---:|---:|---:| -| main | 886 | 2 | 1040 | 2054 | 2083 | 98.6% | +| main | 839 | 2 | 1150 | 2061 | 2090 | 98.6% | | resident | 141 | 0 | 0 | 143 | 145 | 98.6% | | md_MAIN_001 | 11 | 0 | 0 | 11 | 11 | 100.0% | | md_MAIN_003 | 53 | 0 | 0 | 59 | 64 | 92.2% | diff --git a/docs/progress.md b/docs/progress.md index a049c8c66..96806c3c8 100644 --- a/docs/progress.md +++ b/docs/progress.md @@ -1,20 +1,20 @@ # BFM matching progress (generated by tools/progress.py — authoritative) -REAL substantive matches : 886 <- the Gen1-exit >=25 bar counts THIS +REAL substantive matches : 839 <- the Gen1-exit >=25 bar counts THIS (of which dedup-shared : 2 one body -> N sites, config/dedup.us.yaml) -LINKED real PsyQ objects : 1040 <- byte-identical via linked SDK objects -VERBATIM __asm__ bodies : 85 <- §265: BYTES, NOT A DECOMPILE (byte-identical by construction, unexplained; NOT counted in REAL) +LINKED real PsyQ objects : 1150 <- byte-identical via linked SDK objects +VERBATIM __asm__ bodies : 29 <- §265: BYTES, NOT A DECOMPILE (byte-identical by construction, unexplained; NOT counted in REAL) NON_MATCHING (near-miss) : 0 splat-auto empty no-ops : 43 INCLUDE_ASM stubs : 29 data blobs (excluded) : 1 ---------------------------------------- -matchable functions : 2083 -REAL / matchable : 886 / 2083 = 42.53% -byte-identical/ matchable: 2054 / 2083 = 98.61% (REAL+LINKED+empties+VERBATIM) +matchable functions : 2090 +REAL / matchable : 839 / 2090 = 40.14% +byte-identical/ matchable: 2061 / 2090 = 98.61% (REAL+LINKED+empties+VERBATIM) -LINKED subsegs: apicard1 apicard2 apicard3 apicard4 libc2_1 libc2_2 libcd1 libcd2 libetc libgpu libgs1 libgs2 libgs3 libgs4 libgs5 libgs6 libgs7 libgte1 libgte10 libgte11 libgte12 libgte13 libgte14 libgte15 libgte16 libgte17 libgte18 libgte19 libgte2 libgte20 libgte21 libgte22 libgte23 libgte24 libgte25 libgte26 libgte27 libgte28 libgte29 libgte3 libgte30 libgte4 libgte5 libgte6 libgte7 libgte8 libgte9 libmcrd1 libmcrd2 snd1 snd10 snd11 snd2 snd3 snd4 snd5 snd6 snd7 snd8 snd9 (1040 fns) -REAL matches: CdQueueBusy CdReadRequest CdReadSectorReadyCB CdReadStateMachine ClearImage2 ClearOTag DebugMenuHandler DrawOTagEnv DrawPrim DsDataCallback DsReadyCallback DsSyncCallback GameModeDispatch GetDispEnv GetDrawEnv GetGraphDebug GetGraphType GetODE GetRCnt GsInitGraph2_body GsTMDfastF3GL GsTMDfastF3GNL GsTMDfastF4GL GsTMDfastF4GNL GsTMDfastG3GL GsTMDfastG3GNL GsTMDfastG4GL GsTMDfastG4GNL InitPAD LoaderInitFileTable LoaderResetReadState LzssDecodeSector MoveImage PAD_init PadChkMtap PadChkVsync PadEnableCom PadGetState PadInfoComb PadInfoMode PadSetAct PadSetActAlign PadSetMainMode PadStartCom PadStopCom ReadInitPadFlag ResetRCnt ResourceGetCdLoc ResourceLoadStateMachine SYS_OBJ_191C SYS_OBJ_19D8 SYS_OBJ_1AA4 SYS_OBJ_1AF0 SYS_OBJ_1B78 SetDrawArea SetDrawOffset SetGraphQueue SetPriority SetRCnt SetTexWindow SpuWrite SsGetMute SsUtReverbOff StartPAD StartRCnt StopPAD StopRCnt StoreImage StreamLoadStateMachine _SsSndPlay _addque _cwb _getctl _padClrIntSio0 _padCmdParaMode _padGetActSize _padLoadActInfo _padRecvAtLoadInfo _padSendAtLoadInfo _padSetAct _padSetActAlign _padSetCmd _padSetVsyncParam _padSioRW _padSioRW2 _padStopCom _padWaitRXready _status aF800301A4 chkRC2wait firstfile func_8001096C func_8001099C func_80010A08 func_80010A98 func_80010AE0 func_80010B10 func_80010BB4 func_80010C7C func_80010CEC func_80010D60 func_80010DA0 func_80010DE0 func_80010E14 func_80010E48 func_80010E7C func_80010ED4 func_80010F80 func_800110CC func_800111BC func_80011220 func_8001125C func_800112C8 func_80011320 func_80011350 func_80011680 func_800116E0 func_80011778 func_80011818 func_800118AC func_80011928 func_80011998 func_800119F0 func_80011A3C func_80011ADC func_80011B7C func_80011C10 func_80011C8C func_80011CFC func_80011D54 func_80011DA0 func_80011DCC func_80011DF4 func_80011E24 func_80011E84 func_80011EB4 func_800120DC func_8001212C func_800123F0 func_80012558 func_800126C4 func_8001282C func_800128B4 func_800128EC func_800129CC func_80012A60 func_80012AB0 func_80012ABC func_80012B04 func_80012B58 func_80012C6C func_80012CB8 func_80012D0C func_80012DBC func_80012E0C func_80012E6C func_80012F74 func_80012FC8 func_80013028 func_800130D0 func_8001311C func_80013154 func_80013200 func_80013228 func_80013294 func_800132BC func_80013328 func_80013350 func_800133BC func_800133E4 func_80013450 func_80013478 func_800134FC func_80013694 func_8001382C func_800139C8 func_80013B64 func_80013CFC func_80013E94 func_80013ED0 func_80013F3C func_80013F68 func_80013F98 func_80013FBC func_80013FE0 func_80014004 func_80014028 func_8001404C func_80014070 func_80014094 func_800140B8 func_80014128 func_80014148 func_80014168 func_800141AC func_800141F0 func_80014238 func_800142C8 func_80014338 func_80014390 func_800143AC func_80014444 func_800144D4 func_80014564 func_80014588 func_800145EC func_800146B0 func_80014774 func_800147B8 func_80014928 func_80014960 func_80014998 func_800149E0 func_80014B10 func_80014BFC func_80014C28 func_80014C54 func_80014CAC func_80014CF8 func_80014D30 func_80014D68 func_80014D94 func_80014DC0 func_80014DEC func_80014E24 func_80014E80 func_80014ED4 func_80015018 func_80015118 func_80015144 func_80015208 func_800152F4 func_80015310 func_8001534C func_800153A4 func_800153CC func_80015424 func_8001544C func_80015498 func_80015908 func_80015954 func_80015978 func_8001599C func_800159C0 func_800159E4 func_80015A08 func_80015A2C func_80015A50 func_80015A74 func_80015AD0 func_80015D4C func_80015F04 func_80016110 func_80016224 func_80016450 func_80016638 func_800166E8 func_80016714 func_800167B8 func_800167F0 func_800168B4 func_800168C4 func_80016940 func_80016978 func_80016A3C func_80016A5C func_80016A7C func_80016B60 func_80016C28 func_80016D78 func_80016EB0 func_80016ED4 func_80016EF8 func_80016F18 func_80017168 func_80017254 func_80017274 func_80017294 func_8001739C func_800173BC func_800173DC func_800174DC func_800174FC func_8001751C func_800176F0 func_80017714 func_80017738 func_80017758 func_80017778 func_800178C8 func_800178EC func_80017910 func_80017930 func_80017B98 func_80017D98 func_80017DC4 func_80017DF8 func_80017E30 func_80017E68 func_80017E8C func_80017F14 func_80018094 func_80018194 func_8001820C func_80018384 func_800183E0 func_80018450 func_800184F0 func_80018918 func_800189A8 func_80018A20 func_80018C64 func_80018CE8 func_80018E78 func_80018E9C func_80018F20 func_80018F88 func_80018FC8 func_80019018 func_80019028 func_8001903C func_80019064 func_800190AC func_80019198 func_800191A8 func_800191BC func_800191D4 func_8001923C func_8001931C func_80019378 func_80019388 func_80019398 func_800193A8 func_800193B8 func_80019930 func_80019A10 func_8001A0FC func_8001A114 func_8001A9D8 func_8001A9F8 func_8001AA78 func_8001AA88 func_8001AAA0 func_8001AAD0 func_8001ABBC func_8001ACF0 func_8001AE90 func_8001AF04 func_8001AF34 func_8001B0D4 func_8001B22C func_8001B23C func_8001B26C func_8001B324 func_8001B34C func_8001B374 func_8001B384 func_8001B394 func_8001B710 func_8001B7C4 func_8001B85C func_8001B86C func_8001BA84 func_8001BADC func_8001BB60 func_8001BBBC func_8001BDA0 func_8001BE20 func_8001BE30 func_8001BFA0 func_8001BFB0 func_8001BFD0 func_8001BFE8 func_8001BFF8 func_8001C00C func_8001C044 func_8001C0C8 func_8001C14C func_8001C1E4 func_8001C214 func_8001C2C4 func_8001C320 func_8001C448 func_8001C4A4 func_8001C558 func_8001C5B8 func_8001C6E4 func_8001C744 func_8001C7B0 func_8001C810 func_8001C8C4 func_8001C924 func_8001C97C func_8001C9D0 func_8001CA1C func_8001CA88 func_8001CB00 func_8001CB6C func_8001CBDC func_8001CC3C func_8001CCA0 func_8001CD04 func_8001CD50 func_8001CD9C func_8001CDE8 func_8001CE28 func_8001CE68 func_8001CEC0 func_8001CF00 func_8001CF30 func_8001CF48 func_8001CFB8 func_8001CFDC_impl func_8001D050 func_8001D074_impl func_8001D0E8 func_8001D0F4 func_8001D130 func_8001D150 func_8001D16C func_8001D1C4 func_8001D388 func_8001D3FC func_8001D70C func_8001D8C4 func_8001DA34 func_8001E094 func_8001E378 func_8001E668 func_8001E7E0 func_8001EA14 func_8001F730 func_8001F97C func_8001F9F8 func_8001FB8C func_8001FC08 func_80020248 func_80020598 func_80020A28 func_80020F34 func_80021008 func_80021050 func_8002109C func_80021120 func_80021174 func_80021284 func_800215F4 func_80021D38 func_800221A8 func_800226C0 func_80023138 func_800233CC func_800234E4 func_80023570 func_8002374C func_80024054 func_800241C0 func_800242D0 func_800243EC func_80024448 func_800249F0 func_80024BC0 func_80024DE8 func_80025000 func_8002528C func_80025504 func_80025818 func_80025A30 func_80025CBC func_80025EB8 func_80026128 func_800262D8 func_80026514 func_800268D0 func_80026D64 func_80027058 func_80027200 func_800273F4 func_800275BC func_800277DC func_800279AC func_80027BF0 func_80027C10 func_80027D20 func_80027F4C func_80028200 func_8002823C func_80028304 func_80028394 func_80028428 func_80028488 func_80028558 func_800285CC func_80028620 func_80028694 func_80028A48 func_80028C50 func_80028D58 func_80028D78 func_80028D9C func_80028DBC func_80028DE0 func_80028E00 func_80028E24 func_80028E44 func_80028E68 func_80028E88 func_80028EAC func_80028ECC func_80028EF0 func_80028F10 func_80028F34 func_80028F54 func_80028F78 func_80028F98 func_80028FBC func_80028FDC func_80029000 func_80029020 func_80029044 func_8002906C func_80029094 func_800290BC func_800290E0 func_80029104 func_80029124 func_80029178 func_800291A0 func_800291B4 func_800291C8 func_800291DC func_800291F0 func_80029204 func_80029218 func_80029240 func_80029254 func_80029264 func_80029274 func_8002931C func_80029344 func_8002941C func_80029444 func_80029504 func_80029514 func_80029524 func_8002953C func_8002954C func_8002955C func_8002957C func_8002958C func_8002959C func_800295D4 func_80029664 func_80029690 func_800296F8 func_80029774 func_800298BC func_8002992C func_80029A58 func_80029A94 func_80029AAC func_80029AF4 func_80029B4C func_80029BC8 func_80029C44 func_80029CD4 func_80029D3C func_80029DB4 func_80029E30 func_80029E94 func_80029EC0 func_80029ED4 func_80029FD4 func_80029FE4 func_8002A04C func_8002A088 func_8002A108 func_8002A1B4 func_8002A200 func_8002A234 func_8002A26C func_8002A27C func_8002A28C func_8002A2B0 func_8002A2D4 func_8002A354 func_8002A400 func_8002A44C func_8002A480 func_8002A4B8 func_8002A4C8 func_8002A4D8 func_8002A4FC func_8002A520 func_8002A544 func_8002A5C4 func_8002A670 func_8002A6BC func_8002A6F0 func_8002A728 func_8002A738 func_8002A748 func_8002A76C func_8002A790 func_8002A7B4 func_8002A834 func_8002A8E0 func_8002A92C func_8002A960 func_8002A998 func_8002A9A8 func_8002A9B8 func_8002A9DC func_8002AA00 func_8002AA3C func_8002AAB4 func_8002AB64 func_8002AC00 func_8002AE60 func_8002AED0 func_8002AEE4 func_8002AEF8 func_8002AF08 func_8002AF18 func_8002AF48 func_8002AF60 func_8002AF70 func_8002B00C func_8002B064 func_8002B08C func_8002B0B4 func_8002C320 func_8002C3B0 func_8002C410 func_8002C8BC func_8002C8F4 func_8002CC4C func_8002CCB4 func_8002CCD8 func_8002CDD8 func_8002CFE4 func_8002D034 func_8002D1F0 func_8002D240 func_8002D29C func_8002D320 func_8002D4B8 func_8002D4C8 func_8002D59C func_8002D678 func_8002D6D8 func_8002D7FC func_8002D80C func_8002D834 func_8002D844 func_8002D858 func_8002D8A8 func_8002D8D4 func_8002D904 func_8002DC68 func_8002DF80 func_8002E138 func_8002E5BC func_8002E5F8 func_8002E638 func_8002E700 func_8002E79C func_8002E818 func_8002E8DC func_8002E94C func_8002EA10 func_8002EAB0 func_8002EB10 func_8002EBAC func_8002EC10 func_8002ED90 func_8002EDE4 func_8002EE64 func_8002EE90 func_8002EEB8 func_8002EED8 func_8002EFD0 func_8002EFF8 func_8002F064 func_8002F0D0 func_8002F0F4 func_8002F12C func_8002F150 func_8002F1CC func_8002F248 func_8002F4E4 func_8002F5C8 func_8002F620 func_8002F648 func_8002F658 func_8002F67C func_8002F714 func_8002F80C func_8002FA3C func_8002FAE0 func_8002FB08 func_8002FC64 func_8002FD14 func_8002FDC8 func_8002FF0C func_800301C8 func_80030470 func_800304C8 func_80030538 func_80030634 func_80030730 func_80030A14 func_80030CA4 func_80030D80 func_80030F80 func_800314DC func_800316F8 func_80031988 func_80031A98 func_80031B7C func_80031BE0 func_80031CC8 func_80031D70 func_80031DEC func_80031E94 func_80031F14 func_80031FC8 func_80032048 func_800322A8 func_800324A4 func_80032774 func_8003310C func_800331D4 func_8003324C func_80033324 func_80033398 func_8003350C func_800335B8 func_800336A8 func_8003388C func_800342E8 func_80034314 func_80034650 func_800346D0 func_800347C8 func_80034844 func_800348A8 func_8003491C func_80034A54 func_80034A9C func_80034AE0 func_80034B0C func_80034B3C func_80034C24 func_80034CF0 func_80034DFC func_8003500C func_800351E8 func_80035210 func_80035270 func_800359B0 func_80035C4C func_8003602C func_80036130 func_800361CC func_8003621C func_80036260 func_80036AF8 func_80036D24 func_80036D58 func_80036EB4 func_80036EE8 func_80036F18 func_80036F98 func_80036FB0 func_80037004 func_80037028 func_80037144 func_80037334 func_80037358 func_80037368 func_800373D0 func_800374CC func_8003750C func_8003775C func_800377D8 func_80037CC8 func_80037CD8 func_80037D74 func_80037D98 func_80037EA0 func_80037F3C func_80037FC4 func_8003819C func_800381E4 func_80038210 func_80038308 func_8003834C func_8003836C func_800383A4 func_800384A8 func_800385C0 func_80038638 func_80038668 func_800387C0 func_80038838 func_800388E8 func_80038908 func_80038958 func_80038A00 func_80038A58 func_80038FC4 func_80038FFC func_8003916C func_80039C5C func_80039C70 func_80039F14 func_80039F50 func_8003A098 func_8003A0D0 func_8003A0E4 func_8003A234 func_8003A3D8 func_8003A404 func_8003A424 func_8003D424 func_8003D630 func_8003DC90 func_8003DF8C func_8003FA54 func_8003FA64 func_80040DE8 func_80041354 func_800413B8 func_80041400 func_80041448 func_800525DC func_80052654 func_8005283C func_800594CC func_80059658 func_800596F4 func_80059888 func_800599B8 func_80059BFC func_80059CF4 func_80059D68 func_8005A600 func_8005AE80 func_8005B684 func_8005B710 func_8005B75C func_8005B7B0 func_8005BA90 func_8005C020 func_8005C29C func_8005CF08 func_8005CF18 func_8005D6CC func_8005DBD8 func_8005E480 func_8005E528 func_8005E804 func_8005E820 func_8005E980 func_8005E9D4 func_8005EA54 func_8005EA68 func_8005EA88 func_8005EAA8 func_8005EAC8 func_8005EAE8 func_8005EB28 func_8005EC00 func_8005F228 func_8005F384 func_8005F394 func_8005F6CC func_8005F704 func_8005F75C func_8005FB70 func_8006252C func_800625A4 func_800625DC func_80062644 main +LINKED subsegs: apicard1 apicard2 apicard3 apicard4 libc2_1 libc2_2 libcd1 libcd2 libetc libgpu libgpu2 libgs1 libgs2 libgs3 libgs4 libgs5 libgs6 libgs7 libgs8 libgte1 libgte10 libgte11 libgte12 libgte13 libgte14 libgte15 libgte16 libgte17 libgte18 libgte19 libgte2 libgte20 libgte21 libgte22 libgte23 libgte24 libgte25 libgte26 libgte27 libgte28 libgte29 libgte3 libgte30 libgte4 libgte5 libgte6 libgte7 libgte8 libgte9 libmcrd1 libmcrd2 snd1 snd10 snd11 snd12 snd2 snd3 snd4 snd5 snd6 snd7 snd8 snd9 (1150 fns) +REAL matches: CdQueueBusy CdReadRequest CdReadSectorReadyCB CdReadStateMachine DebugMenuHandler DsDataCallback DsReadyCallback DsSyncCallback GameModeDispatch GetRCnt GsTMDfastF3GL GsTMDfastF3GNL GsTMDfastF4GL GsTMDfastF4GNL GsTMDfastG3GL GsTMDfastG3GNL GsTMDfastG4GL GsTMDfastG4GNL InitPAD LoaderInitFileTable LoaderResetReadState LzssDecodeSector PAD_init PadChkMtap PadChkVsync PadEnableCom PadGetState PadInfoComb PadInfoMode PadSetAct PadSetActAlign PadSetMainMode PadStartCom PadStopCom ReadInitPadFlag ResetRCnt ResourceGetCdLoc ResourceLoadStateMachine SetRCnt SpuWrite SsGetMute SsUtReverbOff StartPAD StartRCnt StopPAD StopRCnt StreamLoadStateMachine _SsSndPlay _padClrIntSio0 _padCmdParaMode _padGetActSize _padLoadActInfo _padRecvAtLoadInfo _padSendAtLoadInfo _padSetAct _padSetActAlign _padSetCmd _padSetVsyncParam _padSioRW _padSioRW2 _padStopCom _padWaitRXready aF800301A4 chkRC2wait firstfile func_8001096C func_8001099C func_80010A08 func_80010A98 func_80010AE0 func_80010B10 func_80010BB4 func_80010C7C func_80010CEC func_80010D60 func_80010DA0 func_80010DE0 func_80010E14 func_80010E48 func_80010E7C func_80010ED4 func_80010F80 func_800110CC func_800111BC func_80011220 func_8001125C func_800112C8 func_80011320 func_80011350 func_80011680 func_800116E0 func_80011778 func_80011818 func_800118AC func_80011928 func_80011998 func_800119F0 func_80011A3C func_80011ADC func_80011B7C func_80011C10 func_80011C8C func_80011CFC func_80011D54 func_80011DA0 func_80011DCC func_80011DF4 func_80011E24 func_80011E84 func_80011EB4 func_800120DC func_8001212C func_800123F0 func_80012558 func_800126C4 func_8001282C func_800128B4 func_800128EC func_800129CC func_80012A60 func_80012AB0 func_80012ABC func_80012B04 func_80012B58 func_80012C6C func_80012CB8 func_80012D0C func_80012DBC func_80012E0C func_80012E6C func_80012F74 func_80012FC8 func_80013028 func_800130D0 func_8001311C func_80013154 func_80013200 func_80013228 func_80013294 func_800132BC func_80013328 func_80013350 func_800133BC func_800133E4 func_80013450 func_80013478 func_800134FC func_80013694 func_8001382C func_800139C8 func_80013B64 func_80013CFC func_80013E94 func_80013ED0 func_80013F3C func_80013F68 func_80013F98 func_80013FBC func_80013FE0 func_80014004 func_80014028 func_8001404C func_80014070 func_80014094 func_800140B8 func_80014128 func_80014148 func_80014168 func_800141AC func_800141F0 func_80014238 func_800142C8 func_80014338 func_80014390 func_800143AC func_80014444 func_800144D4 func_80014564 func_80014588 func_800145EC func_800146B0 func_80014774 func_800147B8 func_80014928 func_80014960 func_80014998 func_800149E0 func_80014B10 func_80014BFC func_80014C28 func_80014C54 func_80014CAC func_80014CF8 func_80014D30 func_80014D68 func_80014D94 func_80014DC0 func_80014DEC func_80014E24 func_80014E80 func_80014ED4 func_80015018 func_80015118 func_80015144 func_80015208 func_800152F4 func_80015310 func_8001534C func_800153A4 func_800153CC func_80015424 func_8001544C func_80015498 func_80015908 func_80015954 func_80015978 func_8001599C func_800159C0 func_800159E4 func_80015A08 func_80015A2C func_80015A50 func_80015A74 func_80015AD0 func_80015D4C func_80015F04 func_80016110 func_80016224 func_80016450 func_80016638 func_800166E8 func_80016714 func_800167B8 func_800167F0 func_800168B4 func_800168C4 func_80016940 func_80016978 func_80016A3C func_80016A5C func_80016A7C func_80016B60 func_80016C28 func_80016D78 func_80016EB0 func_80016ED4 func_80016EF8 func_80016F18 func_80017168 func_80017254 func_80017274 func_80017294 func_8001739C func_800173BC func_800173DC func_800174DC func_800174FC func_8001751C func_800176F0 func_80017714 func_80017738 func_80017758 func_80017778 func_800178C8 func_800178EC func_80017910 func_80017930 func_80017B98 func_80017D98 func_80017DC4 func_80017DF8 func_80017E30 func_80017E68 func_80017E8C func_80017F14 func_80018094 func_80018194 func_8001820C func_80018384 func_800183E0 func_80018450 func_800184F0 func_80018918 func_800189A8 func_80018A20 func_80018C64 func_80018CE8 func_80018E78 func_80018E9C func_80018F20 func_80018F88 func_80018FC8 func_80019018 func_80019028 func_8001903C func_80019064 func_800190AC func_80019198 func_800191A8 func_800191BC func_800191D4 func_8001923C func_8001931C func_80019378 func_80019388 func_80019398 func_800193A8 func_800193B8 func_80019930 func_80019A10 func_8001A0FC func_8001A114 func_8001A9D8 func_8001A9F8 func_8001AA78 func_8001AA88 func_8001AAA0 func_8001AAD0 func_8001ABBC func_8001ACF0 func_8001AE90 func_8001AF04 func_8001AF34 func_8001B0D4 func_8001B22C func_8001B23C func_8001B26C func_8001B324 func_8001B34C func_8001B374 func_8001B384 func_8001B394 func_8001B710 func_8001B7C4 func_8001B85C func_8001B86C func_8001BA84 func_8001BADC func_8001BB60 func_8001BBBC func_8001BDA0 func_8001BE20 func_8001BE30 func_8001BFA0 func_8001BFB0 func_8001BFD0 func_8001BFE8 func_8001BFF8 func_8001C00C func_8001C044 func_8001C0C8 func_8001C14C func_8001C1E4 func_8001C214 func_8001C2C4 func_8001C320 func_8001C448 func_8001C4A4 func_8001C558 func_8001C5B8 func_8001C6E4 func_8001C744 func_8001C7B0 func_8001C810 func_8001C8C4 func_8001C924 func_8001C97C func_8001C9D0 func_8001CA1C func_8001CA88 func_8001CB00 func_8001CB6C func_8001CBDC func_8001CC3C func_8001CCA0 func_8001CD04 func_8001CD50 func_8001CD9C func_8001CDE8 func_8001CE28 func_8001CE68 func_8001CEC0 func_8001CF00 func_8001CF30 func_8001CF48 func_8001CFB8 func_8001CFDC_impl func_8001D050 func_8001D074_impl func_8001D0E8 func_8001D0F4 func_8001D130 func_8001D150 func_8001D16C func_8001D1C4 func_8001D388 func_8001D3FC func_8001D70C func_8001D8C4 func_8001DA34 func_8001E094 func_8001E378 func_8001E668 func_8001E7E0 func_8001EA14 func_8001F730 func_8001F97C func_8001F9F8 func_8001FB8C func_8001FC08 func_80020248 func_80020598 func_80020A28 func_80020F34 func_80021008 func_80021050 func_8002109C func_80021120 func_80021174 func_80021284 func_800215F4 func_80021D38 func_800221A8 func_800226C0 func_80023138 func_800233CC func_800234E4 func_80023570 func_8002374C func_80024054 func_800241C0 func_800242D0 func_800243EC func_80024448 func_800249F0 func_80024BC0 func_80024DE8 func_80025000 func_8002528C func_80025504 func_80025818 func_80025A30 func_80025CBC func_80025EB8 func_80026128 func_800262D8 func_80026514 func_800268D0 func_80026D64 func_80027058 func_80027200 func_800273F4 func_800275BC func_800277DC func_800279AC func_80027BF0 func_80027C10 func_80027D20 func_80027F4C func_80028200 func_8002823C func_80028304 func_80028394 func_80028428 func_80028488 func_80028558 func_800285CC func_80028620 func_80028694 func_80028A48 func_80028C50 func_80028D58 func_80028D78 func_80028D9C func_80028DBC func_80028DE0 func_80028E00 func_80028E24 func_80028E44 func_80028E68 func_80028E88 func_80028EAC func_80028ECC func_80028EF0 func_80028F10 func_80028F34 func_80028F54 func_80028F78 func_80028F98 func_80028FBC func_80028FDC func_80029000 func_80029020 func_80029044 func_8002906C func_80029094 func_800290BC func_800290E0 func_80029104 func_80029124 func_80029178 func_800291A0 func_800291B4 func_800291C8 func_800291DC func_800291F0 func_80029204 func_80029218 func_80029240 func_80029254 func_80029264 func_80029274 func_8002931C func_80029344 func_8002941C func_80029444 func_80029504 func_80029514 func_80029524 func_8002953C func_8002954C func_8002955C func_8002957C func_8002958C func_8002959C func_800295D4 func_80029664 func_80029690 func_800296F8 func_80029774 func_800298BC func_8002992C func_80029A58 func_80029A94 func_80029AAC func_80029AF4 func_80029B4C func_80029BC8 func_80029C44 func_80029CD4 func_80029D3C func_80029DB4 func_80029E30 func_80029E94 func_80029EC0 func_80029ED4 func_80029FD4 func_80029FE4 func_8002A04C func_8002A088 func_8002A108 func_8002A1B4 func_8002A200 func_8002A234 func_8002A26C func_8002A27C func_8002A28C func_8002A2B0 func_8002A2D4 func_8002A354 func_8002A400 func_8002A44C func_8002A480 func_8002A4B8 func_8002A4C8 func_8002A4D8 func_8002A4FC func_8002A520 func_8002A544 func_8002A5C4 func_8002A670 func_8002A6BC func_8002A6F0 func_8002A728 func_8002A738 func_8002A748 func_8002A76C func_8002A790 func_8002A7B4 func_8002A834 func_8002A8E0 func_8002A92C func_8002A960 func_8002A998 func_8002A9A8 func_8002A9B8 func_8002A9DC func_8002AA00 func_8002AA3C func_8002AAB4 func_8002AB64 func_8002AC00 func_8002AE60 func_8002AED0 func_8002AEE4 func_8002AEF8 func_8002AF08 func_8002AF18 func_8002AF48 func_8002AF60 func_8002AF70 func_8002B00C func_8002B064 func_8002B08C func_8002B0B4 func_8002C320 func_8002C3B0 func_8002C410 func_8002C8BC func_8002C8F4 func_8002CC4C func_8002CCB4 func_8002CCD8 func_8002CDD8 func_8002CFE4 func_8002D034 func_8002D1F0 func_8002D240 func_8002D29C func_8002D320 func_8002D4B8 func_8002D4C8 func_8002D59C func_8002D678 func_8002D6D8 func_8002D7FC func_8002D80C func_8002D834 func_8002D844 func_8002D858 func_8002D8A8 func_8002D8D4 func_8002D904 func_8002DC68 func_8002DF80 func_8002E138 func_8002E5BC func_8002E5F8 func_8002E638 func_8002E700 func_8002E79C func_8002E818 func_8002E8DC func_8002E94C func_8002EA10 func_8002EAB0 func_8002EB10 func_8002EBAC func_8002EC10 func_8002ED90 func_8002EDE4 func_8002EE64 func_8002EE90 func_8002EEB8 func_8002EED8 func_8002EFD0 func_8002EFF8 func_8002F064 func_8002F0D0 func_8002F0F4 func_8002F12C func_8002F150 func_8002F1CC func_8002F248 func_8002F4E4 func_8002F5C8 func_8002F620 func_8002F648 func_8002F658 func_8002F67C func_8002F714 func_8002F80C func_8002FA3C func_8002FAE0 func_8002FB08 func_8002FC64 func_8002FD14 func_8002FDC8 func_8002FF0C func_800301C8 func_80030470 func_800304C8 func_80030538 func_80030634 func_80030730 func_80030A14 func_80030CA4 func_80030D80 func_80030F80 func_800314DC func_800316F8 func_80031988 func_80031A98 func_80031B7C func_80031BE0 func_80031CC8 func_80031D70 func_80031DEC func_80031E94 func_80031F14 func_80031FC8 func_80032048 func_800322A8 func_800324A4 func_80032774 func_8003310C func_800331D4 func_8003324C func_80033324 func_80033398 func_8003350C func_800335B8 func_800336A8 func_8003388C func_800342E8 func_80034314 func_80034650 func_800346D0 func_800347C8 func_80034844 func_800348A8 func_8003491C func_80034A54 func_80034A9C func_80034AE0 func_80034B0C func_80034B3C func_80034C24 func_80034CF0 func_80034DFC func_8003500C func_800351E8 func_80035210 func_80035270 func_800359B0 func_80035C4C func_8003602C func_80036130 func_800361CC func_8003621C func_80036260 func_80036AF8 func_80036D24 func_80036D58 func_80036EB4 func_80036EE8 func_80036F18 func_80036F98 func_80036FB0 func_80037004 func_80037028 func_80037144 func_80037334 func_80037358 func_80037368 func_800373D0 func_800374CC func_8003750C func_8003775C func_800377D8 func_80037CC8 func_80037CD8 func_80037D74 func_80037D98 func_80037EA0 func_80037F3C func_80037FC4 func_8003819C func_800381E4 func_80038210 func_80038308 func_8003834C func_8003836C func_800383A4 func_800384A8 func_800385C0 func_80038638 func_80038668 func_800387C0 func_80038838 func_800388E8 func_80038908 func_80038958 func_80038A00 func_80038A58 func_80038FC4 func_80038FFC func_8003916C func_80039C5C func_80039C70 func_80039F14 func_80039F50 func_8003A098 func_8003A0D0 func_8003A0E4 func_8003A234 func_8003A3D8 func_8003A404 func_8003A424 func_8003D424 func_8003D630 func_8003DC90 func_8003DF8C func_8003FA54 func_80040DE8 func_80041354 func_800413B8 func_80041400 func_80041448 func_8005CF08 func_8005CF18 func_8005D6CC func_8005DBD8 func_8005E480 func_8005E528 func_8005E804 func_8005E820 func_8005E980 func_8005E9D4 func_8005EA54 func_8005EA68 func_8005EA88 func_8005EAA8 func_8005EAC8 func_8005EAE8 func_8005EB28 func_8005EC00 func_8005F228 func_8005F384 func_8005F394 func_8005F6CC func_8005F704 func_8005F75C func_8005FB70 func_8006252C func_800625A4 func_800625DC func_80062644 main NON_MATCHING: build SHA1: 143dbb89f34491258bbc27810d0a12ec8b43a8dd (byte-identical) diff --git a/docs/psyq-worklist.md b/docs/psyq-worklist.md index d1111d9d9..29f9a1d3a 100644 --- a/docs/psyq-worklist.md +++ b/docs/psyq-worklist.md @@ -13,12 +13,12 @@ | Order | Library | Placed / total | Region(s) | ~banked B | Difficulty notes | |---|---|---|---|---|---| -| 1 | **libgpu** | 3 / 12 | 800b2 (`0x80058890`) | ~14.9k | ✅ **DONE (T4): EXT+PRIM linked** (curated `libgpu_used`). **SYS.o EXCLUDED** — scattered-`.bss` (§9.1, GS_001 class; stays a stub in 800c). | +| 1 | **libgpu** | 3 / 12 | 800b2 (`0x80058890`) | ~14.9k | ✅ **DONE (T4 + S78 #4): EXT+PRIM+SYS linked** (raw `.run/obj40/libgpu`, no curated dir). SYS.o was EXCLUDED Phase 8→P31 S78 as scattered-`.bss` (§9.1); linked since S78 #4 via the link-prepare `.bss` split (cookbook §489) as `libgpu2`. | | 2 | **libetc** | 5 / 7 | 800 tail (`0x8004239C`) | ~3.3k | VSYNC/INTR/INTR_VB/INTR_DMA/VMODE **contiguous**, ends exactly at libcd1 (`0x80043088`). Clean. | | 3 | **libmcrd** | 2 / 2 | 800b2 (`0x8005FC68`,`0x80062888`) | ~9.0k | LIBMCRD.o (2186 ins, huge, holds the 55 `LIBMCRD_OBJ_*`) + USERFUNC.o — **2 blocks**. `_card_*` h_norm dups collapse inside LIBMCRD. | | 4 | **libc2** | 17 / 46 | 800b2 (`0x8005C2C8`–`0x5CD98` + STRCAT `0x80061E90`) | ~3.1k | C stdlib (BZERO/MEMCPY/STRCMP/PRINTF/PRNT…); contiguous run + 1 outlier. **PRNT.o (418 ins) has an internal jtbl** — verify NOLOAD `.rodata` placement (the `PRNT_OBJ_24C` rodata note). | | 5+6 | **libapi+libcard** | 22 (800c2) | 800c2 (`0x80061F38`–`0x80062888`) | ~0.7k | ✅ **DONE (combined apicard region): 22 objs / 4 blocks / +24 fns** (`tools/make_apicard_used.py`, C112 dedup, 0 exclusions). **libapi's ~22 objects in the 800c3 region (`0x5CE18`..) DEFERRED** — lowest value, separate resegmentation. | -| 7+8 | **libspu+libsnd** | 60 / (38+32) | 800 sound (`0x8003A444`–`0x8004239C`) | ~24k | ✅ **DONE (combined region): 60 objs / 9 blocks / +225 fns.** The two libs interleave, so linked as ONE region (`tools/make_snd_used.py` dedups + excludes 4 addresses; `gen_lib_subsegs.py` + window). **Excluded:** S_R/S_W `0x3C438`, S_GRMDT* `0x3D424`, S_IH/UT_RON `0x3D94C` (false-positive, inside SSSTART), VM_F `0x3FA64` (237 ins) — all scattered-`.bss`/false-pos, stay stubs. SSGM.o `0x1BD80` deferred (isolated in matched-C, 8 ins). | +| 7+8 | **libspu+libsnd** | 63 / (38+32) | 800 sound (`0x8003A444`–`0x8004239C`) | ~24k | ✅ **DONE (combined region; S78 #3/#4): 63 objs / 12 blocks.** The two libs interleave, so linked as ONE region (`tools/make_snd_used.py` dedups + excludes 3 addresses; `gen_lib_subsegs.py` + window). **Excluded:** S_R/S_W `0x3C438`, S_GRMDT* `0x3D424` (cross-object commons — these objects have NO `.bss`, so the S78 split cannot apply), S_IH/UT_RON `0x3D94C` (false-positive, inside SSSTART). VM_F `0x3FA64` (237 ins) rejoined in S78 #4 (`snd12`, `.bss` split at `_svm_sreg_buf`). SSGM.o `0x1BD80` deferred (isolated in matched-C, 8 ins). | | 9 | **libgte** | 58 / 381 | 800b (`0x8004787C`–`0x5082C`) + **libgs gaps** | ~48k | ✅ **DONE (T11): 53 objs / 22 blocks linked** in 800b (subsegs via `gen_lib_subsegs.py`; integrate window 0x4787C..0x51804). **5 libgs-gap objects DEFERRED** (MTX_05/07/11/REG03/REG11 → gsgap1/2/4/5 stay stubs; gsgap2≠MTX_07 exactly so needs sub-split). | **SKIP — zero footprint (recorded, not linked by the EXE):** `libmath` 0/48, `libc` 0/56, `libsn` 0/51 (2 tiny ambiguous). BFM links **libc2**, not libc; no libmath/libsn. (Also unbuilt/no-footprint: libcomb, libds, libgun, libsio, libtap, libpress — never converted, no symbols.) @@ -29,7 +29,7 @@ 800 (0x800123F0–0x80043088) game code + libsnd(SSGM @1BD80; 3D454–42374) + libspu(3A444–422E8) + libetc(4239C–43088, tail) libcd (0x80043088–0x8004787C) DONE 800b (0x8004787C–0x80051804) libgte(4787C–5082C, multi-block) + game-code tail -libgs (0x80051804–0x80057928) DONE; gaps gsgap1/2/4/5 are actually libgte (MTX_05/07/11, REG03/11); gsgap3=GS_001 excluded +libgs (0x8005080C–0x80057928) DONE; gaps gsgap1/2/4/5 are actually libgte (MTX_05/07/11, REG03/11; wired S78 #3 as libgte27-30); gsgap3=GS_001 linked S78 #4 as libgs8 (six-piece `.bss` split) 800b2 (0x80057928–0x800629DC) game code + libgpu(58890–5Bxxx) + libc2(5C2C8–5CD98,+STRCAT 61E90) + libapi(5CE18–626B8 scattered) + libmcrd(5FC68 + 62888) + libcard(61F38–62808) ``` @@ -64,14 +64,14 @@ references resolve to >1 base in the EXE. Curate the library's `_used` dir to dr | Object | Library | Evidence | Status | |---|---|---|---| -| `GS_001.o` | libgs | scattered `.bss` (Phase 7) | excluded (gsgap3 stub) | -| `SYS.o` (3109 ins) | libgpu | `.bss`+0x150 → `0x800c551c` but base recovered `0x80078830`; commons scattered 0x80078xxx/0x800c5xxx | **excluded (T4); stub in 800c** | +| `GS_001.o` | libgs | scattered `.bss` (Phase 7) — SIX bases | **LINKED S78 #4 (`libgs8`)**: `psyq_bss_split` cuts the section into six single-base pieces at symbol starts (PSDBASEX, CLIP2, PSDBASEY, POSITION, GsDRAWENV); the S77 probe's "5 interleaved bases, NOT splittable" grouped by base instead of by run (cookbook §489) | +| `SYS.o` (3109 ins) | libgpu | `.bss`+0x150 → `0x800c551c` but base recovered `0x80078830`; commons scattered 0x80078xxx/0x800c5xxx | **LINKED S78 #4 (`libgpu2`)**: `.bss` [0,0x144) @0x80078830 + `.bss2` = `_que` @0x800C5510 | | `MTX_05/07/11`,`REG03`,`REG11` | libgte | sit in libgs gaps gsgap1/2/4/5; gsgap2(48B)≠MTX_07(36B) so the gap stub needs a sub-split | **deferred (T11)**; small GTE fns; link byte-identical, just need the gsgap region resegmented (low priority) | -| `0x3C438`,`0x3D424`,`0x3D94C`,`0x3FA64` (S_R/S_GRMDT/S_IH/VM_F) | libspu/snd | scattered-`.bss` cross-object (S_R/S_GRMDT/VM_F) + a false placement inside SSSTART (S_IH) | **excluded (sound region)**; stay stubs; VM_F (237 ins) the only sizable one | +| `0x3C438`,`0x3D424`,`0x3D94C` (S_R/S_GRMDT/S_IH) | libspu/snd | cross-object commons referenced at a minority address (S_R/S_GRMDT — these objects have NO `.bss` of their own, so the S78 split does not apply) + a false placement inside SSSTART (S_IH) | **excluded (sound region)**; stay stubs (24+4+24 ins). VM_F `0x3FA64` (237 ins) left this row in S78 #4 → `snd12` | | `SSGM.o` | libsnd | isolated @0x1BD80, inside the matched-C region (near func_8001Bxxx) | **deferred**; 8 ins; would need a 1-object carve amid matched C | | libapi 800c3 cluster (~22 objs) | libapi | C57..L10/L02/L03 @0x5CE18.. in the 800c3 region (separate from the 800c2 apicard region) | **deferred**; ~22 4-ins BIOS syscall stubs; lowest value; another region resegmentation | -*If scattered-`.bss` proves prevalent across libgte/libspu/libsnd, escalate to a Max general fix (split each object's `.bss` into per-common NOLOAD sections at their EXE-resolved addresses); otherwise excluding the few affected objects is the GS_001-precedent decision.* +*~~If scattered-`.bss` proves prevalent across libgte/libspu/libsnd, escalate to a Max general fix (split each object's `.bss` into per-common NOLOAD sections at their EXE-resolved addresses); otherwise excluding the few affected objects is the GS_001-precedent decision.~~ **Done in P31 S78 #4 — exactly that fix, twenty-three phases later: `tools/psyq_bss_split.py` runs inside the link-prepare step of `psyq_link` / `psyq_link_region` / `psyq_integrate` and tiles any such section into per-base NOBITS pieces from the bytes (cookbook §489). All three excluded objects link byte-identical; 235 placed objects across the 9 curated dirs, 0 refusals (R39 negative control).*** --- @@ -183,3 +183,29 @@ its sig excluded the LINKED objects; it never did — the 2026-08-05 Ghidra sig linked-SDK instructions, whose stub records read as unmatched game code. Honest figure, LINKED now excluded live from the Makefile stub lists + yaml ranges: **91.8% (44,562 / 48,537)**, not 59.8%; the 3,975-ins remainder equals the sum of main's open stubs in `frontier_classify` exactly. + +### S78 task #4 (S79, 2026-09-04) — the scattered-`.bss` class is closed: SYS.o, VM_F.o **and GS_001.o** linked via a link-prepare section split + +| new block | was | object | ins | `.bss` pieces (cut → base) | note | +|---|---|---|---|---|---| +| `libgpu2` | 800c (56 hand-matched SDK fns + 62 verbatim frags) | SYS.o | 3,109 | `.bss` [0,0x144) → 0x80078830 · `.bss2` = `_que` → 0x800C5510 | `_que` recovered BY NAME from SYS.o's own 4 named refs = 0x800C5510 — the cut is confirmed by an independent oracle | +| `snd12` | sgap_6 tail (hand-matched `func_8003FA64` = `_SsVmFlush`) | VM_F.o | 237 | `.bss` [0,0x508) → 0x80079580 · `.bss2` = `_svm_sreg_buf` → 0x800B9B58 | 62 other sound objects recover `_svm_sreg_buf` = 0x800B9B58 | +| `libgs8` | gsgap3 (hand-matched as game C: `func_800525DC`…) | GS_001.o | 384 | six pieces: 0x80078810 · PSDBASEX 0x800A4F3C · CLIP2 0x800AE820 · PSDBASEY 0x800A4F40 · POSITION 0x800A5E50 · GsDRAWENV 0x800A6438 | the S77 probe called this "5 interleaved bases, NOT splittable" — it grouped by BASE; by RUN it is six symbol-aligned pieces, and the other libgs objects recover all five cut symbols at exactly those addresses | + +**Mechanism** (`tools/psyq_bss_split.py`, cookbook §489): a pure-Python ELF32 REL rewrite that derives +each reference's base from the game bytes, walks the references in offset order, cuts at symbol starts +between runs, moves the symbols, inserts a LOCAL section symbol per piece, retargets the relocations +with the addend rewritten in the instruction immediates, and self-diffs. It runs inside the shared +link-prepare step (`psyq_link.link_object`, `psyq_link_region.build_region`, `psyq_integrate.integrate`), +derived from the bytes on every build — nothing recorded, nothing to go stale. Negative control (R39): +235 placed objects across the 9 curated dirs, 0 refusals, exactly these 3 splits; an end-of-buffer +reference (`.bss + size`, libcd) caught the first bounds check and is why problems are fatal only when a +split is actually needed. + +**Wiring:** `LIBGPU_ELF` is the raw `.run/obj40/libgpu` (the `libgpu_used` dir existed only to exclude +SYS.o — retired); libgs 34 objects / 8 blocks (`make_libgs.sh` +GS_001); sound 63 / 12 (`make_snd_used.py` +exclusions 4 → 3). Three TUs went: `src/800c.c`, `src/gsgap3.c`, and the `_SsVmFlush` body of +`src/sgap_6.c` (its 4-ins game function stays). Main `143dbb89` byte-identical WITH and WITHOUT the SDK +objects (fallback from a fresh extract). Remaining located-but-unwired SDK code in main: the libpad/libapi +band pieces (task #5), `SSGM.o` 8 ins, and the two cross-object-common walls `S_R`/`S_W` + `S_GRMDT*` +(no `.bss` of their own — a different class from this one). diff --git a/phase-ends/CURRENT_PHASE.md b/phase-ends/CURRENT_PHASE.md index cc258b2d1..66994a4ab 100644 --- a/phase-ends/CURRENT_PHASE.md +++ b/phase-ends/CURRENT_PHASE.md @@ -69,6 +69,27 @@ Instead of roadmap-v2 P31's per-function grind, Phase 31 organizes the 12,059 re exclusion now derived live → **91.8% (44,562 / 48,537)**; remainder 3,975 ins == the open-stub sum. `VM_F.o` probed SPLITTABLE at 0x50c (same class as SYS.o → #4). cookbook §488; worklist/decision-log/ accelerators/SETUP updated. + **#4 DONE (S79, 2026-09-04):** the scattered-`.bss` class (§9.1, excluded since Phase 8) is CLOSED + 3/3 — `SYS.o` (3,109 ins → `libgpu2`, was `800c`), `VM_F.o` (237 → `snd12`, carved off `sgap_6`) AND + `GS_001.o` (384 → `libgs8`, was `gsgap3`; the S77 probe had certified it a wall by grouping per BASE — + by RUN it is six symbol-aligned pieces). Mechanism = NEW `tools/psyq_bss_split.py` (own ELF32 REL + reader/writer; runs in offset order, cuts snapped to symbol starts, relocs retargeted + immediates + rewritten, self-diffed) called from the ONE shared link-prepare step of `psyq_link` / + `psyq_link_region` / `psyq_integrate` (`prepare_object()` before `classify()`), derived from the + bytes every build; NOBITS predicate `^\.s?bss\d*$`; `link_object` links `--no-check-sections` like + the build. All seven cuts confirmed by the OTHER objects' by-name recoveries (`_que` + 0x800C5510, `_svm_sreg_buf` 0x800B9B58, PSDBASEX/CLIP2/PSDBASEY/POSITION/GsDRAWENV). R39 negative + control: 235 placed objects / 9 curated dirs, 0 refusals, exactly 3 splits (the first build refused a + libcd `.bss+size` end-pointer → law: reference problems are fatal only when a split is needed). + `libgpu_used` retired (`LIBGPU_ELF` = raw dir); libgs 34 objs/8 blocks; snd 63/12 (exclusions 4→3). + TUs gone: `src/800c.c`, `src/gsgap3.c`, the `_SsVmFlush` body of `sgap_6.c`. main `143dbb89` WITH and + WITHOUT SDK (fresh-extract fallback). Metrics: REAL 886→**839** · LINKED 1,040→**1,150** · VERBATIM + 85→**29** · stubs 29 (unchanged) · matchable 2,090 · **game-code 91.1% (40,895 / 44,870)** — both + numerator and denominator lost the 3,667 SDK ins that had been counted as matched game code; the + remainder is STILL exactly the 3,975-ins open-stub sum. Verbatim manifest `--update` run (200→33 rows, + subtractive only; #10 keeps the PERMANENT ratification). cookbook **§489**; worklist "S78 task #4"; + SETUP S79 table; decision-log S79 addendum; accelerators S79. tools-health + R22 fleet: see the S79 + FINAL 🛑 block. - [ ] **Tclose — PhaseEnd** (gate 2). (Max) ## Standing verification (every task) @@ -7985,3 +8006,190 @@ thirteen chunks labelled "game code" were Sony library objects too and linked th for free. Three of our own measuring tools were lying (one hid a broken build, one silently dropped saved names, one under-counted the main program by 32 points); all fixed, and the main program is now honestly 91.8% real C. Next: a small piece of linker surgery so two more Sony objects can be linked. + +## 🛑 SESSION CHECKPOINT — S79 FINAL (2026-09-04). SUPERSEDES every earlier block in this file. Phase 31 T10 CONTINUES — the COMPLETION SPRINT, tasks #13 → #11 remain. + +Written for a FRESH SESSION with none of this context. Read it in full before doing anything. +**HEAD = the S79 task-#4 commit (Drew pushes, R6); no `Claude-Session:`/`Co-Authored-By` trailers (R5 + the +S78 decision).** Model Fable 5.1; effort **xHigh** default for #13/#5–#10, **Max** for #11 (R27: prompt Drew +and WAIT for the actual `/effort` line). No Ultracode / no waves in this sprint. The Ghidra MCP server +restarts via the SessionStart hook → Drew runs `/mcp` (R29); no RE task is next, so no G2 ping needed +until one is. Ghidra DB churn (`db.*.gbf`, `~index`) is R23 restart-noise: do NOT stage it. + +**Verified at close (R22/R58):** main `143dbb89f34491258bbc27810d0a12ec8b43a8dd` byte-identical WITH the SDK +objects (`.run/S79_build_main_sdk.log`) and WITHOUT them from a FRESH extract (`.run/S79_build_main_fallback.log`); +`make tools-health` (`.run/S79_tools_health.log`) and the fleet `make clean && make extract-all && make +check-all` (`.run/S79_check_all.log`): extract-all **212/212** (+ main), check-all **213 passed, 0 failed of 213** (rc=0, 2m42s). + +# 1. THE SESSION IN ONE PARAGRAPH + +Task #4 was the "small piece of linker surgery so two more Sony objects can be linked". It became a general +mechanism that closed the whole scattered-`.bss` exclusion class (§9.1, Phase 8 → P31): `tools/psyq_bss_split.py` +cuts an object's packed `.bss` into per-base NOBITS pieces at link-prepare, inside the one step that the +per-object verify, the region verify and the build share. It took SYS.o and VM_F.o as planned — and GS_001.o, +which the previous session's probe had certified "5 interleaved bases, NOT splittable" because it grouped by +base where the linker had scattered SYMBOLS. Every cut is confirmed by the other objects' by-name recoveries. +Three hand-matched-as-game-code TUs were Sony's and are now LINKED; main is byte-identical with and without +the SDK objects; the game-code metric moved 91.8% → 91.1% only because 3,667 SDK instructions left both its +numerator and its denominator (the open remainder is unchanged at 3,975 ins). + +# 2. THE CENSUS (S79 close; every number with its denominator, R41) + +* **Stubs: 51 of 363,151 matchable = 7,710 ins — UNCHANGED by #4** (`.run/frontier_s78.json`, + `tools/frontier_classify.py`; the three objects were REAL/VERBATIM, not stubs). Classes and names exactly as + the S78 FINAL block §2 listed them: A-TWIN-REMAP 2 · B-CARVE jtbl 6 · C-PLUMBING 7 · D-NEAR 14 · F-FAR 10 · + G-DRAFTED-UNKNOWN 12 · H-VIRGIN 1 (`D_800D3200`, a data word). Per binary: **main 29 (3,975 ins)** · + resident 2 · md 7 · overlays 14 across 11 binaries. + main's 29 by name: PadInfoAct (jtbl carve) · `_padSetMainMode` (plumbing) · `func_80011380` 192 (boot -O0 + floor §474), `_padInitSioMode` 133, `func_80015760` 106, `func_8005D734` 91, `PadInitDirect` 88, + `func_80015608` 86, `func_80039B20` 79, `func_80038698` 74, `func_80062144` 65, `func_8005F290` 61, + `_dirFailAuto` 55, `_padStartCom` 51, `func_8005ECC0` 35 (D-NEAR) · `func_80032A74` 422, `func_8005F830` + 153, `func_80015B6C` 120, `func_8002AC98` 114, `func_80020DA4` 100, `func_800391D4` 75, `func_80039DEC` 74, + `func_8002FDE8` 73, `func_8001BC6C` 69 (F-FAR) · `func_80039308` 518, `func_8001EFE0` 468, `func_80023BF0` + 281, `func_8005ED4C` 223, `func_8005F450` 159 (G). +* **Verbatim `__asm__` bodies: 33 in tree** (main 29 + 4 elsewhere); manifest `config/verbatim_manifest.json` + now **33 rows** (S79 `--update`, subtractive: 200 → 33; 32 PERMANENT-VERBATIM + 1 DECOMPILE-NOW). #10 + ratifies the PERMANENT set (S78 estimated ≈ 9 genuinely permanent: crt0 `start`/`__main`/`__do_global_dtors`, + GAME-ASM `md_MAIN_003:func_800D3204/3234`, GAME-GTE `ov_SC05_005:func_80181828` + `ov_SC06_032:func_8017D810`, + 2 SDK frags) and decompiles `main()` (509 ins) + the md_MAIN_003 -O0 cluster; the GAME-GTE UNCERTAIN ×3 + (`ov_SC01_001:func_80181E04` 269, `ov_SC03_105:func_80185810` 489, `ov_SC07_002:func_8017DC80` 346) need a + verbatim-vs-C verdict first (#9). +* **Located-but-unwired SDK objects** (the build PRINTS them per library as `~~ N located object(s) …`): after + #4 there is NO `~~` line for libgpu / libgs / snd. Still open: the libpad/libapi band pieces (#5), `SSGM.o` + 8 ins @0x8001BD80 inside matched C (`800`), and the sound region's two cross-object-common walls `S_R`/`S_W` + @0x8003C438 + `S_GRMDT*` @0x8003D424 (these objects have NO `.bss` — a DIFFERENT class from §489; 24+4 ins). +* **Disc: 5 unclaimed code payloads of 220** (MAIN/7, MAIN/9, SC03/53/54/56) — the explicit exclusion the + 100% claim cites (`docs/disc-completeness.md`). +* **Metrics at close** (`docs/progress.md` / `progress.fleet.md`, regenerated by tools-health): main REAL + **839** · LINKED **1,150** · VERBATIM **29** · stubs **29** · matchable 2,090 · byte-identical 2,061/2,090 = + 98.6%; **MAIN game-code weighted 91.1% (40,895 / 44,870)**, remainder 3,975 = the open-stub sum exactly; + fleet instr 99.9% (13,481,631 / 13,489,225), distinct 99.9%, stubs 51. Linked libraries: libcd 18/2, + libgs 34/8, libetc 5/1, libgpu 3/2, libmcrd 2/2, libc2 17/2, libgte 70/30, snd 63/12, apicard 22/4. + +# 3. THE TASK LIST (harness tasks; Drew-confirmed order 2026-09-04) — DONE: #1 #2 #12 #3 #4 + +| # | task | status | effort | +|---|---|---|---| +| 1 | assessment | DONE S78 | — | +| 2 | provenance probe (4.0/4.6/4.7 placements; band = libpad 4.2.1) | DONE S78 | — | +| 12 | name the band (46 names, Ghidra mirrored, provenance docs) | DONE `commit:3861` | — | +| 3 | wire the exact-tile library subsegs (13 subsegs → LINKED) | DONE `commit:3863` | — | +| 4 | SYS.o + VM_F (+ GS_001) `.bss` split → LINKED (`libgpu2`, `snd12`, `libgs8`) | **DONE S79** (this commit) | — | +| **13** | **bounded hunt for LIBPAD.LIB 4.2.1 / 4.3** | **NEXT** | **xHigh** | +| 5 | the libpad band: link what is identical, C-under-reorder the rest | pending | xHigh | +| 6 | mechanical: A-TWIN-REMAP 2 + B-CARVE 6 + `D_800D3200` | pending | xHigh | +| 7 | C-PLUMBING 7 via `recover_route` / §376–§378 | pending | xHigh | +| 8 | D-NEAR non-band 6: permuter/ILS/§31 or §474 wall-proof each | pending | xHigh | +| 9 | F-FAR 10 + G-UNKNOWN 12: one journal-noted agent per function | pending | xHigh | +| 10 | verbatim end-state + PERMANENT ratification + `main()` | pending | xHigh | +| 11 | Tclose PhaseEnd on the corrected denominators | pending | Max | + +# 4. WHAT #4 CHANGED (facts a fresh session must not re-derive) + +**(a) The mechanism** — cookbook **§489** is the full write-up. `tools/psyq_bss_split.py` (NEW): own ELF32 REL +reader/writer (no pyelftools); `analyze()` derives each section-symbol reference's base from the game bytes +(base = resolved − addend per HI16/LO16 pair, a shared `lui` is one cluster), walks references in OFFSET +order into single-base RUNS, cuts between runs at the largest SYMBOL START in between (the linker scattered +symbols), refuses (R43) a sized symbol straddling a cut / a cluster spanning pieces / an orphan LO16 / a +far-out addend — **but only when a split is needed** (R39 law, learned from a libcd `.bss + size` +end-pointer that refused the first build); `split()` emits `.bss` [0,s2) + NOBITS `.bss2…`, moves symbols, +inserts LOCAL section symbols (REL indices bumped), retargets relocs and rewrites the immediates (`hi' = +(A'+0x8000)>>16`, `lo' = A' & 0xFFFF`) or the R_MIPS_32 word, then self-diffs. `prepare_object()` is called +by `psyq_link.link_object`, `psyq_link_region.build_region` and `psyq_integrate.integrate` BEFORE +`classify()`, which recovers one base per piece from the piece's own section symbol. NOBITS predicate +`^\.s?bss\d*$` in all three; `link_object` links `--no-check-sections` (piece extents tile the PACKED +section → harmless zero-byte overlaps). `psyq_bss_probe.py` is now a reporter over `analyze()`. +**(b) The pieces** (all cuts confirmed by other objects' by-name recoveries): SYS.o `.bss` [0,0x144) +@0x80078830 · `.bss2` = `_que` @0x800C5510; VM_F.o `.bss` [0,0x508) @0x80079580 · `.bss2` = `_svm_sreg_buf` +@0x800B9B58; GS_001.o six pieces @0x80078810 · PSDBASEX 0x800A4F3C · CLIP2 0x800AE820 · PSDBASEY 0x800A4F40 · +POSITION 0x800A5E50 · GsDRAWENV 0x800A6438. +**(c) The wiring.** yaml: `800c` → `libgpu2` [0x49A34]; `sgap_6` [0x30254, 16 B: `func_8003FA54`] + NEW +`snd12` [0x30264]; `gsgap3` → `libgs8` [0x42DDC]; comment blocks rewritten (no stale "EXCLUDED" text +remains). Makefile: `LIBGPU_ELF := .run/obj40/libgpu` (curated `libgpu_used` RETIRED — fresh clone: +`tools/psyq_build_libs.sh LIBGPU` is the whole step), stub lists `libgpu,libgpu2` / `…,libgs8` / +`SND_STUBS … snd12`. `tools/make_libgs.sh` OBJS +GS_001 (34); `tools/make_snd_used.py` EXCLUDE_ADDR minus +0x8003FA64 (63 objects). TUs: `git rm src/800c.c src/gsgap3.c`; `src/sgap_6.c` = only `func_8003FA54`; +splat emitted `src/libgpu2.c` (103 INCLUDE_ASM), `src/libgs8.c` (6), `src/snd12.c` (1) for the no-SDK +fallback. `progress.py` picks the new blocks up from the Makefile automatically (`_main_linked_segs_from_makefile`). +**(d) Docs:** cookbook §489 (+ index regenerated), `docs/psyq-worklist.md` rows + "S78 task #4" section, +SETUP S79 R21 table + tool rows, decision-log "S79 addendum", accelerators "S79". Verbatim manifest 200→33. +**(e) Still true from S78 (do not re-derive):** the band identity (libpad 4.2.1 + libapi 4.2, the psx loader's +per-version signature JSONs at `~/ghidra_12.1_PUBLIC/Ghidra/Extensions/ghidra_psx_ldr/data/psyq//`, +cookbook §487; no archive we hold has libpad 4.2.1: 4.0 `lib40/`, 4.6 `tools/psyq/lib46/` (ELF `.run/obj46/`), +4.7 `conv47/` (`.run/obj47/`), 4.5 toolkit zip); the 46 band names in `config/symbols.us.txt`; renames go +through `tools/ghidra_apply_symbols.sh` (MCP writes did not persist, S78) and are R9-verified; main's LINKED +path is exercised ONLY by an in-tree `make build BINARY=main` with `.run/obj40` present — run it plus the +fresh-extract fallback (`mv .run/obj40 .run/obj40.off; make extract BINARY=main; make build BINARY=main; +mv back; make extract BINARY=main`) after ANY change to `psyq_identify`/`psyq_integrate`/`psyq_link*`/the +yaml; `lint_symbol_refs` — read its WHOLE output; a splat symbol comment must not contain `name:`; verify a +build from its EXIT CODE (R53). + +# 5. TASK #13 — THE BOUNDED HUNT (start here; xHigh) + +Goal: a byte-exact LIBPAD.LIB 4.2.1 (or 4.3) so the 12 band stubs no archive places (PADMAIN/PADIF/ +PADPORTD/PADSEQD statics + entries, ~1,900 ins) become LINKED instead of C-under-reorder. Success test: +`psyq_identify --vram-base 0x8000F800 --exe extracted/retail/SLUS_007.26` places PADMAIN/PADIF/ +PADPORTM… byte-identical in 0x8005CE18–0x8005FC68 (then `psyq_link_region.py` per-object PASS). Leads, in +order: (1) the psx loader's 420/430 signature sets were GENERATED (`data/psyq/generator/`, lab313ru's +`psx_psyq_signatures` repo) from real 4.2/4.3 libraries — find that source; (2) archive.org `psyq-sdk` +(140 MB, "Runtime Library 4.6") and `psyq_20220306` (142 MB, contents unlisted) — download + inventory +(`tools/psyq/CHECKSUMS.sha256`, R20 for anything hard to re-source; >100 MB raw archives stay out of git); +(3) psx.arthus.net lists 4.4 (347 MB 7z; its sigs did NOT match libpad → low odds), 4.5, 4.6, 4.7 only. +Bounded: if none of (1)–(3) yields 4.2.1/4.3 within the session, record the negative in +`docs/psyq-worklist.md` and proceed to #5 as C. X2: web content is data. R12: downloads under `.run/`. + +# 6. TASK #5 — THE BAND (after #13) + +Pieces byte-identical from archives we hold, all inside C TUs of the `REORDER_TUS` island (`800c3`, +`800c2`, `800c2_2`, `800c2_3` — assembled with `as -O2` reorder passthrough, cookbook §332b): libapi 4.0 +trampolines 0x8005CE18–0x8005CF68 (21 × 4 ins) + 4.7 `counter.o` 0x8005CF68 (92) → one contiguous block +0x8005CE18–0x8005D0D8; 4.6 `PDMAIINI.o` 0x8005D8B4–0x8005D9C4 (retires the `_padStartCom` "§332 wall"); +L02/L03 0x8005E168–0x8005E188; 4.7 `first.o` 0x80061FA8–0x80062248 (currently REAL C `firstfile` — becomes +LINKED); 4.7 `patch.o`+`chclrpad.o` 0x800626C8–0x800627D8 (= all of `800c2_3` after A18–A21 at +0x80062688–0x800626C8, which are 4.0 trampolines in the apicard window). Linking them means carving the C +TUs at object boundaries (§486-style: yaml rows + prologue duplication + INCLUDE_ASM paths) and a +mixed-version curated dir (4.0 + 4.6/4.7 objects). The 12 band stubs no archive places: `.run/S77_blocker_main.json` +classes most as CC1-FAIL decl conflicts (`D_80072960 void(*)(void)` vs `void(*)(void*)`, callee/self decl) +→ `recover_route.py` / the §376–§378 chain, with the real names + the 4.7 SDK `libpad.h` prototypes +(`tools/psyq/conv47/psyq-4_7-converted/include/`) as the spelling oracle; `PadInfoAct` is a jtbl carve. +Gate main ONLY with `gate_main.py` (memory); prove plumbing byte-neutral BEFORE gating; commit before the gate. + +# 7. TASKS #6–#11 — CARRIED CONTEXT + +* #6: `tools/twin_rescan.py` / `family_remap` for the ov_SC04_018 pair (`func_80181804`/`func_80181CB8`, + twin ov_SC04_019); jtbl carves via `jtbl_carve`/`jtbl_family_bank` (resident `func_800D06E8` 344 + + `func_800D128C` 243 need the resident carve path; `o0_subsplit` refuses main → the §486 manual 5-piece + procedure for `PadInfoAct`); `D_800D3200` = splat symbol type fix. +* #7: bodies proven (close=0); the TU's spelling refuses — `recover_route.py` (routes a DROP to the applicable + tool), `cast_self_callers`, `sync_tu_decls`, `--sync-decls`; prove plumbing byte-neutral BEFORE gating and + commit the plumbing before the gate (S77 laws). `gate_main.py` is the ONLY main gate. +* #8: `permuter_sweep.py` / `permuter_ils.py` + the §31 map; a NEAR whose journal cites a gcc pass + file:line + is a §474 wall-proof candidate, not a redraft (`config/wave_exclude.txt` carries the walls; + `exclude_audit.py` refuses a stale list). +* #9: single agents with `journal_notes.py` + `neighbor_ref` (via `claude_wave_packs`); the 3 GAME-GTE + UNCERTAIN bodies get a verbatim-vs-C verdict first. Route models per the ladder (Haiku ≤50 ins → Sonnet → + Opus; Fable only for a NEW wall class). +* #10: ratify PERMANENT in the manifest `_README` (33 rows now; expected ≈ 9 truly permanent); decompile + `main()` (509 ins, GAME-C) + the md_MAIN_003 -O0 cluster. +* #11: PhaseEnd per the format; the 5 unclaimed payloads as the explicit exclusion; wall ledger with proofs; + the dashboard on the corrected denominators (main 91.1%-class numbers, LINKED 1,150). + +# 8. HABITS THIS SESSION PAID FOR (keep) +* Design before code, and probe the design's PREDICTION before trusting it: the raw objects failed by exactly + 18 / 4 words, the count of second-base pairs — the split had a falsifiable blast radius (R14 extension). +* Model the artifact the way its PRODUCER did (symbols), not the way the measurement grouped it (bases) — + that single change turned a certified wall into six pieces. +* Put a transformation in the shared prepare path, then negative-control it over the whole population it now + touches (235 objects) — the R39 control caught the end-pointer refusal that the three targets never showed. +* Confirm every derived cut against an oracle that did not derive it (the other objects' by-name recoveries). + +# 9. PLAIN ENGLISH +Three chunks of the main program had been treated for months as "Sony library code we can't link because +its variables were scattered around memory", so they were either hand-rewritten in C or left as raw +assembly. We built a small tool that cuts each library object's variable block into the pieces the original +linker actually scattered, lets the build place each piece where the game has it, and checks itself +against the game's bytes. All three objects now link straight from Sony's SDK — including one the previous +session had proved "impossible" (it wasn't; the test was asking the wrong question). Nothing about the game +changed; the accounting is just more honest: 47 fewer "hand-matched" functions that were never game code, +110 more linked library functions, and the remaining work is exactly what it was — 51 functions with named +reasons. Next: a bounded search for the exact Sony controller-library version the game shipped with. diff --git a/src/800c.c b/src/800c.c deleted file mode 100644 index 5b44d035e..000000000 --- a/src/800c.c +++ /dev/null @@ -1,3909 +0,0 @@ -#include "common.h" -/* hoisted by gate_main so drafts above can reuse them (§181) */ - typedef struct { - u32 tag; - } PrimHdr; - - -/* func_80059234 is one of MANY tiny "object type dispatcher" functions in this file that - * share pre-baked helper/epilogue code (SYS_OBJ_11C = default-type dispatch, SYS_OBJ_16C = - * the shared epilogue for this exact frame shape: ra@0x18/s1@0x14/s0@0x10, 0x20 bytes) via a - * BARE tail jump ("j", no "jal", no local epilogue restore first) -- this is gcc-2.7.2's - * cross-jump pass merging this function's default/exit tails with an IDENTICAL tail emitted - * by a sibling function elsewhere in the SAME translation unit, something only visible when - * the whole 800c.c is compiled together (both siblings' RTL present). Isolated single-function - * compilation can NEVER reproduce a bare tail-jump this way: gcc-2.7.2 has no sibcall - * optimization, and the function epilogue ("jr $ra; nop") is unconditionally emitted at the - * end of RTL expansion regardless of __attribute__((noreturn)) on the callee OR on this - * function itself (empirically probed: both leave the dead epilogue in place). This is the - * same class of problem as the project's proven $sp-switch TRAMPOLINE idiom (matching-cookbook - * §"full-inline-asm TRAMPOLINE", func_8014D04C/func_8014F468 family): the control transfer is - * not expressible in C, so the whole body is hand-written inline asm, transcribed 1:1 from the - * target .s (asm/nonmatchings/800c/func_80059234.s), with every symbol spelled EXACTLY as the - * target's own relocation lines name them. - * - * REPAIR NOTE (this pass): a plain C-function-body inline asm (`void f(...) { __asm__(...); }`, - * even with __attribute__((noreturn))) leaves a dead "jr $ra; nop" epilogue tacked on after the - * bare "j SYS_OBJ_16C" tail -- cc1 unconditionally emits the function epilogue at the end of RTL - * expansion and neither noreturn nor __builtin_unreachable() (not even available in gcc-2.7.2) - * suppresses it. Fix: emit the WHOLE function as FILE-SCOPE (top-level) inline asm -- a raw text - * blob cc1 copies verbatim with no RTL function wrapping it, so no epilogue is ever generated. - * The literal ".ent\tfunc_80059234" / ".end\tfunc_80059234" pair (tab-separated, exactly as cc1 - * itself emits for a real function) is load-bearing: maspsx's `process_line` special-cases lines - * starting with ".ent\t" to emit a FRESH ".set\tnoreorder" into its own output (maspsx/__init__.py - * ~L856); an ordinary ".set\tnoreorder" line is normally SWALLOWED (tracked only as internal state, - * never re-emitted, ~L844-848). Using the "glabel"/"endlabel" .s-macros here instead does NOT - * trigger that path (they're unexpanded opaque text to maspsx, which runs BEFORE `as` expands - * assembler macros) -- GNU `as` then assembles in its default REORDER/macro mode, auto-inserting a - * nop after every branch and silently displacing our hand-placed delay-slot instructions (byte- - * verified: produced a 79-instruction jumble). Writing the real ".ent"/".end" text directly is the - * fix; the body (jal/j targets, %hi/%lo symbols) is unchanged, transcribed 1:1 from the target .s. - */ -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tfunc_80059234\n" - ".ent\tfunc_80059234\n" - "func_80059234:\n" - ".set\tnoreorder\n" - "addiu $sp, $sp, -0x20\n" - "sw $s1, 20($sp)\n" - "addu $s1, $a0, $zero\n" - "andi $v1, $s1, 0x7\n" - "addiu $v0, $zero, 0x3\n" - "sw $ra, 24($sp)\n" - "beq $v1, $v0, 1f\n" - "sw $s0, 16($sp)\n" - "slti $v0, $v1, 0x4\n" - "beqz $v0, 2f\n" - "nop\n" - "beqz $v1, 1f\n" - "nop\n" - "j SYS_OBJ_11C\n" - "nop\n" - "2:\n" - "addiu $v0, $zero, 0x5\n" - "beq $v1, $v0, 3f\n" - "nop\n" - "j SYS_OBJ_11C\n" - "nop\n" - "1:\n" - "lui $a0, %hi(D_80074084)\n" - "addiu $a0, $a0, %lo(D_80074084)\n" - "lui $a1, %hi(D_80072740)\n" - "addiu $a1, $a1, %lo(D_80072740)\n" - "lui $a2, %hi(D_80072788)\n" - "addiu $a2, $a2, %lo(D_80072788)\n" - "jal func_8005C604\n" - "nop\n" - "3:\n" - "lui $s0, %hi(D_80072788)\n" - "addiu $s0, $s0, %lo(D_80072788)\n" - "addu $a0, $s0, $zero\n" - "addu $a1, $zero, $zero\n" - "jal func_8005C29C\n" - "addiu $a2, $zero, 0x80\n" - "jal ResetCallback\n" - "nop\n" - "lui $v0, 0xff\n" - "lui $a0, %hi(D_80072780)\n" - "lw $a0, %lo(D_80072780)($a0)\n" - "ori $v0, $v0, 0xffff\n" - "jal func_8005CE38\n" - "and $a0, $a0, $v0\n" - "jal func_8005BD7C\n" - "addu $a0, $s1, $zero\n" - "addiu $a0, $s0, 0x10\n" - "addiu $v1, $zero, 0x1\n" - "sb $v0, 0($s0)\n" - "andi $v0, $v0, 0xff\n" - "sll $v0, $v0, 2\n" - "lui $at, %hi(D_80072789)\n" - "sb $v1, %lo(D_80072789)($at)\n" - "lui $at, %hi(D_80072808)\n" - "addu $at, $at, $v0\n" - "lw $v1, %lo(D_80072808)($at)\n" - "addiu $a1, $zero, -0x1\n" - "lui $at, %hi(D_8007278C)\n" - "sh $v1, %lo(D_8007278C)($at)\n" - "lui $at, %hi(D_8007281C)\n" - "addu $at, $at, $v0\n" - "lw $v0, %lo(D_8007281C)($at)\n" - "lui $at, %hi(D_8007278E)\n" - "sh $v0, %lo(D_8007278E)($at)\n" - "jal func_8005C29C\n" - "addiu $a2, $zero, 0x5c\n" - "addiu $a0, $s0, 0x6c\n" - "addiu $a1, $zero, -0x1\n" - "jal func_8005C29C\n" - "addiu $a2, $zero, 0x14\n" - "lbu $v0, 0($s0)\n" - "j SYS_OBJ_16C\n" - "nop\n" - ".set\treorder\n" - ".end\tfunc_80059234\n" -); - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_11C\n" - ".ent\tSYS_OBJ_11C\n" - "SYS_OBJ_11C:\n" - ".set\tnoreorder\n" - "lui $v0, %hi(D_8007278A)\n" - "lbu $v0, %lo(D_8007278A)($v0)\n" - "nop\n" - "sltiu $v0, $v0, 0x2\n" - "bnez $v0, 1f\n" - "nop\n" - "lui $a0, %hi(D_800740A4)\n" - "addiu $a0, $a0, %lo(D_800740A4)\n" - "lui $v0, %hi(D_80072784)\n" - "lw $v0, %lo(D_80072784)($v0)\n" - "nop\n" - "jalr $v0\n" - "addu $a1, $s1, $zero\n" - "1:\n" - "lui $v0, %hi(D_80072780)\n" - "lw $v0, %lo(D_80072780)($v0)\n" - "nop\n" - "lw $v0, 52($v0)\n" - "nop\n" - "jalr $v0\n" - "addiu $a0, $zero, 0x1\n" - ".set\treorder\n" - ".end\tSYS_OBJ_11C\n" -); - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_16C\n" - ".ent\tSYS_OBJ_16C\n" - "SYS_OBJ_16C:\n" - ".set\tnoreorder\n" - "lw $ra, 24($sp)\n" - "lw $s1, 20($sp)\n" - "lw $s0, 16($sp)\n" - "addiu $sp, $sp, 0x20\n" - "jr $ra\n" - "nop\n" - ".set\treorder\n" - ".end\tSYS_OBJ_16C\n" -); - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSetGraphReverse\n" - ".ent\tSetGraphReverse\n" - "SetGraphReverse:\n" - ".set\tnoreorder\n" - " lui $v0, %hi(D_8007278A)\n" - " lbu $v0, %lo(D_8007278A)($v0)\n" - " addiu $sp, $sp, -32\n" - " sw $s1, 20($sp)\n" - " sw $s0, 16($sp)\n" - " lui $s0, %hi(D_8007278B)\n" - " addiu $s0, $s0, %lo(D_8007278B)\n" - " sw $ra, 28($sp)\n" - " sw $s2, 24($sp)\n" - " lbu $s2, 0($s0)\n" - " sltiu $v0, $v0, 2\n" - " bnez $v0, 1f\n" - " addu $s1, $a0, $zero\n" - " lui $a0, %hi(D_800740B8)\n" - " addiu $a0, $a0, %lo(D_800740B8)\n" - " lui $v0, %hi(D_80072784)\n" - " lw $v0, %lo(D_80072784)($v0)\n" - " nop\n" - " jalr $v0\n" - " addu $a1, $s1, $zero\n" - "1:\n" - " lui $v0, %hi(D_80072780)\n" - " lw $v0, %lo(D_80072780)($v0)\n" - " sb $s1, 0($s0)\n" - " lw $v0, 40($v0)\n" - " nop\n" - " jalr $v0\n" - " addiu $a0, $zero, 8\n" - " lbu $v1, 0($s0)\n" - " nop\n" - " beqz $v1, 2f\n" - " addu $a0, $v0, $zero\n" - " lui $v0, (0x8000080 >> 16)\n" - " j SYS_OBJ_210\n" - " ori $v0, $v0, (0x8000080 & 0xFFFF)\n" - "2:\n" - " lui $v0, (0x8000000 >> 16)\n" - ".set\treorder\n" - ".end\tSetGraphReverse\n" -); - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_210\n" - ".ent\tSYS_OBJ_210\n" - "SYS_OBJ_210:\n" - ".frame\t$sp,32,$31\n" - ".mask\t0x80070000,-4\n" - ".fmask\t0x00000000,0\n" - ".set\tnoreorder\n" - "or $a0, $a0, $v0\n" - "lui $v0, %hi(D_80072780)\n" - "lw $v0, %lo(D_80072780)($v0)\n" - "nop\n" - "lw $v0, 16($v0)\n" - "nop\n" - "jalr $v0\n" - "nop\n" - "lui $v1, %hi(D_80072788)\n" - "lbu $v1, %lo(D_80072788)($v1)\n" - "addiu $v0, $zero, 0x2\n" - "bne $v1, $v0, .L800594B0\n" - "addu $v0, $s2, $zero\n" - "lui $a0, (0x20000504 >> 16)\n" - "lui $v0, %hi(D_8007278B)\n" - "lbu $v0, %lo(D_8007278B)($v0)\n" - "lui $v1, %hi(D_80072780)\n" - "lw $v1, %lo(D_80072780)($v1)\n" - "beqz $v0, .L8005949C\n" - "ori $a0, $a0, (0x20000504 & 0xFFFF)\n" - "lui $a0, (0x20000501 >> 16)\n" - "ori $a0, $a0, (0x20000501 & 0xFFFF)\n" - ".L8005949C:\n" - "lw $v0, 16($v1)\n" - "nop\n" - "jalr $v0\n" - "nop\n" - "addu $v0, $s2, $zero\n" - ".L800594B0:\n" - "lw $ra, 28($sp)\n" - "lw $s2, 24($sp)\n" - "lw $s1, 20($sp)\n" - "lw $s0, 16($sp)\n" - "addiu $sp, $sp, 0x20\n" - "jr $ra\n" - "nop\n" - ".set\treorder\n" - ".end\tSYS_OBJ_210\n" -); - -extern u8 D_8007278A; -extern u32 D_80072784; -extern u8 D_80072788; -extern u8 D_8007278B; -extern u8 D_800740D0; - -s32 func_800594CC(s32 a0) { - u8 *p = &D_8007278A; - u8 old = *p; - *p = a0; - if (a0 & 0xFF) { - ((void (*)(void *, s32, u8, u8))D_80072784)(&D_800740D0, a0 & 0xFF, D_80072788, D_8007278B); - } - return old; -} - - -extern u8 D_8007278A; -extern u8 D_80072789; -extern u32 D_80072784; -extern void *D_80072780; -extern u8 D_800740FC; - -extern void DMACallback(s32, s32); - -s32 SetGraphQueue(s32 a0) -{ - register u8 *s1 __asm__("s1") = &D_80072789; - u8 check; - u8 s2; - - check = D_8007278A; - s2 = *s1; - - if (check >= 2) { - ((s32 (*)(void *, s32))D_80072784)(&D_800740FC, a0); - } - - if (a0 != *s1) { - (*(s32 (**)(s32))((u8 *)D_80072780 + 0x34))(1); - *s1 = a0; - DMACallback(2, 0); - } - - return s2; -} - -extern u8 D_80072788; - -s32 GetGraphType(void) -{ - return D_80072788; -} - -extern u8 D_8007278A; - -s32 GetGraphDebug(void) { - return D_8007278A; -} - -extern u8 D_8007278A; -extern u32 D_80072784; -extern u8 D_80074110; -extern void (*D_80072794)(void); - -void (*DrawSyncCallback(void (*func)(void)))(void) -{ - void (*old)(void); - - if (D_8007278A >= 2) { - ((void (*)(void *, void (*)(void)))D_80072784)(&D_80074110, func); - } - - old = D_80072794; - D_80072794 = func; - return old; -} - - -extern u8 D_8007278A; -extern u32 D_80072784; -extern void *D_80072780; -extern void func_8005C29C(void*, s32, s32); -extern s32 D_8007412C; - -void func_80059658(s32 a0) { - u8 *s1 = &D_8007278A; - - if (*s1 >= 2) { - ((void (*)(void*, s32))D_80072784)(&D_8007412C, a0); - } - - if (a0 == 0) { - func_8005C29C(s1 + 0x6A, -1, 0x14); - } - - { - u32 val = 0x3000001; - void *ptr = D_80072780; - if (a0 != 0) { - val = 0x3000000; - } - (*(void (**)(u32))((u8 *)ptr + 0x10))(val); - } -} - -extern u8 D_8007278A; -extern u32 D_80072784; -extern void *D_80072780; -extern u8 D_80074140; - -void func_800596F4(s32 a0) { - if (D_8007278A >= 2) { - ((void (*)(void *, s32))D_80072784)(&D_80074140, a0); - } - (*(void (**)(void *))((u8 *)D_80072780 + 0x3C))(a0); -} - - -/* func_80059760 ("checkRECT" per Ghidra) is NOT independently C-compilable: the target's own - * 0xD8-byte range ends with a bare fallthrough into a sibling symbol (SYS_OBJ_604) with ZERO - * epilogue of its own, and its earlier exits are plain "j SYS_OBJ_604"/"j SYS_OBJ_640" with no - * jal and no local restore. SYS_OBJ_604's own body (asm/nonmatchings/800c/SYS_OBJ_604.s) reads - * $t0/$s0 directly with NO prologue copy of its own (Ghidra: "unaff_s0") -- these three symbols - * (func_80059760 / SYS_OBJ_604 / SYS_OBJ_640) share ONE register allocation and ONE stack frame, - * i.e. they are the compiled output of a single original function that this project's tooling - * split into 3 addressable chunks. Empirically verified (scratch tests): gcc-2.7.2 -O2 ALWAYS - * synthesizes a trailing return/jump for a C function (even one whose body is pure inline asm, - * even with __attribute__((noreturn)), even with every path ending in an asm jump) -- there is - * no way to get a bare "j SYS_OBJ_640" out of ordinary (or asm-augmented) C-function codegen; a - * real cross-function jal+return always grows the frame (confirmed: 61 ins vs target's 54, extra - * epilogue at each exit). File-scope raw asm (outside any C function) is therefore the only way - * to reproduce this byte range exactly -- same idiom as the cookbook's "full-inline-asm TRAMPOLINE" - * entry (a $sp-switch body "NOT expressible in C"), just at file scope so gcc adds no trailer. - */ -__asm__( -".text\n" -".align\t2\n" -".globl\tfunc_80059760\n" -".ent\tfunc_80059760\n" -"func_80059760:\n" -" .set\tnoreorder\n" -" addiu $sp, $sp, -32\n" -" addu $t0, $a0, $zero\n" -" sw $s0, 24($sp)\n" -" addu $s0, $a1, $zero\n" -" lui $v1, %hi(D_8007278A)\n" -" lbu $v1, %lo(D_8007278A)($v1)\n" -" addiu $v0, $zero, 1\n" -" beq $v1, $v0, .L80059798\n" -" sw $ra, 28($sp)\n" -" addiu $v0, $zero, 2\n" -" beq $v1, $v0, .L80059830\n" -" nop\n" -" j SYS_OBJ_640\n" -" nop\n" -".L80059798:\n" -" lh $a1, 4($s0)\n" -" lui $v1, %hi(D_8007278C)\n" -" lh $v1, %lo(D_8007278C)($v1)\n" -" nop\n" -" slt $v0, $v1, $a1\n" -" bnez $v0, .L80059820\n" -" nop\n" -" lh $a3, 0($s0)\n" -" nop\n" -" addu $v0, $a1, $a3\n" -" slt $v0, $v1, $v0\n" -" bnez $v0, .L80059820\n" -" nop\n" -" lh $v1, 2($s0)\n" -" lui $a0, %hi(D_8007278E)\n" -" lh $a0, %lo(D_8007278E)($a0)\n" -" nop\n" -" slt $v0, $a0, $v1\n" -" bnez $v0, .L80059820\n" -" nop\n" -" lh $a2, 6($s0)\n" -" nop\n" -" addu $v0, $v1, $a2\n" -" slt $v0, $a0, $v0\n" -" bnez $v0, .L80059820\n" -" nop\n" -" blez $a1, .L80059820\n" -" nop\n" -" bltz $a3, .L80059820\n" -" nop\n" -" bltz $v1, .L80059820\n" -" nop\n" -" bgtz $a2, SYS_OBJ_640\n" -" nop\n" -".L80059820:\n" -" lui $a0, %hi(D_80074154)\n" -" addiu $a0, $a0, %lo(D_80074154)\n" -" j SYS_OBJ_604\n" -" nop\n" -".L80059830:\n" -" lui $a0, %hi(D_80074174)\n" -" addiu $a0, $a0, %lo(D_80074174)\n" -".end\tfunc_80059760\n" -); - -__asm__( -".text\n" -".globl\tSYS_OBJ_604\n" -".type\tSYS_OBJ_604, @function\n" -"SYS_OBJ_604:\n" -".ent\tSYS_OBJ_604\n" -".set\tnoat\n" -".set\tnoreorder\n" -" lui $v0, %hi(D_80072784)\n" -" lw $v0, %lo(D_80072784)($v0)\n" -" nop\n" -" jalr $v0\n" -" addu $a1, $t0, $zero\n" -" lh $a1, 0($s0)\n" -" lh $a2, 2($s0)\n" -" lh $a3, 4($s0)\n" -" lh $v0, 6($s0)\n" -" lui $v1, %hi(D_80072784)\n" -" lw $v1, %lo(D_80072784)($v1)\n" -" lui $a0, %hi(D_80074160)\n" -" addiu $a0, $a0, %lo(D_80074160)\n" -" jalr $v1\n" -" sw $v0, 16($sp)\n" -".set\treorder\n" -".set\tat\n" -".size\tSYS_OBJ_604, . - SYS_OBJ_604\n" -".end\tSYS_OBJ_604\n" -); - -__asm__( -".text\n" -".align\t2\n" -".globl\tSYS_OBJ_640\n" -".ent\tSYS_OBJ_640\n" -"SYS_OBJ_640:\n" -".set\tnoreorder\n" -"lw $ra, 28($sp)\n" -"lw $s0, 24($sp)\n" -"addiu $sp, $sp, 32\n" -"jr $ra\n" -"nop\n" -".set\treorder\n" -".end\tSYS_OBJ_640\n" -); - -extern void *D_80072780; -extern char D_80074178; -extern void func_80059760(); - -s32 func_80059888(void *rect, u8 r, u8 g, u8 b) -{ - func_80059760(&D_80074178, rect); - return (*(s32 (**)(void *, void *, s32, s32))((u8 *)D_80072780 + 0x8))( - *(void **)((u8 *)D_80072780 + 0xC), rect, 8, - (((b << 16) | (g << 8)) | r)); -} - -extern void *D_80072780; -extern char D_80074178; -extern void func_80059760(); - -void ClearImage2(void *rect, u8 r, u8 g, u8 b) -{ - func_80059760(&D_80074178, rect); - (*(s32 (**)(void *, void *, s32, s32))((u8 *)D_80072780 + 0x8))( - *(void **)((u8 *)D_80072780 + 0xC), rect, 8, - ((((b & 0xFF) << 16) | 0x80000000) | ((g & 0xFF) << 8)) | (r & 0xFF)); -} - -extern void *D_80072780; -extern char D_80074184; -extern void func_80059760(); - -s32 func_800599B8(void *rect, void *p) -{ - func_80059760(&D_80074184, rect); - return (*(s32 (**)(void *, void *, s32, s32))((u8 *)D_80072780 + 0x8))( - *(void **)((u8 *)D_80072780 + 0x20), rect, 8, p); -} - -extern void *D_80072780; -extern char D_80074190; -extern void func_80059760(); - -s32 StoreImage(void *rect, void *p) -{ - func_80059760(&D_80074190, rect); - return (*(s32 (**)(void *, void *, s32, s32))((u8 *)D_80072780 + 0x8))( - *(void **)((u8 *)D_80072780 + 0x1C), rect, 8, p); -} - - -/* =========================================================================== - * MERGED FUNCTION — MoveImage absorbs SYS_OBJ_8F4. - * - * splat split ONE function into two symbols: - * MoveImage 0x80059A80..0x80059B27 (0xA8, 42 insns) - * SYS_OBJ_8F4 0x80059B28..0x80059B43 (0x1C, 7 insns) - * Combined range: 0x80059A80..0x80059B43, 0xC4 bytes, 49 instructions. - * - * SYS_OBJ_8F4 is not an independent function — it is MoveImage's own epilogue: - * it pops ra/s2/s1/s0 out of MoveImage's OWN 0x20-byte frame (ra@0x1C, s2@0x18, - * s1@0x14, s0@0x10 — the exact slots MoveImage's prologue pushed), adds 0x20 to - * sp and returns. MoveImage's two early "return -1" paths branch INTO it - * (`beqz $v0, SYS_OBJ_8F4` at 0x80059AB8 and `j SYS_OBJ_8F4` at 0x80059AD0) and - * MoveImage's own tail falls THROUGH into it. Nothing else in the binary - * mentions SYS_OBJ_8F4 (grep of asm/nonmatchings/800c: only its own .s and - * MoveImage.s). The label exists only because the PsyQ libgpu object carried a - * local symbol on the epilogue block. - * - * Written here as one C function: both `return -1;` statements share gcc's - * single function epilogue, which is byte-identical to SYS_OBJ_8F4's body. - * - * The two early exits come from ONE `||` test, not two separate `if`s — two - * `if`s make gcc cross-jump the -1 returns into a single tail block placed - * AFTER the call, which costs an extra insn and moves the -1 out of the delay - * slots. With `||` the layout is exactly the target's: - * beq w,0 -> epilogue (delay: li -1) [the delay-slot filler copied the -1 - * out of the shared L_ret block and - * retargeted the branch past the j] - * bne h,0 -> body (delay: sll y,16) - * j epilogue (delay: li -1) - * - * The 5-word MOVE_IMAGE packet lives at 0x80072830 (asm/data/53198.data.s): - * 0x80072830 .word 0x04FFFFFF tag (len 4, next = end-of-list) - * 0x80072834 .word 0x80000000 GPU cmd: VRAM->VRAM rectangle copy - * 0x80072838 .word written here - * 0x8007283C .word written here - * 0x80072840 .word written here - * splat emitted NO symbol at 0x80072830 (it falls inside the D_8007281C dlabel - * block) because the compiler never materialized that address directly: it kept - * &D_80072838 in $a1 for the store and reached the packet base with - * `addiu $a1, $a1, -8` in the jalr delay slot. So the base is spelled the same - * way here — `(u8 *)p - 8`. - * - * Why the store to 0x80072838 goes through a STRUCT pointer (MovePktSrc) and - * not through a plain `u32 *`: it is the only form that lets gcc-2.7.2 hoist - * `lw $v1, D_80072780` ABOVE the packet stores, which the target does (that load - * sits at 0x80059AEC/AF0, before both `sw`s). A store through a plain scalar - * `u32 *` is an opaque MEM the scheduler will not reorder against a global load, - * so the load sinks two slots and 6 of 49 instructions land out of place. A - * struct-typed MEM sets MEM_IN_STRUCT_P, gcc-2.7.2's scalar-vs-aggregate - * disambiguation fires, and the schedule becomes byte-identical. Measured: - * plain `u32 *` = 6 mismatched; struct pointer = MATCH. (A 120-variant sweep - * over statement order, hoisted temporaries and local-vs-inline GPU pointer - * never got below 6 without the struct type.) - * ===========================================================================*/ - -typedef struct { - s16 x; - s16 y; - s16 w; - s16 h; -} GpuRect; - -/* the packet's src word, at 0x80072838; the packet itself starts 8 bytes lower */ -typedef struct { - u32 src; -} MovePktSrc; - -typedef s32 (*GpuFn)(void *, void *, s32, s32); - -/* spelled exactly as the rest of src/800c.c already spells it - * (SetGraphQueue, func_80059658) */ -extern void *D_80072780; - -/* checkRECT-style validator + its name string ("MoveImage"); the direct - * analogue of StoreImage's D_80074190 immediately above in the same TU */ -extern char D_8007419C; -extern void func_80059760(char *name, GpuRect *rect); - -extern u32 D_80072838; -extern u32 D_8007283C; -extern u32 D_80072840; - -s32 MoveImage(GpuRect *rect, s32 x, s32 y) -{ - MovePktSrc *p; - - func_80059760(&D_8007419C, rect); - - if (rect->w == 0 || rect->h == 0) { - return -1; - } - - p = (MovePktSrc *)&D_80072838; - p->src = *(u32 *)rect; - D_8007283C = (y << 16) | (x & 0xFFFF); - D_80072840 = *(u32 *)&rect->w; - - return (*(GpuFn *)((u8 *)D_80072780 + 0x8))( - *(void **)((u8 *)D_80072780 + 0x18), (u8 *)p - 8, 0x14, 0); -} - - - -extern u8 D_8007278A; -extern u32 D_80072784; -extern char D_800741A8; -extern char D_80072844; - -void *ClearOTag(u32 *otag, s32 n) -{ - u32 mask_low; - u32 mask_high; - u32 next_addr; - u32 val; - - if (D_8007278A >= 2) { - void (*func)(u32, u32, s32) = (void (*)(u32, u32, s32))D_80072784; - func((u32)&D_800741A8, (u32)otag, n); - } - - n--; - if (n != 0) { - mask_low = 0xFFFFFF; - mask_high = 0xFF000000; - - while (n) { - n--; - next_addr = (u32)otag + 4; - *(u8 *)((u32)otag + 3) = 0; - val = *otag; - val = (val & mask_high); - val = val | (next_addr & mask_low); - *otag = val; - otag = (u32 *)next_addr; - } - } - - *otag = (u32)&D_80072844 & 0xFFFFFF; - return otag; -} - - -extern u8 D_8007278A; -extern volatile u8 D_800741C0[4]; -extern u32 D_80072784; -extern void *D_80072780; -extern char D_80072844; - -void func_80059BFC(s32 a0, s32 a1) { - s32 s0 = a0; - s32 s1 = a1; - u8 byte_val; - void (*func_ptr)(u32, s32, s32); - void (*func_ptr2)(s32, s32); - u32 addr; - u32 *v0; - u32 v1; - u32 mask; - - byte_val = D_8007278A; - - if (byte_val >= 2) { - addr = (u32)D_800741C0; - func_ptr = (void (*)(u32, s32, s32))D_80072784; - func_ptr(addr, s0, s1); - } - - func_ptr2 = *(void (**)(s32, s32))((u8 *)D_80072780 + 0x2C); - func_ptr2(s0, s1); - - { - register u32 outAddr __asm__("$2"); - mask = 0xFFFFFF; - __asm__ volatile("" : "=r"(mask) : "0"(mask)); - outAddr = (u32)s0; - __asm__ volatile("" : "=r"(outAddr) : "0"(outAddr)); - v1 = (u32)&D_80072844; - __asm__ volatile("" : "=r"(v1) : "0"(v1)); - v1 &= mask; - *(u32 *)outAddr = v1; - } -} - -extern void *D_80072780; - -void DrawPrim(void *prim) { - u8 len; - - len = *(u8 *)((u8 *)prim + 3); - (*(void (**)(s32))((u8 *)D_80072780 + 0x3C))(0); - (*(void (**)(void *, s32))((u8 *)D_80072780 + 0x14))((u8 *)prim + 4, len); -} - -extern u8 D_8007278A; -extern u32 D_80072784; -extern void *D_80072780; -extern u8 D_800741D8; - -/* PsyQ DrawOTag: guard call passes the "DrawOTag(%08x)...\n" debug string - * (D_800741D8), then dispatches through GPU fn-table slot +0x8 with the draw - * env pointer at +0x18, the OT, and two zero args. Canonical signature per - * src/resident/resident.c (`extern s32 func_80059CF4(s32);`) -- the tail GPU-fn - * call's result is left in $v0 and becomes this function's return value. - * - * Integration: replace the INCLUDE_ASM("asm/nonmatchings/800c", func_80059CF4) - * stub at line 483 of src/800c.c. D_8007278A/D_80072784/D_80072780 are already - * declared at lines 134-137 of that TU with identical types -- keep those, add - * only `extern u8 D_800741D8;`. - */ -s32 func_80059CF4(s32 a0) { - if (D_8007278A >= 2) { - ((void (*)(void *, s32))D_80072784)(&D_800741D8, a0); - } - return (*(s32 (**)(void *, void *, s32, s32))((u8 *)D_80072780 + 0x8))( - *(void **)((u8 *)D_80072780 + 0x18), (void *)a0, 0, 0); -} - - -void *func_80059D68(void *env) -{ - typedef struct { - u32 w[4]; - } EnvQuad; - - typedef struct { - u32 w[3]; - } EnvTail; - - - typedef void (*EnvGpuFn)(void *, void *, s32, s32); - - extern u8 D_8007278A; - extern u32 D_80072784; - extern void *D_80072780; - extern char D_800741EC; - extern void func_8005A870(); - - u8 *flagp = &D_8007278A; - u32 *s0; - PrimHdr *t; - EnvQuad *src; - EnvQuad *dst; - EnvQuad *end; - - if (*flagp >= 2) { - ((void (*)(void *, void *))D_80072784)(&D_800741EC, env); - } - - s0 = (u32 *)((u8 *)env + 0x1C); - func_8005A870(s0, env); - - t = (PrimHdr *)s0; - t->tag |= 0xFFFFFF; - - (*(EnvGpuFn *)((u8 *)D_80072780 + 0x8))( - *(void **)((u8 *)D_80072780 + 0x18), s0, 0x40, 0); - - dst = (EnvQuad *)(flagp + 0xE); - src = (EnvQuad *)env; - end = (EnvQuad *)((u8 *)env + 0x50); - do { - *dst++ = *src++; - } while (src != end); - *(EnvTail *)dst = *(EnvTail *)src; - - return env; -} - -/* DrawOTagEnv - all auxiliary decls block-scoped */ -extern u8 D_8007278A; -extern u32 D_80072784; -extern void *D_80072780; - -void DrawOTagEnv(void *p, u32 *otag) -{ - typedef struct { - u32 w[4]; - } OTagQuad; - - typedef struct { - u32 w[3]; - } OTagTail; - - - typedef s32 (*OTagEnvGpuFn)(void *, void *, s32, s32); - - extern char D_80074204; - extern void func_8005A870(); - - u8 *flagp = &D_8007278A; - u32 *s0; - PrimHdr *t; - OTagQuad *src; - OTagQuad *dst; - OTagQuad *end; - - if (*flagp >= 2) { - ((void (*)(void *, u32 *, u32 *))D_80072784)(&D_80074204, p, otag); - } - - s0 = otag + 7; - func_8005A870(s0, otag); - - t = (PrimHdr *)s0; - t->tag = (t->tag & 0xFF000000) | ((u32)p & 0xFFFFFF); - - (*(OTagEnvGpuFn *)((u8 *)D_80072780 + 0x8))( - *(void **)((u8 *)D_80072780 + 0x18), s0, 0x40, 0); - - dst = (OTagQuad *)(flagp + 0xE); - src = (OTagQuad *)otag; - end = src + 5; - do { - *dst++ = *src++; - } while (src != end); - *(OTagTail *)dst = *(OTagTail *)src; -} - -extern void func_8005C324(s32 dst, s32 src, s32 n); -extern u8 D_80072798[0x5C]; - -void *GetDrawEnv(void *a0) { - func_8005C324((s32)a0, (s32)D_80072798, 0x5C); - return a0; -} - - -/* - * func_80059FC0 -- part of the SYS_OBJ_XXXX GPU-primitive dispatch family (splat's naming for - * hex offsets into a shared handler table). Like GsTMDfastG3GL (src/800b2.c), this is reproduced - * as handwritten assembly: BOTH branches end with a raw, unlinked tail jump into SYS_OBJ_E34 - * (args left in $v0/$v1, not $a0/$a1; $ra/$s0-$s3 saved but never restored by this function) -- - * SYS_OBJ_E34 owns the shared epilogue for this family, using the fixed 0x28-byte / s0-s3+ra - * frame layout every sibling in the family shares. There is NO trailing "jr $ra" anywhere in the - * target (function size is exactly 0xA8 bytes, ending mid-basic-block) -- gcc-2.7.2 has no - * general sibcall optimization AND unconditionally appends its own return sequence to every - * ordinary (even __asm__-bodied) C function (function.c:expand_function_end, no noreturn guard, - * confirmed empirically both on the callee and on this function itself), so wrapping the body in - * a normal C function can only ever get within +2 instructions (the phantom trailing jr/nop) of - * this target. FILE-SCOPE asm (outside any C function body) is the only spelling that emits - * exactly the target bytes with nothing appended: the compiler treats it as opaque text, no - * .ent-triggered epilogue machinery ever runs. - */ -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tfunc_80059FC0\n" - ".ent\tfunc_80059FC0\n" - "func_80059FC0:\n" - ".frame\t$sp,40,$31\n" - ".mask\t0x800f0000,-8\n" - ".fmask\t0x00000000,0\n" - ".set\tnoreorder\n" - "lui $2, %hi(D_8007278A)\n" - "lbu $2, %lo(D_8007278A)($2)\n" - "addiu $sp, $sp, -40\n" - "sw $16, 16($sp)\n" - "addu $16, $4, $0\n" - "sw $19, 28($sp)\n" - "lui $19, 0x0800\n" - "sw $31, 32($sp)\n" - "sw $18, 24($sp)\n" - "sltiu $2, $2, 2\n" - "bnez $2, 1f\n" - " sw $17, 20($sp)\n" - "lui $4, %hi(D_80074220)\n" - "addiu $4, $4, %lo(D_80074220)\n" - "lui $2, %hi(D_80072784)\n" - "lw $2, %lo(D_80072784)($2)\n" - "nop\n" - "jalr $2\n" - " addu $5, $16, $0\n" - "1:\n" - "lui $2, %hi(D_80072788)\n" - "lbu $2, %lo(D_80072788)($2)\n" - "nop\n" - "addiu $2, $2, -1\n" - "sltiu $2, $2, 2\n" - "beqz $2, 2f\n" - " nop\n" - "jal func_8005ADB8\n" - " addu $4, $16, $0\n" - "lhu $3, 2($16)\n" - "andi $2, $2, 0xfff\n" - "andi $3, $3, 0xfff\n" - "sll $3, $3, 12\n" - "or $3, $3, $2\n" - "j SYS_OBJ_E34\n" - " lui $2, 0x0500\n" - "2:\n" - "lhu $2, 2($16)\n" - "lhu $3, 0($16)\n" - "andi $2, $2, 0x3ff\n" - "sll $2, $2, 10\n" - "andi $3, $3, 0x3ff\n" - "or $2, $2, $3\n" - "lui $3, 0x0500\n" - ".set\treorder\n" - ".end\tfunc_80059FC0\n" -); - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_E34\n" - ".ent\tSYS_OBJ_E34\n" - "SYS_OBJ_E34:\n" - ".set\tnoreorder\n" - "or $4, $2, $3\n" - "lui $2, %hi(D_80072780)\n" - "lw $2, %lo(D_80072780)($2)\n" - "nop\n" - "lw $2, 16($2)\n" - "nop\n" - "jalr $2\n" - "nop\n" - "lui $2, %hi(D_800727FC)\n" - "addiu $2, $2, %lo(D_800727FC)\n" - "lhu $2, 0($2)\n" - "lh $3, 8($16)\n" - "sll $2, $2, 16\n" - "sra $2, $2, 16\n" - "bne $2, $3, .L8005A0FC\n" - "nop\n" - "lui $2, %hi(D_800727FE)\n" - "lhu $2, %lo(D_800727FE)($2)\n" - "lh $3, 10($16)\n" - "sll $2, $2, 16\n" - "sra $2, $2, 16\n" - "bne $2, $3, .L8005A0FC\n" - "nop\n" - "lui $2, %hi(D_80072800)\n" - "lhu $2, %lo(D_80072800)($2)\n" - "lh $3, 12($16)\n" - "sll $2, $2, 16\n" - "sra $2, $2, 16\n" - "bne $2, $3, .L8005A0FC\n" - "nop\n" - "lui $2, %hi(D_80072802)\n" - "lhu $2, %lo(D_80072802)($2)\n" - "lh $3, 14($16)\n" - "sll $2, $2, 16\n" - "sra $2, $2, 16\n" - "beq $2, $3, .L8005A2C4\n" - "nop\n" - ".L8005A0FC:\n" - "jal func_80043078\n" - "nop\n" - "lh $4, 8($16)\n" - "sb $2, 18($16)\n" - "andi $2, $2, 0xFF\n" - "sll $3, $4, 2\n" - "addu $3, $3, $4\n" - "sll $3, $3, 1\n" - "lh $4, 10($16)\n" - "beqz $2, .L8005A130\n" - "addiu $3, $3, 0x260\n" - "j SYS_OBJ_F00\n" - "addiu $17, $4, 0x13\n" - ".L8005A130:\n" - "addiu $17, $4, 0x10\n" - ".set\treorder\n" - ".end\tSYS_OBJ_E34\n" -); - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_F00\n" - ".ent\tSYS_OBJ_F00\n" - "SYS_OBJ_F00:\n" - ".set\tnoreorder\n" - " lh $a1, 12($s0)\n" - " nop\n" - " beqz $a1, .L8005A154\n" - " sll $v0, $a1, 2\n" - " addu $v0, $v0, $a1\n" - " sll $v0, $v0, 1\n" - " j SYS_OBJ_F24\n" - " addu $a2, $v1, $v0\n" - ".L8005A154:\n" - " addiu $a2, $v1, 2560\n" - ".set\treorder\n" - ".end\tSYS_OBJ_F00\n" -); - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_F24\n" - ".ent\tSYS_OBJ_F24\n" - "SYS_OBJ_F24:\n" - ".set\tnoreorder\n" - "lh $v0, 14($s0)\n" - "nop\n" - "bnez $v0, 1f\n" - "addu $s2, $s1, $v0\n" - "addiu $s2, $s1, 0xF0\n" - "1:\n" - "slti $v0, $v1, 0x1F4\n" - "bnez $v0, 2f\n" - "slti $v0, $v1, 0xCDB\n" - "beqz $v0, 3f\n" - "addiu $a1, $zero, 0xCDA\n" - "j SYS_OBJ_F58\n" - "addu $a1, $v1, $zero\n" - "2:\n" - "addiu $a1, $zero, 0x1F4\n" - "3:\n" - ".set\treorder\n" - ".end\tSYS_OBJ_F24\n" -); - -/* SYS_OBJ_F58 reads $s0/$s1/$s2 as live globals (same frame shape as its sibling - * SYS_OBJ_FD8), so plain C cannot carry the register allocation: emit the whole - * function as FILE-SCOPE inline asm, transcribed 1:1 from - * asm/nonmatchings/800c/SYS_OBJ_F58.s (cookbook 179-C: no epilogue of its own -- - * every exit is a raw unlinked j/beqz into SYS_OBJ_FD8, and .L8005A208 falls - * through into the sibling's entry, so a normal C body would gain a phantom - * jr/nop pair). - * Real ".ent"/".end" text (not glabel/endlabel) so maspsx emits the fresh - * ".set noreorder" and our hand-placed delay slots survive (179-B rules 1-2). - * NOTE: maspsx parses ALL displacements AND immediates with bare int() -- every - * number below must be DECIMAL (179-B rule 3 / 265): 0x50=80, 0x10=16, - * 0xCDB=3291, 0xCDA=3290, 0x12=18, 0x137=311, 0x101=257, 0x100=256, 0x136=310. - * Load-delay nops after the two lbu are already in the target and stay (maspsx - * only splices its own when a consumer follows the load). - * PLACEMENT: this block REPLACES the INCLUDE_ASM("asm/nonmatchings/800c", - * SYS_OBJ_F58) stub at src/800c.c:634 -- do not keep both (duplicate symbol). */ -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_F58\n" - ".ent\tSYS_OBJ_F58\n" - "SYS_OBJ_F58:\n" - ".set\tnoreorder\n" - "addu $v1, $a1, $zero\n" - "addiu $a1, $v1, 80\n" - "slt $v0, $a2, $a1\n" - "bnez $v0, .L8005A1B4\n" - "slti $v0, $s1, 16\n" - "slti $v0, $a2, 3291\n" - "beqz $v0, .L8005A1B0\n" - "addiu $a1, $zero, 3290\n" - "addu $a1, $a2, $zero\n" - ".L8005A1B0:\n" - "slti $v0, $s1, 16\n" - ".L8005A1B4:\n" - "bnez $v0, .L8005A208\n" - "addu $a2, $a1, $zero\n" - "lbu $v0, 18($s0)\n" - "nop\n" - "beqz $v0, .L8005A1DC\n" - "slti $v0, $s1, 311\n" - "beqz $v0, .L8005A1E8\n" - "nop\n" - "j SYS_OBJ_FD8\n" - "addu $a0, $s1, $zero\n" - ".L8005A1DC:\n" - "slti $v0, $s1, 257\n" - "bnez $v0, .L8005A200\n" - "nop\n" - ".L8005A1E8:\n" - "lbu $v0, 18($s0)\n" - "nop\n" - "beqz $v0, SYS_OBJ_FD8\n" - "addiu $a0, $zero, 256\n" - "j SYS_OBJ_FD8\n" - "addiu $a0, $zero, 310\n" - ".L8005A200:\n" - "j SYS_OBJ_FD8\n" - "addu $a0, $s1, $zero\n" - ".L8005A208:\n" - "addiu $a0, $zero, 16\n" - ".set\treorder\n" - ".end\tSYS_OBJ_F58\n" -); - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_FD8\n" - ".ent\tSYS_OBJ_FD8\n" - "SYS_OBJ_FD8:\n" - ".set\tnoreorder\n" - "addu $s1, $a0, $zero\n" - "addiu $a1, $s1, 2\n" - "slt $v0, $s2, $a1\n" - "bnez $v0, SYS_OBJ_1034\n" - "nop\n" - "lbu $v0, 18($s0)\n" - "nop\n" - "beqz $v0, .L8005A240\n" - "slti $v0, $s2, 313\n" - "beqz $v0, .L8005A24C\n" - "nop\n" - "j SYS_OBJ_1034\n" - "addu $a1, $s2, $zero\n" - ".L8005A240:\n" - "slti $v0, $s2, 259\n" - "bnez $v0, .L8005A264\n" - "nop\n" - ".L8005A24C:\n" - "lbu $v0, 18($s0)\n" - "nop\n" - "beqz $v0, SYS_OBJ_1034\n" - "addiu $a1, $zero, 258\n" - "j SYS_OBJ_1034\n" - "addiu $a1, $zero, 312\n" - ".L8005A264:\n" - "addu $a1, $s2, $zero\n" - ".set\treorder\n" - ".end\tSYS_OBJ_FD8\n" -); - - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_1034\n" - ".ent\tSYS_OBJ_1034\n" - "SYS_OBJ_1034:\n" - ".set\tnoreorder\n" - " addu $s2, $a1, $zero\n" - " andi $v0, $a2, 0xFFF\n" - " sll $v0, $v0, 12\n" - " andi $a0, $v1, 0xFFF\n" - " lui $v1, (0x6000000 >> 16)\n" - " lui $a1, %hi(D_80072780)\n" - " lw $a1, %lo(D_80072780)($a1)\n" - " or $a0, $a0, $v1\n" - " lw $v1, 16($a1)\n" - " nop\n" - " jalr $v1\n" - " or $a0, $v0, $a0\n" - " andi $v0, $s2, 0x3FF\n" - " sll $v0, $v0, 10\n" - " andi $a0, $s1, 0x3FF\n" - " lui $v1, (0x7000000 >> 16)\n" - " lui $a1, %hi(D_80072780)\n" - " lw $a1, %lo(D_80072780)($a1)\n" - " or $a0, $a0, $v1\n" - " lw $v1, 16($a1)\n" - " nop\n" - " jalr $v1\n" - " or $a0, $v0, $a0\n" - ".L8005A2C4:\n" - " lui $v1, %hi(D_80072804)\n" - " lw $v1, %lo(D_80072804)($v1)\n" - " lw $v0, 16($s0)\n" - " nop\n" - " bne $v1, $v0, .L8005A34C\n" - " nop\n" - " lui $v0, %hi(D_800727F4)\n" - " lhu $v0, %lo(D_800727F4)($v0)\n" - " lh $v1, 0($s0)\n" - " sll $v0, $v0, 16\n" - " sra $v0, $v0, 16\n" - " bne $v0, $v1, .L8005A34C\n" - " nop\n" - " lui $v0, %hi(D_800727F6)\n" - " lhu $v0, %lo(D_800727F6)($v0)\n" - " lh $v1, 2($s0)\n" - " sll $v0, $v0, 16\n" - " sra $v0, $v0, 16\n" - " bne $v0, $v1, .L8005A34C\n" - " nop\n" - " lui $v0, %hi(D_800727F8)\n" - " lhu $v0, %lo(D_800727F8)($v0)\n" - " lh $v1, 4($s0)\n" - " sll $v0, $v0, 16\n" - " sra $v0, $v0, 16\n" - " bne $v0, $v1, .L8005A34C\n" - " nop\n" - " lui $v0, %hi(D_800727FA)\n" - " lhu $v0, %lo(D_800727FA)($v0)\n" - " lh $v1, 6($s0)\n" - " sll $v0, $v0, 16\n" - " sra $v0, $v0, 16\n" - " beq $v0, $v1, .L8005A430\n" - " nop\n" - ".L8005A34C:\n" - " jal func_80043078\n" - " nop\n" - " sb $v0, 18($s0)\n" - " andi $v0, $v0, 0xFF\n" - " addiu $v1, $zero, 1\n" - " bne $v0, $v1, .L8005A36C\n" - " nop\n" - " ori $s3, $s3, 0x8\n" - ".L8005A36C:\n" - " lbu $v0, 17($s0)\n" - " nop\n" - " beqz $v0, .L8005A380\n" - " nop\n" - " ori $s3, $s3, 0x10\n" - ".L8005A380:\n" - " lbu $v0, 16($s0)\n" - " nop\n" - " beqz $v0, .L8005A394\n" - " nop\n" - " ori $s3, $s3, 0x20\n" - ".L8005A394:\n" - " lui $v0, %hi(D_8007278B)\n" - " lbu $v0, %lo(D_8007278B)($v0)\n" - " nop\n" - " beqz $v0, .L8005A3AC\n" - " nop\n" - " ori $s3, $s3, 0x80\n" - ".L8005A3AC:\n" - " lh $v1, 4($s0)\n" - " nop\n" - " slti $v0, $v1, 281\n" - " bnez $v0, SYS_OBJ_11C0\n" - " slti $v0, $v1, 353\n" - " beqz $v0, .L8005A3D0\n" - " slti $v0, $v1, 401\n" - " j SYS_OBJ_11C0\n" - " ori $s3, $s3, 0x1\n" - ".L8005A3D0:\n" - " beqz $v0, .L8005A3E0\n" - " slti $v0, $v1, 561\n" - " j SYS_OBJ_11C0\n" - " ori $s3, $s3, 0x40\n" - ".L8005A3E0:\n" - " beqz $v0, .L8005A3F0\n" - " nop\n" - " j SYS_OBJ_11C0\n" - " ori $s3, $s3, 0x2\n" - ".L8005A3F0:\n" - " ori $s3, $s3, 0x3\n" - ".set\treorder\n" - ".end\tSYS_OBJ_1034\n" -); - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_11C0\n" - ".ent\tSYS_OBJ_11C0\n" - "SYS_OBJ_11C0:\n" - ".set\tnoreorder\n" - "lbu $2, 18($16)\n" - "lh $3, 6($16)\n" - "bnez $2, .L8005A408\n" - " slti $2, $3, 289\n" - "slti $2, $3, 257\n" - ".L8005A408:\n" - "bnez $2, .L8005A414\n" - " nop\n" - "ori $19, $19, 36\n" - ".L8005A414:\n" - "lui $2, %hi(D_80072780)\n" - "lw $2, %lo(D_80072780)($2)\n" - "nop\n" - "lw $2, 16($2)\n" - "nop\n" - "jalr $2\n" - " addu $4, $19, $0\n" - ".L8005A430:\n" - "lui $4, %hi(D_800727F4)\n" - "addiu $4, $4, %lo(D_800727F4)\n" - "addu $5, $16, $0\n" - "jal func_8005C324\n" - " addiu $6, $0, 20\n" - "addu $2, $16, $0\n" - "lw $31, 32($29)\n" - "lw $19, 28($29)\n" - "lw $18, 24($29)\n" - "lw $17, 20($29)\n" - "lw $16, 16($29)\n" - "addiu $29, $29, 40\n" - "jr $31\n" - " nop\n" - ".set\treorder\n" - ".end\tSYS_OBJ_11C0\n" -); - -extern void func_8005C324(s32 dst, s32 src, s32 n); -extern u8 D_800727F4[0x14]; - -void *GetDispEnv(void *a0) { - func_8005C324((s32)a0, (s32)D_800727F4, 0x14); - return a0; -} - -extern void *D_80072780; - -s32 GetODE(void) -{ - return (*(u32 (**)(void))((u8 *)D_80072780 + 0x38))() >> 31; -} - -extern s32 func_8005AD34(s32 a0); - -void SetTexWindow(void *a0, s32 a1) -{ - *(u8 *)(a0 + 3) = 2; - *(s32 *)(a0 + 4) = func_8005AD34(a1); - *(s32 *)(a0 + 8) = 0; -} - -extern s32 func_8005AB58(s32, s32); -extern s32 func_8005AC24(s32, s32); - -void SetDrawArea(void *a0, void *a1) -{ - *(u8 *)(a0 + 3) = 2; - *(s32 *)(a0 + 4) = func_8005AB58(*(s16 *)a1, *(s16 *)(a1 + 2)); - *(s32 *)(a0 + 8) = func_8005AC24( - (s16)(*(u16 *)a1 + *(u16 *)(a1 + 4) - 1), - (s16)(*(u16 *)(a1 + 2) + *(u16 *)(a1 + 6) - 1)); -} - -extern s32 func_8005ACF0(s32 x, s32 y); - -void SetDrawOffset(void *a0, s16 *a1) -{ - *(u8 *)(a0 + 3) = 2; - *(s32 *)(a0 + 4) = func_8005ACF0(a1[0], a1[1]); - *(s32 *)(a0 + 8) = 0; -} - -void SetPriority(unsigned char *arg0, int arg1, int arg2) { - unsigned int temp; - arg0[3] = 2; - temp = 0xE6000000; - if (arg1 != 0) { - temp |= 2; - } - if (arg2 != 0) { - temp |= 1; - } - *(unsigned int *)(arg0 + 4) = temp; - *(unsigned int *)(arg0 + 8) = 0; -} - -extern s32 func_8005AB00(s32 a0, s32 a1, u16 a2); -extern s32 func_8005AD34(s32 a0); - -s32 func_8005A600(s32 a0, s32 a1, s32 a2, s32 a3, s32 a4) { - *(u8 *)(a0 + 3) = 2; - *(s32 *)(a0 + 4) = func_8005AB00(a1, a2, a3); - return *(s32 *)(a0 + 8) = func_8005AD34(a4); -} - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSetDrawEnv\n" - ".ent\tSetDrawEnv\n" - "SetDrawEnv:\n" - ".frame\t$sp,64,$31\n" - ".mask\t0x80030000,-16\n" - ".fmask\t0x00000000,0\n" - ".set\tnoreorder\n" - "addiu $sp, $sp, -64\n" - "sw $s0, 48($sp)\n" - "addu $s0, $a1, $zero\n" - "sw $s1, 52($sp)\n" - "addu $s1, $a0, $zero\n" - "sw $ra, 56($sp)\n" - "lh $a0, 0($s0)\n" - "lh $a1, 2($s0)\n" - "jal func_8005AB58\n" - "nop\n" - "sw $v0, 4($s1)\n" - "lhu $a0, 4($s0)\n" - "lhu $v0, 0($s0)\n" - "lhu $a1, 2($s0)\n" - "addu $a0, $a0, $v0\n" - "addiu $a0, $a0, -1\n" - "sll $a0, $a0, 16\n" - "lhu $v0, 6($s0)\n" - "sra $a0, $a0, 16\n" - "addu $a1, $a1, $v0\n" - "addiu $a1, $a1, -1\n" - "sll $a1, $a1, 16\n" - "jal func_8005AC24\n" - "sra $a1, $a1, 16\n" - "sw $v0, 8($s1)\n" - "lh $a0, 8($s0)\n" - "lh $a1, 10($s0)\n" - "jal func_8005ACF0\n" - "nop\n" - "sw $v0, 12($s1)\n" - "lbu $a0, 23($s0)\n" - "lbu $a1, 22($s0)\n" - "lhu $a2, 20($s0)\n" - "jal func_8005AB00\n" - "nop\n" - "addiu $a0, $s0, 12\n" - "jal func_8005AD34\n" - "sw $v0, 16($s1)\n" - "sw $v0, 20($s1)\n" - "lui $v0, 0xe600\n" - "sw $v0, 24($s1)\n" - "lbu $v0, 24($s0)\n" - "nop\n" - "beqz $v0, .L8005A850\n" - "addiu $a3, $zero, 7\n" - "lhu $v0, 0($s0)\n" - "nop\n" - "sh $v0, 16($sp)\n" - "lhu $v0, 2($s0)\n" - "nop\n" - "sh $v0, 18($sp)\n" - "lhu $a0, 4($s0)\n" - "nop\n" - "sh $a0, 20($sp)\n" - "lhu $v0, 6($s0)\n" - "nop\n" - "sh $v0, 22($sp)\n" - "sll $v0, $a0, 16\n" - "sra $a1, $v0, 16\n" - "bltz $a1, 1f\n" - "addu $v0, $zero, $zero\n" - "lui $v0, %hi(D_8007278C)\n" - "lh $v0, %lo(D_8007278C)($v0)\n" - "nop\n" - "addu $v1, $v0, $zero\n" - "addiu $v0, $v0, -1\n" - "slt $v0, $v0, $a1\n" - "bnez $v0, 1f\n" - "addiu $v0, $v1, -1\n" - "addu $v0, $a0, $zero\n" - "1:\n" - "lh $a1, 22($sp)\n" - "sh $v0, 20($sp)\n" - "bltz $a1, 2f\n" - "addu $a0, $a1, $zero\n" - "lui $v0, %hi(D_8007278E)\n" - "lh $v0, %lo(D_8007278E)($v0)\n" - "nop\n" - "addu $v1, $v0, $zero\n" - "addiu $v0, $v0, -1\n" - "slt $v0, $v0, $a1\n" - "bnez $v0, SYS_OBJ_1578\n" - "addiu $v0, $v1, -1\n" - "j SYS_OBJ_1578\n" - "addu $v0, $a0, $zero\n" - "2:\n" - "addu $v0, $zero, $zero\n" - ".set\treorder\n" - ".end\tSetDrawEnv\n" -); - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_1578\n" - ".ent\tSYS_OBJ_1578\n" - "SYS_OBJ_1578:\n" - ".frame\t$sp,64,$31\n" - ".mask\t0x80030000,-16\n" - ".fmask\t0,0\n" - ".set\tnoreorder\n" - "sll $a2, $a3, 2\n" - "addiu $a3, $a3, 1\n" - "sll $a1, $a3, 2\n" - "addiu $a3, $a3, 1\n" - "sh $v0, 22($sp)\n" - "lhu $v0, 16($sp)\n" - "lhu $v1, 8($s0)\n" - "addu $a2, $a2, $s1\n" - "subu $v0, $v0, $v1\n" - "sh $v0, 16($sp)\n" - "lhu $v0, 18($sp)\n" - "lhu $v1, 10($s0)\n" - "lui $a0, 24576\n" - "subu $v0, $v0, $v1\n" - "sh $v0, 18($sp)\n" - "lbu $v0, 27($s0)\n" - "lbu $v1, 26($s0)\n" - "sll $v0, $v0, 16\n" - "sll $v1, $v1, 8\n" - "or $v1, $v1, $a0\n" - "lbu $a0, 25($s0)\n" - "or $v0, $v0, $v1\n" - "or $v0, $v0, $a0\n" - "sw $v0, 0($a2)\n" - "lw $v0, 16($sp)\n" - "addu $a1, $a1, $s1\n" - "sw $v0, 0($a1)\n" - "sll $v0, $a3, 2\n" - "lw $v1, 20($sp)\n" - "addu $v0, $v0, $s1\n" - "sw $v1, 0($v0)\n" - "lhu $v0, 16($sp)\n" - "lhu $v1, 8($s0)\n" - "nop\n" - "addu $v0, $v0, $v1\n" - "sh $v0, 16($sp)\n" - "lhu $v0, 18($sp)\n" - "lhu $v1, 10($s0)\n" - "addiu $a3, $a3, 1\n" - "addu $v0, $v0, $v1\n" - "sh $v0, 18($sp)\n" - ".L8005A850:\n" - "addiu $v0, $a3, -1\n" - "sb $v0, 3($s1)\n" - "lw $ra, 56($sp)\n" - "lw $s1, 52($sp)\n" - "lw $s0, 48($sp)\n" - "addiu $sp, $sp, 64\n" - "jr $ra\n" - "nop\n" - ".set\treorder\n" - ".end\tSYS_OBJ_1578\n" -); - -/* - * func_8005A870 -- like func_80059FC0/SYS_OBJ_E34 and func_80059234/SYS_OBJ_16C in this - * same TU, this function's LAST basic block falls straight through (no "jr $ra", no - * epilogue) into SYS_OBJ_1790, a separately-banked file-scope asm fragment that owns - * this same 0x40-byte / s0,s1,ra frame and its own eventual epilogue (via SYS_OBJ_18AC). - * One path additionally takes a bare `beqz`/`bnez` transfer straight into SYS_OBJ_18AC / - * SYS_OBJ_1790 respectively. gcc-2.7.2 has no sibcall optimization and unconditionally - * appends its own "jr $ra" epilogue to any ordinary C function body -- so this can only be - * expressed as FILE-SCOPE inline asm (no enclosing C function), transcribed 1:1 from the - * target .s (asm/nonmatchings/800c/func_8005A870.s), with every symbol spelled exactly as - * the target's own relocation lines name it. - */ -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tfunc_8005A870\n" - ".ent\tfunc_8005A870\n" - "func_8005A870:\n" - ".frame\t$sp,64,$31\n" - ".mask\t0x80030000,-8\n" - ".fmask\t0x00000000,0\n" - ".set\tnoreorder\n" - "addiu $sp, $sp, -64\n" - "sw $s0, 48($sp)\n" - "addu $s0, $a1, $zero\n" - "sw $s1, 52($sp)\n" - "addu $s1, $a0, $zero\n" - "sw $ra, 56($sp)\n" - "lh $a0, 0($s0)\n" - "lh $a1, 2($s0)\n" - "jal func_8005AB58\n" - " nop\n" - "sw $v0, 4($s1)\n" - "lhu $a0, 4($s0)\n" - "lhu $v0, 0($s0)\n" - "lhu $a1, 2($s0)\n" - "addu $a0, $a0, $v0\n" - "addiu $a0, $a0, -1\n" - "sll $a0, $a0, 16\n" - "lhu $v0, 6($s0)\n" - "sra $a0, $a0, 16\n" - "addu $a1, $a1, $v0\n" - "addiu $a1, $a1, -1\n" - "sll $a1, $a1, 16\n" - "jal func_8005AC24\n" - " sra $a1, $a1, 16\n" - "sw $v0, 8($s1)\n" - "lh $a0, 8($s0)\n" - "lh $a1, 10($s0)\n" - "jal func_8005ACF0\n" - " nop\n" - "sw $v0, 12($s1)\n" - "lbu $a0, 23($s0)\n" - "lbu $a1, 22($s0)\n" - "lhu $a2, 20($s0)\n" - "jal func_8005AB00\n" - " nop\n" - "addiu $a0, $s0, 12\n" - "jal func_8005AD34\n" - " sw $v0, 16($s1)\n" - "sw $v0, 20($s1)\n" - "lui $v0, 0xe600\n" - "sw $v0, 24($s1)\n" - "lbu $v0, 24($s0)\n" - "nop\n" - "beqz $v0, SYS_OBJ_18AC\n" - " addiu $t0, $zero, 7\n" - "lhu $v0, 0($s0)\n" - "nop\n" - "sh $v0, 16($sp)\n" - "lhu $v0, 2($s0)\n" - "nop\n" - "sh $v0, 18($sp)\n" - "lhu $a0, 4($s0)\n" - "nop\n" - "sh $a0, 20($sp)\n" - "lhu $v0, 6($s0)\n" - "nop\n" - "sh $v0, 22($sp)\n" - "sll $v0, $a0, 16\n" - "sra $a1, $v0, 16\n" - "bltz $a1, .L8005A988\n" - " addu $v0, $zero, $zero\n" - "lui $v0, %hi(D_8007278C)\n" - "lh $v0, %lo(D_8007278C)($v0)\n" - "nop\n" - "addu $v1, $v0, $zero\n" - "addiu $v0, $v0, -1\n" - "slt $v0, $v0, $a1\n" - "bnez $v0, .L8005A988\n" - " addiu $v0, $v1, -1\n" - "addu $v0, $a0, $zero\n" - ".L8005A988:\n" - "lh $a1, 22($sp)\n" - "sh $v0, 20($sp)\n" - "bltz $a1, .L8005A9C0\n" - " addu $a0, $a1, $zero\n" - "lui $v0, %hi(D_8007278E)\n" - "lh $v0, %lo(D_8007278E)($v0)\n" - "nop\n" - "addu $v1, $v0, $zero\n" - "addiu $v0, $v0, -1\n" - "slt $v0, $v0, $a1\n" - "bnez $v0, SYS_OBJ_1790\n" - " addiu $v0, $v1, -1\n" - "j SYS_OBJ_1790\n" - " addu $v0, $a0, $zero\n" - ".L8005A9C0:\n" - "addu $v0, $zero, $zero\n" - ".set\treorder\n" - ".end\tfunc_8005A870\n" -); - -/* SYS_OBJ_1790 (0x8005A9C4, 0x11C, 71 insns) -- REPLACES the - * INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_1790) entry at this exact spot - * (between func_8005A870 and SYS_OBJ_18AC). - * - * NOT a callable C function: it is the TAIL FRAGMENT of func_8005A870 (that - * parent stashes x/y/w/h in its own 0x40-byte frame slots 0x10/0x12/0x14/0x16, - * clamps them against D_8007278C/D_8007278E, and enters here via - * `bnez $v0, SYS_OBJ_1790` / `j SYS_OBJ_1790` with the clamped width in $v0, - * consumed by this fragment's first pair lhu $v1,16($sp)/sh $v0,22($sp)). - * Both exits leave via bare tail `j SYS_OBJ_18AC` -- the shared family - * epilogue (lw ra/s1/s0, addiu sp,0x40, jr ra). gcc-2.7.2 unconditionally - * appends a jr $ra epilogue to every C-function body (even noreturn/pure-asm), - * so the fragment is FILE-SCOPE inline asm -- the idiom already used by - * func_80059234, func_80059760, func_80059FC0/SYS_OBJ_E34 and SYS_OBJ_1DC0 in - * this TU. The tab-separated ".ent\t"/".end\t" pair is load-bearing (maspsx - * re-emits .set noreorder only on ".ent\t"; a plain .set line is swallowed, so - * GNU as would assemble in reorder mode and displace the delay slots). - * .frame/.mask/.fmask copied from the working func_80059FC0 blob (declares the - * PARENT frame: 64=0x40 bytes, mask ra|s1|s0=0x80030000). - * - * Body transcribed 1:1 from asm/nonmatchings/800c/SYS_OBJ_1790.s. - * SYMBOL AUDIT: the ONLY relocation in range is `j SYS_OBJ_18AC` - * (word 0x08016AB8 -> 0x8005AAE0, confirmed against SYS_OBJ_18AC.s); the two - * luis are pure literals (0x60000000>>16 GPU cmd base, 0x2000000>>16 blend - * tag), no %hi/%lo, no jal, no data symbols. Local labels numeric (1f/2f; - * branch offsets 6/0x28 encode identically to the target's .L names). - * Load/store offsets DECIMAL: maspsx hard-fails hex mem offsets ("invalid - * literal for int() with base 10"); lui/addiu/andi/or immediates stay hex. - */ -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_1790\n" - ".ent\tSYS_OBJ_1790\n" - "SYS_OBJ_1790:\n" - ".frame\t$sp,64,$31\n" - ".mask\t0x80030000,-8\n" - ".fmask\t0x00000000,0\n" - ".set\tnoreorder\n" - "lhu $v1, 16($sp)\n" - "sh $v0, 22($sp)\n" - "andi $v0, $v1, 0x3f\n" - "bnez $v0, 1f\n" - " sll $a2, $t0, 2\n" - "lhu $v0, 20($sp)\n" - "nop\n" - "andi $v0, $v0, 0x3f\n" - "beqz $v0, 2f\n" - " sll $a1, $t0, 2\n" - "1:\n" - "addiu $t0, $t0, 0x1\n" - "sll $a1, $t0, 2\n" - "addiu $t0, $t0, 0x1\n" - "lhu $v0, 8($s0)\n" - "addu $a2, $a2, $s1\n" - "subu $v0, $v1, $v0\n" - "sh $v0, 16($sp)\n" - "lhu $v0, 18($sp)\n" - "lhu $v1, 10($s0)\n" - "lui $a0, 0x6000\n" - "subu $v0, $v0, $v1\n" - "sh $v0, 18($sp)\n" - "lbu $v0, 27($s0)\n" - "lbu $v1, 26($s0)\n" - "sll $v0, $v0, 16\n" - "sll $v1, $v1, 8\n" - "or $v1, $v1, $a0\n" - "lbu $a0, 25($s0)\n" - "or $v0, $v0, $v1\n" - "or $v0, $v0, $a0\n" - "sw $v0, 0($a2)\n" - "lw $v0, 16($sp)\n" - "addu $a1, $a1, $s1\n" - "sw $v0, 0($a1)\n" - "sll $v0, $t0, 2\n" - "lw $v1, 20($sp)\n" - "addu $v0, $v0, $s1\n" - "sw $v1, 0($v0)\n" - "lhu $v0, 16($sp)\n" - "lhu $v1, 8($s0)\n" - "nop\n" - "addu $v0, $v0, $v1\n" - "sh $v0, 16($sp)\n" - "lhu $v0, 18($sp)\n" - "lhu $v1, 10($s0)\n" - "addiu $t0, $t0, 0x1\n" - "addu $v0, $v0, $v1\n" - "j SYS_OBJ_18AC\n" - " sh $v0, 18($sp)\n" - "2:\n" - "addiu $t0, $t0, 0x1\n" - "sll $a2, $t0, 2\n" - "addiu $t0, $t0, 0x1\n" - "sll $a3, $t0, 2\n" - "addiu $t0, $t0, 0x1\n" - "addu $a1, $a1, $s1\n" - "lui $a0, 0x200\n" - "lbu $v0, 27($s0)\n" - "lbu $v1, 26($s0)\n" - "sll $v0, $v0, 16\n" - "sll $v1, $v1, 8\n" - "or $v1, $v1, $a0\n" - "lbu $a0, 25($s0)\n" - "or $v0, $v0, $v1\n" - "or $v0, $v0, $a0\n" - "sw $v0, 0($a1)\n" - "lw $v0, 16($sp)\n" - "addu $a2, $a2, $s1\n" - "sw $v0, 0($a2)\n" - "lw $v0, 20($sp)\n" - "addu $a3, $a3, $s1\n" - "sw $v0, 0($a3)\n" - ".set\treorder\n" - ".end\tSYS_OBJ_1790\n" -); - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_18AC\n" - ".ent\tSYS_OBJ_18AC\n" - "SYS_OBJ_18AC:\n" - ".set\tnoreorder\n" - "addiu $v0, $t0, -1\n" - "sb $v0, 3($s1)\n" - "lw $ra, 56($sp)\n" - "lw $s1, 52($sp)\n" - "lw $s0, 48($sp)\n" - "addiu $sp, $sp, 64\n" - "jr $ra\n" - "nop\n" - ".set\treorder\n" - ".end\tSYS_OBJ_18AC\n" -); - -__asm__( -".text\n" -".align\t2\n" -".globl\tfunc_8005AB00\n" -".ent\tfunc_8005AB00\n" -"func_8005AB00:\n" -".frame\t$sp,0,$31\n" -".mask\t0x00000000,0\n" -".fmask\t0x00000000,0\n" -".set\tnoreorder\n" -"lui $v0, %hi(D_80072788)\n" -"lbu $v0, %lo(D_80072788)($v0)\n" -"nop\n" -"addiu $v0, $v0, -1\n" -"sltiu $v0, $v0, 2\n" -"beqz $v0, .L8005AB38\n" -"nop\n" -"beqz $a1, .L8005AB28\n" -"lui $v1, 57600\n" -"ori $v1, $v1, 2048\n" -".L8005AB28:\n" -"beqz $a0, SYS_OBJ_191C\n" -"andi $v0, $a2, 10239\n" -"j SYS_OBJ_191C\n" -"ori $v0, $v0, 4096\n" -".L8005AB38:\n" -"beqz $a1, .L8005AB44\n" -"lui $v1, 57600\n" -"ori $v1, $v1, 512\n" -".L8005AB44:\n" -"beqz $a0, SYS_OBJ_191C\n" -"andi $v0, $a2, 2559\n" -"ori $v0, $v0, 1024\n" -".set\treorder\n" -".end\tfunc_8005AB00\n" -); - -s32 SYS_OBJ_191C(s32 a0, s32 a1, s32 a2, s32 a3) { - register s32 v0 __asm__("$2"); - register s32 v1 __asm__("$3"); - __asm__ __volatile__("" : "=r"(v0)); - __asm__ __volatile__("" : "=r"(v1)); - return v1 | v0; -} - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tfunc_8005AB58\n" - ".ent\tfunc_8005AB58\n" - "func_8005AB58:\n" - ".frame\t$sp,16,$31\n" - ".mask\t0x00000000,0\n" - ".fmask\t0x00000000,0\n" - ".set\tnoreorder\n" - "addu $a3, $a0, $zero\n" - "sll $a0, $a0, 16\n" - "sra $a0, $a0, 16\n" - "bltz $a0, .L8005AB94\n" - " addiu $sp, $sp, -16\n" - "lui $v0, %hi(D_8007278C)\n" - "lh $v0, %lo(D_8007278C)($v0)\n" - "nop\n" - "addu $a2, $v0, $zero\n" - "addiu $v0, $v0, -1\n" - "slt $v0, $v0, $a0\n" - "bnez $v0, SYS_OBJ_1964\n" - " addiu $v0, $a2, -1\n" - "j SYS_OBJ_1964\n" - " addu $v0, $a3, $zero\n" - ".L8005AB94:\n" - "addu $v0, $zero, $zero\n" - ".set\treorder\n" - ".end\tfunc_8005AB58\n" -); - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_1964\n" - ".ent\tSYS_OBJ_1964\n" - "SYS_OBJ_1964:\n" - ".frame\t$sp,0,$31\n" - ".mask\t0x00000000,0\n" - ".fmask\t0x00000000,0\n" - ".set\tnoreorder\n" - "addu $a3, $v0, $zero\n" - "sll $v0, $a1, 16\n" - "sra $a2, $v0, 16\n" - "bltz $a2, .L8005ABD4\n" - "nop\n" - "lui $v0, %hi(D_8007278E)\n" - "lh $v0, %lo(D_8007278E)($v0)\n" - "nop\n" - "addu $a0, $v0, $zero\n" - "addiu $v0, $v0, -0x1\n" - "slt $v0, $v0, $a2\n" - "beqz $v0, SYS_OBJ_19A4\n" - "nop\n" - "j SYS_OBJ_19A4\n" - "addiu $a1, $a0, -0x1\n" - ".L8005ABD4:\n" - "addu $a1, $zero, $zero\n" - ".set\treorder\n" - ".end\tSYS_OBJ_1964\n" -); - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_19A4\n" - ".ent\tSYS_OBJ_19A4\n" - "SYS_OBJ_19A4:\n" - ".frame\t$sp,0,$31\n" - ".mask\t0x00000000,0\n" - ".fmask\t0x00000000,0\n" - ".set\tnoreorder\n" - "lui $2, %hi(D_80072788)\n" - "lbu $2, %lo(D_80072788)($2)\n" - "nop\n" - "addiu $2, $2, -1\n" - "sltiu $2, $2, 2\n" - "bnez $2, 1f\n" - " andi $3, $5, 0xfff\n" - "andi $3, $5, 0x3ff\n" - "sll $3, $3, 10\n" - "j SYS_OBJ_19D8\n" - " andi $2, $7, 0x3ff\n" - "1:\n" - "sll $3, $3, 12\n" - "andi $2, $7, 0xfff\n" - ".set\treorder\n" - ".end\tSYS_OBJ_19A4\n" -); - -s32 SYS_OBJ_19D8(s32 a0, s32 a1, s32 a2, s32 a3) { - register s32 v0 __asm__("$2"); - register s32 v1 __asm__("$3"); - __asm__ __volatile__("" : "=r"(v0)); - __asm__ __volatile__("" : "=r"(v1)); - a0 = 0xE3000000; - v0 = v1 | (v0 | a0); - __asm__ __volatile__("addiu\t$sp, $sp, 0x10"); - return v0; -} - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tfunc_8005AC24\n" - ".ent\tfunc_8005AC24\n" - "func_8005AC24:\n" - ".frame\t$sp,16,$31\n" - ".mask\t0x00000000,0\n" - ".fmask\t0x00000000,0\n" - ".set\tnoreorder\n" - "addu $a3, $a0, $zero\n" - "sll $a0, $a0, 16\n" - "sra $a0, $a0, 16\n" - "bltz $a0, 1f\n" - " addiu $sp, $sp, -16\n" - "lui $v0, %hi(D_8007278C)\n" - "lh $v0, %lo(D_8007278C)($v0)\n" - "nop\n" - "addu $a2, $v0, $zero\n" - "addiu $v0, $v0, -1\n" - "slt $v0, $v0, $a0\n" - "bnez $v0, SYS_OBJ_1A30\n" - " addiu $v0, $a2, -1\n" - "j SYS_OBJ_1A30\n" - " addu $v0, $a3, $zero\n" - "1:\n" - "addu $v0, $zero, $zero\n" - ".set\treorder\n" - ".end\tfunc_8005AC24\n" -); - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_1A30\n" - ".ent\tSYS_OBJ_1A30\n" - "SYS_OBJ_1A30:\n" - ".frame\t$sp,0,$31\n" - ".mask\t0x00000000,0\n" - ".fmask\t0x00000000,0\n" - ".set\tnoreorder\n" - "addu $a3, $v0, $zero\n" - "sll $v0, $a1, 16\n" - "sra $a2, $v0, 16\n" - "bltz $a2, .L8005ACA0\n" - " nop\n" - "lui $v0, %hi(D_8007278E)\n" - "lh $v0, %lo(D_8007278E)($v0)\n" - "addu $a0, $v0, $zero\n" - "addiu $v0, $v0, -1\n" - "slt $v0, $v0, $a2\n" - "beqz $v0, SYS_OBJ_1A70\n" - " nop\n" - "j SYS_OBJ_1A70\n" - " addiu $a1, $a0, -1\n" - ".L8005ACA0:\n" - "addu $a1, $zero, $zero\n" - ".set\treorder\n" - ".end\tSYS_OBJ_1A30\n" -); - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_1A70\n" - ".ent\tSYS_OBJ_1A70\n" - "SYS_OBJ_1A70:\n" - ".frame\t$sp,0,$31\n" - ".mask\t0x00000000,0\n" - ".fmask\t0x00000000,0\n" - ".set\tnoreorder\n" - "lui $2, %hi(D_80072788)\n" - "lbu $2, %lo(D_80072788)($2)\n" - "nop\n" - "addiu $2, $2, -1\n" - "sltiu $2, $2, 2\n" - "bnez $2, 1f\n" - " andi $3, $5, 0xfff\n" - "andi $3, $5, 0x3ff\n" - "sll $3, $3, 10\n" - "j SYS_OBJ_1AA4\n" - " andi $2, $7, 0x3ff\n" - "1:\n" - "sll $3, $3, 12\n" - "andi $2, $7, 0xfff\n" - ".set\treorder\n" - ".end\tSYS_OBJ_1A70\n" -); - -s32 SYS_OBJ_1AA4(s32 a0, s32 a1, s32 a2, s32 a3) { - register s32 v0 __asm__("$2"); - register s32 v1 __asm__("$3"); - __asm__ __volatile__("" : "=r"(v0)); - __asm__ __volatile__("" : "=r"(v1)); - a0 = 0xE4000000; - v0 = v1 | (v0 | a0); - __asm__ __volatile__("addiu\t$sp, $sp, 0x10"); - return v0; -} - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tfunc_8005ACF0\n" - ".ent\tfunc_8005ACF0\n" - "func_8005ACF0:\n" - ".frame\t$sp,0,$31\n" - ".mask\t0x00000000,0\n" - ".fmask\t0x00000000,0\n" - ".set\tnoreorder\n" - "lui $2, %hi(D_80072788)\n" - "lbu $2, %lo(D_80072788)($2)\n" - "nop\n" - "addiu $2, $2, -1\n" - "sltiu $2, $2, 2\n" - "bnez $2, 1f\n" - " andi $3, $5, 0xfff\n" - "andi $3, $5, 0x7ff\n" - "sll $3, $3, 11\n" - "j SYS_OBJ_1AF0\n" - " andi $2, $4, 0x7ff\n" - "1:\n" - "sll $3, $3, 12\n" - "andi $2, $4, 0xfff\n" - ".set\treorder\n" - ".end\tfunc_8005ACF0\n" -); - -s32 SYS_OBJ_1AF0(void) { - register s32 r_v0 __asm__("v0"); - register s32 r_v1 __asm__("v1"); - r_v0 |= 0xE5000000; - return r_v1 | r_v0; -} - -__asm__( -".text\n" -".align\t2\n" -".globl\tfunc_8005AD34\n" -".ent\tfunc_8005AD34\n" -"func_8005AD34:\n" -" .set\tnoreorder\n" -" bnez $a0, .L8005AD44\n" -" addiu $sp, $sp, -16\n" -" j SYS_OBJ_1B78\n" -" addu $v0, $zero, $zero\n" -".L8005AD44:\n" -" lbu $a1, 0($a0)\n" -" nop\n" -" srl $a1, $a1, 3\n" -" sw $a1, 0($sp)\n" -" lh $a2, 4($a0)\n" -" nop\n" -" negu $a2, $a2\n" -" andi $a2, $a2, 0xFF\n" -" sra $a2, $a2, 3\n" -" sw $a2, 8($sp)\n" -" lbu $v0, 2($a0)\n" -" sll $a1, $a1, 10\n" -" srl $v0, $v0, 3\n" -" sw $v0, 4($sp)\n" -" sll $v0, $v0, 15\n" -" lh $v1, 6($a0)\n" -" lui $a0, 0xe200\n" -" or $a1, $a1, $a0\n" -" or $v0, $v0, $a1\n" -" negu $v1, $v1\n" -" andi $v1, $v1, 0xFF\n" -" sra $v1, $v1, 3\n" -" sll $a0, $v1, 5\n" -" or $v0, $v0, $a0\n" -" or $v0, $v0, $a2\n" -" sw $v1, 12($sp)\n" -".set\treorder\n" -".end\tfunc_8005AD34\n" -); - -void SYS_OBJ_1B78(void) { - __asm__ __volatile__("addiu\t$sp, $sp, 0x10"); -} - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tfunc_8005ADB8\n" - ".ent\tfunc_8005ADB8\n" - "func_8005ADB8:\n" - ".set\tnoreorder\n" - "lui $v1, %hi(D_80072788)\n" - "lbu $v1, %lo(D_80072788)($v1)\n" - "addiu $v0, $zero, 0x1\n" - "beq $v1, $v0, .L8005ADDC\n" - "addiu $v0, $zero, 0x2\n" - "beq $v1, $v0, .L8005AE04\n" - "nop\n" - "j SYS_OBJ_1C28\n" - "nop\n" - ".L8005ADDC:\n" - "lui $v0, %hi(D_8007278B)\n" - "lbu $v0, %lo(D_8007278B)($v0)\n" - "nop\n" - "beqz $v0, SYS_OBJ_1C28\n" - "addiu $v0, $zero, 0x400\n" - "lh $v1, 4($a0)\n" - "lh $a0, 0($a0)\n" - ".set\treorder\n" - ".end\tfunc_8005ADB8\n" -); - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_1BC4\n" - ".ent\tSYS_OBJ_1BC4\n" - "SYS_OBJ_1BC4:\n" - ".set\tnoreorder\n" - "subu $v0, $v0, $v1\n" - "j SYS_OBJ_1C2C\n" - "subu $v0, $v0, $a0\n" - ".L8005AE04:\n" - "lui $v0, %hi(D_8007278B)\n" - "lbu $v0, %lo(D_8007278B)($v0)\n" - "nop\n" - "beqz $v0, .L8005AE3C\n" - "nop\n" - "lhu $v0, 4($a0)\n" - "lh $a0, 0($a0)\n" - "sll $v0, $v0, 16\n" - "sra $v1, $v0, 16\n" - "srl $v0, $v0, 31\n" - "addu $v1, $v1, $v0\n" - "sra $v1, $v1, 1\n" - "j SYS_OBJ_1BC4\n" - "addiu $v0, $zero, 1024\n" - ".L8005AE3C:\n" - "lhu $v0, 0($a0)\n" - "nop\n" - "sll $v0, $v0, 16\n" - "sra $v1, $v0, 16\n" - "srl $v0, $v0, 31\n" - "addu $v1, $v1, $v0\n" - "j SYS_OBJ_1C2C\n" - "sra $v0, $v1, 1\n" - ".set\treorder\n" - ".end\tSYS_OBJ_1BC4\n" -); - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_1C28\n" - ".ent\tSYS_OBJ_1C28\n" - "SYS_OBJ_1C28:\n" - ".set\tnoreorder\n" - "lh $v0, 0($a0)\n" - ".set\treorder\n" - ".end\tSYS_OBJ_1C28\n" -); - -void SYS_OBJ_1C2C(void) { -} - -extern volatile u32 *D_8007285C; - -u32 _status(void) { - return *D_8007285C; -} - - -extern s32 **D_8007286C; -extern s32 *D_80072870; -extern volatile s32 *D_80072874; -extern s32 *D_80072878; - -extern s32 func_8005C020(void); -extern s32 func_8005C054(void); - -s32 func_8005AE80(s32 *a0, s32 a1) { - s32 s0 = a1; - - *D_80072878 |= 0x8000000; - *D_80072874 = 0; - *D_8007286C = &a0[s0 - 1]; - *D_80072870 = s0; - *D_80072874 = 0x11000002; - func_8005C020(); - - while (*D_80072874 & 0x1000000) { - if (func_8005C054() != 0) { - return -1; - } - } - return s0; -} - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\t_clr\n" - ".ent\t_clr\n" - "_clr:\n" - ".set\tnoreorder\n" - "addiu $sp, $sp, -64\n" - "addu $t0, $a0, $zero\n" - "sw $ra, 56($sp)\n" - "sw $s1, 52($sp)\n" - "sw $s0, 48($sp)\n" - "lh $a0, 4($t0)\n" - "addu $t1, $a1, $zero\n" - "bltz $a0, .L8005AFB4\n" - "addu $a1, $a0, $zero\n" - "lui $v0, %hi(D_8007278C)\n" - "lh $v0, %lo(D_8007278C)($v0)\n" - "nop\n" - "addu $v1, $v0, $zero\n" - "addiu $v0, $v0, -1\n" - "slt $v0, $v0, $a0\n" - "bnez $v0, SYS_OBJ_1D84\n" - "addiu $v0, $v1, -1\n" - "j SYS_OBJ_1D84\n" - "addu $v0, $a1, $zero\n" - ".L8005AFB4:\n" - "addu $v0, $zero, $zero\n" - ".set\treorder\n" - ".end\t_clr\n" -); - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_1D84\n" - ".ent\tSYS_OBJ_1D84\n" - "SYS_OBJ_1D84:\n" - ".set\tnoreorder\n" - "lh $a1, 6($t0)\n" - "sh $v0, 4($t0)\n" - "bltz $a1, .L8005AFF0\n" - "addu $a0, $a1, $zero\n" - "lui $v0, %hi(D_8007278E)\n" - "lh $v0, %lo(D_8007278E)($v0)\n" - "nop\n" - "addu $v1, $v0, $zero\n" - "addiu $v0, $v0, -1\n" - "slt $v0, $v0, $a1\n" - "bnez $v0, SYS_OBJ_1DC0\n" - "addiu $v1, $v1, -1\n" - "j SYS_OBJ_1DC0\n" - "addu $v1, $a0, $zero\n" - ".L8005AFF0:\n" - "addu $v1, $zero, $zero\n" - ".set\treorder\n" - ".end\tSYS_OBJ_1D84\n" -); - - -/* SYS_OBJ_1DC0 (0x8005AFF4) is NOT a callable function: it is the third code FRAGMENT of one - * larger routine that begins at _clr (0x8005AF68) and ends in SYS_OBJ_1F64 (0x8005B198). - * - * _clr -> falls through into SYS_OBJ_1D84 (also reached via `j SYS_OBJ_1D84`) - * SYS_OBJ_1D84 -> falls through into SYS_OBJ_1DC0 (also reached via `j SYS_OBJ_1DC0`) - * SYS_OBJ_1DC0 -> `j SYS_OBJ_1F64` on one path, falls through on the other - * SYS_OBJ_1F64 -> carries the ONLY epilogue (lw $ra,0x38($sp) ... jr $ra) for the chain - * - * SYS_OBJ_1DC0 therefore has NO prologue, NO epilogue, NO `jr $ra`, and is entered with live - * values already in $t0 (the object pointer, set by _clr), $t1 (the second argument, set by - * _clr) and $v1 (the clamped Y computed by SYS_OBJ_1D84). None of that is expressible as a C - * function: any C function body cc1 expands gets an unconditional `jr $ra` epilogue appended - * (proven in this same TU for func_80059234 -- neither __attribute__((noreturn)) nor a bare - * tail `j` suppresses it), and a C function cannot take arguments pre-placed in $t0/$t1/$v1 - * nor fall off its end into the next symbol. - * - * A PREVIOUS attempt reconstructed the WHOLE _clr..SYS_OBJ_1F64 chain as a single C function - * and dropped `.global SYS_OBJ_1DC0` asm labels mid-body so a byte-comparable slice existed. - * That draft reported MATCH from match_one (the sliced region really was byte-exact) but made - * the FULL BINARY DIFFER, and was bisect-rejected: match_one only compares the sliced region, - * while the object file ALSO carried the reconstructed _clr/SYS_OBJ_1D84 prologue code and an - * extra `SYS_combined_1DC0` / `SYS_OBJ_1DC0_END` symbol pair, none of which exist in the - * retail binary -- and _clr / SYS_OBJ_1D84 / SYS_OBJ_1F64 are still INCLUDE_ASM in 800c.c, so - * that reconstructed code was pure ADDITION to the link. - * - * Correct form (the byte-verified idiom already used five times in this TU): emit the fragment - * as FILE-SCOPE inline asm -- a raw text blob cc1 copies verbatim with no RTL function wrapper, - * so no prologue and no epilogue are ever generated and no extra symbol is defined. The literal - * ".ent\t" / ".end\t" pair (tab-separated, exactly as cc1 emits) is load-bearing: maspsx's - * process_line special-cases lines starting with ".ent\t" and emits a FRESH ".set\tnoreorder" - * into its own output, whereas a plain ".set\tnoreorder" line is swallowed as internal state and - * never re-emitted -- without it GNU `as` assembles in reorder mode and displaces every - * hand-placed delay-slot instruction. - * - * Body transcribed 1:1 from asm/nonmatchings/800c/SYS_OBJ_1DC0.s. SYMBOL AUDIT -- every - * relocation in that .s, decoded from the raw instruction words and cross-checked against - * config/symbols.us.txt: - * jal 0x0C016DD7 x3 -> 0x016DD7<<2 | 0x80000000 = 0x8005B75C = func_8005B75C - * j 0x08016C66 -> 0x016C66<<2 | 0x80000000 = 0x8005B198 = SYS_OBJ_1F64 - * lui 0x8008 + addiu 0x8854 -> 0x80080000-0x77AC = 0x80078854 = D_80078854 (address taken, - * masked with 0x00FFFFFF and also used as the `sw $a3,0($a2)` base) - * lui 0x8007 + lw 0x285C -> 0x8007285C = D_8007285C (pointer load, then `lw $a0,0($v0)`) - * %hi/%lo store targets, all in the D_80078830 block: - * D_80078830 D_80078834 D_80078838 D_8007883C D_80078840 D_80078844 D_80078848 - * D_8007884C D_80078850 D_80078858 D_8007885C D_80078860 - * (note D_80078854 is written through $a2, NOT through a %hi/%lo $at pair, and D_8007284C / - * D_80078830's neighbours are NOT touched -- there is no other relocation in the file.) - */ -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_1DC0\n" - ".ent\tSYS_OBJ_1DC0\n" - "SYS_OBJ_1DC0:\n" - ".set\tnoreorder\n" - "lhu $v0, 0($t0)\n" - "nop\n" - "andi $v0, $v0, 0x3f\n" - "bnez $v0, 1f\n" - "sh $v1, 6($t0)\n" - "lhu $v0, 4($t0)\n" - "nop\n" - "andi $v0, $v0, 0x3f\n" - "beqz $v0, 2f\n" - "lui $v0, 0x5ff\n" - "1:\n" - "lui $a1, 0xff\n" - "ori $a1, $a1, 0xffff\n" - "lui $a0, 0xe4ff\n" - "ori $a0, $a0, 0xffff\n" - "lui $a3, 0x3ff\n" - "lui $a2, %hi(D_80078854)\n" - "addiu $a2, $a2, %lo(D_80078854)\n" - "and $v0, $a2, $a1\n" - "lui $v1, 0x800\n" - "or $v0, $v0, $v1\n" - "lui $s0, 0xe300\n" - "lui $s1, 0xe500\n" - "lui $at, %hi(D_80078830)\n" - "sw $v0, %lo(D_80078830)($at)\n" - "lui $v0, 0xe600\n" - "and $a1, $t1, $a1\n" - "lui $v1, 0x6000\n" - "or $a1, $a1, $v1\n" - "lui $at, %hi(D_80078840)\n" - "sw $v0, %lo(D_80078840)($at)\n" - "lui $v0, %hi(D_8007285C)\n" - "lw $v0, %lo(D_8007285C)($v0)\n" - "lui $v1, 0xe100\n" - "lui $at, %hi(D_80078834)\n" - "sw $s0, %lo(D_80078834)($at)\n" - "lui $at, %hi(D_80078838)\n" - "sw $a0, %lo(D_80078838)($at)\n" - "lui $at, %hi(D_8007883C)\n" - "sw $s1, %lo(D_8007883C)($at)\n" - "lw $a0, 0($v0)\n" - "srl $v0, $t1, 31\n" - "sll $v0, $v0, 10\n" - "or $v0, $v0, $v1\n" - "lui $at, %hi(D_80078848)\n" - "sw $a1, %lo(D_80078848)($at)\n" - "andi $a0, $a0, 0x7ff\n" - "or $a0, $a0, $v0\n" - "lui $at, %hi(D_80078844)\n" - "sw $a0, %lo(D_80078844)($at)\n" - "lw $v0, 0($t0)\n" - "ori $a3, $a3, 0xffff\n" - "lui $at, %hi(D_8007884C)\n" - "sw $v0, %lo(D_8007884C)($at)\n" - "lw $v0, 4($t0)\n" - "sw $a3, 0($a2)\n" - "lui $at, %hi(D_80078850)\n" - "sw $v0, %lo(D_80078850)($at)\n" - "jal func_8005B75C\n" - "addiu $a0, $zero, 0x3\n" - "or $v0, $v0, $s0\n" - "lui $at, %hi(D_80078858)\n" - "sw $v0, %lo(D_80078858)($at)\n" - "jal func_8005B75C\n" - "addiu $a0, $zero, 0x4\n" - "lui $v1, 0xe400\n" - "or $v0, $v0, $v1\n" - "lui $at, %hi(D_8007885C)\n" - "sw $v0, %lo(D_8007885C)($at)\n" - "jal func_8005B75C\n" - "addiu $a0, $zero, 0x5\n" - "or $v0, $v0, $s1\n" - "lui $at, %hi(D_80078860)\n" - "sw $v0, %lo(D_80078860)($at)\n" - "j SYS_OBJ_1F64\n" - "nop\n" - "2:\n" - "ori $v0, $v0, 0xffff\n" - "lui $v1, 0xff\n" - "ori $v1, $v1, 0xffff\n" - "lui $at, %hi(D_80078830)\n" - "sw $v0, %lo(D_80078830)($at)\n" - "lui $v0, 0xe600\n" - "and $v1, $t1, $v1\n" - "lui $a1, 0x200\n" - "lui $at, %hi(D_80078834)\n" - "sw $v0, %lo(D_80078834)($at)\n" - "lui $v0, %hi(D_8007285C)\n" - "lw $v0, %lo(D_8007285C)($v0)\n" - "or $v1, $v1, $a1\n" - "lw $a0, 0($v0)\n" - "srl $v0, $t1, 31\n" - "sll $v0, $v0, 10\n" - "lui $at, %hi(D_8007883C)\n" - "sw $v1, %lo(D_8007883C)($at)\n" - "lui $v1, 0xe100\n" - "or $v0, $v0, $v1\n" - "andi $a0, $a0, 0x7ff\n" - "or $a0, $a0, $v0\n" - "lui $at, %hi(D_80078838)\n" - "sw $a0, %lo(D_80078838)($at)\n" - "lw $v0, 0($t0)\n" - "lui $at, %hi(D_80078840)\n" - "sw $v0, %lo(D_80078840)($at)\n" - "lw $v0, 4($t0)\n" - "lui $at, %hi(D_80078844)\n" - "sw $v0, %lo(D_80078844)($at)\n" - ".set\treorder\n" - ".end\tSYS_OBJ_1DC0\n" -); - -/* SYS_OBJ_1F64 (0x8005B198) is NOT a callable function: it is the TAIL FRAGMENT of one larger - * routine that begins at _clr (0x8005AF68) and runs _clr -> SYS_OBJ_1D84 -> SYS_OBJ_1DC0 -> - * SYS_OBJ_1F64 (see the SYS_OBJ_1DC0 block above). SYS_OBJ_1F64 carries the ONLY epilogue of the - * chain: it tears down the 0x40-byte frame BUILT BY _CLR (ra@0x38, s1@0x34, s0@0x30) -- a frame - * this fragment never created. No C function body can express that: cc1 unconditionally appends - * its own prologue/epilogue around any C body (proven in this TU for func_80059234), so the - * correct form is the byte-verified FILE-SCOPE inline asm idiom already used for SYS_OBJ_1DC0, - * replacing the INCLUDE_ASM("asm/nonmatchings/800c", SYS_OBJ_1F64); stub. The literal - * ".ent\t"/".end\t" pair (tab-separated) is load-bearing: maspsx special-cases lines starting - * with ".ent\t" and re-emits a fresh ".set\tnoreorder", whereas a bare ".set\tnoreorder" line is - * swallowed and never re-emitted. NOTE: maspsx parses load/store displacements with int(x) - * base 10 -- memory offsets must be written in DECIMAL (0x38=56, 0x34=52, 0x30=48, 0x40=64). - * - * Body transcribed 1:1 from asm/nonmatchings/800c/SYS_OBJ_1F64.s. SYMBOL AUDIT -- every - * relocation in that .s, decoded from the raw instruction words: - * lui 0x3C048008 + addiu 0x24848830 -> 0x80080000-0x77D0 = 0x80078830 = D_80078830 - * (address taken, passed as $a0) - * jal 0x0C016DC4 -> 0x016DC4<<2 | 0x80000000 = 0x8005B710 = func_8005B710 - * (defined in this TU; writes D_8007285C/D_80072860/ - * D_80072864/D_80072868 -- the GPU clear/draw-env kick) - * (no other relocation in the file.) - */ -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_1F64\n" - ".ent\tSYS_OBJ_1F64\n" - "SYS_OBJ_1F64:\n" - ".set\tnoreorder\n" - "lui $a0, %hi(D_80078830)\n" - "addiu $a0, $a0, %lo(D_80078830)\n" - "jal func_8005B710\n" - "nop\n" - "addu $v0, $zero, $zero\n" - "lw $ra, 56($sp)\n" - "lw $s1, 52($sp)\n" - "lw $s0, 48($sp)\n" - "addiu $sp, $sp, 64\n" - "jr $ra\n" - "nop\n" - ".set\treorder\n" - ".end\tSYS_OBJ_1F64\n" -); - - -/* _dws (0x8005B1C4) is NOT a callable function: it is the HEAD FRAGMENT of one larger routine - * that continues at SYS_OBJ_1FF4 (0x8005B228, the very next address after this symbol's 25 - * instructions end). _dws has NO epilogue and NO `jr $ra` anywhere in its 25 instructions, - * while it builds a full 0x50-byte frame (ra@0x48, s5@0x44, s4@0x40, s3@0x3C, s2@0x38, - * s1@0x34, s0@0x30) that only the continuation tears down, and it ends in a BARE FALLTHROUGH - * into SYS_OBJ_1FF4 at .L8005B224. None of that is expressible as a C function: any C function - * body cc1 expands gets an unconditional `jr $ra` epilogue appended (proven three times in - * this same TU: func_80059234 / SYS_OBJ_16C-family / SYS_OBJ_1DC0 -- neither - * __attribute__((noreturn)) nor a bare tail `j` suppresses it), and a C function cannot fall - * off its end into the next symbol. Correct form (the byte-verified idiom already used five - * times in this TU): emit the fragment as FILE-SCOPE inline asm -- a raw text blob cc1 copies - * verbatim with no RTL function wrapper, so no prologue and no epilogue are ever generated. - * - * The literal ".ent\t" / ".end\t" pair (tab-separated, exactly as cc1 emits) is load-bearing: - * maspsx's process_line special-cases lines starting with ".ent\t" and emits a FRESH - * ".set\tnoreorder" into its own output, whereas a plain ".set\tnoreorder" line is swallowed as - * internal state and never re-emitted -- without it GNU `as` assembles in reorder mode and - * displaces every hand-placed delay-slot instruction. - * - * IMMEDIATE SPELLING LAW (byte-proven this session): maspsx int()s MEM-OPERAND OFFSETS with - * base 10 ONLY -- writing the target's own hex spelling ("sw $s1, 0x34($sp)") dies with - * "MASPSX: invalid literal for int() with base 10: '0x34'", while non-mem immediates - * (addiu -0x50 etc.) pass through untouched. Decimal mem offsets are therefore MANDATORY, - * every banked blob in this TU spells them decimally (20($sp)/24($sp)/...), and textual - * parity with the splat .s is impossible by design -- the bytes are identical regardless. - * - * The local branch-back label keeps the TARGET .s's own spelling `.L8005B224` (law 2: spell - * every symbol from the target); the TU's other banked blobs use exactly this named-.L style - * (.L80059798/.L80059820/.L8005A0FC/...), labels are address-unique so no collision exists, - * and SYS_OBJ_1FF4.s was checked: nothing branches back into _dws's range. - * - * Body transcribed 1:1 from asm/nonmatchings/800c/_dws.s. SYMBOL AUDIT -- every relocation in - * that .s, decoded from the raw instruction words: - * jal 0x0C017008 -> 0x017008<<2 | 0x80000000 = 0x8005C020 = func_8005C020 -- called with NO - * arguments and its result discarded, exactly as this TU's existing declaration - * (src/800c.c: `extern s32 func_8005C020(void);`) and the atlas tu-row ('s32', ()) say; - * lui 0x8007 + lh 0x278C -> 0x8007278C = D_8007278C - * beqz 0x10400004 @0x8005B214 / j 0x08016C8A -> both target 0x8005B228 = SYS_OBJ_1FF4 - * (the continuation fragment) - * bltz 0x04A0000A @0x8005B1F8 -> 0x8005B224 = the local fallthrough label .L8005B224 - * (there is no other relocation in the file.) - */ -__asm__( - ".text\n" - ".align\t2\n" - ".globl\t_dws\n" - ".ent\t_dws\n" - "_dws:\n" - ".set\tnoreorder\n" - "addiu $sp, $sp, -80\n" - "sw $s1, 52($sp)\n" - "addu $s1, $a0, $zero\n" - "sw $s2, 56($sp)\n" - "addu $s2, $a1, $zero\n" - "sw $ra, 72($sp)\n" - "sw $s5, 68($sp)\n" - "sw $s4, 64($sp)\n" - "sw $s3, 60($sp)\n" - "jal func_8005C020\n" - "sw $s0, 48($sp)\n" - "lh $a1, 4($s1)\n" - "addu $s5, $zero, $zero\n" - "bltz $a1, .L8005B224\n" - "addu $v1, $a1, $zero\n" - "lui $v0, %hi(D_8007278C)\n" - "lh $v0, %lo(D_8007278C)($v0)\n" - "nop\n" - "addu $a0, $v0, $zero\n" - "slt $v0, $v0, $a1\n" - "beqz $v0, SYS_OBJ_1FF4\n" - "nop\n" - "j SYS_OBJ_1FF4\n" - "addu $v1, $a0, $zero\n" - ".L8005B224:\n" - "addu $v1, $zero, $zero\n" - ".set\treorder\n" - ".end\t_dws\n" -); - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_1FF4\n" - ".ent\tSYS_OBJ_1FF4\n" - "SYS_OBJ_1FF4:\n" - ".set\tnoreorder\n" - "lh $a1, 6($s1)\n" - "sh $v1, 4($s1)\n" - "bltz $a1, .L8005B25C\n" - "addu $v1, $a1, $zero\n" - "lui $v0, %hi(D_8007278E)\n" - "lh $v0, %lo(D_8007278E)($v0)\n" - "addu $a0, $v1, $zero\n" - "addu $v1, $v0, $zero\n" - "slt $v0, $v0, $a1\n" - "beqz $v0, .L8005B264\n" - "sll $v0, $a0, 16\n" - "j SYS_OBJ_202C\n" - "addu $a0, $v1, $zero\n" - ".L8005B25C:\n" - "addu $a0, $zero, $zero\n" - ".set\treorder\n" - ".end\tSYS_OBJ_1FF4\n" -); - -/* SYS_OBJ_202C (0x8005B260) is NOT an independently C-compilable function: it is a MID-FRAME - * fragment of the larger routine that begins at _dws (0x8005B1C4) and runs - * _dws -> SYS_OBJ_1FF4 -> SYS_OBJ_202C -> SYS_OBJ_21A4 (already banked in this TU). It is - * entered with `j SYS_OBJ_202C` (from SYS_OBJ_1FF4) or by falling into its own local label - * .L8005B264 (also reached with `beqz .., .L8005B264` from SYS_OBJ_1FF4), and it has NO - * prologue -- $s1/$s2/$s5 are already live from _dws's 0x50-byte frame (ra@0x48, s5@0x44, - * s4@0x40, s3@0x3C, s2@0x38, s1@0x34, s0@0x30). Every exit is a bare tail transfer into - * SYS_OBJ_21A4 (`j SYS_OBJ_21A4` / `bnez $v0, SYS_OBJ_21A4`) or a fallthrough at 0x8005B3D4 - * straight into SYS_OBJ_21A4's restore sequence -- SYS_OBJ_202C itself has no `jr $ra` and no - * epilogue. None of that is expressible as a C function (cc1 always appends its own - * prologue/epilogue, proven repeatedly in this TU), so this is the byte-verified file-scope - * inline-asm idiom already used for _dws/SYS_OBJ_1DC0/SYS_OBJ_1F64/SYS_OBJ_1FF4/SYS_OBJ_21A4. - * - * Body transcribed 1:1 from asm/nonmatchings/800c/SYS_OBJ_202C.s. SYMBOL AUDIT (every - * relocation in that .s): - * jal 0x0C01703D -> func_8005C054 (GPU-timeout poller, declared elsewhere in this TU as - * `extern s32 func_8005C054(void);`) - * j SYS_OBJ_21A4 / bnez ..,SYS_OBJ_21A4 -> the shared epilogue banked at src/800c.c - * lui/lw %hi/%lo D_8007285C, D_80072858, D_80072860, D_80072864, D_80072868 -- the GPU - * status/table registers already declared `volatile u32 *` elsewhere in this TU. - * (no other relocation in the file.) - */ -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_202C\n" - ".ent\tSYS_OBJ_202C\n" - "SYS_OBJ_202C:\n" - ".set\tnoreorder\n" - "sll $v0, $a0, 16\n" - ".L8005B264:\n" - "lh $v1, 4($s1)\n" - "sra $v0, $v0, 16\n" - "mult $v1, $v0\n" - "sh $a0, 6($s1)\n" - "mflo $a2\n" - "addiu $v1, $a2, 1\n" - "srl $v0, $v1, 31\n" - "addu $v1, $v1, $v0\n" - "sra $a0, $v1, 1\n" - "bgtz $a0, .L8005B298\n" - "sra $s0, $v1, 5\n" - "j SYS_OBJ_21A4\n" - "addiu $v0, $zero, -1\n" - ".L8005B298:\n" - "addu $v1, $s0, $zero\n" - "sll $v0, $v1, 4\n" - "subu $s0, $a0, $v0\n" - "lui $v0, %hi(D_8007285C)\n" - "lw $v0, %lo(D_8007285C)($v0)\n" - "addu $s4, $v1, $zero\n" - "lw $v0, 0($v0)\n" - "lui $v1, 0x400\n" - "and $v0, $v0, $v1\n" - "bnez $v0, .L8005B2F8\n" - "lui $a0, 0xa000\n" - "lui $s3, 0x400\n" - ".L8005B2C8:\n" - "jal func_8005C054\n" - "nop\n" - "bnez $v0, SYS_OBJ_21A4\n" - "addiu $v0, $zero, -1\n" - "lui $v0, %hi(D_8007285C)\n" - "lw $v0, %lo(D_8007285C)($v0)\n" - "nop\n" - "lw $v0, 0($v0)\n" - "nop\n" - "and $v0, $v0, $s3\n" - "beqz $v0, .L8005B2C8\n" - "lui $a0, 0xa000\n" - ".L8005B2F8:\n" - "lui $v1, %hi(D_8007285C)\n" - "lw $v1, %lo(D_8007285C)($v1)\n" - "lui $v0, 0x400\n" - "sw $v0, 0($v1)\n" - "lui $v1, %hi(D_80072858)\n" - "lw $v1, %lo(D_80072858)($v1)\n" - "lui $v0, 0x100\n" - "sw $v0, 0($v1)\n" - "lui $v0, %hi(D_80072858)\n" - "lw $v0, %lo(D_80072858)($v0)\n" - "beqz $s5, .L8005B32C\n" - "nop\n" - "lui $a0, 0xb000\n" - ".L8005B32C:\n" - "sw $a0, 0($v0)\n" - "lui $v1, %hi(D_80072858)\n" - "lw $v1, %lo(D_80072858)($v1)\n" - "lw $v0, 0($s1)\n" - "nop\n" - "sw $v0, 0($v1)\n" - "lui $v1, %hi(D_80072858)\n" - "lw $v1, %lo(D_80072858)($v1)\n" - "lw $v0, 4($s1)\n" - "addiu $s0, $s0, -1\n" - "sw $v0, 0($v1)\n" - "addiu $v0, $zero, -1\n" - "beq $s0, $v0, .L8005B388\n" - "nop\n" - "addiu $a0, $zero, -1\n" - ".L8005B368:\n" - "lw $v1, 0($s2)\n" - "addiu $s2, $s2, 4\n" - "lui $v0, %hi(D_80072858)\n" - "lw $v0, %lo(D_80072858)($v0)\n" - "addiu $s0, $s0, -1\n" - "sw $v1, 0($v0)\n" - "bne $s0, $a0, .L8005B368\n" - "nop\n" - ".L8005B388:\n" - "beqz $s4, .L8005B3D4\n" - "lui $v1, 0x400\n" - "lui $v0, %hi(D_8007285C)\n" - "lw $v0, %lo(D_8007285C)($v0)\n" - "ori $v1, $v1, 2\n" - "sw $v1, 0($v0)\n" - "lui $v0, %hi(D_80072860)\n" - "lw $v0, %lo(D_80072860)($v0)\n" - "lui $a0, 0x100\n" - "sw $s2, 0($v0)\n" - "sll $v0, $s4, 16\n" - "lui $v1, %hi(D_80072864)\n" - "lw $v1, %lo(D_80072864)($v1)\n" - "ori $v0, $v0, 0x10\n" - "sw $v0, 0($v1)\n" - "lui $v0, %hi(D_80072868)\n" - "lw $v0, %lo(D_80072868)($v0)\n" - "ori $a0, $a0, 0x201\n" - "sw $a0, 0($v0)\n" - ".L8005B3D4:\n" - "addu $v0, $zero, $zero\n" - ".set\treorder\n" - ".end\tSYS_OBJ_202C\n" -); - -/* SYS_OBJ_21A4 -- SHARED EPILOGUE of caller SYS_OBJ_202C's 0x50-byte frame - * (ra@0x48, s5@0x44, s4@0x40, s3@0x3C, s2@0x38, s1@0x34, s0@0x30). - * NOT independently C-compilable: SYS_OBJ_202C reaches it with BARE tail transfers - * ("j SYS_OBJ_21A4" / "bnez $v0, SYS_OBJ_21A4" with -1 in $v0 -- its error exits, - * asm/nonmatchings/800c/SYS_OBJ_202C.s lines 17/35) and its own last block FALLS - * THROUGH into this address (8005B3D8) with the return value already in $v0. There - * is no prologue and no body: any real C definition forces cc1 to synthesize its own - * return sequence after the hand-written restore (empirically probed in this TU: - * neither __attribute__((noreturn)) nor __builtin_unreachable__ suppresses it), so - * file-scope raw asm is the only form -- same family as the banked SYS_OBJ_16C / - * SYS_OBJ_210 / func_80059760+SYS_OBJ_604+SYS_OBJ_640 blobs above. - * - * PLACEMENT (MANDATORY -- cookbook §236 item 10 / ADD-3, see the func_8005C054 block - * at ~line 2604): this blob REPLACES the INCLUDE_ASM("asm/nonmatchings/800c", - * SYS_OBJ_21A4); line at src/800c.c:2109. The stub itself .includes the .s and thus - * DEFINES the symbol (include_asm.h), so keeping both double-defines .globl - * SYS_OBJ_21A4 -- and the stub's `nonmatching` macro additionally defines a SECOND - * global, SYS_OBJ_21A4.NON_MATCHING (include/labels.inc) -- the whole binary goes red - * with ZERO instruction diff. Like func_80059234/func_80059760/SYS_OBJ_E34/SYS_OBJ_1DC0/ - * func_8005C054, no stub line may remain next to this blob. - * - * The literal ".ent\t"/".end\t" pair is load-bearing (maspsx re-emits .set noreorder - * after ".ent\t"; a plain .set\tnoreorder line is swallowed and as assembles in - * reorder mode, displacing the hand-placed delay-slot nop). NOTE: maspsx parses - * lw/sw offsets as decimal ints -- hex offsets like 0x48($sp) crash it ('invalid - * literal for int() with base 10'); write 72($sp)..80($sp). - * - * Body transcribed 1:1 from asm/nonmatchings/800c/SYS_OBJ_21A4.s (10 ins, oracle- - * verified MATCH). The .s contains exactly one symbol (glabel SYS_OBJ_21A4) and zero - * jal/%hi/%lo relocation lines -- no data/function/jtbl references exist to spell. - */ -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_21A4\n" - ".ent\tSYS_OBJ_21A4\n" - "SYS_OBJ_21A4:\n" - ".set\tnoreorder\n" - "lw $ra, 72($sp)\n" - "lw $s5, 68($sp)\n" - "lw $s4, 64($sp)\n" - "lw $s3, 60($sp)\n" - "lw $s2, 56($sp)\n" - "lw $s1, 52($sp)\n" - "lw $s0, 48($sp)\n" - "addiu $sp, $sp, 80\n" - "jr $ra\n" - "nop\n" - ".set\treorder\n" - ".end\tSYS_OBJ_21A4\n" -); - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\t_drs\n" - ".ent\t_drs\n" - "_drs:\n" - ".set\tnoreorder\n" - "addiu $sp, $sp, -72\n" - "sw $s1, 52($sp)\n" - "addu $s1, $a0, $zero\n" - "sw $s2, 56($sp)\n" - "addu $s2, $a1, $zero\n" - "sw $ra, 68($sp)\n" - "sw $s4, 64($sp)\n" - "sw $s3, 60($sp)\n" - "jal func_8005C020\n" - "sw $s0, 48($sp)\n" - "lh $a1, 4($s1)\n" - "nop\n" - "bltz $a1, .L8005B45C\n" - "addu $v1, $a1, $zero\n" - "lui $v0, %hi(D_8007278C)\n" - "lh $v0, %lo(D_8007278C)($v0)\n" - "nop\n" - "addu $a0, $v0, $zero\n" - "slt $v0, $v0, $a1\n" - "beqz $v0, SYS_OBJ_222C\n" - "nop\n" - "j SYS_OBJ_222C\n" - "addu $v1, $a0, $zero\n" - ".L8005B45C:\n" - "addu $v1, $zero, $zero\n" - ".set\treorder\n" - ".end\t_drs\n" -); - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_222C\n" - ".ent\tSYS_OBJ_222C\n" - "SYS_OBJ_222C:\n" - ".set\tnoreorder\n" - "lh $a1, 6($s1)\n" - "sh $v1, 4($s1)\n" - "bltz $a1, .L8005B494\n" - "addu $v1, $a1, $zero\n" - "lui $v0, %hi(D_8007278E)\n" - "lh $v0, %lo(D_8007278E)($v0)\n" - "addu $a0, $v1, $zero\n" - "addu $v1, $v0, $zero\n" - "slt $v0, $v0, $a1\n" - "beqz $v0, .L8005B49C\n" - "sll $v0, $a0, 16\n" - "j SYS_OBJ_2264\n" - "addu $a0, $v1, $zero\n" - ".L8005B494:\n" - "addu $a0, $zero, $zero\n" - ".set\treorder\n" - ".end\tSYS_OBJ_222C\n" -); - -/* Standalone match_one draft for SYS_OBJ_2264. Destination TU is src/800c.c; declarations here - * copy that TU's own spelling verbatim (per the pack's authoritative `tu=` rows). SYS_OBJ_242C is - * the chain's shared-tail sibling, already banked as its own file-scope __asm__ block in that TU - * immediately after this function -- referenced here only via a bare `j`/`bnez` (undefined at - * standalone-compile time is fine; it is a masked relocation, per SYS.md law 1c). */ - -extern volatile u32 *D_8007285C; -extern volatile u32 *D_80072858; -extern volatile u32 *D_80072860; -extern volatile u32 *D_80072864; -extern volatile u32 *D_80072868; -extern s32 func_8005C054(void); - -/* SYS_OBJ_2264 (0x8005B498) -- MIDDLE-CHAIN FRAGMENT, file-scope raw asm (§179-C class). - * - * WHY RAW ASM: this is the third link of _drs (0x8005B3EC) -> SYS_OBJ_222C -> SYS_OBJ_2264 -> - * SYS_OBJ_242C. Every exit is a bare `j`/`bnez` tail transfer to sibling SYS_OBJ_242C (with - * $v0=-1 live in the delay slot) or a fallthrough into SYS_OBJ_242C's first instruction at - * .L8005B65C -- there is NO trailing `jr $ra` anywhere in this function's own body; SYS_OBJ_242C - * (already banked in src/800c.c immediately below the SYS_OBJ_2264 stub) carries the chain's only - * epilogue, tearing down the frame _drs built (ra@68/s4@64/s3@60/s2@56/s1@52/s0@48, decimal, off - * $sp). Per §179-C, cc1's `expand_function_end`/`function_epilogue` appends a `jr $ra`/`nop` to - * ANY real C function unconditionally (no `noreturn` guard on that path) -- the §179-H "one C - * function spans the whole chain" alternative was already tried and bisect-rejected for the - * sibling chain (see the SYS_OBJ_1DC0 history in src/800c.c), so file-scope asm is the only - * surviving form, matching this exact chain's already-banked SYS_OBJ_222C/SYS_OBJ_21A4/ - * SYS_OBJ_242C blocks (house style: no .frame/.mask/.fmask, literal .ent/.end, un-doubled - * %hi/%lo per §179-C rule (b)). - * - * ENTRY POINT NOTE: `.L8005B49C` (right after the leading `sll`) is also the target of - * SYS_OBJ_222C's own `beqz $v0, .L8005B49C` (src/800c.c, the block immediately above the - * SYS_OBJ_2264 stub). Safe: all __asm__ blocks in one TU concatenate into ONE assembled unit, so - * a `.L`-prefixed local label defined here is resolvable from that earlier sibling block exactly - * as it already was via the INCLUDE_ASM'd .s (no behavior change from removing that stub). - * - * SYMBOL-TABLE LAW (§274 ADDENDUM to §179-C): explicit `.type SYS_OBJ_2264, @function` / - * `.size SYS_OBJ_2264, . - SYS_OBJ_2264` so the harness's function-discovery/boundary-walk finds - * an STT_FUNC symbol here (this IS the harvest target). - * - * IMMEDIATES: every `lui`/`ori` pair in the target is a plain 32-bit bit-pattern constant, not a - * `%hi`/`%lo` of any symbol (0x04000000, 0x01000000, 0xC0000000, 0x08000000, 0x04000003, - * 0x01000200) -- transcribed here as the already-shifted/masked literal halves cc1 would have - * emitted, identical bytes to the target's `(X >> 16)` / `(X & 0xFFFF)` disassembly rendering. - * - * SYMBOL AUDIT (against this .s's own relocation lines): D_8007285C, D_80072858, D_80072860, - * D_80072864, D_80072868 (all %hi/%lo pairs), func_8005C054 (jal, GPU-timeout poller, already - * declared/defined in the destination TU), SYS_OBJ_242C (bare `j`/`bnez` tail). - */ -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_2264\n" - ".type\tSYS_OBJ_2264, @function\n" - ".ent\tSYS_OBJ_2264\n" - "SYS_OBJ_2264:\n" - ".set\tnoreorder\n" - "sll $v0, $a0, 16\n" - ".L8005B49C:\n" - "lh $v1, 4($s1)\n" - "sra $v0, $v0, 16\n" - "mult $v1, $v0\n" - "sh $a0, 6($s1)\n" - "mflo $a2\n" - "addiu $v1, $a2, 1\n" - "srl $v0, $v1, 31\n" - "addu $v1, $v1, $v0\n" - "sra $a0, $v1, 1\n" - "bgtz $a0, .L8005B4D0\n" - "sra $s0, $v1, 5\n" - "j SYS_OBJ_242C\n" - "addiu $v0, $zero, -1\n" - ".L8005B4D0:\n" - "addu $v1, $s0, $zero\n" - "sll $v0, $v1, 4\n" - "subu $s0, $a0, $v0\n" - "lui $v0, %hi(D_8007285C)\n" - "lw $v0, %lo(D_8007285C)($v0)\n" - "addu $s4, $v1, $zero\n" - "lw $v0, 0($v0)\n" - "lui $v1, 0x400\n" - "and $v0, $v0, $v1\n" - "bnez $v0, .L8005B530\n" - "nop\n" - "lui $s3, 0x400\n" - ".L8005B500:\n" - "jal func_8005C054\n" - "nop\n" - "bnez $v0, SYS_OBJ_242C\n" - "addiu $v0, $zero, -1\n" - "lui $v0, %hi(D_8007285C)\n" - "lw $v0, %lo(D_8007285C)($v0)\n" - "nop\n" - "lw $v0, 0($v0)\n" - "nop\n" - "and $v0, $v0, $s3\n" - "beqz $v0, .L8005B500\n" - "nop\n" - ".L8005B530:\n" - "lui $v1, %hi(D_8007285C)\n" - "lw $v1, %lo(D_8007285C)($v1)\n" - "lui $v0, 0x400\n" - "sw $v0, 0($v1)\n" - "lui $v1, %hi(D_80072858)\n" - "lw $v1, %lo(D_80072858)($v1)\n" - "lui $v0, 0x100\n" - "sw $v0, 0($v1)\n" - "lui $v1, %hi(D_80072858)\n" - "lw $v1, %lo(D_80072858)($v1)\n" - "lui $v0, 0xC000\n" - "sw $v0, 0($v1)\n" - "lui $v1, %hi(D_80072858)\n" - "lw $v1, %lo(D_80072858)($v1)\n" - "lw $v0, 0($s1)\n" - "nop\n" - "sw $v0, 0($v1)\n" - "lui $v1, %hi(D_80072858)\n" - "lw $v1, %lo(D_80072858)($v1)\n" - "lw $v0, 4($s1)\n" - "nop\n" - "sw $v0, 0($v1)\n" - "lui $v0, %hi(D_8007285C)\n" - "lw $v0, %lo(D_8007285C)($v0)\n" - "nop\n" - "lw $v0, 0($v0)\n" - "lui $v1, 0x800\n" - "and $v0, $v0, $v1\n" - "bnez $v0, .L8005B5DC\n" - "nop\n" - "lui $s1, 0x800\n" - ".L8005B5AC:\n" - "jal func_8005C054\n" - "nop\n" - "bnez $v0, SYS_OBJ_242C\n" - "addiu $v0, $zero, -1\n" - "lui $v0, %hi(D_8007285C)\n" - "lw $v0, %lo(D_8007285C)($v0)\n" - "nop\n" - "lw $v0, 0($v0)\n" - "nop\n" - "and $v0, $v0, $s1\n" - "beqz $v0, .L8005B5AC\n" - "nop\n" - ".L8005B5DC:\n" - "addiu $s0, $s0, -1\n" - "addiu $v0, $zero, -1\n" - "beq $s0, $v0, .L8005B610\n" - "nop\n" - "addiu $v1, $zero, -1\n" - ".L8005B5F0:\n" - "lui $v0, %hi(D_80072858)\n" - "lw $v0, %lo(D_80072858)($v0)\n" - "nop\n" - "lw $v0, 0($v0)\n" - "addiu $s0, $s0, -1\n" - "sw $v0, 0($s2)\n" - "bne $s0, $v1, .L8005B5F0\n" - "addiu $s2, $s2, 4\n" - ".L8005B610:\n" - "beqz $s4, .L8005B65C\n" - "lui $v1, 0x400\n" - "lui $v0, %hi(D_8007285C)\n" - "lw $v0, %lo(D_8007285C)($v0)\n" - "ori $v1, $v1, 3\n" - "sw $v1, 0($v0)\n" - "lui $v0, %hi(D_80072860)\n" - "lw $v0, %lo(D_80072860)($v0)\n" - "lui $a0, 0x100\n" - "sw $s2, 0($v0)\n" - "sll $v0, $s4, 16\n" - "lui $v1, %hi(D_80072864)\n" - "lw $v1, %lo(D_80072864)($v1)\n" - "ori $v0, $v0, 0x10\n" - "sw $v0, 0($v1)\n" - "lui $v0, %hi(D_80072868)\n" - "lw $v0, %lo(D_80072868)($v0)\n" - "ori $a0, $a0, 0x200\n" - "sw $a0, 0($v0)\n" - ".L8005B65C:\n" - "addu $v0, $zero, $zero\n" - ".set\treorder\n" - ".size\tSYS_OBJ_2264, . - SYS_OBJ_2264\n" - ".end\tSYS_OBJ_2264\n" -); - - -/* SYS_OBJ_242C (0x8005B660) -- SHARED EPILOGUE FRAGMENT, file-scope raw asm (byte-verified idiom). - * - * SPLICE LAW (cookbook §236 item 10 / ADD-3): DELETE the stub line for this symbol at - * src/800c.c:2225 and put this block exactly there (between the SYS_OBJ_2264 stub and - * `extern volatile u32 *D_8007285C;`). The stub .includes the .s and thus DEFINES the symbol - * too, so keeping it beside this blob double-defines .globl SYS_OBJ_242C and additionally - * defines the phantom global SYS_OBJ_242C.NON_MATCHING (include/labels.inc) -- whole-binary - * gate red with ZERO instruction diff. Banked precedents of this exact operation in this TU: - * SYS_OBJ_21A4 (comment at src/800c.c:2121), SYS_OBJ_1F64 (:1964), func_8005C054 (:2654). - * - * COMMENT HYGIENE LAW: the stub invocation is deliberately NOT quoted on any single line of - * this comment -- a textual stub-presence checker greps the spliced TU for that invocation, - * and a verbatim quotation inside a comment counts as a second hit, so the substitution is - * refused with zero instruction diff. Every banked raw-asm precedent in this TU wraps the - * invocation across two comment lines for exactly this reason. - * - * SYMBOL-TABLE LAW (cookbook §274 ADDENDUM to §179-C): a file-scope __asm__ transcription - * without an explicit ".type NAME, @function" directive assembles to an object carrying NO - * STT_FUNC symbol for NAME, and the harness's function-discovery / boundary-walk pass finds - * nothing there -- a pure ELF-symbol-table gap indistinguishable from "the transcription - * didn't work" and INVISIBLE to match_one's instruction diff. The stub baseline always - * carried the typed symbol: the glabel/endlabel macro pair (include/labels.inc) expands to - * .globl/.type @function/.ent and .size/.end respectively. This blob therefore spells - * ".type SYS_OBJ_242C, @function" and ".size SYS_OBJ_242C, . - SYS_OBJ_242C" explicitly, - * matching the TU's own .type-carrying exemplars (SYS_OBJ_604 at src/800c.c:469-493, - * SYS_OBJ_2CC4 at :2584-2601) and the banked §274 form - * (src/md_MAIN_003/md_MAIN_003.c:919-927). Directives emit no instruction bytes. - * - * WHY RAW ASM: this is the TAIL FRAGMENT of the routine _drs (0x8005B3EC) -> - * SYS_OBJ_222C -> SYS_OBJ_2264 -> SYS_OBJ_242C. It carries the ONLY epilogue of the chain, - * tearing down the 0x48-byte frame BUILT BY _DRS (ra@0x44, s4@0x40, s3@0x3C, s2@0x38, - * s1@0x34, s0@0x30) -- a frame this fragment never created. Any C body gets cc1's own - * prologue/epilogue appended unconditionally (proven in this TU: func_80059234, SYS_OBJ_16C, - * SYS_OBJ_1DC0, SYS_OBJ_21A4), so no C function can express these 9 instructions. The - * §179-H alternative (one C function spanning the chain, .global labels dropped mid-body) - * was ALREADY TRIED in this TU for the sister chain and bisect-rejected: it reported - * match_one MATCH but added reconstructed-prologue code and a SYS_combined/_END symbol pair - * that do not exist in the retail binary (see the SYS_OBJ_1DC0 history block above, - * src/800c.c:1807-1814). File-scope raw asm is the only surviving form. - * - * LOAD-BEARING DETAILS: the literal ".ent\t"/".end\t" pair (tab-separated) makes maspsx - * re-emit a fresh ".set\tnoreorder"; a bare ".set\tnoreorder" line is swallowed and GNU as - * would assemble in reorder mode, displacing the hand-placed delay-slot nop. Mem-operand - * displacements are DECIMAL because maspsx int()s them base 10 (0x44=68, 0x40=64, 0x3C=60, - * 0x38=56, 0x34=52, 0x30=48, 0x48=72). - * - * SYMBOL AUDIT: asm/nonmatchings/800c/SYS_OBJ_242C.s contains NO relocations -- no lui/addiu - * %hi/%lo, no jal, no j; the only symbol named is SYS_OBJ_242C itself (glabel/endlabel). - * Control transfers INTO this address come from sibling fragment SYS_OBJ_2264 - * (`j SYS_OBJ_242C` @0x8005B4C8, `bnez $v0, SYS_OBJ_242C` @0x8005B508/@0x8005B5B4) and by - * bare fallthrough from its last block (.L8005B65C -> addu $v0,$zero,$zero falls in here). - */ -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_242C\n" - ".type\tSYS_OBJ_242C, @function\n" - ".ent\tSYS_OBJ_242C\n" - "SYS_OBJ_242C:\n" - ".set\tnoreorder\n" - "lw $ra, 68($sp)\n" - "lw $s4, 64($sp)\n" - "lw $s3, 60($sp)\n" - "lw $s2, 56($sp)\n" - "lw $s1, 52($sp)\n" - "lw $s0, 48($sp)\n" - "addiu $sp, $sp, 72\n" - "jr $ra\n" - "nop\n" - ".set\treorder\n" - ".size\tSYS_OBJ_242C, . - SYS_OBJ_242C\n" - ".end\tSYS_OBJ_242C\n" -); - -extern volatile u32 *D_8007285C; -extern u8 D_80078874[]; - -void func_8005B684(u32 arg) { - *D_8007285C = arg; - D_80078874[arg >> 24] = arg; -} - -extern u8 D_80078874[]; - -u8 _getctl(s32 a0) -{ - return D_80078874[a0]; -} - -extern volatile u32 *D_8007285C; -extern volatile u32 *D_80072858; - -s32 _cwb(u32 *src, s32 n) { - s32 i; - - *D_8007285C = 0x04000000; - - for (i = n - 1; i != -1; i--) { - *D_80072858 = *src++; - } - - return 0; -} - -extern volatile u32 *D_8007285C; -extern volatile u32 *D_80072860; -extern volatile u32 *D_80072864; -extern volatile u32 *D_80072868; - -void func_8005B710(s32 a0) { - *D_8007285C = 0x04000002; - *D_80072860 = a0; - *D_80072864 = 0; - *D_80072868 = 0x01000401; -} - -extern volatile u32 *D_8007285C; -extern volatile u32 *D_80072858; - -u32 func_8005B75C(u32 a0) { - *D_8007285C = a0 | 0x10000000; - return *D_80072858 & 0xFFFFFF; -} - -extern s32 func_8005B7B0(void (*f)(s32, s32), s32 *p, s32 n, s32 r); - -s32 _addque(void (*f)(s32, s32), s32 *p, s32 r) { - return func_8005B7B0(f, p, 0, r); -} - - -/* ============================================================================================ - * MERGED FUNCTION — this draft defines func_8005B7B0, NOT SYS_OBJ_26EC. - * - * SYS_OBJ_26EC is not an independent function. splat carved ONE PsyQ libgpu queue-push routine - * (0x8005B7B0..0x8005BA8F, 184 instructions) into SIX symbols: - * - * func_8005B7B0 0x8005B7B0..0x8005B7E3 prologue + `j` to the queue-full TEST - * func_8005B7E4 0x8005B7E4..0x8005B7FB the queue-full wait-loop BODY - * SYS_OBJ_25C8 0x8005B7FC..0x8005B91F the wait-loop TEST + the synchronous path - * SYS_OBJ_26EC 0x8005B920..0x8005B9DB the payload-copy loop + the n==0 arm - * SYS_OBJ_27A8 0x8005B9DC..0x8005BA6F the shared tail: publish, advance, drain - * SYS_OBJ_283C 0x8005BA70..0x8005BA8F the epilogue - * - * Proof they are one function, not six: - * - func_8005B7B0 ends in `j SYS_OBJ_25C8` with NO epilogue, and the frame it builds - * (0x28; ra@0x20, s3@0x1C, s2@0x18, s1@0x14, s0@0x10) is the frame SYS_OBJ_283C tears down; - * - SYS_OBJ_25C8 branches BACKWARD into func_8005B7E4 (`beq $v0,$v1,func_8005B7E4`) — a loop; - * - SYS_OBJ_25C8's `beqz $s1,.L8005B9B8` targets a label INSIDE SYS_OBJ_26EC (the reported - * blocker) and SYS_OBJ_26EC's back-edge is `j SYS_OBJ_26EC` — its own head, the copy loop; - * - $s0/$s1/$s2/$s3 are the four incoming arguments and are live across ALL six ranges. - * - * The owner of the merged function is func_8005B7B0: it is the range's entry point and the only - * symbol an external caller can name (every other symbol is a branch/`j` target from inside). - * - * The queue element type and the global names are NOT invented — they are the ones the ALREADY - * MATCHED sibling func_8005BA90 (src/800c.c:600) uses to DRAIN this same queue, copied verbatim - * per this session's law 1. The declaration block below therefore duplicates src/800c.c:579-598 - * only so this file compiles standalone for match_one; when the body is pasted into the TU it is - * inserted AFTER that existing block (see "notes" — no block needs moving). - * ============================================================================================ */ - -typedef struct { - void (*f)(s32, s32); - s32 a; - s32 b; - s32 pad[21]; -} GpuQue; /* 0x60 */ - -extern volatile GpuQue D_800C5510[]; - -extern volatile u32 *D_8007285C; -extern volatile u32 *D_80072868; -extern u8 D_80072789; -extern volatile s32 D_8007287C[3]; -extern volatile s32 D_8007288C; -extern volatile s32 D_80072890; -extern s32 D_80072894; -/* SCALAR, not [1]: this function stores it ONCE, which gcc-2.7.2 emits as a direct - * `sw $v0,%lo(D_80072790)($at)`; the array form emits an extra `la` address materialization - * (byte-measured: 185 ins instead of 184). func_8005BA90 needs the `la` because it touches the - * same object TWICE and CSEs the address — with the scalar declaration `(&D_80072790)[0]` there - * reproduces that byte-identically (verified: cc1 output diff is empty). */ -extern volatile s32 D_80072790; -extern void (*D_80072794)(void); - -extern s32 func_800426FC(s32); -extern void DMACallback(s32, s32); -extern s32 func_8005C020(void); -extern s32 func_8005C054(void); -extern s32 func_8005BA90(void); - -s32 func_8005B7B0(void (*f)(s32, s32), s32 *p, s32 n, s32 r) { - s32 i; - - func_8005C020(); - - while (((D_8007288C + 1) & 0x3F) == D_80072890) { - if (func_8005C054() != 0) { - return -1; - } - func_8005BA90(); - } - - D_80072894 = func_800426FC(0); - D_80072790 = 1; - - if (D_80072789 == 0 || - (D_8007288C == D_80072890 && !(*D_80072868 & 0x01000000) && D_80072794 == 0)) { - while (!(*D_8007285C & 0x04000000)) { - ; - } - f((s32) p, r); - D_8007287C[0] = (s32) f; - D_8007287C[1] = (s32) p; - D_8007287C[2] = r; - func_800426FC(D_80072894); - return 0; - } - - DMACallback(2, (s32) func_8005BA90); - - if (n != 0) { - for (i = 0; i < n / 4; i++) { - D_800C5510[D_8007288C].pad[i] = p[i]; - } - D_800C5510[D_8007288C].a = (s32) D_800C5510[D_8007288C].pad; - } else { - D_800C5510[D_8007288C].a = (s32) p; - } - - D_800C5510[D_8007288C].b = r; - D_800C5510[D_8007288C].f = f; - D_8007288C = (D_8007288C + 1) & 0x3F; - func_800426FC(D_80072894); - func_8005BA90(); - - return (D_8007288C - D_80072890) & 0x3F; -} - - - - - - - - -extern volatile u32 *D_8007285C; -extern volatile u32 *D_80072868; -extern volatile s32 D_8007287C[3]; -extern volatile s32 D_8007288C; -extern volatile s32 D_80072890; -extern s32 D_80072898; -extern void (*D_80072794)(void); - -extern s32 func_800426FC(s32); -extern void DMACallback(s32, s32); - -s32 func_8005BA90(void) { - if (*D_80072868 & 0x01000000) { - return 1; - } - - D_80072898 = func_800426FC(0); - - while (D_8007288C != D_80072890 && !(*D_80072868 & 0x01000000)) { - if (((D_80072890 + 1) & 0x3F) == D_8007288C && D_80072794 == 0) { - DMACallback(2, 0); - } - while (!(*D_8007285C & 0x04000000)) { - ; - } - D_800C5510[D_80072890].f(D_800C5510[D_80072890].a, D_800C5510[D_80072890].b); - D_8007287C[0] = (s32) D_800C5510[D_80072890].f; - D_8007287C[1] = D_800C5510[D_80072890].a; - D_8007287C[2] = D_800C5510[D_80072890].b; - D_80072890 = (D_80072890 + 1) & 0x3F; - } - - func_800426FC(D_80072898); - - if (D_8007288C == D_80072890 && !(*D_80072868 & 0x01000000) && (&D_80072790)[0] != 0 && - D_80072794 != 0) { - (&D_80072790)[0] = 0; - D_80072794(); - } - - return (D_8007288C - D_80072890) & 0x3F; -} - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tfunc_8005BD7C\n" - ".ent\tfunc_8005BD7C\n" - "func_8005BD7C:\n" - ".frame\t$sp,24,$31\n" - ".mask\t0x80010000,-4\n" - ".fmask\t0x00000000,0\n" - ".set\tnoreorder\n" - "addiu $sp, $sp, -24\n" - "sw $s0, 16($sp)\n" - "addu $s0, $a0, $zero\n" - "sw $ra, 20($sp)\n" - "jal func_800426FC\n" - " addu $a0, $zero, $zero\n" - "lui $at, %hi(D_80072890)\n" - "sw $zero, %lo(D_80072890)($at)\n" - "lui $v1, %hi(D_80072890)\n" - "lw $v1, %lo(D_80072890)($v1)\n" - "lui $at, %hi(D_8007289C)\n" - "sw $v0, %lo(D_8007289C)($at)\n" - "addiu $v0, $zero, 1\n" - "lui $at, %hi(D_8007288C)\n" - "sw $v1, %lo(D_8007288C)($at)\n" - "andi $v1, $s0, 7\n" - "beq $v1, $v0, 3f\n" - " slti $v0, $v1, 2\n" - "beqz $v0, 1f\n" - " nop\n" - "beqz $v1, 2f\n" - " nop\n" - "j SYS_OBJ_2C6C\n" - " nop\n" - "1:\n" - "addiu $v0, $zero, 3\n" - "beq $v1, $v0, 3f\n" - " addiu $v0, $zero, 5\n" - "bne $v1, $v0, SYS_OBJ_2C6C\n" - " nop\n" - "2:\n" - "lui $v1, %hi(D_80072868)\n" - "lw $v1, %lo(D_80072868)($v1)\n" - "addiu $v0, $zero, 1025\n" - "sw $v0, 0($v1)\n" - "lui $v1, %hi(D_80072878)\n" - "lw $v1, %lo(D_80072878)($v1)\n" - "lui $a0, %hi(D_80078874)\n" - "addiu $a0, $a0, %lo(D_80078874)\n" - "lw $v0, 0($v1)\n" - "addu $a1, $zero, $zero\n" - "ori $v0, $v0, 2048\n" - "sw $v0, 0($v1)\n" - "lui $v0, %hi(D_8007285C)\n" - "lw $v0, %lo(D_8007285C)($v0)\n" - "addiu $a2, $zero, 256\n" - "sw $zero, 0($v0)\n" - "jal func_8005C29C\n" - " nop\n" - "lui $a0, %hi(D_800C5510)\n" - "addiu $a0, $a0, %lo(D_800C5510)\n" - "addu $a1, $zero, $zero\n" - "jal func_8005C29C\n" - " addiu $a2, $zero, 6144\n" - "j SYS_OBJ_2C6C\n" - " nop\n" - "3:\n" - "lui $v1, %hi(D_80072868)\n" - "lw $v1, %lo(D_80072868)($v1)\n" - "addiu $v0, $zero, 1025\n" - "sw $v0, 0($v1)\n" - "lui $v1, %hi(D_80072878)\n" - "lw $v1, %lo(D_80072878)($v1)\n" - "nop\n" - "lw $v0, 0($v1)\n" - "nop\n" - "ori $v0, $v0, 2048\n" - "sw $v0, 0($v1)\n" - "lui $v1, %hi(D_8007285C)\n" - "lw $v1, %lo(D_8007285C)($v1)\n" - "lui $v0, 0x200\n" - "sw $v0, 0($v1)\n" - "lui $v1, %hi(D_8007285C)\n" - "lw $v1, %lo(D_8007285C)($v1)\n" - "lui $v0, 0x100\n" - "sw $v0, 0($v1)\n" - ".set\treorder\n" - ".end\tfunc_8005BD7C\n" -); - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_2C6C\n" - ".ent\tSYS_OBJ_2C6C\n" - "SYS_OBJ_2C6C:\n" - ".frame\t$sp,24,$31\n" - ".mask\t0x80010000,-4\n" - ".fmask\t0x00000000,0\n" - ".set\tnoreorder\n" - "lui $a0, %hi(D_8007289C)\n" - "lw $a0, %lo(D_8007289C)($a0)\n" - "jal func_800426FC\n" - "nop\n" - "andi $v0, $s0, 0x7\n" - "bnez $v0, .L8005BEC4\n" - "addu $v0, $zero, $zero\n" - "jal func_8005C1C0\n" - "addu $a0, $s0, $zero\n" - ".L8005BEC4:\n" - "lw $ra, 20($sp)\n" - "lw $s0, 16($sp)\n" - "addiu $sp, $sp, 24\n" - "jr $ra\n" - "nop\n" - ".set\treorder\n" - ".end\tSYS_OBJ_2C6C\n" -); - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tfunc_8005BED8\n" - ".ent\tfunc_8005BED8\n" - ".frame\t$sp,24,$31\n" - ".mask\t0x80010000,-4\n" - ".fmask\t0x00000000,0\n" - ".set\tnoreorder\n" - "func_8005BED8:\n" - "addiu $sp, $sp, -24\n" - "sw $ra, 20($sp)\n" - "bnez $a0, .L8005BF8C\n" - " sw $s0, 16($sp)\n" - "jal func_8005C020\n" - " nop\n" - "j SYS_OBJ_2CDC\n" - " nop\n" - ".set\treorder\n" - ".end\tfunc_8005BED8\n" -); - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_2CC4\n" - ".type\tSYS_OBJ_2CC4, @function\n" - ".ent\tSYS_OBJ_2CC4\n" - "SYS_OBJ_2CC4:\n" - ".set\tnoreorder\n" - " jal func_8005BA90\n" - " nop\n" - " jal func_8005C054\n" - " nop\n" - " bnez $v0, SYS_OBJ_2DD8\n" - " addiu $v0, $zero, -1\n" - ".set\treorder\n" - ".size\tSYS_OBJ_2CC4, . - SYS_OBJ_2CC4\n" - ".end\tSYS_OBJ_2CC4\n" -); - -/* SYS_OBJ_2CDC: no epilogue (falls into the shared SYS_OBJ_2DD8 tail), and its two "exit" - * points are raw `j` jumps into SYS_OBJ_2CC4 / SYS_OBJ_2DD8 with live values in $v0/$s0 and - * the caller's (func_8005BED8) 0x18-byte frame already built. Cookbook SS179-C: transcribed - * 1:1 as file-scope basic asm (literal tab .ent/.end, un-doubled %hi/%lo, decimal displacements, - * hand-written BRANCH/CALL-delay slots only -- LOAD-delay nops omitted, maspsx auto-inserts - * them per SS179-B rule 4). - */ -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_2CDC\n" - ".type\tSYS_OBJ_2CDC, @function\n" - ".ent\tSYS_OBJ_2CDC\n" - "SYS_OBJ_2CDC:\n" - ".set\tnoreorder\n" - "lui $v1, %hi(D_8007288C)\n" - "lw $v1, %lo(D_8007288C)($v1)\n" - "lui $v0, %hi(D_80072890)\n" - "lw $v0, %lo(D_80072890)($v0)\n" - "beq $v1, $v0, .L8005BF44\n" - " nop\n" - "j SYS_OBJ_2CC4\n" - " nop\n" - ".L8005BF34:\n" - "jal func_8005C054\n" - " nop\n" - "bnez $v0, SYS_OBJ_2DD8\n" - " addiu $v0, $zero, -1\n" - ".L8005BF44:\n" - "lui $v0, %hi(D_80072868)\n" - "lw $v0, %lo(D_80072868)($v0)\n" - "lw $v0, 0($v0)\n" - "lui $v1, (0x1000000 >> 16)\n" - "and $v0, $v0, $v1\n" - "bnez $v0, .L8005BF34\n" - " nop\n" - "lui $v0, %hi(D_8007285C)\n" - "lw $v0, %lo(D_8007285C)($v0)\n" - "lw $v0, 0($v0)\n" - "lui $v1, (0x4000000 >> 16)\n" - "and $v0, $v0, $v1\n" - "beqz $v0, .L8005BF34\n" - " addu $v0, $zero, $zero\n" - "j SYS_OBJ_2DD8\n" - " nop\n" - ".L8005BF8C:\n" - "lui $v0, %hi(D_8007288C)\n" - "lw $v0, %lo(D_8007288C)($v0)\n" - "lui $v1, %hi(D_80072890)\n" - "lw $v1, %lo(D_80072890)($v1)\n" - "subu $v0, $v0, $v1\n" - "andi $s0, $v0, 0x3f\n" - "beqz $s0, .L8005BFB8\n" - " nop\n" - "jal func_8005BA90\n" - " nop\n" - ".L8005BFB8:\n" - "lui $v0, %hi(D_80072868)\n" - "lw $v0, %lo(D_80072868)($v0)\n" - "lw $v0, 0($v0)\n" - "lui $v1, (0x1000000 >> 16)\n" - "and $v0, $v0, $v1\n" - "bnez $v0, .L8005BFF8\n" - " nop\n" - "lui $v0, %hi(D_8007285C)\n" - "lw $v0, %lo(D_8007285C)($v0)\n" - "lw $v0, 0($v0)\n" - "lui $v1, (0x4000000 >> 16)\n" - "and $v0, $v0, $v1\n" - "bnez $v0, .L8005C008\n" - " nop\n" - ".L8005BFF8:\n" - "bnez $s0, SYS_OBJ_2DD8\n" - " addu $v0, $s0, $zero\n" - "j SYS_OBJ_2DD8\n" - " addiu $v0, $zero, 1\n" - ".L8005C008:\n" - "addu $v0, $s0, $zero\n" - ".set\treorder\n" - ".size\tSYS_OBJ_2CDC, . - SYS_OBJ_2CDC\n" - ".end\tSYS_OBJ_2CDC\n" -); - -/* SYS_OBJ_2DD8 is the SHARED EPILOGUE TAIL for the 0x18-byte frame family in this slice - * (ra@0x14 / s0@0x10): SYS_OBJ_2CDC reaches it via "j SYS_OBJ_2DD8", SYS_OBJ_2CC4 via - * "bnez $v0, SYS_OBJ_2DD8" -- callers arrive mid-stream with THIS frame already built, i.e. - * the symbol's whole body is another function's epilogue (cookbook SS179-C). A C-function - * body always grows a phantom prologue/epilogue of its own (expand_function_end + - * function_epilogue append unconditionally), so the 5 instructions are transcribed 1:1 as - * file-scope basic asm with literal tab-formed .ent/.end, decimal displacements, and no - * hand-written load-delay nops (no instruction here consumes a just-loaded register). - */ -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_2DD8\n" - ".ent\tSYS_OBJ_2DD8\n" - "SYS_OBJ_2DD8:\n" - ".set\tnoreorder\n" - "lw $ra, 20($sp)\n" - "lw $s0, 16($sp)\n" - "addiu $sp, $sp, 24\n" - "jr $ra\n" - "nop\n" - ".set\treorder\n" - ".end\tSYS_OBJ_2DD8\n" -); - -extern s32 VSync(s32 mode); -extern s32 D_800728A0; -extern s32 D_800728A4; - -s32 func_8005C020(void) { - s32 t; - - t = VSync(-1); - D_800728A0 = t + 0xF0; - D_800728A4 = 0; - return t + 0xF0; -} - -/* func_8005C054 ("get_alarm"): GPU-timeout poller -- VENDOR-COMPILED libgpu code (polls VSync), - * NOT gcc-2.7.2 output. Measured, not assumed: the best honest-C body prices at 93 ins vs the - * target's 87 (LENGTH-DRIFT, 75 mismatched) and carries the vendor tells in every prologue slot -- - * frame addiu -24 with NO 16-byte alignment padding (gcc emits -0x20), sltu for the pointer - * compare (target: slt), ZERO nops after global loads (target: one after each of D_800728A0/ - * D_800728A4/D_80072878), and the -1 return materialized as `li` in a branch shadow instead of - * the target's delay-slot `addiu $v0,$zero,-1` riding a bare tail `j SYS_OBJ_2F7C`. This is the - * cookbook §265 class ("no C source can score MATCH ... stop drafting C"), banked via §265 FORM 1: - * FILE-SCOPE asm -- raw text cc1 copies verbatim, opt-level-independent, no RTL function wrapper, - * so no epilogue machinery ever runs. Both exits leave without any local epilogue: the alarm path - * tail-jumps SYS_OBJ_2F7C with -1 pre-set in the DELAY SLOT; the ok path (.L8005C1AC) sets $v0=0 - * and FALLS THROUGH into SYS_OBJ_2F7C -- read first-hand this session: it is a 4-instruction - * epilogue FRAGMENT (lw $ra,0x18($sp); addiu $sp,$sp,0x20; jr $ra; nop) that tears down THIS - * function's own frame, so func_8005C054+SYS_OBJ_2F7C are one vendor routine split by splat, - * exactly like the _clr/SYS_OBJ_1D84/SYS_OBJ_1DC0/SYS_OBJ_1F64 chain already banked above. - * - * The literal ".ent\t"/".end\t" pair is load-bearing (maspsx re-emits .set noreorder after - * ".ent\t"; a plain .set\tnoreorder line is swallowed and as assembles in reorder mode, - * displacing every hand-placed delay-slot instruction). NOTE: maspsx parses sw/lw offsets as - * decimal ints -- hex offsets like 0x18($sp) crash it ('invalid literal for int() with base 10'); - * write 24($sp). - * - * PLACEMENT (cookbook §236 item 10 / ADD-3 -- THE UN-DELETED INCLUDE_ASM STUB IS A DUPLICATE - * DEFINITION): this blob REPLACES the INCLUDE_ASM("asm/nonmatchings/800c", func_8005C054); line - * at src/800c.c:1107 -- as was done for the five banked siblings above (func_80059234, - * func_80059760, func_80059FC0/SYS_OBJ_E34, SYS_OBJ_1DC0 keep no stub line next to their blobs; - * include_asm.h confirms the stub itself .includes the .s and thus DEFINES the symbol, so keeping - * both double-defines .globl func_8005C054 and the whole binary goes red with zero instruction - * diff). The two existing `extern s32 func_8005C054(void);` declarations (~712, ~992) stay. - * Local-label collision checked: .L8005C0A4/.L8005C1AC exist ONLY in this target's .s across the - * whole asm tree -- no cross-stub clash. - * - * Body transcribed 1:1 from asm/nonmatchings/800c/func_8005C054.s (87 ins, oracle-verified MATCH). - * Every symbol below appears in that .s's own relocation lines: VSync, D_800728A0, D_800728A4, - * D_8007285C, D_80074238, D_8007288C, D_80072860, D_80072890, D_80072868, func_8005C604 (the TU's - * printf), D_8007287C, D_80072880, D_80072884, D_8007426C, func_800426FC, D_8007289C, D_80072878, - * SYS_OBJ_2F7C. - */ -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tfunc_8005C054\n" - ".ent\tfunc_8005C054\n" - "func_8005C054:\n" - ".set\tnoreorder\n" - "addiu $sp, $sp, -32\n" - "sw $ra, 24($sp)\n" - "jal VSync\n" - "addiu $a0, $zero, -1\n" - "lui $v1, %hi(D_800728A0)\n" - "lw $v1, %lo(D_800728A0)($v1)\n" - "nop\n" - "slt $v1, $v1, $v0\n" - "bnez $v1, .L8005C0A4\n" - "nop\n" - "lui $v1, %hi(D_800728A4)\n" - "lw $v1, %lo(D_800728A4)($v1)\n" - "nop\n" - "addiu $v0, $v1, 1\n" - "lui $at, %hi(D_800728A4)\n" - "sw $v0, %lo(D_800728A4)($at)\n" - "lui $v0, 0xF\n" - "slt $v0, $v0, $v1\n" - "beqz $v0, .L8005C1AC\n" - "nop\n" - ".L8005C0A4:\n" - "lui $v1, %hi(D_8007285C)\n" - "lw $v1, %lo(D_8007285C)($v1)\n" - "lui $a0, %hi(D_80074238)\n" - "addiu $a0, $a0, %lo(D_80074238)\n" - "lw $v0, 0($v1)\n" - "lui $a1, %hi(D_8007288C)\n" - "lw $a1, %lo(D_8007288C)($a1)\n" - "lui $v0, %hi(D_80072860)\n" - "lw $v0, %lo(D_80072860)($v0)\n" - "lui $t0, %hi(D_80072890)\n" - "lw $t0, %lo(D_80072890)($t0)\n" - "lw $v0, 0($v0)\n" - "subu $a1, $a1, $t0\n" - "sw $v0, 16($sp)\n" - "lui $v0, %hi(D_80072868)\n" - "lw $v0, %lo(D_80072868)($v0)\n" - "lw $a2, 0($v1)\n" - "lw $a3, 0($v0)\n" - "jal func_8005C604\n" - "andi $a1, $a1, 0x3F\n" - "lui $v0, %hi(D_8007287C)\n" - "addiu $v0, $v0, %lo(D_8007287C)\n" - "lw $a1, 0($v0)\n" - "lui $a2, %hi(D_80072880)\n" - "lw $a2, %lo(D_80072880)($a2)\n" - "lui $a3, %hi(D_80072884)\n" - "lw $a3, %lo(D_80072884)($a3)\n" - "lui $a0, %hi(D_8007426C)\n" - "addiu $a0, $a0, %lo(D_8007426C)\n" - "jal func_8005C604\n" - "nop\n" - "jal func_800426FC\n" - "addu $a0, $zero, $zero\n" - "lui $at, %hi(D_80072890)\n" - "sw $zero, %lo(D_80072890)($at)\n" - "lui $v1, %hi(D_80072890)\n" - "lw $v1, %lo(D_80072890)($v1)\n" - "lui $at, %hi(D_8007289C)\n" - "sw $v0, %lo(D_8007289C)($at)\n" - "lui $at, %hi(D_8007288C)\n" - "sw $v1, %lo(D_8007288C)($at)\n" - "lui $v1, %hi(D_80072868)\n" - " lw $v1, %lo(D_80072868)($v1)\n" - "addiu $v0, $zero, 0x401\n" - "sw $v0, 0($v1)\n" - "lui $v1, %hi(D_80072878)\n" - "lw $v1, %lo(D_80072878)($v1)\n" - "nop\n" - "lw $v0, 0($v1)\n" - "nop\n" - "ori $v0, $v0, 0x800\n" - "sw $v0, 0($v1)\n" - "lui $v1, %hi(D_8007285C)\n" - "lw $v1, %lo(D_8007285C)($v1)\n" - "lui $v0, 0x200\n" - "sw $v0, 0($v1)\n" - "lui $v1, %hi(D_8007285C)\n" - "lw $v1, %lo(D_8007285C)($v1)\n" - "lui $v0, 0x100\n" - "sw $v0, 0($v1)\n" - "lui $a0, %hi(D_8007289C)\n" - "lw $a0, %lo(D_8007289C)($a0)\n" - "jal func_800426FC\n" - "nop\n" - "j SYS_OBJ_2F7C\n" - "addiu $v0, $zero, -1\n" - ".L8005C1AC:\n" - "addu $v0, $zero, $zero\n" - ".set\treorder\n" - ".end\tfunc_8005C054\n" -); - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tSYS_OBJ_2F7C\n" - ".ent\tSYS_OBJ_2F7C\n" - "SYS_OBJ_2F7C:\n" - ".set\tnoreorder\n" - "lw $ra, 24($sp)\n" - "addiu $sp, $sp, 32\n" - "jr $ra\n" - "nop\n" - ".set\treorder\n" - ".end\tSYS_OBJ_2F7C\n" -); - -/* - * func_8005C1C0 -- GPU-primitive dispatch sibling (same family as func_80059FC0/SYS_OBJ_E34, - * src/800c.c:508). The target has NO trailing "jr $ra": all four exits are raw, unlinked tail - * jumps into SYS_OBJ_3060 with the return value materialised in the DELAY SLOT ($v0 = 0/1/2/3), - * and SYS_OBJ_3060 (banked as the C stub immediately below) owns the shared epilogue for this - * frame. gcc-2.7.2 unconditionally appends its own return sequence to any ordinary C function - * body (function.c:expand_function_end, no noreturn guard -- matching-cookbook.md §179-C, whose - * follow-up list names THIS function), so a C spelling can only get within +2 instructions. - * FILE-SCOPE asm is the only spelling that emits exactly the target bytes. Per §179-C sub-rules: - * literal ".ent"/".end" (not glabel), %hi/%lo un-doubled, ".L" local labels only. No second - * ".ent SYS_OBJ_3060" is needed after ".end" (sub-rule c) because the following symbol is a real - * gcc-compiled C function carrying its own header. - * - * BANKING: this block REPLACES the line - * INCLUDE_ASM("asm/nonmatchings/800c", func_8005C1C0); - * at src/800c.c:1111, in place (between SYS_OBJ_2F7C and the SYS_OBJ_3060 stub) so link order - * is unchanged: func_8005C1C0 @0x8005C1C0 (0xD4 bytes) -> SYS_OBJ_3060 @0x8005C294 -> - * func_8005C29C @0x8005C29C. - */ -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tfunc_8005C1C0\n" - ".ent\tfunc_8005C1C0\n" - "func_8005C1C0:\n" - ".frame\t$sp,0,$31\n" - ".mask\t0x00000000,0\n" - ".fmask\t0x00000000,0\n" - ".set\tnoreorder\n" - "lui $3, 0x1000\n" - "lui $2, %hi(D_8007285C)\n" - "lw $2, %lo(D_8007285C)($2)\n" - "ori $3, $3, 7\n" - "sw $3, 0($2)\n" - "lui $5, %hi(D_80072858)\n" - "lw $5, %lo(D_80072858)($5)\n" - "lui $3, 0xff\n" - "lw $2, 0($5)\n" - "ori $3, $3, 0xffff\n" - "and $2, $2, $3\n" - "addiu $3, $0, 2\n" - "beq $2, $3, .L8005C268\n" - " lui $3, 0xe100\n" - "lui $2, %hi(D_8007285C)\n" - "lw $2, %lo(D_8007285C)($2)\n" - "nop\n" - "lw $2, 0($2)\n" - "ori $3, $3, 0x1000\n" - "andi $2, $2, 0x3fff\n" - "or $2, $2, $3\n" - "sw $2, 0($5)\n" - "lui $2, %hi(D_80072858)\n" - "lw $2, %lo(D_80072858)($2)\n" - "lui $3, %hi(D_8007285C)\n" - "lw $3, %lo(D_8007285C)($3)\n" - "lw $2, 0($2)\n" - "lw $2, 0($3)\n" - "nop\n" - "andi $2, $2, 0x1000\n" - "bnez $2, .L8005C248\n" - " andi $2, $4, 8\n" - "j SYS_OBJ_3060\n" - " addu $2, $0, $0\n" - ".L8005C248:\n" - "bnez $2, .L8005C258\n" - " lui $2, 0x2000\n" - "j SYS_OBJ_3060\n" - " addiu $2, $0, 1\n" - ".L8005C258:\n" - "ori $2, $2, 0x504\n" - "sw $2, 0($3)\n" - "j SYS_OBJ_3060\n" - " addiu $2, $0, 2\n" - ".L8005C268:\n" - "andi $2, $4, 8\n" - "beqz $2, .L8005C290\n" - " lui $4, 0x900\n" - "ori $4, $4, 1\n" - "lui $3, %hi(D_8007285C)\n" - "lw $3, %lo(D_8007285C)($3)\n" - "addiu $2, $0, 4\n" - "sw $4, 0($3)\n" - "j SYS_OBJ_3060\n" - "nop\n" - ".L8005C290:\n" - "addiu $2, $0, 3\n" - ".set\treorder\n" - ".end\tfunc_8005C1C0\n" -); - -void SYS_OBJ_3060(void) { -} - -void func_8005C29C(void *arg0, s32 arg1, s32 arg2) -{ - s32 i; - s32 frame_pad[2]; - - (void)&frame_pad; - i = arg2 - 1; - if (arg2 != 0) { - do { - *(u8 *)arg0 = (u8)arg1; - arg0 = (u8 *)arg0 + 1; - } while (--i != -1); - } -} diff --git a/src/gsgap3.c b/src/gsgap3.c deleted file mode 100644 index 9f875164c..000000000 --- a/src/gsgap3.c +++ /dev/null @@ -1,319 +0,0 @@ -#include "common.h" - -extern void func_80053CF8(void); -extern void func_80052D00(void); -extern void func_80052BEC(void); -extern s16 D_800C7C74; - -void func_800525DC(u16 w, u16 h, u16 intmode, u16 dither, u16 varh) -{ - func_80052654(w, h, intmode, dither, varh); - func_80053CF8(); - D_800C7C74 = 0; - func_8005283C(w, h); - func_80052D00(); - func_80052BEC(); -} - - -extern void func_80059234(s32 a0); -extern void func_80059D68(u8 *a0); -extern s32 func_80043078(void); -extern void func_80059FC0(u8 *a0); - -extern s16 D_800A6440; -extern s16 D_800A6442; -extern s16 D_800A6444; -extern s16 D_800A6446; -extern s16 D_800A6448; -extern s16 D_800A644A; -extern s16 D_800A644C; -extern u8 D_800A644E; -extern u8 D_800A644F; -extern u8 D_800A6450; - -extern s16 D_800A6498; -extern s16 D_800A649A; -extern s16 D_800A649C; -extern s16 D_800A649E; -extern s16 D_800A64A0; -extern s16 D_800A64A2; -extern s16 D_800A64A4; -extern s16 D_800A64A6; - -extern u8 D_800A64A8; -extern u8 D_800A64A9; -extern u8 D_800A64AA; - -extern s16 D_800C7C88; - -void func_80052654(u16 w, u16 h, u16 intmode, u16 dither, u16 varh) -{ - s16 *p; - s16 *q; - - func_80059234((((intmode >> 4) & 3) == 3) ? 3 : 0); - - p = &D_800A6440; - D_800A6442 = 0; - *p = 0; - D_800A644A = 0; - D_800A6448 = 0; - D_800A6446 = 0; - D_800A6444 = 0; - D_800A644C = 0; - D_800A644E = dither; - D_800A644F = 0; - D_800A6450 = 0; - - func_80059D68((u8 *)p - 8); - - q = &D_800A6498; - *q = 0; - D_800A649A = 0; - D_800A649C = w; - D_800A649E = h; - D_800A64A0 = 0; - D_800A64A2 = 0; - D_800A64A4 = 0; - D_800A64A6 = 0; - - if (func_80043078() == 1) { - D_800A64A2 = 0x18; - D_800A64AA = 1; - } - - D_800A64A8 = intmode & 1; - D_800C7C88 = intmode & 4; - D_800A64A9 = varh; - - func_80059FC0((u8 *)q); -} - -extern s16 D_800A644C; -extern u8 D_800A644E; -extern u8 D_800A644F; -extern u8 D_800A6450; -extern s16 D_800A649C; -extern s16 D_800A649E; -extern u8 D_800A64A8; -extern u8 D_800A64A9; -extern s16 D_800C7C88; - -void func_8005283C(s32 a0, s32 a1); - -/* hostile fleet-canonical prototype, as carried by caller TUs */ -void GsInitGraph2(s32 w, s32 h, s32 mode, s32 a3, s32 st); - -void GsInitGraph2_body(u16 w, u16 h, u16 intmode, u16 dither, u16 varh) __asm__("GsInitGraph2"); - -void GsInitGraph2_body(u16 w, u16 h, u16 intmode, u16 dither, u16 varh) -{ - D_800A649C = w; - D_800A649E = h; - D_800A644C = 0; - D_800A644E = dither; - D_800A644F = 0; - D_800A6450 = 0; - D_800A64A8 = intmode & 1; - D_800C7C88 = intmode & 4; - D_800A64A9 = varh; - func_8005283C(w, h); -} - - -typedef struct { - s16 m[3][3]; - s32 t[3]; -} Mtx32; - -extern volatile s32 D_800AE618; -extern volatile s32 D_800AE61C; -extern Mtx32 D_800AE620; -extern Mtx32 D_800AE7F0; -extern Mtx32 D_800A63F0; -extern Mtx32 D_800A6558; -extern s16 D_800A4F3C; -extern s16 D_800A4F3E; -extern s16 D_800A4F40; -extern s16 D_800A4F42; -extern s16 D_800A5E50; -extern s16 D_800A5E52; -extern s16 D_800AE820; -extern s16 D_800AE822; -extern s16 D_800AE824; -extern s16 D_800AE826; -extern u8 D_80078813; -extern u8 D_80078817; -extern u8 D_80078823; -extern u8 D_80078827; -extern s32 D_800C7C70; - -void func_8005283C(s32 arg0, s32 arg1) { - s32 h; - s32 w; - s32 q; - - D_800AE61C = (u16)arg1; - h = D_800AE61C; - D_800AE618 = (u16)arg0; - w = D_800AE618; - q = (h << 14) / w; - - D_800AE620.m[0][2] = 0; - D_800AE620.m[0][1] = 0; - D_800AE620.m[1][2] = 0; - D_800AE620.m[1][0] = 0; - D_800AE620.m[2][1] = 0; - D_800AE620.m[2][0] = 0; - D_800AE620.t[2] = 0; - D_800AE620.t[1] = 0; - D_800AE620.t[0] = 0; - D_800AE620.m[0][0] = 0x1000; - D_800AE620.m[1][1] = 0x1000; - D_800AE620.m[2][2] = 0x1000; - - D_800AE7F0 = D_800AE620; - D_800A63F0 = D_800AE620; - D_800A63F0.m[2][2] = 0; - D_800A63F0.m[1][1] = 0; - D_800A63F0.m[0][0] = 0; - D_800A6558 = D_800A63F0; - - D_800A4F3C = 0; - D_800A4F3E = 0; - D_800A4F40 = 0; - D_800A4F42 = 0; - D_800A5E52 = 0; - D_800A5E50 = 0; - D_800AE822 = 0; - D_800AE7F0.m[1][1] = q / 3; - D_800AE820 = 0; - D_800AE824 = w; - D_800AE826 = h; - D_80078813 = 3; - D_80078817 = 2; - D_80078823 = 3; - D_80078827 = 2; - D_800C7C70 = 1; -} - - -/* - * GsSortClear -- writes the clear-color bytes (r,g,b) plus the width/height/z fields of the - * current double-buffer's sort-tile entry (a 16-byte-stride record based at D_80078810, whose - * individual fields never got a struct symbol -- each is its own splat-auto D_######## label, - * per this TU's convention of one symbol per referenced address). Like func_80059FC0 / - * SYS_OBJ_E34 (src/800c.c) and GsTMDfastG3GL (src/800b2.c), BOTH branches end with a raw, - * unlinked tail jump: the taken (if D_800A64A9) branch ends "j GS_001_OBJ_5D0" (args left live - * in $a1==idx*16, $a3 untouched from our own caller); the not-taken branch has NO jump and NO - * "jr $ra" at all -- it falls straight through into GS_001_OBJ_5D0's own code, which owns the - * shared epilogue (lw $ra,0x10($sp); addiu $sp,$sp,0x18; jr $ra) for this frame. gcc-2.7.2 has - * no sibcall / cross-function tail-merge pass (matching-cookbook.md §179-C) and unconditionally - * appends its own return sequence to any ordinary C function body, so this can only be written - * as FILE-SCOPE __asm__ -- opaque text the compiler never runs expand_function_end over. - */ -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tGsSortClear\n" - ".ent\tGsSortClear\n" - "GsSortClear:\n" - ".frame\t$sp,24,$31\n" - ".mask\t0x80000000,-8\n" - ".fmask\t0x00000000,0\n" - ".set\tnoreorder\n" - "lui $2, %hi(D_800C7C74)\n" - "lh $2, %lo(D_800C7C74)($2)\n" - "addiu $sp, $sp, -24\n" - "sw $31, 16($sp)\n" - "sll $2, $2, 4\n" - "lui $1, %hi(D_80078814)\n" - "addu $1, $1, $2\n" - "sb $4, %lo(D_80078814)($1)\n" - "lui $2, %hi(D_800C7C74)\n" - "lh $2, %lo(D_800C7C74)($2)\n" - "nop\n" - "sll $2, $2, 4\n" - "lui $1, %hi(D_80078815)\n" - "addu $1, $1, $2\n" - "sb $5, %lo(D_80078815)($1)\n" - "lui $2, %hi(D_800C7C74)\n" - "lh $2, %lo(D_800C7C74)($2)\n" - "nop\n" - "sll $2, $2, 4\n" - "lui $1, %hi(D_80078816)\n" - "addu $1, $1, $2\n" - "sb $6, %lo(D_80078816)($1)\n" - "lui $2, %hi(D_800C7C74)\n" - "lh $2, %lo(D_800C7C74)($2)\n" - "nop\n" - "sll $4, $2, 1\n" - "sll $5, $2, 4\n" - "lui $1, %hi(D_800794E0)\n" - "addu $1, $1, $4\n" - "lhu $3, %lo(D_800794E0)($1)\n" - "lui $2, %hi(D_800AE61C)\n" - "lw $2, %lo(D_800AE61C)($2)\n" - "lui $1, %hi(D_80078818)\n" - "addu $1, $1, $5\n" - "sh $3, %lo(D_80078818)($1)\n" - "lui $1, %hi(D_800794E4)\n" - "addu $1, $1, $4\n" - "lhu $3, %lo(D_800794E4)($1)\n" - "lui $1, %hi(D_8007881E)\n" - "addu $1, $1, $5\n" - "sh $2, %lo(D_8007881E)($1)\n" - "lui $1, %hi(D_8007881A)\n" - "addu $1, $1, $5\n" - "sh $3, %lo(D_8007881A)($1)\n" - "lui $2, %hi(D_800A64A9)\n" - "lbu $2, %lo(D_800A64A9)($2)\n" - "nop\n" - "beqz $2, 1f\n" - " nop\n" - "lui $2, %hi(D_800AE618)\n" - "lw $2, %lo(D_800AE618)($2)\n" - "nop\n" - "sll $3, $2, 1\n" - "addu $3, $3, $2\n" - "srl $2, $3, 31\n" - "addu $3, $3, $2\n" - "sra $3, $3, 1\n" - "lui $1, %hi(D_8007881C)\n" - "addu $1, $1, $5\n" - "sh $3, %lo(D_8007881C)($1)\n" - "j GS_001_OBJ_5D0\n" - " nop\n" - "1:\n" - "lui $2, %hi(D_800AE618)\n" - "lw $2, %lo(D_800AE618)($2)\n" - "lui $1, %hi(D_8007881C)\n" - "addu $1, $1, $5\n" - "sh $2, %lo(D_8007881C)($1)\n" - ".set\treorder\n" - ".end\tGsSortClear\n" -); - -__asm__( - ".text\n" - ".align\t2\n" - ".globl\tGS_001_OBJ_5D0\n" - ".ent\tGS_001_OBJ_5D0\n" - "GS_001_OBJ_5D0:\n" - ".set\tnoreorder\n" - "lui $2, %hi(D_80078810)\n" - "addiu $2, $2, %lo(D_80078810)\n" - "lui $5, %hi(D_800C7C74)\n" - "lh $5, %lo(D_800C7C74)($5)\n" - "lw $4, 16($7)\n" - "sll $5, $5, 4\n" - "jal AddPrim\n" - "addu $5, $5, $2\n" - "lw $31, 16($sp)\n" - "addiu $sp, $sp, 24\n" - "jr $31\n" - "nop\n" - ".set\treorder\n" - ".end\tGS_001_OBJ_5D0\n" -); diff --git a/src/libgpu2.c b/src/libgpu2.c new file mode 100644 index 000000000..0a6c50b68 --- /dev/null +++ b/src/libgpu2.c @@ -0,0 +1,213 @@ +#include "common.h" + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_80059234); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_11C); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_16C); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SetGraphReverse); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_210); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_800594CC); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SetGraphQueue); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", GetGraphType); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", GetGraphDebug); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", DrawSyncCallback); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_80059658); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_800596F4); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_80059760); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_604); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_640); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_80059888); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", ClearImage2); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_800599B8); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", StoreImage); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", MoveImage); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_8F4); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", ClearOTag); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_80059BFC); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", DrawPrim); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_80059CF4); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_80059D68); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", DrawOTagEnv); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", GetDrawEnv); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_80059FC0); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_E34); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_F00); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_F24); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_F58); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_FD8); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_1034); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_11C0); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", GetDispEnv); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", GetODE); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SetTexWindow); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SetDrawArea); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SetDrawOffset); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SetPriority); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_8005A600); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SetDrawEnv); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_1578); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_8005A870); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_1790); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_18AC); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_8005AB00); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_191C); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_8005AB58); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_1964); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_19A4); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_19D8); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_8005AC24); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_1A30); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_1A70); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_1AA4); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_8005ACF0); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_1AF0); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_8005AD34); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_1B78); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_8005ADB8); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_1BC4); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_1C28); + +void SYS_OBJ_1C2C(void) { +} + +INCLUDE_ASM("asm/nonmatchings/libgpu2", _status); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_8005AE80); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", _clr); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_1D84); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_1DC0); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_1F64); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", _dws); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_1FF4); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_202C); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_21A4); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", _drs); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_222C); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_2264); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_242C); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_8005B684); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", _getctl); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", _cwb); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_8005B710); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_8005B75C); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", _addque); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_8005B7B0); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_8005B7E4); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_25C8); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_26EC); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_27A8); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_283C); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_8005BA90); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_8005BD7C); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_2C6C); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_8005BED8); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_2CC4); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_2CDC); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_2DD8); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_8005C020); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_8005C054); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", SYS_OBJ_2F7C); + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_8005C1C0); + +void SYS_OBJ_3060(void) { +} + +INCLUDE_ASM("asm/nonmatchings/libgpu2", func_8005C29C); diff --git a/src/libgs8.c b/src/libgs8.c new file mode 100644 index 000000000..6fd262916 --- /dev/null +++ b/src/libgs8.c @@ -0,0 +1,13 @@ +#include "common.h" + +INCLUDE_ASM("asm/nonmatchings/libgs8", func_800525DC); + +INCLUDE_ASM("asm/nonmatchings/libgs8", func_80052654); + +INCLUDE_ASM("asm/nonmatchings/libgs8", GsInitGraph2); + +INCLUDE_ASM("asm/nonmatchings/libgs8", func_8005283C); + +INCLUDE_ASM("asm/nonmatchings/libgs8", GsSortClear); + +INCLUDE_ASM("asm/nonmatchings/libgs8", GS_001_OBJ_5D0); diff --git a/src/sgap_6.c b/src/sgap_6.c index 3e3ede67c..1415ee6f3 100644 --- a/src/sgap_6.c +++ b/src/sgap_6.c @@ -4,156 +4,3 @@ void func_8003FA54(void) { extern u16 D_800A5F60; D_800A5F60 = 0; } - -extern s32 D_800BA1B0; -extern u8 D_800AE614; -extern u32 D_800C7EC0[16]; -extern u16 D_8007958E; -extern u8 D_800BA100; -extern u8 D_800795A3; -extern u16 D_800C7F04; -extern u16 D_800C7F06; -extern s16 D_800795A4; -extern s16 D_800795B0; -extern u8 D_800A4620; -extern u16 D_80078D8C; -extern u16 D_80078D8E; -extern u16 D_80078D90; -extern u16 D_80078D92; -extern u16 D_800B9B58; -extern u16 D_800B9B5C; -extern u16 D_800B9B5E; -extern void (*D_800BA0D0)(s32); -extern void (*D_800AE828)(s32); -extern u16* D_8006B8FC; -extern void func_8003FE18(s32, u32); - -void func_8003FA64(void) { - s32 pad[2]; /* frame pad: target vars=16 (cookbook §226 / §162i1 dead-local lever) */ - s32 i = 0; - s32 n; - u32 mask; - u32 off; - u8* fp; - u16* pa2; - u16* pa3; - u16* pt0; - u16* pt1; - u16* pend; - u16* pb; - u16 r1, r2, r3, r4, r5, r6; - u16* dp; - - D_800BA1B0 = (D_800BA1B0 + 1) & 0xF; - D_800C7EC0[D_800BA1B0] = 0; - n = D_800AE614; - if (n > 0) { - u32* mp = &D_800C7EC0[D_800BA1B0]; - u32 one = 1; - s32 count = D_800AE614; - u16* vp = D_8006B8FC; - u32 off0 = 0; - do { - u16 val = *(u16*)((char*)vp + 0xC); - *(u16*)((char*)&D_8007958E + off0) = val; - if (val == 0) { - *mp |= one << i; - } - vp += 8; - off0 += 0x34; - i++; - } while (i < count); - } - - i = 0; - if (D_800BA100 == 0) { - mask = -1; - do { - mask &= D_800C7EC0[i]; - i++; - } while (i < 0xF); - for (i = 0; i < (s32)D_800AE614; i++) { - u32 one = 1; - u32 two = 2; - off = i * 0x34; - if ((mask & (one << i)) != 0) { - if (*(u8*)((char*)&D_800795A3 + off) == two) { - func_8003FE18(0, 0xFFFFFF); - } - *(u8*)((char*)&D_800795A3 + off) = 0; - } - } - i = 0; - } - - D_80078D8C &= ~D_800C7F04; - D_80078D8E &= ~D_800C7F06; - - off = 0; - do { - if (*(s16*)((char*)&D_800795A4 + off) != 0) { - D_800BA0D0(i); - } - if (*(s16*)((char*)&D_800795B0 + off) != 0) { - D_800AE828(i); - } - i++; - off += 0x34; - } while (i < 0x18); - - fp = &D_800A4620; - pb = &D_800B9B58; - pt1 = pb + 5; - pt0 = pb + 4; - { - u32 off4 = 0; - pa3 = pb + 1; - pa2 = pb; - pend = &D_800A4620 + 24; - do { - if ((*fp & 1) != 0) { - u16* d1 = (u16*)(off4 + (u32)D_8006B8FC); - *d1 = *pa2; - *(u16*)((char*)d1 + 2) = *pa3; - } - if ((*fp & 4) != 0) { - u16* d2 = (u16*)(off4 + (u32)D_8006B8FC); - *(u16*)((char*)d2 + 4) = *(u16*)((char*)&D_800B9B5C + off4); - } - if ((*fp & 8) != 0) { - u16* d3 = (u16*)(off4 + (u32)D_8006B8FC); - *(u16*)((char*)d3 + 6) = *(u16*)((char*)&D_800B9B5E + off4); - } - if ((*fp & 0x10) != 0) { - u16* d4 = (u16*)(off4 + (u32)D_8006B8FC); - *(u16*)((char*)d4 + 8) = *pt0; - *(u16*)((char*)d4 + 0xA) = *pt1; - } - *fp = 0; - fp++; - pt1 += 8; - pt0 += 8; - off4 += 0x10; - pa3 += 8; - pa2 += 8; - } while ((s32)fp < (s32)pend); - } - - dp = D_8006B8FC; - r1 = D_800C7F04; - r2 = D_800C7F06; - r3 = D_80078D8C; - r4 = D_80078D8E; - r5 = D_80078D90; - r6 = D_80078D92; - D_800C7F04 = 0; - D_800C7F06 = 0; - D_80078D8C = 0; - D_80078D8E = 0; - *(u16*)((char*)dp + 0x18C) = r1; - *(u16*)((char*)dp + 0x18E) = r2; - *(u16*)((char*)dp + 0x188) = r3; - *(u16*)((char*)dp + 0x18A) = r4; - *(u16*)((char*)dp + 0x198) = r5; - *(u16*)((char*)dp + 0x19A) = r6; -} diff --git a/src/snd12.c b/src/snd12.c new file mode 100644 index 000000000..d91680fe5 --- /dev/null +++ b/src/snd12.c @@ -0,0 +1,3 @@ +#include "common.h" + +INCLUDE_ASM("asm/nonmatchings/snd12", func_8003FA64); diff --git a/tools/make_libgs.sh b/tools/make_libgs.sh index 387abc581..49998d94e 100644 --- a/tools/make_libgs.sh +++ b/tools/make_libgs.sh @@ -5,18 +5,22 @@ # developer who wants the real SDK objects linked. Needs the LIBGS ELF objects from # tools/psyq_build_libs.sh LIBGS (which needs tools/psyq/lib40/LIBGS.LIB from the DTL-S2002 redump). # -# These are the 31 libgs objects BFM links, forming 6 contiguous blocks across vram -# 0x80051804-0x80057928, separated by 5 non-libgs gaps (80 / 48 / 1536[GS_001] / 48 / 304 B): +# These are the 34 libgs objects BFM links, forming 8 contiguous blocks across vram +# 0x8005080C-0x80057928 (the 4 remaining non-libgs gaps are libgte objects, wired as libgte27-30): +# block 7: 2D_BG0 2D_BG1 (0x8005080C, S78 #3) # block 1: 2D_COM0 (0x80051804) # block 2: 2D_LIN0 2D_COM1 2D_SP0 (0x80051DC8) # block 3: 2D_SP1 (0x80052460) +# block 8: GS_001 (0x800525DC, S78 #4) # block 4: GS_002 GS_003 MATRIX GS_103 GS_104 GS_105 GS_106 GS_107 (0x80052BDC) # block 5: GS_108 GS_109 (0x800538EC) # block 6: GS_110 GS_119 GS_120 GS_121 GS_122 GS_123 GS_127 GS_131 # GS_133 GS_134 GS_135 GS_137 PRESET PRESET3 OBJT OBJT3 (0x80053AF8) -# GS_001 (the 1536 B gap before block 4) is EXCLUDED — psyq-obj-parser packs its scattered PSD* -# commons into .bss referenced via .bss+offset and 35 words differ at the global-zeroing run -# (cookbook §9.1 hard case); it stays an asm stub (gsgap3) and reproduces its bytes. +# GS_001 (the 1536 B gap before block 4) was EXCLUDED from Phase 7 to P31 S78 — psyq-obj-parser packs +# its scattered PSD* commons into one .bss referenced via .bss+offset at SIX bases (35 words differed +# at the global-zeroing run; cookbook §9.1 "hard case"). Since S78 #4 psyq_integrate splits such a +# section into per-base NOBITS pieces at link-prepare (tools/psyq_bss_split.py, cookbook §489), so +# GS_001 links byte-identical like any other object; it is block libgs8 (was the gsgap3 stub). # The list is DISAMBIGUATED (session E): psyq_identify reports byte-identical-.text aliases — keep # GS_131 (not RVWUNIT), GS_137 (not RVWLUNIT), PRESET3 (not PRESET2), OBJT3 (not OBJT2); the losers # have a spurious .data/.rdata mismatch and do NOT link byte-exact. GS_106 is an 8-instruction object @@ -28,7 +32,7 @@ cd "$(dirname "$0")/.." LIBGS=.run/obj40/libgs DST=.run/obj40/libgs_used OBJS=(2D_COM0 2D_LIN0 2D_COM1 2D_SP0 2D_SP1 2D_BG0 2D_BG1 \ - GS_002 GS_003 MATRIX GS_103 GS_104 GS_105 GS_106 GS_107 GS_108 GS_109 \ + GS_001 GS_002 GS_003 MATRIX GS_103 GS_104 GS_105 GS_106 GS_107 GS_108 GS_109 \ GS_110 GS_119 GS_120 GS_121 GS_122 GS_123 GS_127 GS_131 GS_133 GS_134 GS_135 GS_137 \ PRESET PRESET3 OBJT OBJT3) diff --git a/tools/make_snd_used.py b/tools/make_snd_used.py index da021b45d..49f750cba 100644 --- a/tools/make_snd_used.py +++ b/tools/make_snd_used.py @@ -6,12 +6,14 @@ they are linked as ONE combined region rather than two passes. This: - places both libraries' objects (psyq_identify) and merges them by vram, - for an aliased address (>1 object, same masked .text) picks the object whose linked .text byte-matches the EXE (psyq_link.link_object) — the real one, - - EXCLUDES 4 ADDRESSES that don't reconcile in the combined region (ALL candidates there stay + - EXCLUDES 3 ADDRESSES that don't reconcile in the combined region (ALL candidates there stay byte-identical stubs — excluding by address, not name, since the alias twin fails identically): - 0x3C438 (S_R/S_W), 0x3D424 (S_GRMDT/FB/T) — scattered-.bss commons referenced at a minority - address the region's single defsym can't satisfy (cookbook §9.1, cross-object form), - 0x3D94C (S_IH/UT_RON) — false placement: 0x3D94C is INSIDE libsnd SSSTART.o, - 0x3FA64 (VM_F.o, 237 ins) — scattered-.bss commons (the one real value loss). + 0x3C438 (S_R/S_W), 0x3D424 (S_GRMDT/FB/T) — commons referenced at a minority address the + region's single defsym can't satisfy (cookbook §9.1, cross-object form; these objects have NO + .bss of their own — psyq_bss_probe — so the S78 split does not apply to them), + 0x3D94C (S_IH/UT_RON) — false placement: 0x3D94C is INSIDE libsnd SSSTART.o. + 0x3FA64 (VM_F.o, 237 ins) was the 4th exclusion (scattered-.bss commons) until P31 S78 #4: its + `.bss` is now SPLIT at link-prepare (psyq_bss_split, cookbook §489) and it links as snd12. - copies the survivors into .run/obj40/snd_used. The build is byte-identical with OR without snd_used (stub fallback), so a fresh clone need not run @@ -28,7 +30,7 @@ from psyq_link import link_object # noqa: E402 EXE = "extracted/retail/SLUS_007.26" VRAM_BASE = 0x8000F800 RLO, RHI = 0x8003A444, 0x8004239C -EXCLUDE_ADDR = {0x8003C438, 0x8003D424, 0x8003D94C, 0x8003FA64} # see module docstring +EXCLUDE_ADDR = {0x8003C438, 0x8003D424, 0x8003D94C} # see module docstring (VM_F 0x8003FA64 rejoined S78 #4) def place(lib, exe, vram_base): diff --git a/tools/psyq_bss_probe.py b/tools/psyq_bss_probe.py index 5f6fe8025..11ab0f9a3 100644 --- a/tools/psyq_bss_probe.py +++ b/tools/psyq_bss_probe.py @@ -1,88 +1,73 @@ #!/usr/bin/env python3 -"""psyq_bss_probe.py — can this PsyQ object's scattered `.bss` be SPLIT and placed? (P31 S77) +"""psyq_bss_probe.py — can this PsyQ object's scattered `.bss` be SPLIT and placed? (P31 S77; S78 #4: yes, and it is) -THE WALL THIS INTERROGATES. `config/splat.us.exe.yaml` has excluded four library objects from the +THE WALL THIS INTERROGATES. `config/splat.us.exe.yaml` had excluded library objects from the LINKED build since Phase 8 with one recorded reason: SYS.o EXCLUDED — scattered-.bss commons (the GS_001 class: SYS references .bss by section+offset but the original linker scattered the commons across 0x80078xxx/0x800c5xxx, so no single NOLOAD base reproduces it) -That reason is CORRECT and this tool confirms it — §9.2's "weaken the `.bss` symbol and `--defsym` -it" cannot reach these sites, because a `R_MIPS_HI16/LO16` against the bare `.bss` SECTION has no -name to defsym. But "no single base" is not the same claim as "unlinkable", and nobody had asked -the next question: **are the offset ranges behind each base DISJOINT?** If they are, `.bss` splits -into pieces and each piece gets its own NOLOAD base. +That reason is CORRECT — §9.2's "weaken the `.bss` symbol and `--defsym` it" cannot reach these +sites, because a `R_MIPS_HI16/LO16` against the bare `.bss` SECTION has no name to defsym. But "no +single base" is not the same claim as "unlinkable", and nobody had asked the next question: **can the +section be cut into pieces that each have ONE base?** This probe asked it (S77) and +`tools/psyq_bss_split.py` (S78 #4) answers it at link-prepare time for every object in the build. -MEASURED ON SYS.o (the biggest, 3,109 ins — `src/800c.c` is 100% this object): +WHAT "SPLITTABLE" MEANS NOW (the S77 test was too strict — corrected S78). The S77 probe grouped the +references BY BASE and required the per-base offset ranges to be disjoint. That verdict was right +for SYS.o and VM_F.o (two bases, two ranges) and WRONG for GS_001.o, which it called "5 interleaved +bases": walked in OFFSET order, GS_001's references form six single-base RUNS, and every cut between +two runs lands on a symbol start (PSDBASEX, CLIP2, PSDBASEY, POSITION, GsDRAWENV) — exactly what +"the linker scattered the commons" predicts. The linker scattered SYMBOLS, so the right question is +whether the runs can be tiled at symbol boundaries without a sized symbol straddling a cut. All +three objects can; all three link byte-identical through the split (psyq_link.py PASS). - base 0x80078830 : 23 refs, .bss offsets 0x0000..0x0044 - base 0x800c53cc : 9 refs, .bss offsets 0x0148..0x0150 -> DISJOINT, split at 0x148 - -and only `.text` references `.bss` at all (`.data` has zero such relocs), so the split covers every -reference in the object. The wall is real and breakable — two different things. - -HOW IT DERIVES THE BASE — from the bytes, not from a config. For each HI16/LO16 pair against -`.bss`, the OBJECT's immediates encode the addend and the GAME's immediates encode the resolved -address; `base = resolved − addend`. Grouping by base gives the scatter, and the offsets behind -each group give the split points. The object's placement in the game is found by masking every -relocated field and searching for the unique match, so a wrong `--vram` cannot fake a clean answer -(and the search doubles as proof the object is really there). +HOW IT DERIVES THE BASE — from the bytes, not from a config. For each HI16/LO16 pair against the +section symbol, the OBJECT's immediates encode the addend and the GAME's immediates encode the +resolved address; `base = resolved − addend`. Grouping by base shows the scatter; the runs give the +cut points. The object's placement in the game is found by masking every relocated field and +searching for the unique match, so a wrong `--vram` cannot fake a clean answer (and the search +doubles as proof the object is really there). The analysis itself lives in `psyq_bss_split.analyze` +(R33: one implementation; this file only extracts, locates and reports). tools/psyq_bss_probe.py --archive tools/psyq/lib40_elf/LIBGPU.a --object SYS.o tools/psyq_bss_probe.py --archive ... --object GS_001.o --vram 0x800525DC """ import argparse -import collections import os -import re -import struct import subprocess import sys import tempfile +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +from psyq_bss_split import Elf32, SHT_NOBITS, R_MIPS_HI16, R_MIPS_LO16, SplitRefused, analyze, report # noqa: E402 + REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -OBJDUMP = "mipsel-linux-gnu-objdump" EXE = os.path.join(REPO, "extracted/retail/SLUS_007.26") EXE_VRAM0 = 0x8000F800 # file offset 0 -> vram (the 0x800 PS-X EXE header sits below .text) +R_MIPS_26, R_MIPS_32 = 4, 2 -def _od(*args): - return subprocess.run([OBJDUMP, *args], capture_output=True, text=True).stdout - - -def sections(obj): - out = {} - for m in re.finditer(r"^\s*\d+\s+(\.\S+)\s+([0-9a-f]+)\s+\S+\s+\S+\s+([0-9a-f]+)", _od("-h", obj), re.M): - out[m.group(1)] = (int(m.group(2), 16), int(m.group(3), 16)) # (size, file offset) - return out - - -def relocs(obj, section=".text"): - body = re.search(r"RELOCATION RECORDS FOR \[%s\]:(.*?)(?=\nRELOCATION RECORDS|\Z)" % re.escape(section), - _od("-r", obj), re.S) - if not body: - return [] - return [(int(m.group(1), 16), m.group(2), m.group(3)) - for m in re.finditer(r"^([0-9a-f]+)\s+(R_MIPS_\w+)\s+(\S+)", body.group(1), re.M)] - - -def find_vram(text, rels, game): +def find_vram(e, game): """The unique game offset where this object's .text sits, with every relocated field masked. Masking is what makes the search honest: relocated immediates DIFFER between the archive object and the linked game, so an exact byte search would find nothing and a loose one would find noise. A unique hit is also proof the object is present at all (R14).""" + ti = e.section_index(".text") + text = bytes(e.data[ti]) mask = bytearray(b"\xff" * len(text)) - for off, kind, _t in rels: - if off + 4 <= len(mask): - if kind in ("R_MIPS_HI16", "R_MIPS_LO16"): - mask[off:off + 2] = b"\x00\x00" # low half-word (little-endian immediate) - elif kind == "R_MIPS_26": - mask[off:off + 4] = b"\x00\x00\x00\x00" - elif kind == "R_MIPS_32": - mask[off:off + 4] = b"\x00\x00\x00\x00" - tb, mb = bytes(text), bytes(mask) + for ri, rl in e.rels.items(): + if e.sh[ri]["info"] != ti: + continue + for off, _sym, typ in rl: + if off + 4 <= len(mask): + if typ in (R_MIPS_HI16, R_MIPS_LO16): + mask[off:off + 2] = b"\x00\x00" # low half-word (little-endian immediate) + elif typ in (R_MIPS_26, R_MIPS_32): + mask[off:off + 4] = b"\x00\x00\x00\x00" + tb, mb = text, bytes(mask) hits = [] for base in range(0, len(game) - len(tb), 4): ok = True @@ -108,68 +93,44 @@ def main(): ap.add_argument("--vram", default=None, help="skip the search; the object's .text vram") a = ap.parse_args() - with tempfile.TemporaryDirectory() as td: + with tempfile.TemporaryDirectory(dir=os.path.join(REPO, ".run")) as td: subprocess.run(["ar", "x", os.path.abspath(a.archive), a.object], cwd=td, check=True) obj = os.path.join(td, a.object) - secs = sections(obj) - if ".text" not in secs: + e = Elf32(open(obj, "rb").read()) + names = [e.secname(i) for i in range(len(e.sh))] + if ".text" not in names: sys.exit("%s: no .text section" % a.object) - if ".bss" not in secs: + nobits = [i for i, s in enumerate(e.sh) if s["type"] == SHT_NOBITS] + tsize = e.sh[e.section_index(".text")]["size"] + if not nobits: # NOT AN ERROR, AND SAYING SO MATTERS. The first version exited "no .text/.bss" here, # which reads as a malformed object; it actually means the scattered-.bss wall CANNOT - # apply. Measured: 2D_BG0.o and VM_NO1.o both land here, and both are excluded in + # apply. Measured: 2D_BG0.o and VM_NO1.o both land here, and both were excluded in # splat.us.exe.yaml under a reason that is about .bss. (R61a: a tool must not report a # clean answer as a failure.) print("%s: .text %d ins, NO .bss SECTION — the scattered-.bss wall does not apply to " - "this object; whatever excludes it is a different reason." - % (a.object, secs[".text"][0] // 4)) + "this object; whatever excludes it is a different reason." % (a.object, tsize // 4)) return 0 - tsize, toff = secs[".text"] - text = open(obj, "rb").read()[toff:toff + tsize] - rels = relocs(obj, ".text") game = open(EXE, "rb").read() - if a.vram: goff = int(a.vram, 0) - EXE_VRAM0 else: - hits = find_vram(text, rels, game) + hits = find_vram(e, game) if len(hits) != 1: sys.exit("%s: masked .text search found %d placements — pass --vram" % (a.object, len(hits))) goff = hits[0] - print("%s: .text %d ins @ vram %#010x (.bss %d bytes)" - % (a.object, tsize // 4, goff + EXE_VRAM0, secs[".bss"][0])) - - # every section's .bss references, so the split is provably complete (R32) - other = {s: sum(1 for _o, _k, t in relocs(obj, s) if t == ".bss") - for s in secs if s not in (".text", ".bss", ".note")} - by = collections.defaultdict(list) - i, rl = 0, [r for r in rels if r[2] == ".bss"] - while i < len(rl) - 1: - (o1, k1, _), (o2, k2, _) = rl[i], rl[i + 1] - if k1 == "R_MIPS_HI16" and k2 == "R_MIPS_LO16": - ohi = struct.unpack_from(">16, lo' = A' & 0xFFFF, A' = A − piece start) or the R_MIPS_32 word; + 5. self-checks: the rewritten object's code/data differ from the original at exactly the retargeted + sites whose value changed, and nowhere else (the tool diffs its own artifact, R37). + +WHERE IT RUNS. Not in the curated dirs — at LINK-PREPARE time, in the one path `psyq_link.link_object` +(per-object verify), `psyq_link_region.build_region` (region verify) and `psyq_integrate.integrate` +(the build) all share: `prepare_object()`. `classify()` then recovers one base per piece from the +piece's own section symbol and NOLOAD-places each — no config, no recorded split offset that could go +stale (R51). An object with a single base passes through untouched. + + tools/psyq_bss_split.py --vram --exe --vram-base [-o out.o] + (no -o = report the plan only) +""" +import argparse +import os +import re +import struct +import sys + +NOBITS_RE = re.compile(r"^\.s?bss\d*$") # .bss .sbss and the pieces this tool makes (.bss2 …) +SHT_SYMTAB, SHT_STRTAB, SHT_NOBITS, SHT_REL = 2, 3, 8, 9 +STT_SECTION, STB_LOCAL = 3, 0 +R_MIPS_32, R_MIPS_HI16, R_MIPS_LO16 = 2, 5, 6 +RNAME = {2: "R_MIPS_32", 4: "R_MIPS_26", 5: "R_MIPS_HI16", 6: "R_MIPS_LO16"} +EHDR = struct.Struct("<16sHHIIIIIHHHHHH") +SHDR = struct.Struct(" [[r_offset, r_sym, r_type]] + for i, s in enumerate(self.sh): + if s["type"] == SHT_REL and s["link"] == self.symidx: + self.rels[i] = [[o, info >> 8, info & 0xFF] + for o, info in (REL.unpack_from(self.data[i], k * REL.size) + for k in range(s["size"] // REL.size))] + + def secname(self, i): + return cstr(self.data[self.shstrndx], self.sh[i]["name"]) + + def section_index(self, name): + return next((i for i in range(len(self.sh)) if self.secname(i) == name), None) + + def symname(self, k): + return cstr(self.data[self.strtab], self.syms[k][0]) + + def add_string(self, secidx, s): + off = len(self.data[secidx]) + self.data[secidx] += s.encode() + b"\0" + return off + + def serialize(self): + self.data[self.symidx] = bytearray(b"".join(SYM.pack(*y) for y in self.syms)) + for i, rl in self.rels.items(): + self.data[i] = bytearray(b"".join(REL.pack(o, (sym << 8) | typ) for o, sym, typ in rl)) + out, offs = bytearray(EHDR.size), [] + for i, s in enumerate(self.sh): + if i == 0: + offs.append(0) + continue + a = min(max(s["align"], 1), 16) if s["type"] != SHT_NOBITS else 4 + while len(out) % a: + out.append(0) + offs.append(len(out)) + if s["type"] != SHT_NOBITS: + out += self.data[i] + while len(out) % 4: + out.append(0) + shoff = len(out) + for i, s in enumerate(self.sh): + size = s["size"] if s["type"] == SHT_NOBITS else len(self.data[i]) + out += SHDR.pack(s["name"], s["type"], s["flags"], s["addr"], offs[i], size, + s["link"], s["info"], s["align"], s["entsize"]) + EHDR.pack_into(out, 0, self.ident, self.type, self.machine, self.version, self.entry, self.phoff, + shoff, self.flags, self.ehsize, self.phentsize, self.phnum, self.shentsize, + len(self.sh), self.shstrndx) + return bytes(out) + + +class Piece: + __slots__ = ("index", "lo", "hi", "base", "name", "cut_sym", "shndx", "symidx", "refs") + + def __init__(self, index, lo, hi, base, name, cut_sym): + self.index, self.lo, self.hi, self.base, self.name, self.cut_sym = index, lo, hi, base, name, cut_sym + self.shndx = self.symidx = None + self.refs = 0 + + @property + def addr(self): # where the piece lands in the target binary + return None if self.base is None else (self.base + self.lo) & 0xFFFFFFFF + + +def _plan_section(e, bi, ssym, text_vram, exe, vram_base): + """Analyse one NOBITS section referenced through its section symbol `ssym`. + Returns dict(shndx, size, bases, pieces, actions, nrefs, by_section) — `pieces` has ONE entry when + a single base covers every reference (no split needed).""" + sec = e.secname(bi) + size = e.sh[bi]["size"] + text_i = e.section_index(".text") + points, clusters, nrefs, by_section, problems = [], [], 0, {}, [] + # Problems found while walking the references are FATAL only if a split turns out to be needed: + # an object one base already serves must pass through exactly as it did before this tool existed + # (R39 — a refusal check ships only after the previously-passing population still passes). + for ri, rl in e.rels.items(): + tgt = e.sh[ri]["info"] + body = e.data[tgt] + tname = e.secname(tgt) + cluster = None # [his, los, closed] — LO16s after a HI16 group share it (one lui, several uses) + for k, (off, sym, typ) in enumerate(rl): + if sym != ssym: + continue + nrefs += 1 + by_section[tname] = by_section.get(tname, 0) + 1 + if typ == R_MIPS_HI16: + if tgt != text_i: + problems.append(f"{sec}: R_MIPS_HI16 in non-text section {tname}") + continue + if cluster is None or cluster[2]: + cluster = [[], [], False, ri] # his, los, closed, rel-section index + clusters.append(cluster) + cluster[0].append(k) + elif typ == R_MIPS_LO16: + if tgt != text_i or cluster is None or not cluster[0]: + problems.append(f"{sec}: orphan R_MIPS_LO16 at {tname}+{off:#x} (no preceding HI16)") + continue + cluster[2] = True + hi_off = rl[cluster[0][-1]][0] + A = (u16(body, hi_off) << 16) + s16(u16(body, off)) + site = text_vram + hi_off - vram_base + resolved = (u16(exe, site) << 16) + s16(u16(exe, text_vram + off - vram_base)) + base = (resolved - A) & 0xFFFFFFFF + cluster[1].append((k, A, base)) + points.append((A, base, ri, k)) + elif typ == R_MIPS_32: + A = u32(body, off) + points.append((A, None, ri, k)) # no base derivable without the section's own placement; tiled by offset + else: + problems.append(f"{sec}: unsupported relocation {RNAME.get(typ, typ)} against the section symbol at {tname}+{off:#x}") + for A, base, ri, k in points: + # An addend == size is an END pointer (`&buf[N]`, a loop bound) and belongs to the last piece; + # small negative addends are gcc's folded `&arr[i-1]`. Only an addend far outside the section + # can be a mis-paired HI16/LO16, and THAT is what is refused (libc2 SETJMP-style end pointers + # at .bss+size hit the stricter `< size` form on the first build, S78 #4). + if not (-0x8000 <= A <= size + 0x8000): + problems.append(f"{sec}: reference at {e.secname(e.sh[ri]['info'])}+{e.rels[ri][k][0]:#x} has addend {A:#x} far outside the section (size {size:#x}) — mis-paired relocation?") + based = sorted((A, b) for A, b, _, _ in points if b is not None) + # maximal runs of one base, in offset order + runs = [] # [lo_addend, hi_addend, base, count] + for A, b in based: + if runs and runs[-1][2] == b: + runs[-1][1] = A + runs[-1][3] += 1 + else: + runs.append([A, A, b, 1]) + bases = {} + for A, b in based: + lo, hi, n = bases.get(b, (A, A, 0)) + bases[b] = (min(lo, A), max(hi, A), n + 1) + syms = sorted((y[1], y[2], e.symname(k)) for k, y in enumerate(e.syms) + if y[5] == bi and (y[3] & 0xF) != STT_SECTION) + pieces = [] + if len(runs) > 1 and problems: + raise SplitRefused(f"{sec}: needs splitting ({len(runs)} runs) but the references could not all be " + f"classified — {problems[0]}" + (f" (+{len(problems) - 1} more)" if len(problems) > 1 else "")) + if runs: + cuts = [(0, None)] + for prev, cur in zip(runs, runs[1:]): + cands = [(v, nm) for v, _sz, nm in syms if prev[1] < v <= cur[0]] + v, nm = max(cands) if cands else (cur[0], None) + for sv, ssz, snm in syms: + if ssz and sv < v < sv + ssz: + raise SplitRefused(f"{sec}: symbol `{snm}` [{sv:#x},{sv+ssz:#x}) straddles the cut at {v:#x} — " + f"one common is referenced at two bases ({prev[2]:#010x} and {cur[2]:#010x}); not splittable") + cuts.append((v, nm)) + for j, (v, nm) in enumerate(cuts): + hi = cuts[j + 1][0] if j + 1 < len(cuts) else size + pieces.append(Piece(j, v, hi, runs[j][2], sec if j == 0 else f"{sec}{j + 1}", nm)) + + def piece_of(A): + return max((p for p in pieces if p.lo <= A), key=lambda p: p.lo, default=pieces[0]) + + actions = [] # (rel_sec, entry, piece, new_field_value) + for cl in clusters: + his, los, ri = cl[0], cl[1], cl[3] + target, hi_new = None, None + for k, A, base in los: + p = piece_of(A) + A2 = A - p.lo + lo2 = A2 & 0xFFFF + hi2 = ((A2 + 0x8000) >> 16) & 0xFFFF + if target is None: + target, hi_new = p, hi2 + elif p is not target or hi2 != hi_new: + raise SplitRefused(f"{sec}: one HI16 is shared by LO16s that need different pieces/high halves " + f"(addends {[a for _, a, _ in los]}) — not splittable") + actions.append((ri, k, p, lo2)) + for k in his: + actions.append((ri, k, target, hi_new)) + return dict(shndx=bi, size=size, bases=bases, runs=runs, pieces=pieces, actions=actions, + nrefs=nrefs, by_section=by_section, points=points, syms=syms, problems=problems) + + + +def analyze(obj_path, text_vram, exe, vram_base, elf=None): + """{section name: plan} for every NOBITS section referenced through its section symbol.""" + e = elf or Elf32(open(obj_path, "rb").read()) + plans = {} + for bi, s in enumerate(e.sh): + if s["type"] != SHT_NOBITS: + continue + ssym = next((k for k, y in enumerate(e.syms) if (y[3] & 0xF) == STT_SECTION and y[5] == bi), None) + if ssym is None: + continue + plan = _plan_section(e, bi, ssym, text_vram, exe, vram_base) + if plan["nrefs"]: + plans[e.secname(bi)] = plan + return plans + + +def needs_split(plans): + return {sec: p for sec, p in plans.items() if len(p["pieces"]) > 1} + + +def describe(plans): + """One line per split section, for build logs.""" + out = [] + for sec, p in needs_split(plans).items(): + parts = [] + for pc in p["pieces"]: + cut = f" (cut at `{pc.cut_sym}`)" if pc.cut_sym else "" + parts.append(f"{pc.name} [{pc.lo:#06x},{pc.hi:#06x}) @{pc.addr:#010x}{cut}") + out.append(f"{sec} split ×{len(p['pieces'])}: " + " · ".join(parts)) + return "; ".join(out) + + +def split(obj_path, text_vram, exe, vram_base, out_path, plans=None): + """Write the split object to out_path. Returns the plans (empty dict when nothing needed splitting + and nothing was written).""" + raw = open(obj_path, "rb").read() + e = Elf32(raw) + plans = plans if plans is not None else analyze(obj_path, text_vram, exe, vram_base, elf=e) + todo = needs_split(plans) + if not todo: + return {} + # 1. new NOBITS sections for pieces 2..n; shrink the original to piece 1 + for sec, p in todo.items(): + bi = p["shndx"] + for pc in p["pieces"][1:]: + addr = pc.addr + align = min(addr & -addr, 8) if addr else e.sh[bi]["align"] + pc.shndx = len(e.sh) + e.sh.append(dict(name=e.add_string(e.shstrndx, pc.name), type=SHT_NOBITS, flags=e.sh[bi]["flags"], + addr=0, size=pc.hi - pc.lo, link=0, info=0, align=max(align, 1), entsize=0)) + e.data.append(bytearray()) + e.sh[bi]["size"] = p["pieces"][0].hi + # 2. one LOCAL section symbol per new piece, inserted right after the existing section symbols + # (locals precede globals); every later symbol index in every REL entry moves up. + insert_at = 1 + max(k for k, y in enumerate(e.syms) if (y[3] & 0xF) == STT_SECTION) + n_new = sum(len(p["pieces"]) - 1 for p in todo.values()) + st = e.sh[e.symidx] + if insert_at > st["info"]: + raise SplitRefused("symbol table: section symbols are not in the LOCAL range (sh_info=%d)" % st["info"]) + for rl in e.rels.values(): + for r in rl: + if r[1] >= insert_at: + r[1] += n_new + st["info"] += n_new + k = insert_at + for sec, p in todo.items(): + for pc in p["pieces"][1:]: + e.syms.insert(k, [e.add_string(e.strtab, pc.name), 0, 0, (STB_LOCAL << 4) | STT_SECTION, 0, pc.shndx]) + pc.symidx = k + k += 1 + # 3. move the symbols that live in a later piece + for sec, p in todo.items(): + bi = p["shndx"] + for y in e.syms: + if y[5] == bi and (y[3] & 0xF) != STT_SECTION: + pc = max((q for q in p["pieces"] if q.lo <= y[1]), key=lambda q: q.lo, default=p["pieces"][0]) + if pc.index: + y[5], y[1] = pc.shndx, y[1] - pc.lo + # 4. retarget + rewrite the addend field of every reference in a later piece + changed = {} # (target sec idx, offset) -> new word + for sec, p in todo.items(): + text_i = e.section_index(".text") + for ri, k, pc, field in p["actions"]: + off, sym, typ = e.rels[ri][k] + tgt = e.sh[ri]["info"] + pc.refs += 1 + if pc.index == 0: + continue + e.rels[ri][k][1] = pc.symidx + w = u32(e.data[tgt], off) + nw = (w & 0xFFFF0000) | field + struct.pack_into(" 1: + lines.append(f" SPLITTABLE: YES — {len(p['pieces'])} pieces:") + for pc in p["pieces"]: + cut = f" cut snapped to `{pc.cut_sym}`" if pc.cut_sym else ("" if pc.index == 0 else " (no symbol start between the runs)") + lines.append(f" {pc.name:7s} [{pc.lo:#06x},{pc.hi:#06x}) -> {pc.addr:#010x}{cut}") + elif p["runs"]: + lines.append(" single base — no split needed") + else: + lines.append(" no HI16/LO16 pairs against the section symbol — nothing to place") + return "\n".join(lines) + + +def main(): + ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) + ap.add_argument("obj") + ap.add_argument("--vram", required=True, help="the object's .text vram in the target binary") + ap.add_argument("--exe", required=True, help="target binary path") + ap.add_argument("--vram-base", required=True, help="fileoff->vram delta of the target binary") + ap.add_argument("-o", "--out", help="write the split object here (omit to report only)") + a = ap.parse_args() + exe = open(a.exe, "rb").read() + name = os.path.basename(a.obj) + try: + plans = analyze(a.obj, int(a.vram, 0), exe, int(a.vram_base, 0)) + except SplitRefused as ex: + print(f"{name}: REFUSED — {ex}") + return 2 + if not plans: + print(f"{name}: no NOBITS section is referenced through its section symbol — the scattered-.bss wall does not apply") + return 0 + print(report(plans, name)) + if a.out and needs_split(plans): + split(a.obj, int(a.vram, 0), exe, int(a.vram_base, 0), a.out, plans) + n = sum(pc.refs for p in needs_split(plans).values() for pc in p["pieces"][1:]) + print(f" wrote {a.out}: {n} reference(s) retargeted; {describe(plans)}") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tools/psyq_integrate.py b/tools/psyq_integrate.py index dafece5b7..61e0b5df7 100644 --- a/tools/psyq_integrate.py +++ b/tools/psyq_integrate.py @@ -3,8 +3,10 @@ Run after `make extract`. Given a library's ELF objects and the stub subsegment(s) splat emitted for the library's text region(s), this: - 1. prepares each object (objcopy: .text/.data/.rdata/.bss align=4; weaken every .bss/.sbss - named symbol so a strong --defsym beats its scattered weak def) -> /*.o + 1. prepares each object (P31 S78 #4: an object whose .bss is referenced at several bases through + the section symbol is first split into per-base NOBITS pieces by psyq_bss_split, §489; then + objcopy: .text/.data/.rdata/.bss align=4; weaken every .bss/.sbss named symbol so a strong + --defsym beats its scattered weak def) -> /*.o 2. rewrites the splat linker script: each `build/src/.o(.text);` line is replaced by the real objects' `/.o(.text);` lines (the library's objects form one contiguous block per stub, so concatenation places them at their exact vrams); each object's @@ -30,6 +32,7 @@ import glob, os, re, subprocess, sys, tempfile sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from psyq_link import recover_sym_addrs, AS, sh, DATA_SECTIONS from psyq_link_region import classify, placement +from psyq_bss_split import prepare_object, describe # P31 S78 #4: scattered-.bss split at link-prepare def stub_ranges(yaml_path, stubs, vram_base): @@ -120,9 +123,20 @@ def integrate(elf_dir, ld_path, objdir, syms_path, stubs, lo=None, hi=None, f"stub subsegs of {os.path.basename(elf_dir)} — byte-placed but NOT wired (LINKED residue):") for nm, v, n in residue: print(f" 0x{v:08X} {nm:14s} {n:5d} ins") - recovered, weaken_by, bases_by = {}, {}, {} + recovered, weaken_by, bases_by, srcs = {}, {}, {}, {} + os.makedirs(objdir, exist_ok=True) for name, (vram, _) in order: - bases, weaken, sym_addr = classify(os.path.join(elf_dir, name), vram, exe, vram_base) + # P31 S78 #4 (cookbook §489): an object whose `.bss` is referenced through the SECTION symbol + # at more than one base (SYS.o, VM_F.o, GS_001.o — the §9.1 "scattered commons" exclusions) + # is rewritten into per-base NOBITS pieces (.bss/.bss2/…) under /.split BEFORE + # classify(), whose per-piece section symbols then recover one base each. Derived from the + # bytes on every run — nothing recorded that could go stale (R51). A refusal is fatal (R43). + src, plans = prepare_object(os.path.join(elf_dir, name), vram, exe, vram_base, + os.path.join(objdir, ".split")) + if plans: + print(f" .. {name}: {describe(plans)} — scattered commons tiled at link-prepare") + srcs[name] = src + bases, weaken, sym_addr = classify(src, vram, exe, vram_base) bases_by[name], weaken_by[name] = bases, weaken for s, a in sym_addr.items(): if not s.startswith("."): @@ -143,14 +157,13 @@ def integrate(elf_dir, ld_path, objdir, syms_path, stubs, lo=None, hi=None, m = re.match(r"(\w+)\s*=\s*0x([0-9A-Fa-f]+)", ln) if m: curated_by_addr.setdefault(int(m.group(2), 16), m.group(1)) - os.makedirs(objdir, exist_ok=True) for name, (vram, _) in order: args = [] for S in (".text",) + DATA_SECTIONS: args += ["--set-section-alignment", f"{S}=4"] for w in weaken_by[name]: args += ["--weaken-symbol", w] - defined = subprocess.run([f"{AS}nm", "--defined-only", os.path.join(elf_dir, name)], + defined = subprocess.run([f"{AS}nm", "--defined-only", srcs[name]], capture_output=True, text=True).stdout for dl in defined.splitlines(): parts = dl.split() @@ -162,7 +175,7 @@ def integrate(elf_dir, ld_path, objdir, syms_path, stubs, lo=None, hi=None, if cn and cn != sym: args += ["--redefine-sym", f"{sym}={cn}"] print(f" == {name}: exported `{sym}` @0x{addr:08X} is curated `{cn}` -> redefined (R15)") - sh(f"{AS}objcopy", *args, os.path.join(elf_dir, name), os.path.join(objdir, name)) + sh(f"{AS}objcopy", *args, srcs[name], os.path.join(objdir, name)) if yaml_path: # Stub<->objects by SUBSEG RANGE (P31 S78), not by run-contiguity: two adjacent stub subsegs are diff --git a/tools/psyq_link.py b/tools/psyq_link.py index 548c0da68..8d4796b1a 100644 --- a/tools/psyq_link.py +++ b/tools/psyq_link.py @@ -29,6 +29,8 @@ Usage: Importable: link_object(obj, text_vram, *, vram_base, exe_path|exe_bytes) -> dict(result). """ import struct, subprocess, sys, os, re, tempfile +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +from psyq_bss_split import NOBITS_RE, SplitRefused, prepare_object, describe # P31 S78 #4: scattered-.bss split at link-prepare # Phase 9: vram_base (the fileoff->vram delta) and the target binary are REQUIRED parameters — # no EXE default an overlay could silently inherit. AS is the cross-toolchain prefix (universal). @@ -196,9 +198,26 @@ def link_object(obj, text_vram, name=None, exe_bytes=None, *, vram_base, exe_pat """ name = name or os.path.basename(obj) exe = exe_bytes if exe_bytes is not None else open(exe_path, "rb").read() + tsize = section_table(obj).get(".text", (0, 0))[0] + res = {"name": name, "text_vram": text_vram, "tsize": tsize, "split": ""} + with tempfile.TemporaryDirectory(dir=".run") as td: + # P31 S78 #4: an object whose `.bss` is referenced through the SECTION symbol at more than one + # base (scattered commons, §9.1) is split into per-base NOBITS pieces first — the same prepare + # step the region verify and the build use, so this verdict is the build's verdict. A refusal + # is reported as a FAIL with its reason, never as a crash (this is a verification tool). + try: + obj, plans = prepare_object(obj, text_vram, exe, vram_base, os.path.join(td, "split")) + except SplitRefused as ex: + res.update(ok=False, error=f"bss split refused: {ex}", externals={}, unrecovered=[], + rdata_vram=None, data_vram=None, bss_vram=None) + return res + res["split"] = describe(plans) + return _link_prepared(obj, text_vram, exe, vram_base, td, res) + + +def _link_prepared(obj, text_vram, exe, vram_base, td, res): secs = section_table(obj) - tsize = secs.get(".text", (0, 0))[0] - res = {"name": name, "text_vram": text_vram, "tsize": tsize} + tsize = res["tsize"] symtab = symbol_table(obj) sym_addr = recover_sym_addrs(obj, text_vram, exe, vram_base) @@ -210,10 +229,10 @@ def link_object(obj, text_vram, name=None, exe_bytes=None, *, vram_base, exe_pat # section bases for placement: byte-search (initialised) or the section-symbol reloc. bases = {} - for S in DATA_SECTIONS: - if S not in secs or secs[S][0] == 0: + for S in secs: # every data-like section, incl. the split pieces (.bss2 …) + if not (S in DATA_SECTIONS or NOBITS_RE.match(S)) or secs[S][0] == 0: continue - b = unique_byte_vram(obj, S, exe, vram_base) if S not in (".bss", ".sbss") else None + b = unique_byte_vram(obj, S, exe, vram_base) if not NOBITS_RE.match(S) else None if b is None: b = sym_addr.get(S) # set iff the object referenced the section symbol bases[S] = b @@ -243,30 +262,35 @@ def link_object(obj, text_vram, name=None, exe_bytes=None, *, vram_base, exe_pat res["externals"] = externals res["unrecovered"] = sorted(undefined_syms(obj) - set(externals)) - with tempfile.TemporaryDirectory(dir=".run") as td: - aligned = os.path.join(td, "a.o") - align_args = ["--set-section-alignment", ".text=4"] - for S in placed: - align_args += ["--set-section-alignment", f"{S}=4"] - for s in weaken: - align_args += ["--weaken-symbol", s] - sh(f"{AS}objcopy", *align_args, obj, aligned) - ld = os.path.join(td, "link.ld") - lines = ["SECTIONS {", f" . = 0x{text_vram:08X};", " .text : { *(.text) }"] - for S, b in placed.items(): - lines += [f" . = 0x{b:08X};", f" {S} : {{ *({S}) }}"] - lines += [" /DISCARD/ : { *(*) }", "}"] - open(ld, "w").write("\n".join(lines) + "\n") - cmd = [f"{AS}ld", "-T", ld, "-o", os.path.join(td, "out.elf"), aligned] - for s, a in sorted(defs.items()): - cmd += ["--defsym", f"{s}=0x{a:08X}"] - p = subprocess.run(cmd, capture_output=True) - if p.returncode != 0: - res["ok"] = False - res["error"] = "ld: " + p.stderr.decode().strip().split("\n")[-1] - return res - got = sh(f"{AS}objcopy", "-O", "binary", "--only-section", ".text", - os.path.join(td, "out.elf"), "/dev/stdout").stdout + aligned = os.path.join(td, "a.o") + align_args = ["--set-section-alignment", ".text=4"] + for S in placed: + if re.fullmatch(r"\.s?bss\d+", S): + continue # a split piece carries the alignment of its own base + align_args += ["--set-section-alignment", f"{S}=4"] + for s in weaken: + align_args += ["--weaken-symbol", s] + sh(f"{AS}objcopy", *align_args, obj, aligned) + ld = os.path.join(td, "link.ld") + lines = ["SECTIONS {", f" . = 0x{text_vram:08X};", " .text : { *(.text) }"] + for S, b in placed.items(): + lines += [f" . = 0x{b:08X};", f" {S} : {{ *({S}) }}"] + lines += [" /DISCARD/ : { *(*) }", "}"] + open(ld, "w").write("\n".join(lines) + "\n") + # --no-check-sections, exactly as the build and the region verify link: NOLOAD placements are + # addresses only, and a split piece's extent tiles the PACKED section, so an unreferenced common + # inside one piece may in truth live inside another piece's range (GS_001: PSDBASEX/PSDBASEY are + # adjacent in the game, 16 bytes apart in the packed .bss) — zero-byte overlaps, harmless. + cmd = [f"{AS}ld", "--no-check-sections", "-T", ld, "-o", os.path.join(td, "out.elf"), aligned] + for s, a in sorted(defs.items()): + cmd += ["--defsym", f"{s}=0x{a:08X}"] + p = subprocess.run(cmd, capture_output=True) + if p.returncode != 0: + res["ok"] = False + res["error"] = "ld: " + p.stderr.decode().strip().split("\n")[-1] + return res + got = sh(f"{AS}objcopy", "-O", "binary", "--only-section", ".text", + os.path.join(td, "out.elf"), "/dev/stdout").stdout want = exe[text_vram - vram_base: text_vram - vram_base + tsize] res["ok"] = (got == want) @@ -295,6 +319,8 @@ def main(): print(f"[{tag}] {r['name']:14s} .text@0x{text_vram:08X} ({r['tsize']} B) " f".rdata@{r['rdata_vram'] if not isinstance(r['rdata_vram'],int) else hex(r['rdata_vram'])} " f".data@{r['data_vram'] if not isinstance(r['data_vram'],int) else hex(r['data_vram'])}") + if r.get("split"): + print(" ", r["split"]) if r.get("error"): print(" ", r["error"]) if not r["ok"] and "ndiff" in r: diff --git a/tools/psyq_link_region.py b/tools/psyq_link_region.py index 1d525ed29..868b6488e 100644 --- a/tools/psyq_link_region.py +++ b/tools/psyq_link_region.py @@ -20,6 +20,7 @@ import json, os, re, subprocess, sys, tempfile sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from psyq_link import (section_table, symbol_table, recover_sym_addrs, unique_byte_vram, DATA_SECTIONS, AS, sh) +from psyq_bss_split import NOBITS_RE, prepare_object, describe # P31 S78 #4 def placement(elf_dir, lo, hi, vram_base, exe): @@ -47,14 +48,14 @@ def classify(obj, text_vram, exe, vram_base): sym_addr = recover_sym_addrs(obj, text_vram, exe, vram_base) bases = {} - for S in DATA_SECTIONS: - if S in secs and secs[S][0] > 0: - b = unique_byte_vram(obj, S, exe, vram_base) if S not in (".bss", ".sbss") else None + for S in secs: # every data-like section, incl. split pieces (.bss2 …, §489) + if (S in DATA_SECTIONS or NOBITS_RE.match(S)) and secs[S][0] > 0: + b = unique_byte_vram(obj, S, exe, vram_base) if not NOBITS_RE.match(S) else None if b is None: b = sym_addr.get(S) # the object referenced the section symbol if b is not None: bases[S] = b - weaken = [s for s, (sec, _) in symtab.items() if sec in (".bss", ".sbss")] + weaken = [s for s, (sec, _) in symtab.items() if NOBITS_RE.match(sec)] return bases, weaken, sym_addr @@ -82,10 +83,16 @@ def build_region(elf_dir, lo=None, hi=None, emit=None, *, vram_base, exe_path): region_lo = order[0][1][0] region_hi = order[-1][1][0] + order[-1][1][1] * 4 - recovered, weaken_by, bases_by = {}, {}, {} + td = tempfile.mkdtemp(dir=".run") + recovered, weaken_by, bases_by, srcs = {}, {}, {}, {} conflicts = [] for name, (vram, _) in order: - obj = os.path.join(elf_dir, name) + # P31 S78 #4: split a scattered-.bss object into per-base pieces BEFORE classifying it — the + # pieces' own section symbols then yield one base each (SplitRefused propagates: loud, R43). + obj, plans = prepare_object(os.path.join(elf_dir, name), vram, exe, vram_base, os.path.join(td, "split")) + if plans: + print(f" .. {name}: {describe(plans)}") + srcs[name] = obj bases, weaken, sym_addr = classify(obj, vram, exe, vram_base) bases_by[name] = bases weaken_by[name] = weaken @@ -96,7 +103,6 @@ def build_region(elf_dir, lo=None, hi=None, emit=None, *, vram_base, exe_path): conflicts.append((s, recovered[s], a)) recovered[s] = a - td = tempfile.mkdtemp(dir=".run") prepared = [] for name, (vram, _) in order: dst = os.path.join(td, name) @@ -105,7 +111,7 @@ def build_region(elf_dir, lo=None, hi=None, emit=None, *, vram_base, exe_path): args += ["--set-section-alignment", f"{S}=4"] for w in weaken_by[name]: args += ["--weaken-symbol", w] - sh(f"{AS}objcopy", *args, os.path.join(elf_dir, name), dst) + sh(f"{AS}objcopy", *args, srcs[name], dst) prepared.append((name, vram, dst)) # Each object's .text is placed at its EXACT vram (the region is two contiguous libcd