VM inventory
A census of every VM-shaped subsystem in the retail runtime - anything that walks a bytecode or record stream through a dispatcher, or advances a per-entity state byte through a switch each frame - with three independent facts for each: how completely it is decoded, whether the Rust port implements it, and whether a live caller in the port reaches it.
Three facts to keep apart
- “Five VMs” is an orientation, not a census. Five bytecode-and-state drivers share the actor model. The
0x2Fextension, the0x4Csub-dispatcher and the battle-action, world-map and tile-board state machines are separate dispatchers with their own tables. - “Ported” is not “live”. Port status and reachability are separate columns. A faithful, tested module that nothing outside its crate calls is inert.
- Whether the disc uses an op is a third fact. A ported, live handler can still have no carrier - no shipped scene issuing that opcode. For the field VM a disc-wide opcode census answers it per arm, and its zeros separate “no fixture drives this” from “there is nothing to drive”.
How the dispatchers nest
The inventory
| Subsystem | Driver | Op / state space | Port |
|---|---|---|---|
| Actor / sprite VM | FUN_801D6628 | 13 opcodes, table 0x801CED70 | engine-vm root; live in the shop widget choreography |
| Move VM | FUN_80023070 | 71 opcodes 0x00..0x46, table 0x80010778 | move_vm |
| Move-VM extension | FUN_801D362C | 61 sub-opcodes, table 0x801CE868 | move_vm::ext |
| Motion VM, pursue / patrol | FUN_8003774C | 22-slot table 0x80010EE0 | motion_vm |
| Motion VM, scripted | FUN_80038158 | 32-slot table 0x80010FE8, ops 0x01..=0x20 | ambient_motion |
| Field / event VM | FUN_801DE840 | 43 opcodes 0x21..0x4F with gaps | field |
| Field VM MENU_CTRL | inline in the field VM | 16 outer nibbles; two reach the error printer | field::step::menu_ctrl |
| Effect VM | FUN_801E0088 | none - see below | effect_vm |
| Battle-action SM | FUN_801E295C | 256-slot table 0x801CED44, sparse bands, no default arm | battle_action |
| World-map entity SM | FUN_801DA51C | 5 states | world_map |
| Tile-board walk SM | FUN_801EF2B0 | 15 states, table 0x801CF65C | engine-minigames::tile_board |
| Cast-module phase machine | one tick per PROT 0903..0966 image | per image: the ctx+0x279 byte through a word table or a compare chain | cast_module_ticks |
| Per-actor anim dispatch | FUN_80021DF4 | 7 dispatch bytes at actor[+0x5A] | anim_vm |
| Title-screen tick | FUN_801DD35C | 25-slot table 0x801CF244 | title_overlay |
| Per-prim render dispatch | FUN_80043390 | 20 kind slots × 4 alpha banks | prim_dispatch |
| Status-effect ticker | FUN_801E752C | per-actor condition set | status_effects |
Every row has a live caller in the port. The battle-action state machine is the one row whose decode is graded partial: its table is sparse and not every band is mapped.
The cast band is 64 dispatchers and one row
Each of the 64 slot-B images carries its own phase machine over the same context byte, so the “cast-module phase machine” is not one interpreter - it is a family that shares an ABI. The battle-action state machine re-enters the paged module’s tick every frame and advances only on a zero return. See cast modules.
The effect VM has no opcode space
A low opcode count is not evidence of an incomplete decode, and here the count is zero by construction. FUN_801E0088 has no central switch on a per-slot opcode byte: the bytes that look like state tokens are 5.3 fixed-point wait counters, and the walker is a pair of countdown-driven cursor walks. Searching for its opcode table is a documented dead end.
Ported but inert
“Inert” is a reachability statement, not a correctness one. Two support modules stay inert today: the title sprite-emit primitives, and a standalone walker over the 0x2F dispatcher. The second is owed no host - a disc-wide reference scan finds exactly one caller of that dispatcher, and the port hosts that caller.
See also
The per-row decode status, the two-ports-of-one-function note on the title tick, the inert list and the count of dispatcher copies are in docs/subsystems/vm-inventory.md.