How it works

Almost every PSX game has a built-in archive that bundles the small files together so the disc can stream them efficiently. Legaia's archive is PROT.DAT, and it has its own table of contents (TOC) — a list saying "entry N starts at sector S and is L bytes long". Before the game can do anything, it has to read that table into RAM. That's job one.

Job two is wiring up a small asset-type dispatcher. The PROT entries don't all hold the same kind of data — some are textures, some are 3D meshes, some are dialog blobs, some are animation containers. Each entry's first byte is a type tag, and there's a single function that reads that tag and routes the bytes to the right per-format parser. Once the dispatcher's helper tables are populated, every later "load this entry" call works.

Job three: the boot code reaches a top-level game-mode state machine. This is a 28-entry table where each slot is a function pointer for one major mode of the game — boot, title, field, battle, world map, menu, cutscene, etc. The mode pointer changes whenever the game transitions; the per-frame loop just calls "whatever the current mode's handler says". The title-screen overlay is loaded next, and the actor VM inside it starts ticking the splash animation.

One important quirk: the script that drives every running script — the field VM — is not in the main executable. It lives in a RAM overlay loaded from the disc when you enter a town or field map. That's why the boot path here is so short: most of the gameplay code isn't in SCUS_942.54 at all.

TOC loader

Function
FUN_8003E4E8
Reads
First three sectors of PROT.DAT (= 6 KB)
Lands at
0x801C70F0 in RAM
Called from
FUN_8003EFE8 and FUN_8003F08C at boot

The on-disc TOC and the in-RAM TOC have different strides — the on-disc-to-in-RAM transformation runs once at boot, but its function hasn't been reversed yet. See the PROT.DAT format spec for the byte layout.

After the TOC is in RAM, two resolvers are usable:

ResolverModeUsed by
FUN_8003E8A8Index-based (PROT entry number in)Streaming loader, dev-build sound branch
FUN_8003E6BCPath-based (resolves data\battle\efect.dat, h:\PROT\FIELD\<scene>\…)Most retail-build code paths

The path-based opener runs the dev-style filename through the CDNAME.TXT name map to find the index, then delegates to the index-based resolver. It's a thin layer.

Asset-type dispatcher

Function
FUN_8001F05C
Calling convention
result = FUN_8001F05C(byte *src_data, u32 type_and_size, int param3, int copy_only)
Encoding
type_and_size packs the type byte in the high 8 bits, size in the low 24 bits

Every TIM, TMD, MES, ANM, etc. is reached through this one function. The boot path doesn't call it itself — it just makes sure the buffer pointers it writes to are valid. FUN_80020224 (the asset descriptor walker) is one of the dispatcher's two static call sites and is invoked from the town overlay's FUN_801D6704 (MAIN_INIT) at runtime. See Asset loader for the full story.

Game-mode state machine

The 28-mode state machine table at 0x8007078C is the top-level "what is the game doing" dispatcher. Each entry is a (handler_addr, …) tuple corresponding to a major mode — boot, title, field, battle, world map, menu, cutscene, and so on.

The script VM that drives every running script is not in SCUS_942.54. It lives in RAM overlays at 0x801C0000+, loaded on demand:

VMDriverLives in
Actor / sprite VMFUN_801D6628Title-screen overlay
Field / event VMFUN_801DE840Town / field overlay
Effect VM clusterFUN_801DE914 / 801DFDF8 / 801E0088Battle overlay

Debug flags

Two RAM bytes that several subsystems branch on at boot time and beyond:

AddressRole
_DAT_8007B8C2Dev/retail build toggle. Sound init, the field loader, and the monster-bank loader all carry an "if dev" branch keyed on this byte.
_DAT_8007B98FSeparate debug-mode flag (NA build offset; JP retail uses 0x07D51F, an 0x1B90 build-shift).

Neither flag has a writer in SCUS_942.54. The input dispatcher FUN_8001822C reads them but doesn't write them. The writers must live in an unswept overlay (most likely the option-menu / cheat-menu cluster), and TCRF GameShark codes confirm both flags are runtime-writable.