feat(phase-13): T3+T4 — new_overlay.sh + dup-pair & free-roam onboarded byte-identical

- tools/new_overlay.sh: one-command overlay onboarding (template instantiate +
  @TRAILING@ carve + overlays.mk + 4-dict sentinel-insert + extract/build/check);
  idempotent (re-run = no-op, no dupe entries)
- T3: ov_SC03_001 (free-roam, 815,887 B) byte-identical f8fd92f5
- T2 (onboard): ov_SC01_005 + ov_SC01_006 (byte-identical pair) both 56760dbe
- template tokens unquoted (correct YAML int types); SETUP §2.8 MCP-reconnect note (R21)
- 6 binaries now build byte-identical (main, resident, 4 overlays)
This commit is contained in:
Drew T
2026-06-16 16:44:01 -06:00
parent ce07b72794
commit 67592993ea
20 changed files with 16572 additions and 10 deletions
+1
View File
@@ -0,0 +1 @@
56760dbec7757f12d18d7e40242a0b05280ff444 ov_SC01_005
+1
View File
@@ -0,0 +1 @@
56760dbec7757f12d18d7e40242a0b05280ff444 ov_SC01_006
+1
View File
@@ -0,0 +1 @@
f8fd92f59c6871577c61cb626cb9ddb0db5ba884 ov_SC03_001
+64 -1
View File
@@ -8,7 +8,7 @@
# recipe): EXE -> the extracted 0.4.dec, VRAM_BASE/TEXT_LO = the shared slot 0x80128158,
# nested asm/<ov> + src/<ov> + build/<ov>, per-binary undefined_*_auto + GHIDRA_PROG.
# =============================================================================
OVERLAY_BINARIES := ov_SC01_077
OVERLAY_BINARIES := ov_SC01_077 ov_SC01_005 ov_SC01_006 ov_SC03_001
# --- ov_SC01_077 (location overlay SC01/FILE_077, vram 0x80128158 — Phase 13 T1) ---
# The milestone overlay (load byte-proven, Phase 3 T6b). 731,607 B (0xB29D7) -> end vram
@@ -32,3 +32,66 @@ ov_SC01_077_ASM_DIR := asm/ov_SC01_077
ov_SC01_077_SRC_DIR := src/ov_SC01_077
ov_SC01_077_UNDEF_SYMS := build/ov_SC01_077/undefined_syms_auto.txt
ov_SC01_077_UNDEF_FUNCS := build/ov_SC01_077/undefined_funcs_auto.txt
# --- ov_SC01_005 (location overlay SC01/FILE_005, vram 0x80128158 — onboarded by new_overlay.sh) ---
ov_SC01_005_EXE := extracted/retail/SC01.CD.dir/FILE_005.dir/0.4.dec
ov_SC01_005_NAME := ov_SC01_005
ov_SC01_005_OUT_DIR := build/ov_SC01_005
ov_SC01_005_OUT := $(ov_SC01_005_OUT_DIR)/$(ov_SC01_005_NAME)
ov_SC01_005_ELF := $(ov_SC01_005_OUT).elf
ov_SC01_005_MAPFILE := $(ov_SC01_005_OUT).map
ov_SC01_005_LD_SCRIPT := $(ov_SC01_005_OUT).ld
ov_SC01_005_SPLAT_YAML := config/splat.ov_SC01_005.yaml
ov_SC01_005_CHECK_SHA := config/check.ov_SC01_005.sha
ov_SC01_005_SYMBOLS := config/symbols.ov_SC01_005.txt
ov_SC01_005_SIG := .run/sig.ov_SC01_005.jsonl
ov_SC01_005_GHIDRA_PROG := ov_SC01_005
ov_SC01_005_VRAM_BASE := 0x80128158
ov_SC01_005_TEXT_LO := 0x80128158
ov_SC01_005_TEXT_HI := 0x801CE061
ov_SC01_005_ASM_DIR := asm/ov_SC01_005
ov_SC01_005_SRC_DIR := src/ov_SC01_005
ov_SC01_005_UNDEF_SYMS := build/ov_SC01_005/undefined_syms_auto.txt
ov_SC01_005_UNDEF_FUNCS := build/ov_SC01_005/undefined_funcs_auto.txt
# --- ov_SC01_006 (location overlay SC01/FILE_006, vram 0x80128158 — onboarded by new_overlay.sh) ---
ov_SC01_006_EXE := extracted/retail/SC01.CD.dir/FILE_006.dir/0.4.dec
ov_SC01_006_NAME := ov_SC01_006
ov_SC01_006_OUT_DIR := build/ov_SC01_006
ov_SC01_006_OUT := $(ov_SC01_006_OUT_DIR)/$(ov_SC01_006_NAME)
ov_SC01_006_ELF := $(ov_SC01_006_OUT).elf
ov_SC01_006_MAPFILE := $(ov_SC01_006_OUT).map
ov_SC01_006_LD_SCRIPT := $(ov_SC01_006_OUT).ld
ov_SC01_006_SPLAT_YAML := config/splat.ov_SC01_006.yaml
ov_SC01_006_CHECK_SHA := config/check.ov_SC01_006.sha
ov_SC01_006_SYMBOLS := config/symbols.ov_SC01_006.txt
ov_SC01_006_SIG := .run/sig.ov_SC01_006.jsonl
ov_SC01_006_GHIDRA_PROG := ov_SC01_006
ov_SC01_006_VRAM_BASE := 0x80128158
ov_SC01_006_TEXT_LO := 0x80128158
ov_SC01_006_TEXT_HI := 0x801CE061
ov_SC01_006_ASM_DIR := asm/ov_SC01_006
ov_SC01_006_SRC_DIR := src/ov_SC01_006
ov_SC01_006_UNDEF_SYMS := build/ov_SC01_006/undefined_syms_auto.txt
ov_SC01_006_UNDEF_FUNCS := build/ov_SC01_006/undefined_funcs_auto.txt
# --- ov_SC03_001 (location overlay SC03/FILE_001, vram 0x80128158 — onboarded by new_overlay.sh) ---
ov_SC03_001_EXE := extracted/retail/SC03.CD.dir/FILE_001.dir/0.4.dec
ov_SC03_001_NAME := ov_SC03_001
ov_SC03_001_OUT_DIR := build/ov_SC03_001
ov_SC03_001_OUT := $(ov_SC03_001_OUT_DIR)/$(ov_SC03_001_NAME)
ov_SC03_001_ELF := $(ov_SC03_001_OUT).elf
ov_SC03_001_MAPFILE := $(ov_SC03_001_OUT).map
ov_SC03_001_LD_SCRIPT := $(ov_SC03_001_OUT).ld
ov_SC03_001_SPLAT_YAML := config/splat.ov_SC03_001.yaml
ov_SC03_001_CHECK_SHA := config/check.ov_SC03_001.sha
ov_SC03_001_SYMBOLS := config/symbols.ov_SC03_001.txt
ov_SC03_001_SIG := .run/sig.ov_SC03_001.jsonl
ov_SC03_001_GHIDRA_PROG := ov_SC03_001
ov_SC03_001_VRAM_BASE := 0x80128158
ov_SC03_001_TEXT_LO := 0x80128158
ov_SC03_001_TEXT_HI := 0x801EF467
ov_SC03_001_ASM_DIR := asm/ov_SC03_001
ov_SC03_001_SRC_DIR := src/ov_SC03_001
ov_SC03_001_UNDEF_SYMS := build/ov_SC03_001/undefined_syms_auto.txt
ov_SC03_001_UNDEF_FUNCS := build/ov_SC03_001/undefined_funcs_auto.txt
+103
View File
@@ -0,0 +1,103 @@
# splat config TEMPLATE — Brave Fencer Musashi location overlays (SCxx.CD/FILE_nnn/0.4.dec)
# =============================================================================
# Phase 13: the reusable flat-blob splat config for a LOCATION OVERLAY. ~134 overlays
# all stream into the SAME RAM slot (vram 0x80128158) and chain into the resident engine
# (0x800CEDF8) + the EXE. This is a TEMPLATE: the @TOKEN@ placeholders are substituted to
# produce config/splat.<alias>.yaml — by tools/new_overlay.sh (Phase 13 T4), or by hand
# (Phase 13 T1a for the first overlay). It is NOT a valid splat config until instantiated.
#
# Placeholders:
# ov_SC01_005 binary alias, ov_<SCxx>_<nnn> e.g. ov_SC01_077
# extracted/retail/SC01.CD.dir/FILE_005.dir/0.4.dec extracted 0.4.dec payload path e.g. extracted/retail/SC01.CD.dir/FILE_077.dir/0.4.dec
# 56760dbec7757f12d18d7e40242a0b05280ff444 sha1 of the 0.4.dec (the build-identity target; also -> config/check.<alias>.sha)
# 0x80128158 load vram (the shared overlay slot) e.g. 0x80128158 (constant across overlays today;
# parameterized so a future non-0x80128158 overlay needs no template edit)
# 0x5A20C file offset where code ends -> data tail begins (iterated vs the byte check, T1b)
# 0xA5F09 file size in bytes (the EOF marker; = the 0.4.dec length)
#
# Modeled on config/splat.resident.yaml (the Phase-10 flat-blob recipe), with overlays'
# differences: (1) code at file offset 0x0 (overlays open with a function prologue, NOT a
# leading data word like the resident — so NO leading-rodata trick by default; see the
# commented `head` slot for the rare pre-code-data overlay); (2) symbol_addrs_path ALSO
# stacks config/symbols.resident.txt because overlays reference resident engine globals;
# (3) vram is the overlay slot. Everything else matches the resident options verbatim.
#
# Byte-match is robust to the exact text/data split (splat round-trips the bytes — the
# resident precedent); iterate 0x5A20C against `make check BINARY=ov_SC01_005` (Phase-5/10
# precedent). LZSS is NOT in the verify path — we match the DECOMPRESSED 0.4.dec (repack is Gen3).
name: ov_SC01_005
sha1: 56760dbec7757f12d18d7e40242a0b05280ff444
options:
basename: ov_SC01_005
target_path: extracted/retail/SC01.CD.dir/FILE_005.dir/0.4.dec
elf_path: build/ov_SC01_005/ov_SC01_005.elf
# base_path is resolved relative to THIS yaml's dir (config/), so `..` = repo root
base_path: ..
platform: psx
compiler: PSYQ
asm_path: asm/ov_SC01_005
src_path: src/ov_SC01_005
# asset_path scoped per-alias so a `bin` subseg (the trailing-partial-word carve, below) lands at
# assets/ov_SC01_005/*.bin and never collides with another overlay's same-named asset. The Makefile's
# build/assets/%.o rule incbin's it into a linkable object.
asset_path: assets/ov_SC01_005
# build_path = build (NOT build/<alias>): splat writes the .ld's object paths under
# $(build_path), and the Makefile's pattern rules build them at build/asm/** + build/src/**.
# Only the elf/ld/output live in build/<alias>/.
build_path: build
ld_script_path: build/ov_SC01_005/ov_SC01_005.ld
ld_dependencies: True
# Per-binary undefined-symbol outputs (under build/<alias>/), so `make clean`'s `rm -rf build`
# covers them and binaries never share a stale file.
undefined_syms_auto_path: build/ov_SC01_005/undefined_syms_auto.txt
undefined_funcs_auto_path: build/ov_SC01_005/undefined_funcs_auto.txt
find_file_boundaries: False
# NO gp_value: overlays are -G0 (verify zero ($gp)/%gp_rel in the disasm). Omitting it -> no _gp.
o_as_suffix: True
use_legacy_include_asm: False
section_order: [".rodata", ".text", ".data", ".bss"]
# Stacked symbols: shared engine globals (symbols.us.txt) + resident engine globals the overlay
# calls (symbols.resident.txt) + the overlay-local names/boundaries (symbols.<alias>.txt, seeded
# T1c from sig_image + duplicates.cross.md; R13/R15-tagged, overlay-region only).
symbol_addrs_path:
- config/symbols.us.txt
- config/symbols.resident.txt
- config/symbols.ov_SC01_005.txt
subalign: 2
string_encoding: ASCII
data_string_encoding: ASCII
rodata_string_guesser_level: 2
data_string_guesser_level: 2
# Enable if maspsx reorders INCLUDE_ASM output in c-mode (unused for the EXE/resident):
# include_asm_macro_style: maspsx_hack
segments:
- name: ov_SC01_005
type: code
start: 0x0
vram: 0x80128158
# align 4 (not the code default 16): MIPS is word-aligned; mirrors the EXE/resident choice.
align: 4
subsegments:
# OPTIONAL leading pre-code data/rodata island (rare): if an overlay begins with a data
# word BEFORE its first function (the resident's case), uncomment a `head` subseg here and
# shift the code start. Mark it `rodata` (section_order places .rodata first) so it lands at
# 0x80128158 ahead of the code, a 1-word analogue of main's rodata-island (no ld_interleave).
# - [0x0, rodata, head]
- [0x0, c, ov_SC01_005] # code: starts at file 0x0 (overlays open with a prologue)
- [0x5A20C, data, tail] # data tail: pointer tables + packed data (split iterated)
- [0xA5F08, bin, trailing] # final 1 bytes (EOF not 4-aligned; spimdisasm drops a partial word)
- [0xA5F09] # EOF marker = the 0.4.dec byte length
# @TRAILING@ (above) is replaced by tools/new_overlay.sh: for a non-4-aligned overlay it becomes
# ` - [0x<word_floor>, bin, trailing]` (the final 1-3 bytes spimdisasm's data path drops);
# for a 4-aligned overlay the marker line is removed. The Makefile build/assets/%.o rule + the
# objcopy end-align TRIM finish the job. Hand-instantiated configs (ov_SC01_077) inline the carve.
+103
View File
@@ -0,0 +1,103 @@
# splat config TEMPLATE — Brave Fencer Musashi location overlays (SCxx.CD/FILE_nnn/0.4.dec)
# =============================================================================
# Phase 13: the reusable flat-blob splat config for a LOCATION OVERLAY. ~134 overlays
# all stream into the SAME RAM slot (vram 0x80128158) and chain into the resident engine
# (0x800CEDF8) + the EXE. This is a TEMPLATE: the @TOKEN@ placeholders are substituted to
# produce config/splat.<alias>.yaml — by tools/new_overlay.sh (Phase 13 T4), or by hand
# (Phase 13 T1a for the first overlay). It is NOT a valid splat config until instantiated.
#
# Placeholders:
# ov_SC01_006 binary alias, ov_<SCxx>_<nnn> e.g. ov_SC01_077
# extracted/retail/SC01.CD.dir/FILE_006.dir/0.4.dec extracted 0.4.dec payload path e.g. extracted/retail/SC01.CD.dir/FILE_077.dir/0.4.dec
# 56760dbec7757f12d18d7e40242a0b05280ff444 sha1 of the 0.4.dec (the build-identity target; also -> config/check.<alias>.sha)
# 0x80128158 load vram (the shared overlay slot) e.g. 0x80128158 (constant across overlays today;
# parameterized so a future non-0x80128158 overlay needs no template edit)
# 0x5A20C file offset where code ends -> data tail begins (iterated vs the byte check, T1b)
# 0xA5F09 file size in bytes (the EOF marker; = the 0.4.dec length)
#
# Modeled on config/splat.resident.yaml (the Phase-10 flat-blob recipe), with overlays'
# differences: (1) code at file offset 0x0 (overlays open with a function prologue, NOT a
# leading data word like the resident — so NO leading-rodata trick by default; see the
# commented `head` slot for the rare pre-code-data overlay); (2) symbol_addrs_path ALSO
# stacks config/symbols.resident.txt because overlays reference resident engine globals;
# (3) vram is the overlay slot. Everything else matches the resident options verbatim.
#
# Byte-match is robust to the exact text/data split (splat round-trips the bytes — the
# resident precedent); iterate 0x5A20C against `make check BINARY=ov_SC01_006` (Phase-5/10
# precedent). LZSS is NOT in the verify path — we match the DECOMPRESSED 0.4.dec (repack is Gen3).
name: ov_SC01_006
sha1: 56760dbec7757f12d18d7e40242a0b05280ff444
options:
basename: ov_SC01_006
target_path: extracted/retail/SC01.CD.dir/FILE_006.dir/0.4.dec
elf_path: build/ov_SC01_006/ov_SC01_006.elf
# base_path is resolved relative to THIS yaml's dir (config/), so `..` = repo root
base_path: ..
platform: psx
compiler: PSYQ
asm_path: asm/ov_SC01_006
src_path: src/ov_SC01_006
# asset_path scoped per-alias so a `bin` subseg (the trailing-partial-word carve, below) lands at
# assets/ov_SC01_006/*.bin and never collides with another overlay's same-named asset. The Makefile's
# build/assets/%.o rule incbin's it into a linkable object.
asset_path: assets/ov_SC01_006
# build_path = build (NOT build/<alias>): splat writes the .ld's object paths under
# $(build_path), and the Makefile's pattern rules build them at build/asm/** + build/src/**.
# Only the elf/ld/output live in build/<alias>/.
build_path: build
ld_script_path: build/ov_SC01_006/ov_SC01_006.ld
ld_dependencies: True
# Per-binary undefined-symbol outputs (under build/<alias>/), so `make clean`'s `rm -rf build`
# covers them and binaries never share a stale file.
undefined_syms_auto_path: build/ov_SC01_006/undefined_syms_auto.txt
undefined_funcs_auto_path: build/ov_SC01_006/undefined_funcs_auto.txt
find_file_boundaries: False
# NO gp_value: overlays are -G0 (verify zero ($gp)/%gp_rel in the disasm). Omitting it -> no _gp.
o_as_suffix: True
use_legacy_include_asm: False
section_order: [".rodata", ".text", ".data", ".bss"]
# Stacked symbols: shared engine globals (symbols.us.txt) + resident engine globals the overlay
# calls (symbols.resident.txt) + the overlay-local names/boundaries (symbols.<alias>.txt, seeded
# T1c from sig_image + duplicates.cross.md; R13/R15-tagged, overlay-region only).
symbol_addrs_path:
- config/symbols.us.txt
- config/symbols.resident.txt
- config/symbols.ov_SC01_006.txt
subalign: 2
string_encoding: ASCII
data_string_encoding: ASCII
rodata_string_guesser_level: 2
data_string_guesser_level: 2
# Enable if maspsx reorders INCLUDE_ASM output in c-mode (unused for the EXE/resident):
# include_asm_macro_style: maspsx_hack
segments:
- name: ov_SC01_006
type: code
start: 0x0
vram: 0x80128158
# align 4 (not the code default 16): MIPS is word-aligned; mirrors the EXE/resident choice.
align: 4
subsegments:
# OPTIONAL leading pre-code data/rodata island (rare): if an overlay begins with a data
# word BEFORE its first function (the resident's case), uncomment a `head` subseg here and
# shift the code start. Mark it `rodata` (section_order places .rodata first) so it lands at
# 0x80128158 ahead of the code, a 1-word analogue of main's rodata-island (no ld_interleave).
# - [0x0, rodata, head]
- [0x0, c, ov_SC01_006] # code: starts at file 0x0 (overlays open with a prologue)
- [0x5A20C, data, tail] # data tail: pointer tables + packed data (split iterated)
- [0xA5F08, bin, trailing] # final 1 bytes (EOF not 4-aligned; spimdisasm drops a partial word)
- [0xA5F09] # EOF marker = the 0.4.dec byte length
# @TRAILING@ (above) is replaced by tools/new_overlay.sh: for a non-4-aligned overlay it becomes
# ` - [0x<word_floor>, bin, trailing]` (the final 1-3 bytes spimdisasm's data path drops);
# for a 4-aligned overlay the marker line is removed. The Makefile build/assets/%.o rule + the
# objcopy end-align TRIM finish the job. Hand-instantiated configs (ov_SC01_077) inline the carve.
+103
View File
@@ -0,0 +1,103 @@
# splat config TEMPLATE — Brave Fencer Musashi location overlays (SCxx.CD/FILE_nnn/0.4.dec)
# =============================================================================
# Phase 13: the reusable flat-blob splat config for a LOCATION OVERLAY. ~134 overlays
# all stream into the SAME RAM slot (vram 0x80128158) and chain into the resident engine
# (0x800CEDF8) + the EXE. This is a TEMPLATE: the @TOKEN@ placeholders are substituted to
# produce config/splat.<alias>.yaml — by tools/new_overlay.sh (Phase 13 T4), or by hand
# (Phase 13 T1a for the first overlay). It is NOT a valid splat config until instantiated.
#
# Placeholders:
# ov_SC03_001 binary alias, ov_<SCxx>_<nnn> e.g. ov_SC01_077
# extracted/retail/SC03.CD.dir/FILE_001.dir/0.4.dec extracted 0.4.dec payload path e.g. extracted/retail/SC01.CD.dir/FILE_077.dir/0.4.dec
# f8fd92f59c6871577c61cb626cb9ddb0db5ba884 sha1 of the 0.4.dec (the build-identity target; also -> config/check.<alias>.sha)
# 0x80128158 load vram (the shared overlay slot) e.g. 0x80128158 (constant across overlays today;
# parameterized so a future non-0x80128158 overlay needs no template edit)
# 0x650C8 file offset where code ends -> data tail begins (iterated vs the byte check, T1b)
# 0xC730F file size in bytes (the EOF marker; = the 0.4.dec length)
#
# Modeled on config/splat.resident.yaml (the Phase-10 flat-blob recipe), with overlays'
# differences: (1) code at file offset 0x0 (overlays open with a function prologue, NOT a
# leading data word like the resident — so NO leading-rodata trick by default; see the
# commented `head` slot for the rare pre-code-data overlay); (2) symbol_addrs_path ALSO
# stacks config/symbols.resident.txt because overlays reference resident engine globals;
# (3) vram is the overlay slot. Everything else matches the resident options verbatim.
#
# Byte-match is robust to the exact text/data split (splat round-trips the bytes — the
# resident precedent); iterate 0x650C8 against `make check BINARY=ov_SC03_001` (Phase-5/10
# precedent). LZSS is NOT in the verify path — we match the DECOMPRESSED 0.4.dec (repack is Gen3).
name: ov_SC03_001
sha1: f8fd92f59c6871577c61cb626cb9ddb0db5ba884
options:
basename: ov_SC03_001
target_path: extracted/retail/SC03.CD.dir/FILE_001.dir/0.4.dec
elf_path: build/ov_SC03_001/ov_SC03_001.elf
# base_path is resolved relative to THIS yaml's dir (config/), so `..` = repo root
base_path: ..
platform: psx
compiler: PSYQ
asm_path: asm/ov_SC03_001
src_path: src/ov_SC03_001
# asset_path scoped per-alias so a `bin` subseg (the trailing-partial-word carve, below) lands at
# assets/ov_SC03_001/*.bin and never collides with another overlay's same-named asset. The Makefile's
# build/assets/%.o rule incbin's it into a linkable object.
asset_path: assets/ov_SC03_001
# build_path = build (NOT build/<alias>): splat writes the .ld's object paths under
# $(build_path), and the Makefile's pattern rules build them at build/asm/** + build/src/**.
# Only the elf/ld/output live in build/<alias>/.
build_path: build
ld_script_path: build/ov_SC03_001/ov_SC03_001.ld
ld_dependencies: True
# Per-binary undefined-symbol outputs (under build/<alias>/), so `make clean`'s `rm -rf build`
# covers them and binaries never share a stale file.
undefined_syms_auto_path: build/ov_SC03_001/undefined_syms_auto.txt
undefined_funcs_auto_path: build/ov_SC03_001/undefined_funcs_auto.txt
find_file_boundaries: False
# NO gp_value: overlays are -G0 (verify zero ($gp)/%gp_rel in the disasm). Omitting it -> no _gp.
o_as_suffix: True
use_legacy_include_asm: False
section_order: [".rodata", ".text", ".data", ".bss"]
# Stacked symbols: shared engine globals (symbols.us.txt) + resident engine globals the overlay
# calls (symbols.resident.txt) + the overlay-local names/boundaries (symbols.<alias>.txt, seeded
# T1c from sig_image + duplicates.cross.md; R13/R15-tagged, overlay-region only).
symbol_addrs_path:
- config/symbols.us.txt
- config/symbols.resident.txt
- config/symbols.ov_SC03_001.txt
subalign: 2
string_encoding: ASCII
data_string_encoding: ASCII
rodata_string_guesser_level: 2
data_string_guesser_level: 2
# Enable if maspsx reorders INCLUDE_ASM output in c-mode (unused for the EXE/resident):
# include_asm_macro_style: maspsx_hack
segments:
- name: ov_SC03_001
type: code
start: 0x0
vram: 0x80128158
# align 4 (not the code default 16): MIPS is word-aligned; mirrors the EXE/resident choice.
align: 4
subsegments:
# OPTIONAL leading pre-code data/rodata island (rare): if an overlay begins with a data
# word BEFORE its first function (the resident's case), uncomment a `head` subseg here and
# shift the code start. Mark it `rodata` (section_order places .rodata first) so it lands at
# 0x80128158 ahead of the code, a 1-word analogue of main's rodata-island (no ld_interleave).
# - [0x0, rodata, head]
- [0x0, c, ov_SC03_001] # code: starts at file 0x0 (overlays open with a prologue)
- [0x650C8, data, tail] # data tail: pointer tables + packed data (split iterated)
- [0xC730C, bin, trailing] # final 3 bytes (EOF not 4-aligned; spimdisasm drops a partial word)
- [0xC730F] # EOF marker = the 0.4.dec byte length
# @TRAILING@ (above) is replaced by tools/new_overlay.sh: for a non-4-aligned overlay it becomes
# ` - [0x<word_floor>, bin, trailing]` (the final 1-3 bytes spimdisasm's data path drops);
# for a 4-aligned overlay the marker line is removed. The Makefile build/assets/%.o rule + the
# objcopy end-align TRIM finish the job. Hand-instantiated configs (ov_SC01_077) inline the carve.
+14 -9
View File
@@ -25,11 +25,11 @@
# Byte-match is robust to the exact text/data split (splat round-trips the bytes — the
# resident precedent); iterate @CODE_END@ against `make check BINARY=@ALIAS@` (Phase-5/10
# precedent). LZSS is NOT in the verify path — we match the DECOMPRESSED 0.4.dec (repack is Gen3).
name: "@ALIAS@"
sha1: "@SHA1@"
name: @ALIAS@
sha1: @SHA1@
options:
basename: "@ALIAS@"
target_path: "@DEC_PATH@"
basename: @ALIAS@
target_path: @DEC_PATH@
elf_path: build/@ALIAS@/@ALIAS@.elf
# base_path is resolved relative to THIS yaml's dir (config/), so `..` = repo root
base_path: ..
@@ -81,10 +81,10 @@ options:
# include_asm_macro_style: maspsx_hack
segments:
- name: "@ALIAS@"
- name: @ALIAS@
type: code
start: 0x0
vram: "@VRAM@"
vram: @VRAM@
# align 4 (not the code default 16): MIPS is word-aligned; mirrors the EXE/resident choice.
align: 4
subsegments:
@@ -93,6 +93,11 @@ segments:
# shift the code start. Mark it `rodata` (section_order places .rodata first) so it lands at
# @VRAM@ ahead of the code, a 1-word analogue of main's rodata-island (no ld_interleave).
# - [0x0, rodata, head]
- [0x0, c, "@ALIAS@"] # code: starts at file 0x0 (overlays open with a prologue)
- ["@CODE_END@", data, tail] # data tail: pointer tables + packed data to EOF (split iterated, T1b)
- ["@EOF@"] # EOF marker = the 0.4.dec byte length
- [0x0, c, @ALIAS@] # code: starts at file 0x0 (overlays open with a prologue)
- [@CODE_END@, data, tail] # data tail: pointer tables + packed data (split iterated)
@TRAILING@
- [@EOF@] # EOF marker = the 0.4.dec byte length
# @TRAILING@ (above) is replaced by tools/new_overlay.sh: for a non-4-aligned overlay it becomes
# ` - [0x<word_floor>, bin, trailing]` (the final 1-3 bytes spimdisasm's data path drops);
# for a 4-aligned overlay the marker line is removed. The Makefile build/assets/%.o rule + the
# objcopy end-align TRIM finish the job. Hand-instantiated configs (ov_SC01_077) inline the carve.
+3
View File
@@ -0,0 +1,3 @@
// config/symbols.ov_SC01_005.txt — overlay SC01/FILE_005 local symbols (Phase 13+)
// R13/R15: overlay-REGION ONLY (vram 0x80128158..0x801CE061); NEVER merged into config/symbols.us.txt.
// count=0
+3
View File
@@ -0,0 +1,3 @@
// config/symbols.ov_SC01_006.txt — overlay SC01/FILE_006 local symbols (Phase 13+)
// R13/R15: overlay-REGION ONLY (vram 0x80128158..0x801CE061); NEVER merged into config/symbols.us.txt.
// count=0
+3
View File
@@ -0,0 +1,3 @@
// config/symbols.ov_SC03_001.txt — overlay SC03/FILE_001 local symbols (Phase 13+)
// R13/R15: overlay-REGION ONLY (vram 0x80128158..0x801EF467); NEVER merged into config/symbols.us.txt.
// count=0
+9
View File
@@ -23,6 +23,15 @@ BINARIES = {
"ov_SC01_077": dict(baseimg="expected/build/ov_SC01_077/ov_SC01_077.elf",
myimg="build/ov_SC01_077/ov_SC01_077.elf",
mapfile="build/ov_SC01_077/ov_SC01_077.map"),
"ov_SC01_005": dict(baseimg="expected/build/ov_SC01_005/ov_SC01_005.elf",
myimg="build/ov_SC01_005/ov_SC01_005.elf",
mapfile="build/ov_SC01_005/ov_SC01_005.map"),
"ov_SC01_006": dict(baseimg="expected/build/ov_SC01_006/ov_SC01_006.elf",
myimg="build/ov_SC01_006/ov_SC01_006.elf",
mapfile="build/ov_SC01_006/ov_SC01_006.map"),
"ov_SC03_001": dict(baseimg="expected/build/ov_SC03_001/ov_SC03_001.elf",
myimg="build/ov_SC03_001/ov_SC03_001.elf",
mapfile="build/ov_SC03_001/ov_SC03_001.map"),
# <<< overlays: tools/new_overlay.sh inserts ov_* entries above this line (Phase 13) >>>
}
+2
View File
@@ -181,6 +181,8 @@ Lifecycle scripts (under `tools/`):
- **`ghidra_mcp_stop.sh`** — the **only persistence event**: it requests a clean save+close by dropping the `.run/mcp-stop.req` sentinel, waits for the server to report **"Save succeeded"**, then releases the project `.rep` lock. **Never `SIGKILL` the server to stop it** — that skips the save and loses the work. Clean stop is the save.
- **`ghidra_mcp_verify.sh <addr> <name>`** — read-only persistence re-check (rule R9): after a clean stop, re-reads the named symbol at the address to confirm the write actually landed on disk.
**Client reconnect after a server restart (operational, Phase 13).** Restarting the server (`stop` then `start` — e.g. for a headless raw-blob import per R23, or to serve a different program) **drops the Claude Code MCP client's SSE connection**: every `mcp__ghidra__*` call then **times out** until the client reconnects, and Claude **cannot** run `/mcp` itself. So the rhythm after any server restart / program switch is: **pause and ask Drew to run `/mcp`**, then make one cheap `get_binary_info` call (G2) before continuing. Do not try the calls, hit timeouts, and work around them. (Memory: `mcp-reconnect-after-restart`.)
**Session hooks (committed `.claude/settings.json`, as of 2026-06-15):**
- `SessionStart` → runs `ghidra_mcp_start.sh` (auto-starts the MCP server when a Claude Code session begins).
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+6
View File
@@ -20,6 +20,12 @@ BINARIES = {
md="docs/difficulty.resident.md", csv=".run/difficulty.resident.csv"),
"ov_SC01_077": dict(src="src/ov_SC01_077", asm="asm/ov_SC01_077/nonmatchings",
md="docs/difficulty.ov_SC01_077.md", csv=".run/difficulty.ov_SC01_077.csv"),
"ov_SC01_005": dict(src="src/ov_SC01_005", asm="asm/ov_SC01_005/nonmatchings",
md="docs/difficulty.ov_SC01_005.md", csv=".run/difficulty.ov_SC01_005.csv"),
"ov_SC01_006": dict(src="src/ov_SC01_006", asm="asm/ov_SC01_006/nonmatchings",
md="docs/difficulty.ov_SC01_006.md", csv=".run/difficulty.ov_SC01_006.csv"),
"ov_SC03_001": dict(src="src/ov_SC03_001", asm="asm/ov_SC03_001/nonmatchings",
md="docs/difficulty.ov_SC03_001.md", csv=".run/difficulty.ov_SC03_001.csv"),
# <<< overlays: tools/new_overlay.sh inserts ov_* entries above this line (Phase 13) >>>
}
SRCS = ASM_ROOT = MD = CSV = None # set by main() from --binary
+3
View File
@@ -27,6 +27,9 @@ BINARIES = {
"main": dict(sig=".run/sig.SLUS_007.26.jsonl", md="docs/duplicates.md"),
"resident": dict(sig=".run/sig.resident.jsonl", md="docs/duplicates.resident.md"),
"ov_SC01_077": dict(sig=".run/sig.ov_SC01_077.jsonl", md="docs/duplicates.ov_SC01_077.md"),
"ov_SC01_005": dict(sig=".run/sig.ov_SC01_005.jsonl", md="docs/duplicates.ov_SC01_005.md"),
"ov_SC01_006": dict(sig=".run/sig.ov_SC01_006.jsonl", md="docs/duplicates.ov_SC01_006.md"),
"ov_SC03_001": dict(sig=".run/sig.ov_SC03_001.jsonl", md="docs/duplicates.ov_SC03_001.md"),
# <<< overlays: tools/new_overlay.sh inserts ov_* entries above this line (Phase 13) >>>
}
CROSS_MD = "docs/duplicates.cross.md"
+131
View File
@@ -0,0 +1,131 @@
#!/usr/bin/env bash
# tools/new_overlay.sh <SCxx> <FILE_nnn> — onboard a BFM location overlay as a build binary (Phase 13).
# =============================================================================
# One command: instantiate the splat config from config/splat.us.overlay.template.yaml,
# compute the build-identity hash + code/data boundary, register the binary in the
# generated config/overlays.mk (the Makefile -include's it — the hand-maintained Makefile
# body is NEVER touched) and in the 4 report/diff tools' BINARIES dicts (sentinel-anchored,
# idempotent, syntax-checked), then `make extract && make build` to byte-verify the overlay
# against its on-disk 0.4.dec payload. Re-running is a clean no-op (idempotent).
#
# All overlays load to the shared slot vram 0x80128158 (position-locked, Phase 3). The
# trailing-partial-word carve (for the ~75% of overlays whose decompressed size isn't
# 4-aligned) + the objcopy end-align trim are handled automatically.
#
# tools/new_overlay.sh SC01 005 # -> ov_SC01_005, byte-matched at 100% INCLUDE_ASM
# =============================================================================
set -euo pipefail
cd "$(dirname "$0")/.." # repo root
[ $# -eq 2 ] || { echo "usage: tools/new_overlay.sh <SCxx> <FILE_nnn> e.g. tools/new_overlay.sh SC01 005"; exit 2; }
SC="$1"; FILE="$2"
ALIAS="ov_${SC}_${FILE}"
DEC="extracted/retail/${SC}.CD.dir/FILE_${FILE}.dir/0.4.dec"
VRAM="0x80128158"
PYV=".venv/bin/python"
[ -f "$DEC" ] || { echo "ERROR: payload not found: $DEC (run extraction first)"; exit 1; }
SHA1="$(sha1sum "$DEC" | cut -d' ' -f1)"
EOFSZ="$(stat -c%s "$DEC")"
EOFHEX="$(printf '0x%X' "$EOFSZ")"
TEXTHI="$(printf '0x%X' $((0x80128158 + EOFSZ)))"
# code_end = end of the last sig_image function as a file offset (vram - base). Sign if absent.
SIG=".run/sig.${ALIAS}.jsonl"
[ -f "$SIG" ] || $PYV tools/sig_image.py --image "$DEC" --vram-base "$VRAM" --bootstrap --name "$ALIAS" >/dev/null
CODEEND="$(tail -1 "$SIG" | $PYV -c "import sys,json; r=json.loads(sys.stdin.readline()); a=int(r['addr'],16); print('0x%X' % (a + r['nins']*4 - 0x80128158))")"
echo "Onboarding $ALIAS ($DEC)"
echo " sha1=$SHA1 size=$EOFHEX code_end=$CODEEND text_hi=$TEXTHI"
# 1) splat config from the template (sed the @TOKENS@), then resolve @TRAILING@ (the non-4-aligned carve)
YAML="config/splat.${ALIAS}.yaml"
sed -e "s|@ALIAS@|$ALIAS|g" -e "s|@DEC_PATH@|$DEC|g" -e "s|@SHA1@|$SHA1|g" \
-e "s|@VRAM@|$VRAM|g" -e "s|@CODE_END@|$CODEEND|g" -e "s|@EOF@|$EOFHEX|g" \
config/splat.us.overlay.template.yaml > "$YAML"
if [ $((EOFSZ % 4)) -ne 0 ]; then
FLOOR="$(printf '0x%X' $(( (EOFSZ/4)*4 )))"; NB=$((EOFSZ - (EOFSZ/4)*4))
sed -i "s|^@TRAILING@\$| - [$FLOOR, bin, trailing] # final $NB bytes (EOF not 4-aligned; spimdisasm drops a partial word)|" "$YAML"
else
sed -i "/^@TRAILING@\$/d" "$YAML"
fi
echo " wrote $YAML"
# 2) build-identity hash
echo "$SHA1 $ALIAS" > "config/check.${ALIAS}.sha"
# 3) overlay-local symbols (don't clobber an existing curated file)
if [ ! -f "config/symbols.${ALIAS}.txt" ]; then
cat > "config/symbols.${ALIAS}.txt" <<EOF
// config/symbols.${ALIAS}.txt — overlay ${SC}/FILE_${FILE} local symbols (Phase 13+)
// R13/R15: overlay-REGION ONLY (vram ${VRAM}..${TEXTHI}); NEVER merged into config/symbols.us.txt.
// count=0
EOF
fi
# 4) register in config/overlays.mk (generated registry, -include'd by the Makefile). Idempotent.
MK="config/overlays.mk"
if ! grep -q "^${ALIAS}_EXE " "$MK"; then
grep -qE "^OVERLAY_BINARIES :=.* ${ALIAS}( |\$)" "$MK" || sed -i "s|^OVERLAY_BINARIES :=.*|& ${ALIAS}|" "$MK"
cat >> "$MK" <<EOF
# --- ${ALIAS} (location overlay ${SC}/FILE_${FILE}, vram ${VRAM} — onboarded by new_overlay.sh) ---
${ALIAS}_EXE := ${DEC}
${ALIAS}_NAME := ${ALIAS}
${ALIAS}_OUT_DIR := build/${ALIAS}
${ALIAS}_OUT := \$(${ALIAS}_OUT_DIR)/\$(${ALIAS}_NAME)
${ALIAS}_ELF := \$(${ALIAS}_OUT).elf
${ALIAS}_MAPFILE := \$(${ALIAS}_OUT).map
${ALIAS}_LD_SCRIPT := \$(${ALIAS}_OUT).ld
${ALIAS}_SPLAT_YAML := config/splat.${ALIAS}.yaml
${ALIAS}_CHECK_SHA := config/check.${ALIAS}.sha
${ALIAS}_SYMBOLS := config/symbols.${ALIAS}.txt
${ALIAS}_SIG := .run/sig.${ALIAS}.jsonl
${ALIAS}_GHIDRA_PROG := ${ALIAS}
${ALIAS}_VRAM_BASE := ${VRAM}
${ALIAS}_TEXT_LO := ${VRAM}
${ALIAS}_TEXT_HI := ${TEXTHI}
${ALIAS}_ASM_DIR := asm/${ALIAS}
${ALIAS}_SRC_DIR := src/${ALIAS}
${ALIAS}_UNDEF_SYMS := build/${ALIAS}/undefined_syms_auto.txt
${ALIAS}_UNDEF_FUNCS := build/${ALIAS}/undefined_funcs_auto.txt
EOF
echo " + config/overlays.mk"
fi
# 5) register in the 4 report/diff tools' BINARIES dicts (sentinel-anchored, idempotent, syntax-checked)
$PYV - "$ALIAS" <<'PY'
import sys, ast
alias = sys.argv[1]
SENT = "inserts ov_* entries above this line"
entries = {
"diff_settings.py": (f' "{alias}": dict(baseimg="expected/build/{alias}/{alias}.elf",\n'
f' myimg="build/{alias}/{alias}.elf",\n'
f' mapfile="build/{alias}/{alias}.map"),\n'),
"tools/progress.py": (f' "{alias}": dict(build="build/{alias}/{alias}", check="config/check.{alias}.sha",\n'
f' src="src/{alias}", asm="asm/{alias}/nonmatchings", out="docs/progress.{alias}.md"),\n'),
"tools/difficulty.py": (f' "{alias}": dict(src="src/{alias}", asm="asm/{alias}/nonmatchings",\n'
f' md="docs/difficulty.{alias}.md", csv=".run/difficulty.{alias}.csv"),\n'),
"tools/dup_report.py": (f' "{alias}": dict(sig=".run/sig.{alias}.jsonl", md="docs/duplicates.{alias}.md"),\n'),
}
for path, entry in entries.items():
txt = open(path).read()
if f'"{alias}":' in txt:
continue # idempotent
out, done = [], False
for ln in txt.splitlines(keepends=True):
if SENT in ln and not done:
out.append(entry); done = True
out.append(ln)
new = "".join(out)
ast.parse(new, path) # syntax-check before writing
open(path, "w").write(new)
print(f" + {path}")
PY
# 6) extract + build + byte-check
echo "Building $ALIAS ..."
make extract BINARY="$ALIAS" >/dev/null
make build BINARY="$ALIAS"
echo "Done. $ALIAS onboarded; run 'make check BINARY=$ALIAS' anytime, or 'make check-all' for the fleet."
+6
View File
@@ -25,6 +25,12 @@ BINARIES = {
src="src/resident", asm="asm/resident/nonmatchings", out="docs/progress.resident.md"),
"ov_SC01_077": dict(build="build/ov_SC01_077/ov_SC01_077", check="config/check.ov_SC01_077.sha",
src="src/ov_SC01_077", asm="asm/ov_SC01_077/nonmatchings", out="docs/progress.ov_SC01_077.md"),
"ov_SC01_005": dict(build="build/ov_SC01_005/ov_SC01_005", check="config/check.ov_SC01_005.sha",
src="src/ov_SC01_005", asm="asm/ov_SC01_005/nonmatchings", out="docs/progress.ov_SC01_005.md"),
"ov_SC01_006": dict(build="build/ov_SC01_006/ov_SC01_006", check="config/check.ov_SC01_006.sha",
src="src/ov_SC01_006", asm="asm/ov_SC01_006/nonmatchings", out="docs/progress.ov_SC01_006.md"),
"ov_SC03_001": dict(build="build/ov_SC03_001/ov_SC03_001", check="config/check.ov_SC03_001.sha",
src="src/ov_SC03_001", asm="asm/ov_SC03_001/nonmatchings", out="docs/progress.ov_SC03_001.md"),
# <<< overlays: tools/new_overlay.sh inserts ov_* entries above this line (Phase 13) >>>
}
BINARY = next((sys.argv[i + 1] for i, x in enumerate(sys.argv)