Drew T
d9517a013b
refactor(phase-9): T2 — thread vram_base/exe through psyq_link.py
...
- recover_sym_addrs/unique_byte_vram/link_object take vram_base (+ link_object
exe_path), defaulting to the kept EXE module globals (TRANSITIONAL — removed in
T8 at the no-EXE-default end state, once every caller passes explicitly)
- argparse main() with --vram-base/--exe (in-process importers unaffected: the
globals + defaults keep psyq_integrate/link_region/make_* green)
- negative control: TOC.o --vram-base 0x8000F900 -> FAIL (.rdata shifts +0x100),
0x8000F800 -> PASS, bare defaults -> PASS; clean build -> 143dbb89 BYTE-IDENTICAL
2026-06-15 20:30:19 -06:00
Drew T
11a9bdc032
feat(phase-8): link libapi+libcard combined 800c2 region (T7+T8) — 22 objs / +24 fns
...
- libapi (BIOS syscall trampolines) + libcard interleave in 0x61F38..0x62888; linked as
one combined region (4 blocks apicard1..4) via tools/make_apicard_used.py (C112.o shared,
byte-match dedup, 0 exclusions)
- subsegs via gen_lib_subsegs.py; integrate window 0x61F38..0x62888; region verified 22/22
- rm'd src/800c2.c (region starts with a lib block) -> splat regenerates apicard1..4 + frags
- dual byte-gate PASS: 143dbb89 with and without the apicard objects
- LINKED 935 -> 959 (+24); REAL still 43; byte-identical 49.81%
- libapi's ~22 objects in the 800c3 region DEFERRED (lowest value); SSGM + the scattered-.bss
exclusions documented in docs/psyq-worklist.md
LIBRARY CEILING: 8 PsyQ libraries linked byte-identical (959 LINKED fns); byte-identical
coverage 20.31% (libcd+libgs only) -> 49.81%. Remaining = documented low-value deferrals.
2026-06-15 18:59:14 -06:00
Drew T
8bbf2e8e4d
feat(phase-8): link libspu+libsnd combined sound region (T9+T10) — 60 objs / +225 fns
...
- libspu and libsnd interleave in 0x3A444..0x4239C (the 800-subseg tail), so they link
as ONE combined region rather than two tangled passes
- NEW tools/make_snd_used.py: build the curated combined dir — merge both libs by vram,
pick the byte-matching object per aliased address (link_object), exclude 4 addresses
that don't reconcile in-region (kept as byte-identical stubs):
0x3C438 S_R/S_W, 0x3D424 S_GRMDT/FB/T — scattered-.bss commons, cross-object (§9.1)
0x3D94C S_IH/UT_RON — false placement (inside libsnd SSSTART.o)
0x3FA64 VM_F (237 ins) — scattered-.bss commons (the one real loss)
- subsegs via gen_lib_subsegs.py (9 snd blocks + 8 sgap game/excluded-stub gaps);
integrate window 0x3A444..0x4239C; region byte-verified 60/60
- src/800.c trimmed at [0x3A444,0x4239C): kept 732 items < 0x3A444 (ALL matched C +
game + the deferred SSGM stub preserved), 0 real-C moved
- dual byte-gate PASS: 143dbb89 with and without the sound objects
- LINKED 710 -> 935 (+225); REAL still 43; byte-identical 48.66% (nearly half the EXE)
- deferred: SSGM.o @0x1BD80 (isolated, matched-C region, 8 ins)
2026-06-15 18:54:21 -06:00
Drew T
c4a627b22b
feat(phase-8): link libgte byte-identical (T11, value-first) — 53/58 objs / +120 fns
...
- NEW tools/gen_lib_subsegs.py: generate splat subseg lines + integrate stub list for a
multi-block library (section-size-correct block ends — bakes in the libc2/T6 boundary
gotcha so it can't recur). Reused for libspu/libsnd next.
- libgte = GTE math, 53 objects in 22 blocks across the old 800b region (game code
interleaved as 800b/800b_2..800b_7). Resegmented from the generator; integrate window
0x4787C..0x51804 so it sees exactly the 22 in-region blocks
- 5 libgs-gap libgte objects (MTX_05/07/11/REG03/REG11) DEFERRED — gsgap1/2/4/5 stay
stubs (gsgap2 != MTX_07 exactly, needs a sub-split); documented in worklist
- progress.py linked_subsegs() now resolves `$(VAR)` stub lists (LIBGTE_STUBS) — the long
multi-block lists are passed via a make var
- region byte-verified 58/58 (clean, no scattered .bss); rm'd src/800b.c (region starts
with a lib block) so splat regenerates the fragments; 22 src/libgteN.c + 6 game frags
- dual byte-gate PASS: 143dbb89 with and without the libgte objects
- LINKED 590 -> 710 (+120); REAL still 43; byte-identical 37.93%
- reordered remaining libs value-first (libspu/libsnd next; dense libcard/libapi last)
2026-06-15 18:43:27 -06:00
Drew T
c27a4432eb
feat(phase-8): library survey + progress.py LINKED category (T1-T2)
...
- T1: docs/psyq-worklist.md — byte-confirmed PsyQ footprint map (psyq_identify
over the original EXE): 9 footprint libs (199 placements) ranked ascending
difficulty; 3 skip (libmath/libc/libsn = 0 footprint). Findings: the libgs
"gaps" are libgte objects; heavy game/library interleaving (800=game+libspu+
libsnd+libetc, 800b~libgte, 800b2=game+libgpu/libc2/libapi/libmcrd/libcard);
cross-library aliases (C112, UT_RON/S_IH, S_R/S_W)
- T2: tools/progress.py LINKED category — INCLUDE_ASM stubs in integrated library
subsegs counted as a distinct byte-identical bucket; linked-subseg set sourced
from the Makefile's psyq_integrate calls (single source of truth -> auto-updates
per integration, no manifest drift). libcd+libgs: 340 stubs -> LINKED;
byte-identical/matchable now 425/2093 = 20.31%. Build unchanged (143dbb89)
- phase-ends/CURRENT_PHASE.md: Phase 8 plan + per-task log
2026-06-15 18:00:56 -06:00
Drew T
6f248462dd
chore(gen2-prep): Gen2 roadmap + private-repo backup hardening + SETUP/submodule fixes
...
- docs/gen2-roadmap.md: approved Gen2 plan (phases 8-15; finish-EXE-first,
two-repo LATE public flip, substantial exit) + Backup & disaster-recovery policy
- back up irreplaceable / hard-to-re-source artifacts to the private remote (R20):
- track ghidra/ (the RE database; *.lock/tmp*.ps transients excluded)
- tools/psyq/ working libs/tools (minus the two >100MB raw source archives)
- tools/bin/*.tar.gz (old-gcc cc1 compiler sources; extracted binaries stay regenerable)
- tools/ghidra-ext/ (GhidrAssistMCP 2.8.0 + ghidra_psx_ldr 2026.06.04 installer zips)
- .claude/settings.json: SessionStart + SessionEnd hooks (auto-start / clean-save the
headless Ghidra MCP); moved out of the gitignored settings.local.json so they are backed up
- docs/SETUP.md: document the MCP server lifecycle + persistence model + session hooks (§2.8),
a tooling inventory, .run/ runtime scratch (§1a), and the backup posture (§ Backup) — R21
- .gitmodules: ignore=dirty on the 4 submodules (maspsx/asm-differ/m2c/decomp-permuter) —
silences the phantom "modified" state from generated pycache + cross-filesystem filemode;
gitlinks unchanged (still at the pinned commits)
- rules R20 (back up irreplaceable work + gathered tooling; loosens R8) and R21 (keep
SETUP.md current) recorded in memory; to be formalized at the next PhaseEnd
2026-06-15 17:15:31 -06:00
Drew T
49db81d8ae
feat(phase-7): Gen1 close-out — matching loop industrialized, PsyQ libs linked, LZSS matched (v1.7.0)
...
- reports (Task 3): tools/{progress,difficulty,dup_report}.py + make report/sig-refresh
(deterministic digests); harvest to 43 REAL matches incl. LzssDecodeSector
- per-module -O0 split (Task 5.5): src/boot.c + Makefile per-file CC1FLAGS (cookbook §6)
- PsyQ SDK linking (sessions C-G): split/build/identify/link/integrate pipeline
(tools/psyq_*.py, make_libgs.sh, ld_interleave.py, split_src_region.py) — libcd (18 obj)
+ FULL libgs (31 obj / 6 blocks) linked BYTE-IDENTICAL from real PsyQ 4.0 libs; byte-
identical with or without the SDK objects (stub fallback); cookbook §7/§8/§9.1-9.5
- LZSS MATCHED byte-for-byte (session F): §5a cross-jump barrier + §10 regalloc/schedule
idioms, ground-truthed against pinned gcc-2.7.2 source (the Gen1 LZSS gate)
- file-loader cluster: 6 matched + 5 NON_MATCHING-drafted (CdReadStateMachine,
CdReadSectorReadyCB, StreamLoadStateMachine new this session, valid under -DNON_MATCHING);
SaveLoadRoutine DEFERRED to Q#5 (save/memcard, documented stub)
- README Gen1-complete; worklog preserved -> phase-ends/logs/Phase7.md
- rules R17 (web-research compiler quirks), R18 (plain-English session summaries),
R19 (preserve phase worklog out of load order)
- MILESTONE: Gen1 EXIT confirmed — byte-identical build, 43 matches incl LZSS, 7 zero-
regression sessions, loader cluster matched/drafted, overlay map emulator-proven
- bumps project version 1.6.0 -> 1.7.0
2026-06-15 13:44:32 -06:00
Drew T
f91a67a6fe
feat(phase-7): libgs block 6 linked byte-identical (16 objs / 26 SDK funcs) — session F
...
- resegment 800b -> [800b pre][libgs6][800b2 post]; psyq_integrate the 16 contiguous
block-6 libgs objects (GS_110/119/120/121/122/123/127/131/133/134/135/137, PRESET,
PRESET3, OBJT, OBJT3) at vram 0x80053AF8-0x80057928; make check BYTE-IDENTICAL
- fix the resegment-triggered spimdisasm boundary instability: declare GsMulCoord2/3
(real MATRIX.o funcs, verified via the PsyQ object, R15 Ghidra-mirror pending) +
carve the s8 data descriptor table [0x53198,data,53198] (D_80062998 was shadowed by
a mis-detected func_80062998); ld_interleave FRONT_DATA -> 53198.data.o
- psyq_integrate multi-library support: per-lib NOLOAD section namespacing (.nl_<tag>_*)
so the 2nd integration's NOLOAD isn't skipped (was discarding OBJT3 .rdata/.bss);
trial-link includes sibling *_externals.ld (kills the '31 UNRESOLVED' false alarm);
global NOLOAD re-sort by vram (kills 'dot moved backwards')
- tools/make_libgs_block6.sh: reproducible curated-dir regen (disambiguated 16 objects)
- gated on [ -d .run/obj40/libgs_block6 ]: fresh-clone stub fallback verified byte-identical
- cookbook s9.4 (multi-library integration gotchas); CURRENT_PHASE updated
- next: full libgs integration (other 5 blocks), then Task 6 close-out + Task 7 PhaseEnd
2026-06-15 10:48:08 -06:00
Drew T
038e7de532
feat(phase-7): LZSS cross-jump barrier breakthrough + libgs byte-verified — session E checkpoint
...
- LZSS: defeated gcc 2.7.2 -O2 cross-jump-merge of the twin state-save tails with a
zero-byte __asm__ __volatile__("" ::: "memory") barrier (find_cross_jump bails on
ASM_INPUT; ground-truthed vs gcc-2.7.2.3 jump.c by a web-research subagent).
LzssDecodeSector now 122 instructions (correct structure); ~3 regalloc/scheduling
swaps remain -> C kept under #ifdef NON_MATCHING, default build = stub = BYTE-IDENTICAL
- surgical rodata carve (lean LZSS path, no libgs needed): splat carves ONLY
jtbl_80072A38 ([0x63238,.rodata,800] bounded by [0x6324C,data,6324C]); ld_interleave
wired into `make extract` as the .data->.rodata->.data sandwich (TAIL_DATA=6324C.data.o)
- libgs: 31/32 used objects byte-verified IDENTICAL to real PsyQ libgs 4.0 (0 conflicts,
69 externals); GS_001 deferred (psyq-obj-parser .bss-common scattering); 6-block
resegmentation wiring pending. psyq_identify.py now skips data-only objects (GLOBAL.o)
- cookbook: §3a (web-research compiler internals — escalation tier above the permuter)
+ §5a (the cross-jump barrier idiom) — both reusable
- build BYTE-IDENTICAL (143dbb89f34491258bbc27810d0a12ec8b43a8dd) throughout
2026-06-15 01:47:18 -06:00
Drew T
3788a89b3c
feat(phase-7): libcd linked into byte-identical build (58 SDK funcs) — session D checkpoint
...
The first real PsyQ library is sourced from real SDK objects in the byte-identical
build, replacing the libcd-region asm stubs. Tasks 2'.1/2'.2/2'.3 — the whole
PsyQ-library-into-build mechanism, proven on the simplest library (libcd).
- psyq_link.py: per-object byte-link engine — recovers externals from the EXE's
resolved relocations (R_MIPS_26 / HI16+LO16); weakens psyq-obj-parser's
mislabelled common-style .bss globals so a strong --defsym wins
- psyq_link_lib.py: whole-library verify — 18/18 libcd objects byte-identical
- psyq_link_region.py: region link via NOLOAD data placement (no carving) +
weaken-all-.bss; gap-aware per-object placement
- psyq_integrate.py: build wiring — splat resegment swap + per-object .text at
vram + NOLOAD data; external resolution (func_<addr> aliases, symbols.us.txt
jump-table names, recovered St*/CD_* globals, all weakened .bss commons);
idempotent; conditional on tools/psyq/ (fresh clone builds via stubs)
- split_src_region.py: H5-safe src/*.c split at vram boundaries (preserves
matched C + NON_MATCHING blocks)
- splat.us.exe.yaml: 5-way text split [pre][libcd1][gap][libcd2][post]
- src/800.c trimmed to <0x80043088; src/{800b,gap,libcd1,libcd2}.c splat stubs
- Makefile: libcd integration in the $(OUT) recipe (conditional + idempotent)
- cookbook §9.1/9.2/9.3 (the reusable mechanism for libgs/Gen2); CURRENT_PHASE
session-D log; ≥3-session green bar A/B/C/+D
- make clean && extract && build && check -> 143dbb89... BYTE-IDENTICAL
2026-06-14 23:13:39 -06:00
Drew T
26b71c5b2d
feat(phase-7): PsyQ library-linking proven byte-exact + rodata-island mechanism — session C checkpoint
...
- rodata-island mechanism PROVEN: migration (dotted .rodata sibling named "800")
+ tools/ld_interleave.py (.data->.rodata->.data linker placement) + data-in-text
carve; rodata/data sizes come out byte-exact. +24 residual root-caused to the
.align-3 jumptable file-split padding (6 sites; spim suggests 8 splits)
- PsyQ 4.0 library linking PROVEN end-to-end: libcd SYS.o (483 instrs, full TU + 21
externals + internal .rdata/.data relocs) links BYTE-IDENTICAL to BFM
- tools/psyq_lib_split.py: split Sony LIB\x01 archive -> member .OBJ
- tools/psyq_build_libs.sh: .LIB -> psyq-obj-parser -> ELF .a (14 BFM libs)
- tools/psyq_identify.py: relocation-masked search -> object link addresses
(libcd 18/25 used, contiguous from 0x80043088)
- external symbols recovered from the EXE's own resolved relocations
- section-alignment 8->4 fix (psyq-obj-parser over-aligns; the +4 mismatch is the tell)
- cookbook §8 (rodata island) + §9 (PsyQ library-linking recipe); CURRENT_PHASE full
diagnosis, asset inventory, and resume plan
- 3rd consecutive green session (143dbb89 BYTE-IDENTICAL) -> Gen1 >=3-session bar MET
- SDK assets (PsyQ 4.0 USA DTL-S2002 libs + psyq-obj-parser) staged gitignored under
tools/psyq/; no function matches added (architectural session)
2026-06-14 21:24:10 -06:00
Drew T
8ffb7f0607
feat(phase-7): -O0 split + 4 matches (42 real) + libcd.h — session B checkpoint
...
- per-file -O0 mechanism: split text c-subseg into boot@-O0 (src/boot.c) + 800@-O2
via splat resegmentation + Makefile target-specific CC1FLAGS; the boot/main/
game-mode-dispatch module (0x80010000-0x800123F0) is -O0, not the pinned -O2
(per-module compiler mixing, SETUP §5.5). Regression-gated byte-identical.
- 4 byte-matches (38->42 real, make check BYTE-IDENTICAL throughout): GameModeDispatch
(-O0 register-ptr far member), DebugMenuHandler (-O0 reserved-slot local), CdQueueBusy
(-O2 if/else order + branch polarity), CdReadRequest (-O2 early-return fall-through)
- PsyQ infra: include/psyq/libcd.h (CdlLOC/CdlFILE from the .gdt) + 4 named symbols
(CdSearchFile/CdPosToInt/CdIntToPos/VSync) in symbols.us.txt; func_* stubs renamed
- loader cluster non-jtbl COMPLETE (6 matched + 2 drafted): NON_MATCHING drafts of
LoaderInitFileTable + ResourceLoadStateMachine (logically faithful, residuals in-source)
- tooling: progress.py/difficulty.py fixed for the multi-file split (glob src/*.c, all
asm dirs, skip forward-decls); deterministic; 42 real / 4 NM
- flywheel: matching-cookbook §6 (-O0 detection + idioms), §7 (PsyQ types/symbols), T4
- build byte-identical 143dbb89f34491258bbc27810d0a12ec8b43a8dd from a full clean cycle
2026-06-14 19:37:05 -06:00
Drew T
379185a799
feat(phase-7): matching reports + 24 matches (38 real) — session A checkpoint
...
Mid-phase checkpoint (Drew-directed; phase NOT closed — R8 exception).
- reports (Task 3): tools/{progress,difficulty,dup_report}.py + `make report`
(deterministic) + `make sig-refresh`; authoritative baseline 38 real / 2050
matchable; empties audit 42/42 genuine jr;nop; docs/{progress,difficulty,
duplicates}.md digests
- matches (Tasks 4-5): +24 byte-identical (22 accessor leaves via the harvest
pattern + ResourceGetCdLoc + LoaderResetReadState); make check BYTE-IDENTICAL
throughout (143dbb89...)
- config/symbols.us.txt: declare func_80047CAC (R15) — fixes a latent
non-reproducibility (spimdisasm 1.41.0 auto-detect of an 8B inter-fn blob was
unstable across clean extracts; the committed Phase-6 baseline did not
deterministically rebuild)
- Task 1 rodata-island foundation: investigated (migration co-locates jump
tables + resolves refs, but byte-identity blocked by splat global-migration +
contiguous linker placement vs BFM's monolithic segment) -> DEFERRED to Task 2'
with a candidate fix; full findings in phase-ends/CURRENT_PHASE.md
- phase-ends/CURRENT_PHASE.md: reordered plan, loader-cluster triage, per-session
green-check log (1 of >=3 needed for the Gen1-exit milestone)
2026-06-14 17:36:12 -06:00
Drew T
5f937bdda5
feat(phase-6): compiler pinned + matching loop proven (14 matches) — LZSS to Phase 7
...
- splat.us.exe.yaml: text subseg asm->c (INCLUDE_ASM scaffold); include/common.h
(committed prelude); Makefile c-rule cpp->cc1->maspsx->as + -Map
- PIN (G8): gcc-2.7.2-psx -O2 -G0 -mips1 -mcpu=3000 -mgas -msoft-float -fgnu-linker
+ maspsx --aspsx-version=2.56 --expand-div; byte-exact on func_80018F20 +
instruction-identical across 3 idiom classes; --expand-div REQUIRED for div/rem
(SETUP.md §5.4 PINNED, Makefile MASPSX_FLAGS)
- harness: diff_settings.py (asm-differ mipsel object mode), tools/decompile.py
(m2c wrapper), tools/permuter/ (decomp-permuter harness + objdump shim), expected/
- 14 real functions matched (asm-differ score 0): func_80018F20 + 13 accessors;
+14 splat-auto empty no-ops; make check BYTE-IDENTICAL throughout
- 2 instruction-identical near-misses guarded NON_MATCHING (func_80015A74 scheduling,
func_80016714 phantom frame) -> decomp-permuter candidates
- flywheel: docs/matching-cookbook.md, memory + CLAUDE.md step 5 (consult+evolve), R16
- requirements-python.txt: venv freeze (pycparser<3.0 pinned — permuter needs plyparser)
- LZSS spike: needs jump-table-in-rodata workflow (102 tables, mixed blob) -> Phase 7
- venv: asm-differ + permuter deps installed
- bumps project version 1.5.0 -> 1.6.0
2026-06-14 14:47:01 -06:00
Drew T
ffe2352db2
feat(phase-4): matching-build toolchain (WSL) — make check-env green
...
- apt: build-essential, binutils-mipsel-linux-gnu 2.42 (+gcc-mipsel 12.x), ninja
1.11.1, python3-pip/venv, libelf-dev, clang-format, p7zip, bchunk, bsdmainutils
- .venv + splat64 0.41.0 ([mips]: spimdisasm 1.41.0, rabbitizer 1.16.2, PyYAML 6.0.3)
- 4 pinned submodules under tools/: maspsx@874855c5, decomp-permuter@b44b0622,
asm-differ@2ad4a4a4, m2c@4266cc28 (.gitmodules)
- old-gcc 0.17 cc1 candidates -> tools/bin/gcc-2.7.2-{psx,cdk}/ (32-bit i386 static;
tarballs are flat + same-named -> per-subdir extraction); CHECKSUMS.sha256 committed
(gitignore exception !/tools/bin/*.sha256); psx cc1 self-id "GNU C 2.7.2 [AL 1.1,
MM 40] Sony Playstation"
- Makefile: check-env (.ONESHELL bash) asserts python>=3.12, venv import splat, both
cc1 (stdin smoke), maspsx, mipsel as/ld/objcopy, sha1(EXE)==EXPECTED_EXE_SHA1;
binutils>=2.38 -> WARN (verdict deferred to Phase 5, §4.5); extract/build/check/
expected/clean are loud-failing Phase-5 stubs (names per §6.3)
- docs/SETUP.md: as-built versions; §4.7 corrected (i386, flat-tarball fix); §4.8
deferred to Phase 6; ledger #5 confirmed (Ubuntu 24.04.4), #6 (2.42), #7 (sha256)
- MILESTONE: make check-env exits 0; zero ROM-derived bytes staged
- bumps project version 1.3.1 -> 1.4.0
2026-06-14 03:56:07 -06:00
Drew T
3207d52491
feat(phase-3.5): prototype research spike — go/no-go (protos don't accelerate Gen1 matching)
...
- extract_proto_exe.py: subdir-aware proto main-EXE extraction (reuses iso9660); extracted
sep8 SLUS_007.26 (413,696 B) + aug31 MUSASHI/USA_DEMO.EXE (415,744 B, base 0x80018000)
- ghidra_import.sh: reusable headless import; both protos imported into the bfm project
(sep8 1726 funcs, aug31 1737 funcs, both PsyQ 4.0.0), R9-verified
- DumpFunctionSignatures.java + match_protos.py: 3-tier (exact/norm/seq) cross-binary
correspondence; MIPS normalizer validated by anchors
- FINDINGS: (T2) no debug symbols in either proto — Hidden Palace "no symbols" VERIFIED;
recon "Sep-8 less-stripped" REFUTED by per-file byte compare. (T3) Sep-8 99.6% byte-identical
to retail (only 3 funcs differ: DebugMenuHandler, CdReadSectorReadyCB, SaveLoadRoutine);
Aug-31 66% norm-identical, 862 1:1 correspondences. (T4) demo shares retail's 18-entry
game-mode dispatch architecture but the handler code diverged — Q#10 resolved
- VERDICT (docs/proto-correspondence.md): NO-GO as a Gen1 label/symbol accelerator; GO to retain
Sep-8 (Phase-6 compiler corroborant) + both (Gen2 assets); proto-side labels in
config/symbols.proto-{sep8,demo}.txt (R13-tagged, never feed symbols.us.txt)
- reorg extracted/ into per-ROM subfolders (extracted/retail/, extracted/proto/); nested
gitignore allowlist; extractor defaults updated; manifest --verify PASS
- memory-map.md: Phase-3.5 block + demo dispatch anchors; Q#10 RESOLVED; §5 proto notes VERIFIED
- ghidra_mcp_start.sh: PROG arg to serve a prototype
- rules R13 (proto-provenance/confidence tagging), R14 (verify recon counts vs bytes)
- bumps project version 1.3.0 -> 1.3.1
2026-06-14 03:19:23 -06:00
Drew T
bd5e21b366
feat(phase-3): file-loader & overlay-map RE + PCSX-Redux runtime oracle
...
- RE'd the full file-loader/overlay subsystem in Ghidra via MCP: CdReadRequest ->
CdReadStateMachine (hand-rolled CdControl SeekL/ReadN reader, NOT PsyQ CdRead);
LIST.CD RAM cache cdFileLocTable + ResourceGetCdLoc/resourceIdMap lookup; LZSS
staging buffer 0x80079A70; loadDestPtrTable; ~50 symbols named (T1-T5,T8)
- T6b MILESTONE: resident blob @0x800CEDF8 + location overlay @0x80128158 proven
byte-identical (sha1-equal contiguous prefixes) vs live PCSX-Redux RAM; blobs
imported into Ghidra (ImportOverlay.java); overlay-map table -> memory-map.md §4.3
- PCSX-Redux runtime oracle: Windows-native build, WSL reads RAM via the web API
at 172.17.208.1:8081; ledger #4 resolved
- live-verified player/time state: gold(/10) HP BP day hour tiredness boss-HP;
save-header template (Q#5) + debug-menu dispatch (Q#9: DEBUG.BIN path is dead)
- overlay map: 13 area-states across SC01/02/03, 2 duplicate pairs, location x
chapter keying, free-roam vs menu-hub granularity
- resolves Open Q#1/#3/#4/#5/#6/#8/#9/#12; corrects SLUS-90029 (FF8 demo, not BFM)
- 2 US prototypes acquired + CRC-verified (Aug-31 1369DE07, Sep-8 5C24728E)
- rules R9 (verify persistence), R10 (>=3-datapoint live verification),
R11 (runtime oracle Windows-native, bridged to WSL)
- bumps project version 1.2.0 -> 1.3.0
2026-06-14 02:04:28 -06:00
Drew T
b6ea3a2747
feat(phase-2): deterministic disc/.CD/PAC/LZSS extraction pipeline
...
- extract.py: one-command full-disc extraction (27 files: 24 Track-1 verbatim
+ 3 .DA as raw CD-DA audio from tracks 2-4) over the frozen iso9660.py
- cd_archive.py + pac.py: .CD TOC walker + PAC splitter, {index}.{type} naming
(no collisions; 447 sub-files, 1189 entries), SQV detection (98)
- lzss.py: game-semantics decoder (pos==0 terminator, -1 bias) + 5 unit tests;
138 type-4 decoded clean (0 warnings)
- manifest.py: deterministic JSON-Lines manifest (1801 artifacts) + --verify
- crosscheck.py + tools/brave-CUE/posix_shim.h: build CUE's brave from source
(GPL untouched), byte-compare; 1484 raw identical, 138/138 type-4 F6
- docs/formats.md: F5 counts (SC02=43), F2 refuted, F6 resolved, F1 type-7=139
- docs/effort-map.md + CLAUDE.md: Effort-map check rule (R7), Ultracode fix
- .gitignore: /extracted/* + !manifest/EXE exceptions; brave _build/
- install gcc 13.3.0 for the oracle
- milestone: one command extracts the full disc; MAIN.CD=49 sub-files; decoder
agrees byte-for-byte with CUE up to the game pos==0 terminator; zero ROM
staged; project version 1.1.0 -> 1.2.0
2026-06-13 19:47:42 -06:00
Drew T
5b6ffc0664
chore(phase-1): headless .gdt attach + MCP type-resolution test (ledger #2 )
...
- tools/ghidra_scripts/ImportPsyqGdt.java: opens psyq400.gdt and resolve()s
all 2599 PsyQ 4.0 types into the program DTM (205 -> 2609), registering
psyq400 as a SourceArchive; saved to ghidra/bfm.rep
- verified over MCP: types get DRAWENV -> full 92-byte struct (/LIBGPU.H),
SVECTOR (/LIBGTE.H) -> the .gdt "attach" is doable headlessly, no GUI
- docs/SETUP.md: ledger #2 RESOLVED; §2.5 step 5 answered (import types into
the program; MCP type tools then resolve them)
2026-06-13 16:46:03 -06:00
Drew T
36a366ba3f
chore(phase-1): install RE stack + headless import (PsyQ 4.0.0, MCP live)
...
- WSL RE stack installed: JDK 21.0.11, Ghidra 12.1 PUBLIC, GhidrAssistMCP
v2.8.0, ghidra_psx_ldr 2026.06.04 (extensions extracted into
Ghidra/Extensions/ at version=12.1; exact-12.1 pin held, no version-lock)
- headless import of extracted/SLUS_007.26: PSX loader auto-selected
(PSX:LE:32:default), PsyQ Version = 4.0.0 recorded, 1726 functions,
saved to ghidra/bfm.{gpr,rep} (gitignored)
- GhidrAssistMCP headless server verified on 127.0.0.1:8080 (41 tools);
get_code(0x80018730) returns the LZSS streaming decompressor
(milestone substance, also confirmed via headless decompiler)
- tools/ghidra_scripts: DumpProgramInfo.java, DecompileAt.java (helpers)
- docs/SETUP.md: confirm PsyQ 4.0.0; 41 tools + async get_code/SSE notes;
headless -loader rejected -> use auto-detect; extension-install path;
ledger #1 moot, #12 resolved
2026-06-13 15:52:37 -06:00
Drew T
de7f015436
feat(extract): ISO9660/MODE2 disc reader + SLUS_007.26 extractor
...
Reusable iso9660.py (Phase 2 foundation) + extract_exe.py with --list and --verify-disc. Adversarially verified: extracted EXE SHA1 143dbb89f34491258bbc27810d0a12ec8b43a8dd (413696 B), and --verify-disc confirms Track-1 SHA1 b44f0f0a19936f23b26188b658e13201a6a9c211 == redump (dump is canonical).
2026-06-10 23:43:31 -06:00
Drew T
d4334fc1ca
plan files created
2026-06-10 22:02:07 -06:00