RAM map slice 1, generated state accessors, peek/poke by name #18

Merged
Gatchan merged 6 commits from ram-map into main 2026-10-29 10:40:34 +00:00
Owner

RAM map slice 1, generated state accessors, and peek/poke by RAM-map name.

Content

  • re/ram_map.toml: the reviewed draft (187 vars, 4 structs, regions, RAM code images), evidence kept. Format, generator rules and decisions are in docs/ram_map.md.
    • Open question 1 resolved by measurement: the title New Game/Continue menu is event command $AB, so a new game is seeded too. With a blank SRAM, $307FF1 = 0, so $1F6D and $1FA1-$1FA5 hold $0D (power-on seeds 0, 1, 2, 5; US and JP).
    • Settled: accessor prefixes (<subsystem>_, save uses game_), bitsN gives bit accessors, text6 is a 6-element byte value.
    • The other open questions are now issues: #14 (DP layout per mode for struct storage), #15 ($0630-$0632 timing bytes), #16 (width doubts), #17 (documented entries, JP unverified entries).
  • tools/gen_state.py generates core/state/state_gen.h (static inline get/set accessors: 8/16/24/32-bit, signed, arrays, record fields, elements, bit sets, index constants, STATE_BY_VERSION when US/JP addresses differ, STATE_CHECK asserts in debug builds) and core/state/state_gen.c (name table). The generated files are committed, so a build needs no Python. ctest tools.gen_state.check fails when they drift from the map. Storage struct is refused until it is implemented.
  • core/state/state_battle.h is removed: battle_random.c uses the generated battle_rng_index.
  • Debug API ff6_debug_var_find(core, "characters[2].hp", &var), ff6_debug_var_count/name. Drive server: peek <name> returns addr, size and value= decoded with the element width; poke <name> <hex>[,...]. Raw offset access is unchanged. The MCP tools ff6_peek/ff6_poke accept name (and value).
  • tools/draft.py and tools/ff6sym.py come from the workspace prototypes. They take paths from options or from environment.toml (tools/ff6env.py). The draft printer prints RAM-map names for WRAM operands (rd8(g, vblank_flag), party_pos.y) and also accepts plain labels (battle Rand). tools/ram_map_check.py is the map verifier, moved from the workspace.

Validation

  • Builds: debug, release, clang, mingw: 0 warnings.
  • ctest release (all, slow included): 13/13 passed (rom.ports 307 s/308 s). Debug --fast: 10/10 passed.
  • Shadow, ff6cli --frames 9500 --input tests/inputs/newgame_first_battle.txt --port all=shadow: battle/Rand 13/13 US, 16/16 JP, 0 mismatch (unchanged).
  • Python: tools/tests/test_gen_state.py 7/7. tools/tests/test_disasm_tools.py all OK (skips without the disassembly). tools/mcp/tests/test_ff6_drive.py ALL OK, with the new name peek/poke checks.
  • tools/ram_map_check.py: 187 vars, 0 errors, 0 warnings, 158 JP listing checks passed.

Fixes #7

🤖 Generated with Claude Code

RAM map slice 1, generated state accessors, and peek/poke by RAM-map name. ## Content - `re/ram_map.toml`: the reviewed draft (187 vars, 4 structs, regions, RAM code images), evidence kept. Format, generator rules and decisions are in `docs/ram_map.md`. - Open question 1 resolved by measurement: the title New Game/Continue menu is event command `$AB`, so a new game is seeded too. With a blank SRAM, `$307FF1` = 0, so `$1F6D` and `$1FA1-$1FA5` hold `$0D` (power-on seeds 0, 1, 2, 5; US and JP). - Settled: accessor prefixes (`<subsystem>_`, `save` uses `game_`), `bitsN` gives bit accessors, `text6` is a 6-element byte value. - The other open questions are now issues: #14 (DP layout per mode for struct storage), #15 (`$0630-$0632` timing bytes), #16 (width doubts), #17 (documented entries, JP unverified entries). - `tools/gen_state.py` generates `core/state/state_gen.h` (static inline get/set accessors: 8/16/24/32-bit, signed, arrays, record fields, elements, bit sets, index constants, `STATE_BY_VERSION` when US/JP addresses differ, `STATE_CHECK` asserts in debug builds) and `core/state/state_gen.c` (name table). The generated files are **committed**, so a build needs no Python. ctest `tools.gen_state.check` fails when they drift from the map. Storage `struct` is refused until it is implemented. - `core/state/state_battle.h` is removed: `battle_random.c` uses the generated `battle_rng_index`. - Debug API `ff6_debug_var_find(core, "characters[2].hp", &var)`, `ff6_debug_var_count/name`. Drive server: `peek <name>` returns `addr`, `size` and `value=` decoded with the element width; `poke <name> <hex>[,...]`. Raw offset access is unchanged. The MCP tools `ff6_peek`/`ff6_poke` accept `name` (and `value`). - `tools/draft.py` and `tools/ff6sym.py` come from the workspace prototypes. They take paths from options or from `environment.toml` (`tools/ff6env.py`). The draft printer prints RAM-map names for WRAM operands (`rd8(g, vblank_flag)`, `party_pos.y`) and also accepts plain labels (`battle Rand`). `tools/ram_map_check.py` is the map verifier, moved from the workspace. ## Validation - Builds: debug, release, clang, mingw: 0 warnings. - `ctest` release (all, slow included): 13/13 passed (rom.ports 307 s/308 s). Debug `--fast`: 10/10 passed. - Shadow, `ff6cli --frames 9500 --input tests/inputs/newgame_first_battle.txt --port all=shadow`: battle/Rand **13/13 US, 16/16 JP, 0 mismatch** (unchanged). - Python: `tools/tests/test_gen_state.py` 7/7. `tools/tests/test_disasm_tools.py` all OK (skips without the disassembly). `tools/mcp/tests/test_ff6_drive.py` ALL OK, with the new name peek/poke checks. - `tools/ram_map_check.py`: 187 vars, 0 errors, 0 warnings, 158 JP listing checks passed. Fixes #7 🤖 Generated with [Claude Code](https://claude.com/claude-code)
187 vars, 4 structs, regions and RAM code images, US/JP checked (0 errors,
158 JP listing checks). New-game RNG seed measured: the title menu is event
command $AB, a blank SRAM gives $0D in $1F6D/$1FA1-$1FA5 (US and JP).
Open questions moved to #14, #15, #16, #17.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
core/state/state_gen.{h,c} generated from re/ram_map.toml (wram storage,
debug-build index checks); ff6_debug_var_find resolves name[i].field[j].
unit.state tests the accessors and the lookup on a fake WRAM. refs #7

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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!18
No description provided.