feat(opcodes): migrate to opcodes.toml as single source of truth; regenerate artifacts

- 248 opcodes seeded from Kelebek + corpus arg-types; 23 inferences migrated
- source = provenance (frida/unicorn methods = inference + confirm_by, not grounded)
- 0x90/0x97 enriched with depends_on + details
- differential-verified: SC0830/MENU disasm byte-identical, vm0 --test PASS, sweep 282/294

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-07-06 13:11:33 -04:00
parent cee746250b
commit 9f140fda83
3 changed files with 7880 additions and 98 deletions

1045
docs/opcode-reference.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,98 +1,30 @@
"""Himegari-specific opcode INFERENCE layer (sits on top of age_opcodes.py).
`age_opcodes.py` is the verbatim Kelebek table (opcode number + argc, validated 481/481).
Many opcodes have only engine-address labels (`u004xxxx`). This module records what the
top-frequency unnamed opcodes *mean*, inferred from operand types, disassembly context,
and neighbouring named ops (see `vm-map/himegari-opcode-notes.md` for the evidence).
These are INFERENCES, not ground truth. Fields:
name short mnemonic for the disassembler
category marker | structural | computational | draw | audio | adv | control
noop True = safe for the Godot VM v1 to skip (no state/visible effect expected)
False = has an effect; must be implemented (or knowingly stubbed)
confidence high | med | low
method how the inference was reached / how to confirm:
structure | context | harness (confirm via dialogue diff in Phase 4) |
frida (needs live capture) | unicorn (micro-exec)
note one-line rationale / caveat
Consumed by `sys4load.render_listing` (nicer disassembly) and, later, the Godot VM.
"""
from __future__ import annotations
INFERRED: dict[int, dict] = {
# ---- statement / scope scaffolding: zero-arg, no operands, bracket statements ----
0x1f4: dict(name="stmt-begin", category="marker", noop=True, confidence="high",
method="structure", note="zero-arg; opens scripts, pairs with stmt-end 0x1f5"),
0x1f5: dict(name="stmt-end", category="marker", noop=True, confidence="high",
method="structure", note="zero-arg; precedes exit/next-stmt, pairs with 0x1f4"),
0x1d5: dict(name="cond-block", category="marker", noop=True, confidence="high",
method="context", note="zero-arg; ALWAYS follows jcc — marks conditional body entry"),
0x1bc: dict(name="block-mark", category="marker", noop=True, confidence="high",
method="context", note="zero-arg; follows jcc/mov, precedes mov/ret — block boundary"),
0x1bf: dict(name="call-end", category="marker", noop=True, confidence="med",
method="context", note="zero-arg; call->0x1bf->stmt-end — end-of-call-statement marker"),
# ---- statement metadata carrying an id (tentative no-op, confirm via harness) ----
0x21b: dict(name="line-id?", category="marker", noop=True, confidence="med",
method="harness", note="1 imm; mov->0x21b->stmt-end; near save/load-messkip — likely line/stmt id, verify not msg-control"),
0x1d2: dict(name="stmt-desc?", category="marker", noop=True, confidence="med",
method="harness", note="2 imm; immediately after stmt-begin 0x1f4 — statement descriptor?"),
0x258: dict(name="decl?", category="marker", noop=True, confidence="low",
method="harness", note="2 imm; runs in a chain right after script-entry 0x259, enumerating ids — prologue declaration/registration?"),
# ---- structural ----
0x71: dict(name="label-def", category="structural", noop=True, confidence="high",
method="structure", note="1 imm; count == T1 table size -> the label/anchor T1 indexes. v1 no-op; revisit if menu/callback dispatch looks up by id"),
# ---- input / UI hotspot (u0041Bxxx/Cxxx widget module; see himegari-opcode-notes.md) ----
0x90: dict(name="hotspot-branch", category="input", noop=False, confidence="high",
method="structure", note="argc7: x y w h + 3 code targets (0xffffffff=unused). "
"Cursor/input hotspot hit-test; branches per interaction (inferred hover-enter->flag=1 / "
"hover-leave->flag=0 / click->run-action), FALLS THROUGH to pc+1 on no-match "
"(design-confirmed: enc.len 15 lands on the next stmt). HEADLESS: fall through = correct "
"no-input behaviour (proven safe by 279 CLEAN scenes). Occurs ONLY in a shared ADV-chrome "
"subroutine, identical in all 301 ADV scripts (8/script = 5 imm-rect buttons @y=572 "
"x=684..772 20x20 toggling G[0x6c9..0x6cd] + 3 local-operand keyed forms). Model live in A2; "
"confirm target->state mapping via input capture/Frida."),
0x97: dict(name="hotspot-reg?", category="input", noop=False, confidence="med",
method="frida", note="argc5: v1 v2 1 1 <action-id imm>; NO code targets. Interleaves with "
"0x90 in the ADV-chrome subroutine -> companion register-hotspot / set-widget-action "
"(trailing imm = action id 0x0/0x7/0x8). u0041C150, same widget cluster as 0x90/0x91/0x92/0x95."),
# ---- computational (exact behaviour via Unicorn micro-exec) ----
0x215: dict(name="count?", category="computational", noop=False, confidence="med",
method="unicorn", note="2 args -> writes global then result tested >0 (gre/lt) — count/search-returns-index helper"),
0x1a2: dict(name="resolve-handle?", category="computational", noop=False, confidence="low",
method="frida", note="1 local-ptr from lookup-array, then create-texture — resolves a looked-up resource/handle"),
# ---- ADV / text-display (effectful; confirm via Frida) ----
0x7a: dict(name="text-param?", category="adv", noop=False, confidence="med",
method="frida", note="3 args (imm/computed/imm); sub computes a value then 0x7a then show-text — text speed/wait/window param"),
# ---- draw / UI (0x420-0x421 graphics family; effectful; Frida) ----
0x202: dict(name="draw-blit?", category="draw", noop=False, confidence="med",
method="frida", note="5 args (coords/sizes); preceded by coord arithmetic, near draw ops"),
0x203: dict(name="draw?", category="draw", noop=False, confidence="med",
method="frida", note="4 args; chains with 0x202/draw-texture"),
0x1f7: dict(name="ui-elem?", category="draw", noop=False, confidence="med",
method="frida", note="2 args; 0x420 family, pairs with 0x1fa — create/begin a UI element"),
0x1fa: dict(name="ui-clear?", category="draw", noop=False, confidence="med",
method="frida", note="1 arg (element id); follows 0x1f7 — show/hide/clear UI element by id"),
0x217: dict(name="gfx-geom?", category="draw", noop=False, confidence="low",
method="frida", note="4 global-ints; part of a 0x217/0x218/0x21a geometry chain"),
0x218: dict(name="gfx-geom?", category="draw", noop=False, confidence="low",
method="frida", note="4 global-ints; chains with 0x21a/0x217"),
0x21a: dict(name="gfx-geom?", category="draw", noop=False, confidence="low",
method="frida", note="4 global-ints; chains with 0x218/0x217"),
0x1ff: dict(name="draw?", category="draw", noop=False, confidence="low",
method="frida", note="4 args (global+imms); follows 0x217, then call"),
# ---- audio (0x41D family, near play-sound-effect 0xb4) ----
0xb6: dict(name="snd-ctrl?", category="audio", noop=False, confidence="low",
method="frida", note="1 imm; self-chains, 0x41D family near play-sound-effect/0xb5 — sound channel/volume/stop control"),
}
# Names ending in "?" are low/medium-confidence guesses; the disassembler shows them
# so listings read better than `u004xxxx`, but the VM must not treat non-noop ops as
# no-ops without Frida/Unicorn/harness confirmation (see `method`).
# DO NOT EDIT -- generated from vm-map/opcodes.toml by tools/opcodes_build.py --build
"""Inferred Himegari opcode semantics (generated). sys4load reads INFERRED[op]['name']."""
from __future__ import annotations
INFERRED: dict[int, dict] = {
0x71: dict(name='label-def', category='structural', noop=True, confidence='high', source='investigation', summary='1 imm; count == T1 table size -> the label/anchor T1 indexes. v1 no-op; revisit if menu/callback dispatch looks up by id'),
0x7a: dict(name='text-param?', category='adv', noop=False, confidence='med', source='inference', summary='3 args (imm/computed/imm); sub computes a value then 0x7a then show-text — text speed/wait/window param'),
0x90: dict(name='hotspot-branch', category='input', noop=True, confidence='high', source='investigation', summary='cursor/input hotspot hit-test: rect (x,y,w,h) -> 3-way branch on interaction, else fall through to pc+1'),
0x97: dict(name='hotspot-reg?', category='input', noop=True, confidence='med', source='inference', summary='companion register-hotspot / set-widget-action (argc5: v1 v2 1 1 <action-id>; NO code targets)'),
0xb6: dict(name='snd-ctrl?', category='audio', noop=False, confidence='low', source='inference', summary='1 imm; self-chains, 0x41D family near play-sound-effect/0xb5 — sound channel/volume/stop control'),
0x1a2: dict(name='resolve-handle?', category='compute', noop=False, confidence='low', source='inference', summary='1 local-ptr from lookup-array, then create-texture — resolves a looked-up resource/handle'),
0x1bc: dict(name='block-mark', category='marker', noop=True, confidence='high', source='inference', summary='zero-arg; follows jcc/mov, precedes mov/ret — block boundary'),
0x1bf: dict(name='call-end', category='marker', noop=True, confidence='med', source='inference', summary='zero-arg; call->0x1bf->stmt-end — end-of-call-statement marker'),
0x1d2: dict(name='stmt-desc?', category='marker', noop=True, confidence='med', source='harness', summary='2 imm; immediately after stmt-begin 0x1f4 — statement descriptor?'),
0x1d5: dict(name='cond-block', category='marker', noop=True, confidence='high', source='inference', summary='zero-arg; ALWAYS follows jcc — marks conditional body entry'),
0x1f4: dict(name='stmt-begin', category='marker', noop=True, confidence='high', source='investigation', summary='zero-arg; opens scripts, pairs with stmt-end 0x1f5'),
0x1f5: dict(name='stmt-end', category='marker', noop=True, confidence='high', source='investigation', summary='zero-arg; precedes exit/next-stmt, pairs with 0x1f4'),
0x1f7: dict(name='ui-elem?', category='draw', noop=False, confidence='med', source='inference', summary='2 args; 0x420 family, pairs with 0x1fa — create/begin a UI element'),
0x1fa: dict(name='ui-clear?', category='draw', noop=False, confidence='med', source='inference', summary='1 arg (element id); follows 0x1f7 — show/hide/clear UI element by id'),
0x1ff: dict(name='draw?', category='draw', noop=False, confidence='low', source='inference', summary='4 args (global+imms); follows 0x217, then call'),
0x202: dict(name='draw-blit?', category='draw', noop=False, confidence='med', source='inference', summary='5 args (coords/sizes); preceded by coord arithmetic, near draw ops'),
0x203: dict(name='draw?', category='draw', noop=False, confidence='med', source='inference', summary='4 args; chains with 0x202/draw-texture'),
0x215: dict(name='count?', category='compute', noop=False, confidence='med', source='inference', summary='2 args -> writes global then result tested >0 (gre/lt) — count/search-returns-index helper'),
0x217: dict(name='gfx-geom?', category='draw', noop=False, confidence='low', source='inference', summary='4 global-ints; part of a 0x217/0x218/0x21a geometry chain'),
0x218: dict(name='gfx-geom?', category='draw', noop=False, confidence='low', source='inference', summary='4 global-ints; chains with 0x21a/0x217'),
0x21a: dict(name='gfx-geom?', category='draw', noop=False, confidence='low', source='inference', summary='4 global-ints; chains with 0x218/0x217'),
0x21b: dict(name='line-id?', category='marker', noop=True, confidence='med', source='harness', summary='1 imm; mov->0x21b->stmt-end; near save/load-messkip — likely line/stmt id, verify not msg-control'),
0x258: dict(name='decl?', category='marker', noop=True, confidence='low', source='harness', summary='2 imm; runs in a chain right after script-entry 0x259, enumerating ids — prologue declaration/registration?'),
}

6805
vm-map/opcodes.toml Normal file

File diff suppressed because it is too large Load Diff