From a5e5ea45ef67efb94d98193ce54fd5d3d04fb23a Mon Sep 17 00:00:00 2001 From: Drew T <50529377+Druthulu@users.noreply.github.com> Date: Mon, 27 Jul 2026 11:01:59 -0600 Subject: [PATCH] =?UTF-8?q?fix(phase-29):=20jtbl=5Fcarve=20=E2=80=94=20gua?= =?UTF-8?q?rd=20the=20--like=20role-transfer;=20the=20=C3=97137=20sweep=20?= =?UTF-8?q?goes=200/3=20->=203/3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ROOT CAUSE of the 0/3 (found by reading the tool's ACTUAL invocation, not by guessing): jtbl_family_bank calls `jtbl_carve --func --like `, and the role-transfer keys on the SUBSEG ROLE (`ov_SC01_077_a` -> `_a`). Its premise — "same family => same span structure" — silently breaks when the exemplar and the sibling host the function in subsegs with DIFFERENT roles, which happens whenever the exemplar has a split the sibling does not. MEASURED: func_8012AAAC lives in `ov_SC01_077_a` (role `_a`) in the exemplar but in the MAIN subseg (role ``) in every sibling. The transfer therefore looked up `ov_SC01_077` — an unrelated SEVEN-table span belonging to entirely different functions — and stamped those starts onto a sibling span holding one table. jtbl_rodata_pads then refused with `consumed 1 rodata .align(s) but 2 pad spec(s) given — table-count drift`, and jtbl_family_bank deliberately does NOT treat that error as isolate-fixable, so all 137 siblings returned a bare `gate-fail` with the cause discarded. THE FIX: transfer only when the exemplar's subseg for THIS FUNCTION has the sibling's role; otherwise derive the span from the sibling's own carve (which was already computing it correctly). Fail-open is not acceptable here — a wrong table set corrupts the image, so the guard defaults to local derivation. MEASURED RESULT: the 3-member probe goes 0/3 -> 3/3 BANKED. R22 clean-fleet: extract-all 139/139, check-all 140 passed / 0 failed. Two earlier hypotheses were tested and are recorded honestly in CURRENT_PHASE.md: the sibling call-site casts (real conflict, fixed, byte-neutral — but NOT the blocker) and my own carve-alone test (which fails by construction for this shape, because a stub object does not emit the table its 2-entry spec describes — the tool splices the body BEFORE building, so its path is the valid one). --- config/overlays.mk | 9 ++-- config/splat.ov_SC01_000.yaml | 39 ++++++++-------- config/splat.ov_SC01_001.yaml | 39 ++++++++-------- config/splat.ov_SC01_004.yaml | 39 ++++++++-------- src/ov_SC01_000/ov_SC01_000.c | 83 ++++++++++++++++++++++++++++++++++- src/ov_SC01_001/ov_SC01_001.c | 83 ++++++++++++++++++++++++++++++++++- src/ov_SC01_004/ov_SC01_004.c | 83 ++++++++++++++++++++++++++++++++++- tools/jtbl_carve.py | 32 +++++++++++++- 8 files changed, 340 insertions(+), 67 deletions(-) diff --git a/config/overlays.mk b/config/overlays.mk index 6d71145f3..c3eec0c7c 100644 --- a/config/overlays.mk +++ b/config/overlays.mk @@ -130,7 +130,8 @@ ov_SC01_000_ELF := $(ov_SC01_000_OUT).elf ov_SC01_000_MAPFILE := $(ov_SC01_000_OUT).map ov_SC01_000_LD_SCRIPT := $(ov_SC01_000_OUT).ld ov_SC01_000_SPLAT_YAML := config/splat.ov_SC01_000.yaml -ov_SC01_000_JTBL_INTERLEAVE := --order tail.data.o,ov_SC01_000.o,tail2.data.o,ov_SC01_000_jr_8012ACE0.o,tail3.data.o,ov_SC01_000_jr_80135888.o,tail4.data.o,ov_SC01_000_jr_80135A4C.o,tail5.data.o,ov_SC01_000_jr_80135D20.o,tail6.data.o,ov_SC01_000_jr_801380E0.o,tail7.data.o,ov_SC01_000_jr_8013F350.o,tail8.data.o,ov_SC01_000_jr_8013FFD8.o,tail9.data.o,ov_SC01_000_jr_80140608.o,tail10.data.o,ov_SC01_000_jr_8015444C.o,tail11.data.o,ov_SC01_000_jr_80154C24.o,ov_SC01_000_jr_801588CC.o,tail12.data.o,ov_SC01_000_jr_80159C84.o,tail13.data.o,ov_SC01_000_jr_8015A3C8.o,tail14.data.o,ov_SC01_000_jr_8015AE2C.o,tail15.data.o,ov_SC01_000_jr_8015C32C.o,tail16.data.o,ov_SC01_000_jr_8016AB6C.o,tail17.data.o,ov_SC01_000_jr_801734BC.o,tail18.data.o,ov_SC01_000_jr_80178D40.o,tail19.data.o,ov_SC01_000_jr_8017A4AC.o,tail20.data.o,ov_SC01_000_jr_8017AE2C.o,ov_SC01_000_jr_8017BEBC.o,tail21.data.o,trailing.o # Phase-26 §8 jtbl-rodata carve +ov_SC01_000_JTBL_INTERLEAVE := --order tail.data.o,ov_SC01_000.o,ov_SC01_000_jr_8012ACE0.o,tail2.data.o,ov_SC01_000_jr_80135888.o,tail3.data.o,ov_SC01_000_jr_80135A4C.o,tail4.data.o,ov_SC01_000_jr_80135D20.o,tail5.data.o,ov_SC01_000_jr_801380E0.o,tail6.data.o,ov_SC01_000_jr_8013F350.o,tail7.data.o,ov_SC01_000_jr_8013FFD8.o,tail8.data.o,ov_SC01_000_jr_80140608.o,tail9.data.o,ov_SC01_000_jr_8015444C.o,tail10.data.o,ov_SC01_000_jr_80154C24.o,ov_SC01_000_jr_801588CC.o,tail11.data.o,ov_SC01_000_jr_80159C84.o,tail12.data.o,ov_SC01_000_jr_8015A3C8.o,tail13.data.o,ov_SC01_000_jr_8015AE2C.o,tail14.data.o,ov_SC01_000_jr_8015C32C.o,tail15.data.o,ov_SC01_000_jr_8016AB6C.o,tail16.data.o,ov_SC01_000_jr_801734BC.o,tail17.data.o,ov_SC01_000_jr_80178D40.o,tail18.data.o,ov_SC01_000_jr_8017A4AC.o,tail19.data.o,ov_SC01_000_jr_8017AE2C.o,ov_SC01_000_jr_8017BEBC.o,tail20.data.o,trailing.o # Phase-26 §8 jtbl-rodata carve +build/src/ov_SC01_000/ov_SC01_000.o: JTBL_PADS := 0,0 # §8e pads (jtbl_carve.py) tables=+0x0,+0x14 build/src/ov_SC01_000/ov_SC01_000_jr_8012ACE0.o: JTBL_PADS := 0,0 # §8e pads (jtbl_carve.py) build/src/ov_SC01_000/ov_SC01_000_jr_8013F350.o: JTBL_PADS := 0,0 # §8e pads (jtbl_carve.py) tables=+0x0,+0x20 build/src/ov_SC01_000/ov_SC01_000_jr_80154C24.o: JTBL_PADS := 0,0 # §8e pads (jtbl_carve.py) tables=+0x0,+0x24 @@ -157,7 +158,8 @@ ov_SC01_001_ELF := $(ov_SC01_001_OUT).elf ov_SC01_001_MAPFILE := $(ov_SC01_001_OUT).map ov_SC01_001_LD_SCRIPT := $(ov_SC01_001_OUT).ld ov_SC01_001_SPLAT_YAML := config/splat.ov_SC01_001.yaml -ov_SC01_001_JTBL_INTERLEAVE := --order tail.data.o,ov_SC01_001.o,tail2.data.o,ov_SC01_001_jr_8012ACE0.o,tail3.data.o,ov_SC01_001_jr_80135888.o,tail4.data.o,ov_SC01_001_jr_80135A4C.o,tail5.data.o,ov_SC01_001_jr_80135D20.o,tail6.data.o,ov_SC01_001_jr_801380E0.o,tail7.data.o,ov_SC01_001_jr_8013F350.o,tail8.data.o,ov_SC01_001_jr_8013FFD8.o,tail9.data.o,ov_SC01_001_jr_80140608.o,tail10.data.o,ov_SC01_001_jr_8015444C.o,tail11.data.o,ov_SC01_001_jr_80154C24.o,ov_SC01_001_jr_801588CC.o,tail12.data.o,ov_SC01_001_jr_80159C84.o,tail13.data.o,ov_SC01_001_jr_8015A3C8.o,tail14.data.o,ov_SC01_001_jr_8015AE2C.o,tail15.data.o,ov_SC01_001_jr_8015C32C.o,tail16.data.o,ov_SC01_001_jr_8016AB6C.o,tail17.data.o,ov_SC01_001_jr_801734BC.o,tail18.data.o,ov_SC01_001_jr_80178D40.o,tail19.data.o,ov_SC01_001_jr_8017A4AC.o,tail20.data.o,ov_SC01_001_jr_8017AE2C.o,ov_SC01_001_jr_8017BEBC.o,ov_SC01_001_jr_8017D2DC.o,tail21.data.o,trailing.o # Phase-26 §8 jtbl-rodata carve +ov_SC01_001_JTBL_INTERLEAVE := --order tail.data.o,ov_SC01_001.o,ov_SC01_001_jr_8012ACE0.o,tail2.data.o,ov_SC01_001_jr_80135888.o,tail3.data.o,ov_SC01_001_jr_80135A4C.o,tail4.data.o,ov_SC01_001_jr_80135D20.o,tail5.data.o,ov_SC01_001_jr_801380E0.o,tail6.data.o,ov_SC01_001_jr_8013F350.o,tail7.data.o,ov_SC01_001_jr_8013FFD8.o,tail8.data.o,ov_SC01_001_jr_80140608.o,tail9.data.o,ov_SC01_001_jr_8015444C.o,tail10.data.o,ov_SC01_001_jr_80154C24.o,ov_SC01_001_jr_801588CC.o,tail11.data.o,ov_SC01_001_jr_80159C84.o,tail12.data.o,ov_SC01_001_jr_8015A3C8.o,tail13.data.o,ov_SC01_001_jr_8015AE2C.o,tail14.data.o,ov_SC01_001_jr_8015C32C.o,tail15.data.o,ov_SC01_001_jr_8016AB6C.o,tail16.data.o,ov_SC01_001_jr_801734BC.o,tail17.data.o,ov_SC01_001_jr_80178D40.o,tail18.data.o,ov_SC01_001_jr_8017A4AC.o,tail19.data.o,ov_SC01_001_jr_8017AE2C.o,ov_SC01_001_jr_8017BEBC.o,ov_SC01_001_jr_8017D2DC.o,tail20.data.o,trailing.o # Phase-26 §8 jtbl-rodata carve +build/src/ov_SC01_001/ov_SC01_001.o: JTBL_PADS := 0,0 # §8e pads (jtbl_carve.py) tables=+0x0,+0x14 build/src/ov_SC01_001/ov_SC01_001_jr_8012ACE0.o: JTBL_PADS := 0,0 # §8e pads (jtbl_carve.py) build/src/ov_SC01_001/ov_SC01_001_jr_8013F350.o: JTBL_PADS := 0,0 # §8e pads (jtbl_carve.py) tables=+0x0,+0x20 build/src/ov_SC01_001/ov_SC01_001_jr_80154C24.o: JTBL_PADS := 0,0 # §8e pads (jtbl_carve.py) tables=+0x0,+0x24 @@ -454,7 +456,8 @@ ov_SC01_004_ELF := $(ov_SC01_004_OUT).elf ov_SC01_004_MAPFILE := $(ov_SC01_004_OUT).map ov_SC01_004_LD_SCRIPT := $(ov_SC01_004_OUT).ld ov_SC01_004_SPLAT_YAML := config/splat.ov_SC01_004.yaml -ov_SC01_004_JTBL_INTERLEAVE := --order tail.data.o,ov_SC01_004.o,tail2.data.o,ov_SC01_004_jr_8012ACE0.o,tail3.data.o,ov_SC01_004_jr_80135888.o,tail4.data.o,ov_SC01_004_jr_80135A4C.o,tail5.data.o,ov_SC01_004_jr_80135D20.o,tail6.data.o,ov_SC01_004_jr_801380E0.o,tail7.data.o,ov_SC01_004_jr_8013F350.o,tail8.data.o,ov_SC01_004_jr_8013FFD8.o,tail9.data.o,ov_SC01_004_jr_80140608.o,tail10.data.o,ov_SC01_004_jr_8015444C.o,tail11.data.o,ov_SC01_004_jr_80154C24.o,ov_SC01_004_jr_801588CC.o,tail12.data.o,ov_SC01_004_jr_80159C84.o,tail13.data.o,ov_SC01_004_jr_8015A3C8.o,tail14.data.o,ov_SC01_004_jr_8015AE2C.o,tail15.data.o,ov_SC01_004_jr_8015C32C.o,tail16.data.o,ov_SC01_004_jr_8016AB6C.o,tail17.data.o,ov_SC01_004_jr_801734BC.o,tail18.data.o,ov_SC01_004_jr_80178D40.o,tail19.data.o,ov_SC01_004_jr_8017A4AC.o,tail20.data.o,ov_SC01_004_jr_8017AE2C.o,ov_SC01_004_jr_8017BE9C.o,tail21.data.o,trailing.o # Phase-26 §8 jtbl-rodata carve +ov_SC01_004_JTBL_INTERLEAVE := --order tail.data.o,ov_SC01_004.o,ov_SC01_004_jr_8012ACE0.o,tail2.data.o,ov_SC01_004_jr_80135888.o,tail3.data.o,ov_SC01_004_jr_80135A4C.o,tail4.data.o,ov_SC01_004_jr_80135D20.o,tail5.data.o,ov_SC01_004_jr_801380E0.o,tail6.data.o,ov_SC01_004_jr_8013F350.o,tail7.data.o,ov_SC01_004_jr_8013FFD8.o,tail8.data.o,ov_SC01_004_jr_80140608.o,tail9.data.o,ov_SC01_004_jr_8015444C.o,tail10.data.o,ov_SC01_004_jr_80154C24.o,ov_SC01_004_jr_801588CC.o,tail11.data.o,ov_SC01_004_jr_80159C84.o,tail12.data.o,ov_SC01_004_jr_8015A3C8.o,tail13.data.o,ov_SC01_004_jr_8015AE2C.o,tail14.data.o,ov_SC01_004_jr_8015C32C.o,tail15.data.o,ov_SC01_004_jr_8016AB6C.o,tail16.data.o,ov_SC01_004_jr_801734BC.o,tail17.data.o,ov_SC01_004_jr_80178D40.o,tail18.data.o,ov_SC01_004_jr_8017A4AC.o,tail19.data.o,ov_SC01_004_jr_8017AE2C.o,ov_SC01_004_jr_8017BE9C.o,tail20.data.o,trailing.o # Phase-26 §8 jtbl-rodata carve +build/src/ov_SC01_004/ov_SC01_004.o: JTBL_PADS := 0,0 # §8e pads (jtbl_carve.py) tables=+0x0,+0x14 build/src/ov_SC01_004/ov_SC01_004_jr_8012ACE0.o: JTBL_PADS := 0,0 # §8e pads (jtbl_carve.py) build/src/ov_SC01_004/ov_SC01_004_jr_8013F350.o: JTBL_PADS := 0,0 # §8e pads (jtbl_carve.py) tables=+0x0,+0x20 build/src/ov_SC01_004/ov_SC01_004_jr_80154C24.o: JTBL_PADS := 0,0 # §8e pads (jtbl_carve.py) tables=+0x0,+0x24 diff --git a/config/splat.ov_SC01_000.yaml b/config/splat.ov_SC01_000.yaml index f88efcdea..da962154e 100644 --- a/config/splat.ov_SC01_000.yaml +++ b/config/splat.ov_SC01_000.yaml @@ -119,47 +119,46 @@ segments: - [0x53d64, c, ov_SC01_000_jr_8017BEBC] - [0x56a64, data, tail] - [0x7b0e8, .rodata, ov_SC01_000] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x7b0fc, data, tail2] - [0x7b1c4, .rodata, ov_SC01_000_jr_8012ACE0] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x7b2a4, data, tail3] + - [0x7b2a4, data, tail2] - [0x7b2bc, .rodata, ov_SC01_000_jr_80135888] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x7b2d0, data, tail4] + - [0x7b2d0, data, tail3] - [0x7b2d4, .rodata, ov_SC01_000_jr_80135A4C] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x7b2e8, data, tail5] + - [0x7b2e8, data, tail4] - [0x7b2ec, .rodata, ov_SC01_000_jr_80135D20] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x7b300, data, tail6] + - [0x7b300, data, tail5] - [0x7b33c, .rodata, ov_SC01_000_jr_801380E0] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x7b3a0, data, tail7] + - [0x7b3a0, data, tail6] - [0x7b9ac, .rodata, ov_SC01_000_jr_8013F350] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x7b9e0, data, tail8] + - [0x7b9e0, data, tail7] - [0x7b9e4, .rodata, ov_SC01_000_jr_8013FFD8] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x7ba18, data, tail9] + - [0x7ba18, data, tail8] - [0x7ba54, .rodata, ov_SC01_000_jr_80140608] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x7ba68, data, tail10] + - [0x7ba68, data, tail9] - [0x7ba80, .rodata, ov_SC01_000_jr_8015444C] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x7baec, data, tail11] + - [0x7baec, data, tail10] - [0x7bb5c, .rodata, ov_SC01_000_jr_80154C24] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - [0x7bba0, .rodata, ov_SC01_000_jr_801588CC] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x7bbe8, data, tail12] + - [0x7bbe8, data, tail11] - [0x7bc48, .rodata, ov_SC01_000_jr_80159C84] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x7bc7c, data, tail13] + - [0x7bc7c, data, tail12] - [0x7bc80, .rodata, ov_SC01_000_jr_8015A3C8] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x7bc9c, data, tail14] + - [0x7bc9c, data, tail13] - [0x7bca0, .rodata, ov_SC01_000_jr_8015AE2C] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x7bcbc, data, tail15] + - [0x7bcbc, data, tail14] - [0x7bce0, .rodata, ov_SC01_000_jr_8015C32C] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x7bcfc, data, tail16] + - [0x7bcfc, data, tail15] - [0x7bd14, .rodata, ov_SC01_000_jr_8016AB6C] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x7bd34, data, tail17] + - [0x7bd34, data, tail16] - [0x7bdb4, .rodata, ov_SC01_000_jr_801734BC] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x7bdc8, data, tail18] + - [0x7bdc8, data, tail17] - [0x7bf70, .rodata, ov_SC01_000_jr_80178D40] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x7c0e8, data, tail19] + - [0x7c0e8, data, tail18] - [0x7c178, .rodata, ov_SC01_000_jr_8017A4AC] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x7c204, data, tail20] + - [0x7c204, data, tail19] - [0x7c208, .rodata, ov_SC01_000_jr_8017AE2C] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - [0x7c21c, .rodata, ov_SC01_000_jr_8017BEBC] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x7c23c, data, tail21] + - [0x7c23c, data, tail20] - [0x7D78C, bin, trailing] # final 3 bytes (EOF not 4-aligned; spimdisasm drops a partial word) - [0x7D78F] # 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 diff --git a/config/splat.ov_SC01_001.yaml b/config/splat.ov_SC01_001.yaml index 943b38d1f..720e60768 100644 --- a/config/splat.ov_SC01_001.yaml +++ b/config/splat.ov_SC01_001.yaml @@ -120,48 +120,47 @@ segments: - [0x55184, c, ov_SC01_001_jr_8017D2DC] - [0x5b6b4, data, tail] - [0xc31c0, .rodata, ov_SC01_001] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0xc31d4, data, tail2] - [0xc329c, .rodata, ov_SC01_001_jr_8012ACE0] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0xc337c, data, tail3] + - [0xc337c, data, tail2] - [0xc3394, .rodata, ov_SC01_001_jr_80135888] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0xc33a8, data, tail4] + - [0xc33a8, data, tail3] - [0xc33ac, .rodata, ov_SC01_001_jr_80135A4C] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0xc33c0, data, tail5] + - [0xc33c0, data, tail4] - [0xc33c4, .rodata, ov_SC01_001_jr_80135D20] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0xc33d8, data, tail6] + - [0xc33d8, data, tail5] - [0xc3414, .rodata, ov_SC01_001_jr_801380E0] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0xc3478, data, tail7] + - [0xc3478, data, tail6] - [0xc3a84, .rodata, ov_SC01_001_jr_8013F350] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0xc3ab8, data, tail8] + - [0xc3ab8, data, tail7] - [0xc3abc, .rodata, ov_SC01_001_jr_8013FFD8] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0xc3af0, data, tail9] + - [0xc3af0, data, tail8] - [0xc3b2c, .rodata, ov_SC01_001_jr_80140608] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0xc3b40, data, tail10] + - [0xc3b40, data, tail9] - [0xc3b58, .rodata, ov_SC01_001_jr_8015444C] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0xc3bc4, data, tail11] + - [0xc3bc4, data, tail10] - [0xc3c34, .rodata, ov_SC01_001_jr_80154C24] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - [0xc3c78, .rodata, ov_SC01_001_jr_801588CC] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0xc3cc0, data, tail12] + - [0xc3cc0, data, tail11] - [0xc3d20, .rodata, ov_SC01_001_jr_80159C84] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0xc3d54, data, tail13] + - [0xc3d54, data, tail12] - [0xc3d58, .rodata, ov_SC01_001_jr_8015A3C8] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0xc3d74, data, tail14] + - [0xc3d74, data, tail13] - [0xc3d78, .rodata, ov_SC01_001_jr_8015AE2C] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0xc3d94, data, tail15] + - [0xc3d94, data, tail14] - [0xc3db8, .rodata, ov_SC01_001_jr_8015C32C] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0xc3dd4, data, tail16] + - [0xc3dd4, data, tail15] - [0xc3dec, .rodata, ov_SC01_001_jr_8016AB6C] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0xc3e0c, data, tail17] + - [0xc3e0c, data, tail16] - [0xc3e8c, .rodata, ov_SC01_001_jr_801734BC] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0xc3ea0, data, tail18] + - [0xc3ea0, data, tail17] - [0xc4048, .rodata, ov_SC01_001_jr_80178D40] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0xc41c0, data, tail19] + - [0xc41c0, data, tail18] - [0xc4250, .rodata, ov_SC01_001_jr_8017A4AC] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0xc42dc, data, tail20] + - [0xc42dc, data, tail19] - [0xc42e0, .rodata, ov_SC01_001_jr_8017AE2C] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - [0xc42f4, .rodata, ov_SC01_001_jr_8017BEBC] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - [0xc4314, .rodata, ov_SC01_001_jr_8017D2DC] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0xc4508, data, tail21] + - [0xc4508, data, tail20] - [0xCB06C, bin, trailing] # final 3 bytes (EOF not 4-aligned; spimdisasm drops a partial word) - [0xCB06F] # 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 diff --git a/config/splat.ov_SC01_004.yaml b/config/splat.ov_SC01_004.yaml index 8307b199a..3be2a591c 100644 --- a/config/splat.ov_SC01_004.yaml +++ b/config/splat.ov_SC01_004.yaml @@ -119,47 +119,46 @@ segments: - [0x53d44, c, ov_SC01_004_jr_8017BE9C] - [0x57078, data, tail] - [0x655a0, .rodata, ov_SC01_004] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x655b4, data, tail2] - [0x6567c, .rodata, ov_SC01_004_jr_8012ACE0] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x6575c, data, tail3] + - [0x6575c, data, tail2] - [0x65774, .rodata, ov_SC01_004_jr_80135888] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x65788, data, tail4] + - [0x65788, data, tail3] - [0x6578c, .rodata, ov_SC01_004_jr_80135A4C] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x657a0, data, tail5] + - [0x657a0, data, tail4] - [0x657a4, .rodata, ov_SC01_004_jr_80135D20] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x657b8, data, tail6] + - [0x657b8, data, tail5] - [0x657f4, .rodata, ov_SC01_004_jr_801380E0] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x65858, data, tail7] + - [0x65858, data, tail6] - [0x65e64, .rodata, ov_SC01_004_jr_8013F350] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x65e98, data, tail8] + - [0x65e98, data, tail7] - [0x65e9c, .rodata, ov_SC01_004_jr_8013FFD8] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x65ed0, data, tail9] + - [0x65ed0, data, tail8] - [0x65f0c, .rodata, ov_SC01_004_jr_80140608] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x65f20, data, tail10] + - [0x65f20, data, tail9] - [0x65f38, .rodata, ov_SC01_004_jr_8015444C] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x65fa4, data, tail11] + - [0x65fa4, data, tail10] - [0x66014, .rodata, ov_SC01_004_jr_80154C24] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - [0x66058, .rodata, ov_SC01_004_jr_801588CC] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x660a0, data, tail12] + - [0x660a0, data, tail11] - [0x66100, .rodata, ov_SC01_004_jr_80159C84] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x66134, data, tail13] + - [0x66134, data, tail12] - [0x66138, .rodata, ov_SC01_004_jr_8015A3C8] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x66154, data, tail14] + - [0x66154, data, tail13] - [0x66158, .rodata, ov_SC01_004_jr_8015AE2C] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x66174, data, tail15] + - [0x66174, data, tail14] - [0x66198, .rodata, ov_SC01_004_jr_8015C32C] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x661b4, data, tail16] + - [0x661b4, data, tail15] - [0x661cc, .rodata, ov_SC01_004_jr_8016AB6C] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x661ec, data, tail17] + - [0x661ec, data, tail16] - [0x6626c, .rodata, ov_SC01_004_jr_801734BC] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x66280, data, tail18] + - [0x66280, data, tail17] - [0x66428, .rodata, ov_SC01_004_jr_80178D40] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x665a0, data, tail19] + - [0x665a0, data, tail18] - [0x66630, .rodata, ov_SC01_004_jr_8017A4AC] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x666bc, data, tail20] + - [0x666bc, data, tail19] - [0x666c0, .rodata, ov_SC01_004_jr_8017AE2C] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - [0x666d4, .rodata, ov_SC01_004_jr_8017BE9C] # Phase-26 §8 jtbl-rodata carve (jtbl_carve.py) - - [0x666f4, data, tail21] + - [0x666f4, data, tail20] - [0x68274, bin, trailing] # final 3 bytes (EOF not 4-aligned; spimdisasm drops a partial word) - [0x68277] # 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 diff --git a/src/ov_SC01_000/ov_SC01_000.c b/src/ov_SC01_000/ov_SC01_000.c index e8c9b94c7..9e8e9fe09 100644 --- a/src/ov_SC01_000/ov_SC01_000.c +++ b/src/ov_SC01_000/ov_SC01_000.c @@ -712,7 +712,88 @@ DEFINE_func_8012A908() /* dedup: shared engine-core @0x8012A908 (src/shared) */ DEFINE_func_8012A988() /* dedup: shared engine-core @0x8012A988 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_000/nonmatchings/ov_SC01_000", func_8012AAAC); + +extern void func_8012AAAC(void *arg0); + +void func_8012AAAC(void *arg0) { + void *ptr; + s32 link; + s32 next; + s32 saved; + s32 cnt; + s32 back; + s32 head; + + M2C_FIELD(arg0, u16 *, 0x72) = (u16) (M2C_FIELD(arg0, u16 *, 0x72) & 0xBFFF); + ptr = (void *) (M2C_FIELD(arg0, s32 *, 0x90) + (M2C_FIELD(arg0, s32 *, 0x94) * 8)); + if (M2C_FIELD(ptr, s16 *, 4) < 0) { + switch (M2C_FIELD(ptr, s16 *, 4)) { + case -2: + link = M2C_FIELD(arg0, s32 *, 0x9C); + if (link == 0) { + M2C_FIELD(arg0, s16 *, 0x98) = 0; + break; + } + goto pop; + case -1: + link = M2C_FIELD(arg0, s32 *, 0x9C); + if (link != 0) { +pop: + back = M2C_FIELD(arg0, s16 *, 0x9A); + M2C_FIELD(arg0, s32 *, 0x90) = link; + M2C_FIELD(arg0, s32 *, 0x9C) = 0; + M2C_FIELD(arg0, s16 *, 0x9A) = 0; + M2C_FIELD(arg0, s32 *, 0x94) = back; + func_8012AAAC(arg0); + break; + } + M2C_FIELD(arg0, s32 *, 0x94) = 0; + func_8012AAAC(arg0); + M2C_FIELD(arg0, u16 *, 0x72) = (u16) (M2C_FIELD(arg0, u16 *, 0x72) | 0x4000); + break; + case -4: + head = M2C_FIELD(ptr, s32 *, 0); + M2C_FIELD(arg0, s32 *, 0x94) = 0; + M2C_FIELD(arg0, s32 *, 0x9C) = 0; + M2C_FIELD(arg0, s16 *, 0x9A) = 0; + M2C_FIELD(arg0, s32 *, 0x90) = head; + M2C_FIELD(arg0, u16 *, 0x72) = (u16) (M2C_FIELD(arg0, u16 *, 0x72) & 0xF9FF); + func_8012AAAC(arg0); + break; + case -3: + cnt = M2C_FIELD(arg0, s32 *, 0x94) + 1; + M2C_FIELD(arg0, s32 *, 0x94) = cnt; + if (M2C_FIELD(arg0, s32 *, 0x9C) != 0) { + func_8012AAAC(arg0); + break; + } + saved = M2C_FIELD(arg0, s32 *, 0x90); + next = M2C_FIELD(ptr, s32 *, 0); + M2C_FIELD(arg0, s32 *, 0x94) = 0; + M2C_FIELD(arg0, s32 *, 0x9C) = 0; + M2C_FIELD(arg0, s16 *, 0x9A) = 0; + M2C_FIELD(arg0, s32 *, 0x90) = next; + M2C_FIELD(arg0, u16 *, 0x72) = (u16) (M2C_FIELD(arg0, u16 *, 0x72) & 0xF9FF); + func_8012AAAC(arg0); + M2C_FIELD(arg0, s32 *, 0x9C) = saved; + M2C_FIELD(arg0, s16 *, 0x9A) = (s16) cnt; + break; + case -50: + M2C_FIELD(arg0, s32 *, 0x94) = M2C_FIELD(arg0, s32 *, 0x94) + 1; + func_8012AAAC(arg0); + M2C_FIELD(arg0, u16 *, 0x72) = (u16) (M2C_FIELD(arg0, u16 *, 0x72) | 0x2000); + break; + case -5: + M2C_FIELD(arg0, u16 *, 0x72) = (u16) (M2C_FIELD(arg0, u16 *, 0x72) | 0x400); + M2C_FIELD(arg0, s32 *, 0x94) = M2C_FIELD(arg0, s32 *, 0x94) - 1; + func_8012AAAC(arg0); + break; + } + } else { + M2C_FIELD(M2C_FIELD(arg0, void **, 0x20), s32 *, 0x20) = M2C_FIELD(ptr, s32 *, 0); + M2C_FIELD(arg0, s16 *, 0x98) = M2C_FIELD(ptr, s16 *, 4); + } +} extern void func_8012AAAC(); diff --git a/src/ov_SC01_001/ov_SC01_001.c b/src/ov_SC01_001/ov_SC01_001.c index 68aa63cec..b54018ce8 100644 --- a/src/ov_SC01_001/ov_SC01_001.c +++ b/src/ov_SC01_001/ov_SC01_001.c @@ -714,7 +714,88 @@ DEFINE_func_8012A908() /* dedup: shared engine-core @0x8012A908 (src/shared) */ DEFINE_func_8012A988() /* dedup: shared engine-core @0x8012A988 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_001/nonmatchings/ov_SC01_001", func_8012AAAC); + +extern void func_8012AAAC(void *arg0); + +void func_8012AAAC(void *arg0) { + void *ptr; + s32 link; + s32 next; + s32 saved; + s32 cnt; + s32 back; + s32 head; + + M2C_FIELD(arg0, u16 *, 0x72) = (u16) (M2C_FIELD(arg0, u16 *, 0x72) & 0xBFFF); + ptr = (void *) (M2C_FIELD(arg0, s32 *, 0x90) + (M2C_FIELD(arg0, s32 *, 0x94) * 8)); + if (M2C_FIELD(ptr, s16 *, 4) < 0) { + switch (M2C_FIELD(ptr, s16 *, 4)) { + case -2: + link = M2C_FIELD(arg0, s32 *, 0x9C); + if (link == 0) { + M2C_FIELD(arg0, s16 *, 0x98) = 0; + break; + } + goto pop; + case -1: + link = M2C_FIELD(arg0, s32 *, 0x9C); + if (link != 0) { +pop: + back = M2C_FIELD(arg0, s16 *, 0x9A); + M2C_FIELD(arg0, s32 *, 0x90) = link; + M2C_FIELD(arg0, s32 *, 0x9C) = 0; + M2C_FIELD(arg0, s16 *, 0x9A) = 0; + M2C_FIELD(arg0, s32 *, 0x94) = back; + func_8012AAAC(arg0); + break; + } + M2C_FIELD(arg0, s32 *, 0x94) = 0; + func_8012AAAC(arg0); + M2C_FIELD(arg0, u16 *, 0x72) = (u16) (M2C_FIELD(arg0, u16 *, 0x72) | 0x4000); + break; + case -4: + head = M2C_FIELD(ptr, s32 *, 0); + M2C_FIELD(arg0, s32 *, 0x94) = 0; + M2C_FIELD(arg0, s32 *, 0x9C) = 0; + M2C_FIELD(arg0, s16 *, 0x9A) = 0; + M2C_FIELD(arg0, s32 *, 0x90) = head; + M2C_FIELD(arg0, u16 *, 0x72) = (u16) (M2C_FIELD(arg0, u16 *, 0x72) & 0xF9FF); + func_8012AAAC(arg0); + break; + case -3: + cnt = M2C_FIELD(arg0, s32 *, 0x94) + 1; + M2C_FIELD(arg0, s32 *, 0x94) = cnt; + if (M2C_FIELD(arg0, s32 *, 0x9C) != 0) { + func_8012AAAC(arg0); + break; + } + saved = M2C_FIELD(arg0, s32 *, 0x90); + next = M2C_FIELD(ptr, s32 *, 0); + M2C_FIELD(arg0, s32 *, 0x94) = 0; + M2C_FIELD(arg0, s32 *, 0x9C) = 0; + M2C_FIELD(arg0, s16 *, 0x9A) = 0; + M2C_FIELD(arg0, s32 *, 0x90) = next; + M2C_FIELD(arg0, u16 *, 0x72) = (u16) (M2C_FIELD(arg0, u16 *, 0x72) & 0xF9FF); + func_8012AAAC(arg0); + M2C_FIELD(arg0, s32 *, 0x9C) = saved; + M2C_FIELD(arg0, s16 *, 0x9A) = (s16) cnt; + break; + case -50: + M2C_FIELD(arg0, s32 *, 0x94) = M2C_FIELD(arg0, s32 *, 0x94) + 1; + func_8012AAAC(arg0); + M2C_FIELD(arg0, u16 *, 0x72) = (u16) (M2C_FIELD(arg0, u16 *, 0x72) | 0x2000); + break; + case -5: + M2C_FIELD(arg0, u16 *, 0x72) = (u16) (M2C_FIELD(arg0, u16 *, 0x72) | 0x400); + M2C_FIELD(arg0, s32 *, 0x94) = M2C_FIELD(arg0, s32 *, 0x94) - 1; + func_8012AAAC(arg0); + break; + } + } else { + M2C_FIELD(M2C_FIELD(arg0, void **, 0x20), s32 *, 0x20) = M2C_FIELD(ptr, s32 *, 0); + M2C_FIELD(arg0, s16 *, 0x98) = M2C_FIELD(ptr, s16 *, 4); + } +} extern void func_8012AAAC(); diff --git a/src/ov_SC01_004/ov_SC01_004.c b/src/ov_SC01_004/ov_SC01_004.c index 6360941c2..be22a53d5 100644 --- a/src/ov_SC01_004/ov_SC01_004.c +++ b/src/ov_SC01_004/ov_SC01_004.c @@ -720,7 +720,88 @@ DEFINE_func_8012A908() /* dedup: shared engine-core @0x8012A908 (src/shared) */ DEFINE_func_8012A988() /* dedup: shared engine-core @0x8012A988 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_004/nonmatchings/ov_SC01_004", func_8012AAAC); + +extern void func_8012AAAC(void *arg0); + +void func_8012AAAC(void *arg0) { + void *ptr; + s32 link; + s32 next; + s32 saved; + s32 cnt; + s32 back; + s32 head; + + M2C_FIELD(arg0, u16 *, 0x72) = (u16) (M2C_FIELD(arg0, u16 *, 0x72) & 0xBFFF); + ptr = (void *) (M2C_FIELD(arg0, s32 *, 0x90) + (M2C_FIELD(arg0, s32 *, 0x94) * 8)); + if (M2C_FIELD(ptr, s16 *, 4) < 0) { + switch (M2C_FIELD(ptr, s16 *, 4)) { + case -2: + link = M2C_FIELD(arg0, s32 *, 0x9C); + if (link == 0) { + M2C_FIELD(arg0, s16 *, 0x98) = 0; + break; + } + goto pop; + case -1: + link = M2C_FIELD(arg0, s32 *, 0x9C); + if (link != 0) { +pop: + back = M2C_FIELD(arg0, s16 *, 0x9A); + M2C_FIELD(arg0, s32 *, 0x90) = link; + M2C_FIELD(arg0, s32 *, 0x9C) = 0; + M2C_FIELD(arg0, s16 *, 0x9A) = 0; + M2C_FIELD(arg0, s32 *, 0x94) = back; + func_8012AAAC(arg0); + break; + } + M2C_FIELD(arg0, s32 *, 0x94) = 0; + func_8012AAAC(arg0); + M2C_FIELD(arg0, u16 *, 0x72) = (u16) (M2C_FIELD(arg0, u16 *, 0x72) | 0x4000); + break; + case -4: + head = M2C_FIELD(ptr, s32 *, 0); + M2C_FIELD(arg0, s32 *, 0x94) = 0; + M2C_FIELD(arg0, s32 *, 0x9C) = 0; + M2C_FIELD(arg0, s16 *, 0x9A) = 0; + M2C_FIELD(arg0, s32 *, 0x90) = head; + M2C_FIELD(arg0, u16 *, 0x72) = (u16) (M2C_FIELD(arg0, u16 *, 0x72) & 0xF9FF); + func_8012AAAC(arg0); + break; + case -3: + cnt = M2C_FIELD(arg0, s32 *, 0x94) + 1; + M2C_FIELD(arg0, s32 *, 0x94) = cnt; + if (M2C_FIELD(arg0, s32 *, 0x9C) != 0) { + func_8012AAAC(arg0); + break; + } + saved = M2C_FIELD(arg0, s32 *, 0x90); + next = M2C_FIELD(ptr, s32 *, 0); + M2C_FIELD(arg0, s32 *, 0x94) = 0; + M2C_FIELD(arg0, s32 *, 0x9C) = 0; + M2C_FIELD(arg0, s16 *, 0x9A) = 0; + M2C_FIELD(arg0, s32 *, 0x90) = next; + M2C_FIELD(arg0, u16 *, 0x72) = (u16) (M2C_FIELD(arg0, u16 *, 0x72) & 0xF9FF); + func_8012AAAC(arg0); + M2C_FIELD(arg0, s32 *, 0x9C) = saved; + M2C_FIELD(arg0, s16 *, 0x9A) = (s16) cnt; + break; + case -50: + M2C_FIELD(arg0, s32 *, 0x94) = M2C_FIELD(arg0, s32 *, 0x94) + 1; + func_8012AAAC(arg0); + M2C_FIELD(arg0, u16 *, 0x72) = (u16) (M2C_FIELD(arg0, u16 *, 0x72) | 0x2000); + break; + case -5: + M2C_FIELD(arg0, u16 *, 0x72) = (u16) (M2C_FIELD(arg0, u16 *, 0x72) | 0x400); + M2C_FIELD(arg0, s32 *, 0x94) = M2C_FIELD(arg0, s32 *, 0x94) - 1; + func_8012AAAC(arg0); + break; + } + } else { + M2C_FIELD(M2C_FIELD(arg0, void **, 0x20), s32 *, 0x20) = M2C_FIELD(ptr, s32 *, 0); + M2C_FIELD(arg0, s16 *, 0x98) = M2C_FIELD(ptr, s16 *, 4); + } +} extern void func_8012AAAC(); diff --git a/tools/jtbl_carve.py b/tools/jtbl_carve.py index 33aa42ce1..6ccea9705 100644 --- a/tools/jtbl_carve.py +++ b/tools/jtbl_carve.py @@ -511,6 +511,36 @@ def build_carve(ov, funcs): # persistence (tables=) + the --like transfer are what make sibling sweeps possible # (the func_8013F350 lesson: a pre-§8e Phase-26 merged double had NO recoverable # structure — interval carry mis-defaulted it to [0]). + def _like_role_matches(ov_name, sub_name, fns): + """Is the `--like` role-transfer VALID for this subseg? (Phase 29 SESSION-21) + + The transfer's premise is "same family => same span structure", and it keys on the SUBSEG + ROLE (`ov_SC01_077_a` -> `_a`). That premise silently breaks when the exemplar and the + sibling host the function in subsegs with DIFFERENT roles — which happens whenever the + exemplar has a split the sibling does not. + + MEASURED (func_8012AAAC): the exemplar hosts it in `ov_SC01_077_a` (role `_a`) while every + sibling hosts it in the MAIN subseg (role ``). The transfer therefore looked up + `ov_SC01_077` — an unrelated 7-table span belonging to different functions — and stamped + those starts onto a sibling span that holds one table. The pad stage then refused with + `consumed 1 rodata .align(s) but 2 pad spec(s) given — table-count drift`, and + jtbl_family_bank deliberately does NOT treat that error as isolate-fixable, so all 137 + siblings returned a bare `gate-fail` with no cause attached. + + So: transfer ONLY when the exemplar's subseg for THIS function has the sibling's role. + Otherwise derive the span locally, which is what the sibling's own carve already computes + correctly. Fail-open is not acceptable here — a wrong table set corrupts the image.""" + if not LIKE_OV: + return False + want = role(sub_name, ov_name) + for f in fns: + try: + if role(func_subseg(LIKE_OV, f), LIKE_OV) == want: + return True + except SystemExit: + continue # not present in the exemplar — cannot vouch for it + return False + prior_map = current_pads_specs(ov) old_span_start = {sub: s for (s, _e, sub) in existing} # pre-merge span starts (for rebase) new_offs = {} # sub -> new table offs added this run @@ -555,7 +585,7 @@ def build_carve(ov, funcs): starts.add(base + old_span_start[sub]) if sub in SPAN_TABLES_OVERRIDE: starts.update(SPAN_TABLES_OVERRIDE[sub]) - if LIKE_OV: + if LIKE_OV and _like_role_matches(ov, sub, funcs): lk = like_map.get(LIKE_OV + role(sub, ov)) if lk is not None and lk[1] is not None: # role-transfer: same family => same span structure; rebase rel offsets on THIS