Read a moby handler: the chain works, with two caveats and a 110 discrepancy

Followed the chain through -- dispatch table to handler address to disassembly --
and read level 0's class 2 handler at 0x00380a88:

    0x00380a84: jal   0x2ee0d0
    0x00380a88: .word 0x0240202d          <- VU1 microcode, not a failure
    0x00380a8c: lwc1  $f12, 0x40($s1)
    0x00380a98: addiu $a0, $s0, 0x20
    0x00380aa0: swc1  $f0, 0x18($s4)
    0x00380ab0: swc1  $f0, 0x14($s4)

Floats out of one structure, written back into another, with VU1 work alongside --
what a transform update should look like. The chain from an asset observation to the
game's own code is now complete and usable.

TWO CAVEATS, both learned by hitting them:

VU1 microcode interleaves with CPU code. 0x0240202d is a COP2 opcode, not an
undecodable word. A tool that counts .word lines as failures is counting the wrong
thing -- a trap I walked into earlier today with the region walkers, now recorded
so it is not repeated.

Handlers are not all independent functions. Level 0's class 2 is at 0x380a88 and
class 0x0E at 0x380a90 -- EIGHT BYTES apart -- and 72 of the 5,788 records sit
within 16 bytes of the one before them. Consecutive classes share one routine with
per-class entry points inside it, so reading "a handler" gives a fragment. That
matters downstream: a class's behaviour is not one function, and assuming
otherwise would misattribute shared code.

A DISCREPANCY WITH THE REFERENCE

The decomp reports 5,598 of 5,788 moby handlers (96.7%) preceded by a jr ra within
three words. Measured here, the same way, over the same 5,788 records: 5,488
(94.8%). Same population, same test, 110 handlers different.

Both figures support the premise, so nothing turns on it, and I am recording it
rather than picking the number that suits. The reference measured on 2026-10-02
against its own pinned overlay set, so a method or version difference is as
plausible as a data difference and there is no basis here for saying which. The
test asserts the premise (>90%) and deliberately NOT either exact figure.

Asserted in moby_handlers_are_overwhelmingly_function_entries.

264 tests.
This commit is contained in:
2026-10-14 03:40:59 +02:00
parent d611026f07
commit 18af702420
2 changed files with 142 additions and 0 deletions
+44
View File
@@ -3196,3 +3196,47 @@ The camera and sound handler addresses fall inside section 6 of the same overlay
which the working disassembler can read directly.
Asserted in `camera_and_sound_dispatch_tables_decode_at_their_documented_widths`.
## The handler chain works, with two caveats and one discrepancy
With the dispatch tables decoded and the disassembler fixed, a moby handler can
actually be read. Level 0's class 2, handler `0x00380a88`:
0x00380a84: jal 0x2ee0d0
0x00380a88: .word 0x0240202d <- VU1 microcode, not a decoding failure
0x00380a8c: lwc1 $f12, 0x40($s1)
0x00380a98: addiu $a0, $s0, 0x20
0x00380aa0: swc1 $f0, 0x18($s4)
0x00380ab0: swc1 $f0, 0x14($s4)
Floats read out of one structure and written back into another, with VU1 work
alongside -- which is what a transform update should look like.
### Two caveats before reading one
**VU1 microcode is interleaved with CPU code.** `0x0240202d` is a COP2 opcode, not
an undecodable word. A disassembly window will run `.word` lines that are
instructions in a different processor, and a tool that counts them as failures is
counting the wrong thing.
**Handlers are not all independent functions.** Level 0's class 2 is at
`0x380a88` and class `0x0E` at `0x380a90` -- **eight bytes apart** -- and 72 of the
5,788 records sit within 16 bytes of the one before them. So consecutive classes
share one routine with per-class entry points inside it, and reading "a handler"
gives a fragment, not a whole function.
### And a discrepancy with the reference
`docs/MOBY-DISPATCH-TABLES.md` reports 5,598 of 5,788 moby handlers (96.7%)
preceded by a `jr ra` within three words. Measured here, the same way, over the
same 5,788 records: **5,488 (94.8%)**.
Same population, same test, 110 handlers different. Both figures confirm the
premise, so nothing turns on it, and the residual is recorded rather than explained
away. The reference measured on 2026-10-02 against its own pinned overlay set, so
a difference in method or version is as plausible as a difference in the data, and
there is no basis here for saying which. The test asserts the premise (>90%) and
deliberately not either exact figure.
Asserted in `moby_handlers_are_overwhelmingly_function_entries`.