ff6sym: segment-scoped labels; RAM trace lists $1500 -> CutsceneNMI jumps #28

Merged
Gatchan merged 2 commits from fix-ff6sym-ram into main 2026-10-29 19:03:58 +00:00
Owner

Fixes #25

Finding

ff6sym.py 7E:7233 with the US .dbg already prints CutsceneNMI+$0 (src/cutscene/cutscene_main.asm:195); the bad output in the issue is exactly what the JP .dbg gives for that address: JP UpdatePPU is at $7E:71F1, and $7233 - $71F1 = $42. The cutscene program is assembled per version (CutsceneNMI US $7E:7233, JP $7E:71BF), so a US address resolved with --version jp_v10 (or a JP trace read without it) gives a JP neighbour. Only one segment runs from WRAM (cutscene_wram, start $7E:5000, both versions), and its labels carry run addresses: the RAM label choice itself was right.

A real defect did exist in the label search: it walked back across segment boundaries, so an address past the end of a segment got the last label of the previous one (e.g. 7E:7C70, past cutscene_wram end $7E:7C63, printed TownPal1+$2D; data tables got a local label of the code before them, e.g. C0:E031 DTETbl + local DrawSwitches).

Changes

  • tools/ff6sym.py: a label names an address only inside its own segment (labels carry their segment end); docstring explains the version pitfall. draft.py follows the new label tuple.
  • RAM trace (core/port/ram_trace.c, core/api/ff6_debug.h, hosts/cli/main.c): new edge kind FF6_RAM_EDGE_JUMP (TSV jump): RAM to RAM transfer that changes RAM region (low RAM / $7E / $7F, mirrors normalised), i.e. trampoline 00:1500 -> CutsceneNMI. Debug only, no effect on emulation.
  • tools/ram_trace_report.py: lists "RAM->RAM jumps between banks"; accepts - (stdin) for the trace.
  • tools/tests/test_disasm_tools.py (tools.disasm, skips without the disassembly): US 7E:7233 and JP 7E:71BF -> CutsceneNMI+$0; JP 7E:7233 -> UpdatePPU+$42 (documents the mixup); 7E:7C70 -> no label; report lists 00:1500 -> CutsceneNMI as a jump, US and JP.
  • docs/ram_trace.md updated.

Evidence

  • ff6cli --frames 800 --trace-ram: US jump 00:1500 7E:7233 433 368 800, JP jump 00:1500 7E:71BF 434 367 800; report: 00:1500 ? -> 7E:7233 CutsceneNMI+$0 (@7233+$0) (JP 7E:71BF CutsceneNMI+$0).
  • Old vs new resolver on 1 176 sampled addresses per version (ROM C0-FF + cutscene RAM): 57 differ, all either a local label from a previous segment dropped (global unchanged) or an address outside every segment (no source line) now unlabelled.
  • python3 tools/draft.py field Reset works; tools.disasm: 12/12 OK.
  • Builds clean (0 warnings): debug, clang, mingw. release --fast 20/20, debug --fast 20/20.

🤖 Generated with Claude Code

Fixes #25 ## Finding `ff6sym.py 7E:7233` with the US `.dbg` already prints `CutsceneNMI+$0` (`src/cutscene/cutscene_main.asm:195`); the bad output in the issue is exactly what the **JP** `.dbg` gives for that address: JP `UpdatePPU` is at `$7E:71F1`, and `$7233 - $71F1 = $42`. The cutscene program is assembled per version (CutsceneNMI US `$7E:7233`, JP `$7E:71BF`), so a US address resolved with `--version jp_v10` (or a JP trace read without it) gives a JP neighbour. Only one segment runs from WRAM (`cutscene_wram`, start `$7E:5000`, both versions), and its labels carry run addresses: the RAM label choice itself was right. A real defect did exist in the label search: it walked back across segment boundaries, so an address past the end of a segment got the last label of the previous one (e.g. `7E:7C70`, past `cutscene_wram` end `$7E:7C63`, printed `TownPal1+$2D`; data tables got a local label of the code before them, e.g. `C0:E031` `DTETbl` + local `DrawSwitches`). ## Changes - `tools/ff6sym.py`: a label names an address only inside its own segment (labels carry their segment end); docstring explains the version pitfall. `draft.py` follows the new label tuple. - RAM trace (`core/port/ram_trace.c`, `core/api/ff6_debug.h`, `hosts/cli/main.c`): new edge kind `FF6_RAM_EDGE_JUMP` (TSV `jump`): RAM to RAM transfer that changes RAM region (low RAM / `$7E` / `$7F`, mirrors normalised), i.e. trampoline `00:1500` -> `CutsceneNMI`. Debug only, no effect on emulation. - `tools/ram_trace_report.py`: lists "RAM->RAM jumps between banks"; accepts `-` (stdin) for the trace. - `tools/tests/test_disasm_tools.py` (tools.disasm, skips without the disassembly): US `7E:7233` and JP `7E:71BF` -> `CutsceneNMI+$0`; JP `7E:7233` -> `UpdatePPU+$42` (documents the mixup); `7E:7C70` -> no label; report lists `00:1500 -> CutsceneNMI` as a jump, US and JP. - `docs/ram_trace.md` updated. ## Evidence - `ff6cli --frames 800 --trace-ram`: US `jump 00:1500 7E:7233 433 368 800`, JP `jump 00:1500 7E:71BF 434 367 800`; report: `00:1500 ? -> 7E:7233 CutsceneNMI+$0 (@7233+$0)` (JP `7E:71BF CutsceneNMI+$0`). - Old vs new resolver on 1 176 sampled addresses per version (ROM C0-FF + cutscene RAM): 57 differ, all either a local label from a previous segment dropped (global unchanged) or an address outside every segment (no source line) now unlabelled. - `python3 tools/draft.py field Reset` works; tools.disasm: 12/12 OK. - Builds clean (0 warnings): debug, clang, mingw. `release --fast` 20/20, `debug --fast` 20/20. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Gatchan/FF6Portage!28
No description provided.