At a glance

Main RAM
2 MB at 0x80000000..0x801FFFFF; the 1 KB scratchpad at 0x1F800000 is separate silicon
Executable
SCUS_942.54 loads at 0x80010000 (~960 KB of code + data); its data segment holds every persistent global
Game state block
0x80084140: four character records at 0x80084708 + n*0x414, story flags 0x80085600, item bag 0x80085958 - the bytes a save is composed from
Overlay window
0x801C0000+, 256 KB; field / battle / menu overlays all load at 0x801CE818, one at a time
Mode selector
0x8007B83C picks which overlay's loop runs next frame
Provenance
Each row names a FUN_ address, a dump file or the cheat code that pinned it - see how we know
Full table
docs/reference/memory-map.md - grep it for your address

Region map

code SCUS_942.54 data runtime buffers overlay window 0x1F800000 scratchpad, 1 KB 0x80010000 .. 0x800FFFFF 0x80100000 .. 0x801BFFFF BIOS 0x80000000 0x80100000 0x801C0000 0x80200000 0x800EC9E8 battle actor pool 0x80084140 game state: character records, story flags, item bag 0x801CE818 field 0897 / battle 0898 / menu 0899 - one resident not main RAM: tick byte, field-VM flag word, primitive cursor
Low addresses on the left, drawn to scale. The executable owns nearly half the machine; the overlay window is where the per-mode code goes.
RangeSizeHolds
0x80000000..0x8000FFFF64 KBBIOS workspace: kernel, thread state, exception vectors. Game code never touches it.
0x80010000..0x8005FFFF320 KBSCUS_942.54 code: game logic plus the statically linked PsyQ libraries (libsnd, libspu, libcd, libapi).
0x80060000..0x800FFFFF640 KBSCUS_942.54 data: jump tables, static game tables, then the live game-state block and the battle actor pool.
0x80100000..0x801BFFFF768 KBRuntime data buffers: asset slabs (TIMs, TMDs, sound banks), per-scene state, the dialog buffer.
0x801C0000..0x801FFFFF256 KBOverlay window - the in-RAM PROT TOC at 0x801C70F0, one resident overlay at 0x801CE818, persistent effect state in 0x801F0000+, and the stack growing down from the top.
0x1F800000..0x1F8003FF1 KBPSX scratchpad - per-frame transients and the field-VM flag word. Table below.

Interactive map

Order: low addresses on top. Hover for a one-liner, click for full detail.

BIOS / OS area
0x80000000 - 0x8000FFFF PSX BIOS workspace, kernel TCB, exception vectors
SCUS_942.54 (the game executable)
0x80010000 - 0x8005FFFF SCUS code (.text + libsnd / libspu / libcd / libapi)
0x80060000 - 0x800FFFFF SCUS .rodata + .data + .bss (jump tables, global state, character records, story flags)
Key globals
0x801C9370 Battle 8-actor pointer table
0x80084708 + n*0x414 Per-character record (4 slots; display name at internal +0x2A7). Slot 3 (Terra) runs into the story-flag bitmap at 0x80085600, so its tail (+0x2BC..) aliases the globals.
0x80085958 Item inventory (2-byte stride, alternating id/count; live window is 128 or 256 slots, not the 72 the cheat corpus spans)
0x80074358 - 0x80074367 4×u32 active-ability bitmask
0x800845B4 Point Card counter (u32; unmapped by every public cheat archive). Shop buy commit FUN_801db7f4 accrues price/20 per unit when item 0xFE (the Point Card) is held, cap 9,999,999. GameShark-style max: 800845B4 967F + 800845B6 0098.
0x801C70F0 In-RAM PROT.DAT TOC (loaded at boot)
0x8007BD24 Pointer to active battle context struct
0x8007BC3C + 0x801F351C..3528 World-map render-pipeline gate flag + params
0x8007C34C..0x36C Actor-list slot table (7 linked-list heads consumed by FUN_8002519c)
0x800EB654 Active battle context struct (pointed to by 0x8007BD24)
Runtime data buffers
0x80100000 - 0x801BFFFF Runtime data buffers (asset slabs, per-scene state, dialog buffer)
Runtime overlay window
0x801C0000 - 0x801CFFFF Overlay header / shared dispatch region
0x801D0000 - 0x801EFFFF Overlay code (varies by game mode: title / town / battle / menu)
0x801F0000 - 0x80205FFF Extended overlay region (used by 256 KB town overlay)
Not main RAM: the scratchpad
0x1F800000 - 0x1F8003FF 1 KB PSX scratchpad: per-frame tick byte, the field-VM transient flag word, the primitive write cursor, tile-flag bitmap base
Stack
~0x801FFF00 (top, grows down) CPU stack

Click any row above to see details.

How to read an address

  • Every address is a PSX virtual address. Main RAM starts at 0x80000000, so 0x80084708 is byte 0x84708 into the 2 MB. DAT_8007B83C is Ghidra's automatic label for data at that address, the way FUN_8003E4E8 labels a function (key functions).
  • The executable is only the bottom of the picture. Its data segment holds the persistent state, but most game logic lives in overlays - chunks of code streamed off the disc per game mode.
  • An overlay-window address is ambiguous on its own. Field, battle and menu code all load at the same base and only one is resident, so the same address means different things in different modes. Rows in that range say which overlay they belong to.
  • 0x1F800000 is not main RAM. It is the scratchpad, and a flag a script tests may live there rather than in the 2 MB map.
  • "Exact semantics open" is a real value. Where a global is only partly understood the row says so rather than guessing.

Game-mode state machine

The game is a loop over a mode - title, field, battle, FMV, menu - and one cell picks which mode runs next frame. These are the companions of the 28-entry × 24-byte mode-dispatch table at 0x8007078C (the table itself is on the boot page).

AddressTypePurpose
0x8007B83Cu16Next game-mode index (master mode selector): 0x02 field-launch, 0x03 field-run, 0x15 battle, 0x1A STR FMV. Also indexes the mode table, whose +0x14 param seeds the lower 16 bits of the field-VM flag word 0x1F800394 on each mode switch. The front end writes it six times on the way from the logo to the field, and each store lives in the handler that hands off - there is no table field naming the next mode, which is why a trace that samples the word once, early, reads the title screen as running under the logo-init mode rather than the card mode it actually runs under.
0x8007B87CindexMode index rendered on the dev CONFIG / test screen; indexes the same table at stride 24, which independently confirms the entry stride.
0x8007B7ACmodeReads as the outgoing / previous game mode: the mode-entry prologue gates its whole field-state snapshot on == 3 (MAIN MODE). An inference from the guard's purpose, not a pinned writer.

Static (SCUS-resident) globals

These live in the executable's data segment and mean the same thing in every mode. The persistent game state - the values a save file is composed from - is all here.

AddressTypePurpose
0x80084708 + n*0x414u8[0x414]Per-character record (4 slots; display name at +0x2A7). Slot 3 (Terra) runs into the story-flag bitmap, so its tail aliases the globals. Layout: save record.
0x80085600..0x80085800u8[512]Story-flag bitmap window (Door of Wind, town-visited markers).
0x80085758u8[]Fourth flag bank - the bitfield the field-VM SET / CLEAR / TEST ops address as (idx >> 3, 0x80 >> (idx & 7)). The opcode encoding spans idx = 0x000..=0xFFF plus 0x8000..=0x8FFF, so it is not a fixed 256-bit array.
0x80085958u8[]Item inventory (= save block +0x1818), 2-byte stride (id, count). The active window is 128 or 256 slots - never 72, which is the "Have 99 Items" cheat's page span. Mechanism: inventory.
0x80084540u16The loaded scene's raw CDNAME define - two above the extraction-frame index (town01 3, town0c 0x15). The "Map Modifier" cheat; View Credits writes 0x030C.
0x80088758 / 0x8007B806record[] / s16Resident CDNAME define table (16-byte records, define at +0xC) and its count - what the Door items' travel arts scan for a destination.
0x80073F00i16Dialog pager auto-press countdown: op 4C 89 sets it, and the waiting box presses confirm for the player when it runs out.
0x80084570u32Game-time play counter - advances per frame (~60/s), not per second; the save screen divides it down for HH:MM:SS.
0x80084594 / 0x80084598u8 / u8[]Party member count / member ids (sorted insertion, cap 4). 0x80084599 / 0x8008459A are the Noa / Gala join gates.
0x8008459C / 0x800845A4u32Party gold / casino coin bank.
0x800845B4u32Point Card counter (unmapped by every public cheat archive). The shop buy commit accrues price/20 * qty when item 0xFE is held, capped at 9,999,999.
0x8008444Cu32Persistent fishing-points counter; the lure row, rod stat and point-exchange purchase mask sit beside it at 0x80084450 / 0x80084454 / 0x8008446C (fishing).
0x80077828u8[]Per-monster steal table, 1-based id at +id*2, each entry [chance, item] - chance first. Not in the monster record. Steal table.
0x80076C10u8[0x18] × 103Screen-element placement table - the content boxes every battle plate, party panel and Muscle Dome layout derives its chrome from. One table, three names.
0x800743584×u32Active-ability bitmask; the party's per-character ability blocks are ORed into it each frame.
0x8007A6BCu16Shared "currently-acting character" HP/MP scratch - every "Infinite HP/MP" cheat hits this first.
0x8007B450u16Menu-request register the menu overlay polls each frame; also the field-VM STATE_RESUME (op 0x49) tristate register.
0x8007B5FCu32Encounter step counter, one word across doors; every writer is the same reroll routine, from five sites ("No Random Battles" writes 0x0377).
0x8007B6A8u8Save-anywhere allow flag: bit 0 of the scene header's second byte, stored at scene entry. The same bit raises the field-fog cap on every overworld.
0x8007B6F4 / 0x8007B790u16GTE H projection register (focal length / zoom; the "camera mode word" and "small maps" labels come from a cheat database reading the same word outside world-map mode) / camera pitch, the first of the angle trio.
0x8007BB80..0x8007BBA0u32 / i32Menu list-kernel state cluster: window-slide latch, pad-edge word, selected-row payload, scroll top, mode/result, selected row, class nibble, row count (field menu).
0x8007BB04 / 0x8007BB08ptrThe overworld's screen-curvature pair: the second holds a quadratic drop ramp, the first the table of screen-Y offsets built from it, which the overworld's leaves, the fog and the drop shadow add to each vertex's screen Y.

Battle globals

A battle is addressed through a handful of pointers and small per-seat arrays in the executable's data segment; the actors themselves live in a pool further up.

AddressTypePurpose
0x8007BD24 → 0x800EB654ptrBattle context pointer (0 in the field). +0x07 action-state cursor, +0x13 active slot, +0x276 tutorial byte, +0x279 cast-module phase, +0x28A battle-mode counter.
0x801C9370ptr[8]Battle actor pointer table: party in slots 0-2, monsters in 3-7.
0x800EC9E8 + n*0x2D4u8[0x2D4]Battle actor pool; HP at +0x14C, AP gauge at +0x170. Cheat citations.
0x8007BD0Cu8[4]Formation cell - per-slot monster id (monster m is actor slot m + 3). The AI picker switches on it, so each case is bespoke AI for one monster id.
0x8007BD10u8[]Per-seat character id, 1-based (1 Vahn, 2 Noa, 3 Gala): selects the record, the mesh install slot, the element row and the attack camera's jump table.
0x8007BD74ptrSide-band streaming buffer: one 0x10800-byte slot of summon.dat / readef.DAT at a time (summon / readef).
0x8007B6D8 / 0x8007B724u16[4] / u32Pending-SFX cue ring (counter at battle ctx +0x9) / last-played SFX id, the cue router's dedupe compare.
0x801F6950u32Battle-action overlay PRNG state - overlay-resident, so its draws never perturb the SCUS rand() stream.
0x801F69D8u32 + codeSlot-B overlay window: PROT 0900's jump-table head, the world-map band, and the paged per-spell cast module while a capture-class cast runs.

Asset chain and actor tables

How the loader and the renderer find what is resident: the in-RAM table of contents, the global mesh table every scene fills, and the linked lists the per-frame actor walk consumes.

AddressTypePurpose
0x801C70F0TOCIn-RAM PROT.DAT TOC, populated at boot. An entry's size is the sector gap to the next entry (PROT.DAT).
0x801C6EA4ptrCurrent world / scene struct pointer. Its +0x2E is the submode stamp and +0x40 the parked return state - a write-only word: no image loads it at any width, and a live read watch across a submode enter records none.
0x801C6ED8[CdlLOC, u32] × 34CD-XA streaming-clip table, slot i = file XA<i+1>.XA; built at boot by ISO9660 lookup, so it survives disc relayout (cutscene).
0x8007C018ptr[N]Global TMD pointer table, one writer. Entries [0..4] are the five character meshes; the rest is the scene's TMD pack. Details.
0x8007B774 / 0x8007BB38 / 0x8007B824 / 0x8007B6F8u32Its install counter / last installed index / per-pack start index / kingdom-TMD prefix offset (how far world-map actor kinds are shifted past the party meshes).
0x8007B7DC / 0x80083E58ptr / ptr[N]VDF buffer pointer / its parallel sub-entry pointer table, consumed for actor instance bring-up.
0x8007B888 / 0x8007B840ptrMOVE / MOVE2 buffer bases (scene-dependent; not installed into the TMD table).
0x8007C34C..0x8007C36Cu32[7]Actor-list slot table: seven linked-list heads the per-frame actor walk dispatches through node[+0x0C]; five are separate render passes.
0x8007C348 / 0x8007C364u32Actor allocator free-list stack / player context pointer (0x80083794 in the captures; +0x10 carries the encounter-active flag).
0x801C6460 / 0x801C66A0u16[64] / slotsScratchpad slot table written by op 0x4C / 64-slot ramp scheduler pool (stride 0x20).
0x8007326C / 0x8007329Crows / ptr[2]TMD per-mode descriptor table (6 × 8 B) / two pointers between it and the widget class table - role unidentified, recorded so they are not read as the class table's head.
The global TMD pointer table

Every populated entry [0..DAT_8007BB38] is a post-fixup Legaia TMD (magic 0x80000002, group descriptors at +0xC, stride 0x1C). The sole writer is the installer at FUN_80026B4C @ 0x80026BA8; its store through gp[+0x820] is what hides the walker counter from Ghidra's xref database. A settled field-scene snapshot (dolk) holds 143 entries: five character meshes from PROT 0874 section 0, then a contiguous 138-entry scene pack installed by the single descriptor walk. Type-0x05 slot-4 bodies never install here - only dispatcher cases 0x02 / 0x09 reach the installer. Consumers: the world-map top-view renderer, the SCUS and overlay actor allocators, the table walker and the per-party-member equipment-conditional group patch (character mesh).

0x80076C10 - one table, three names

Three subsystems index this array and each named it after itself - a battle "pose-slot array", the party-panel "publish target", the Muscle Dome "element layout table". They cite the same base and the same 0x18 stride; a record is a screen-element placement. The clone helper FUN_801D5778 writes dst[+0xA] = src[+0xA] - 0x140, and 0x140 is 320, the display width: the field is a screen X and the operation is "stage this element one screen to the left".

OffsetField
+0x00 / +0x01element id, seat A / seat B (usually equal; records 41 / 42 carry them byte-swapped)
+0x02 / +0x04seat A x / y
+0x06 / +0x08content width / box height, shared by both seats (0x0C for the plate-run family; roster panels 50, framed windows 120 / 42 / 28 / 26)
+0x0A / +0x0Cseat B x / y - the pair FUN_801D5778 pushes by a screen width; which seat is parked is per record, so "from / to" is the safe name
+0x0E / +0x0Fkind, seat A / seat B
+0x10 / +0x1213 on the framed-window and roster rows, else 0, and no spawn arm reads it / zero in all 103 records
+0x14content string pointer, measured by the rendered-width kernel FUN_80035F04 into +0x06; the battle name plaque points it at the actor's display-name buffer actor+0x1BC (not an animation descriptor)

103 initialised records run 0x80076C10..0x800775B8; index 129 would be the steal table, and the placement shape stops at 103 (every coordinate within ±416). A record is a content box; the chrome is derived, not stored - pen = (x, y - 2), plate = (x - 8, y - 6) sized (w + 16, 20). Parser legaia_asset::screen_elements; packet evidence on battle.

Sound + audio path

The sound subsystem keeps a small cluster of path strings and state words in BSS - what tells the loader to look under sound\, which bank is resident, and the handshake that swaps one BGM for another.

AddressPurpose
0x8007B380..0x8007B3DCPer-extension flag/mode table plus the path-string cluster ("sound\", ".spk", ".LZS", "bse.dat", ".dpk", ".MAP", ".PCH", ".pac", "STR"). 0x8007B3A4 in the middle is not sound data - it is the equipment-swap selector table (character mesh).
0x8007B750Sound flag word coordinating the BGM track-swap handshake (bit 1 pause, bit 3 load settled, bit 4 release ack) - audio.
0x8007B8D0Sound subsystem current-bundle pointer (gp+0x5B8): bse.dat's 0x1800-byte buffer during battle, repointed at a scene's prescript bundle on every field load - bse.dat.
0x8007B64Bu8Backdrop last-object keep flag (gp+0x333): zero means the battle loader FUN_800513F0 trims object index 1 from both backdrop actors; one writer, the field handoff FUN_801D9E1C.
0x8007B990Runtime SFX descriptor-bank record table (gp+0x678), bse.dat's in battle. Written once by FUN_8001FA88; read by the cue router FUN_8004FE5C and the overlay-0971 sound test, both rewriting byte +4 (category) of record[cue_id - 0x200].
0x8007B910 / 0x8008457CLive audio level (0..255, halved into libsnd's 0..0x7F by every reader) / its persistent reference. Not screen brightness - that is 0x8007B440.
0x8007BB20..0x8007BB34Timed sound-source auto-release: armed flag, latched level, caller tag, deadline, elapsed (advanced by the tick byte, so the deadline is cadence-invariant).
0x8007BAC8 / 0x8007BC64BGM request id / the music_01 bank's raw define (990): the pool base for ids ≥ 2000 (music tracks), and for a scene-local id the fallback load + 2 - global slot 2, never a scene bank. The request id has four writers on the whole disc, all in the field overlay: the music opcode’s two arms, the developer menu’s sound-test row, and a conditional clear inside the per-scene initializer - so the scene loader clears the track and the script installs it.
0x80070536Bound voice id of the field-BGM sound source, written at track attach.
0x800788B8Streamed-voice clip duration table, 0x110 entries (index = cue id − 0x100), read by the arts shout and the Seru cast voice alike. Live rows run to 0x10F with interior zero runs; neither reader bounds the index, so a consumer modelling a shorter table drops the high cues in silence.
0x8007B854Ambient-particle master gate. One field-VM opcode raises it and its neighbour clears it, both stores in a jump delay slot; of its six references disc-wide none is pad state, so a field script decides per scene whether ambience emits at all.
0x801CD2B8 / 0x801CD2C0SsAPI slot-allocation bitmap / 16-entry per-slot sequence-state pointer table.
0x8007BD30 / 0x8007BD5CEffect-runtime pool (16-byte head + 128 child + 32 master slots) / effect 2-pack wrapper buffer pointer - effect VM.
0x8007B7F8 / 0x8007B81CCosine / sine views of the shared trig LUT (4096 * sin over 5120 i16 entries at 0x80070A2C - one revolution plus the quarter turn cosine needs, which is why consumers mask the angle with 0xFFF).

Debug flags and the pad

AddressPurpose
0x8007B8C2Dev/retail loader-path selector: 40 lh reads, written once at cold boot to 1. Details.
0x8007B98FIn-game debug menu enable - byte 3 of the debug-mode word 0x8007B98C. Poking it to 1 brings up the debug menu on SELECT+Triangle (dev menu).
0x8007B7C0 / 0x8007B450Debug-dispatch trigger / parameter slot.
0x8007B850Per-frame held button mask, packed (face/shoulder byte in bits 0-7, dpad/system byte in bits 8-15); port 1 fills the high half only in debug mode. Engine mirror retail_pad.
0x8007B7C4 / 0x8007B874Changed-this-frame mask / newly-pressed edge mask.
0x80089128 / 0x8007B938 / 0x8007B93C32-entry held-mask history ring / its AND (held for the full window) / the auto-repeat pulse the menus use, rearming every 8 vsyncs.
0x8007B868Dev/dual-mode gate the actor-sound family checks (retail 0); its only stores are a boot store of a constant 0 and a bit-clear, so the developer screens it gates (Baka Fighter's keyframe editor among them) are unreachable on a retail disc.
0x8007B8C2 - the build-mode selector

Every one of its 40 read sites splits the same way: non-zero opens assets by PROT-TOC index through the in-RAM table; zero opens by filename through FUN_800608F0, whose whole body is break 0x103 - a PsyQ dev-station host trap retail hardware cannot service. main() writes the halfword once at cold boot:

80015f00  jal  0x8003F084      ; two-instruction leaf: returns 1
80015f04  nop
80015f08  sh   v0,0x5aa(gp)    ; gp = 0x8007B318, so EA = 0x8007B8C2

The store is gp-relative, which is why sweeps for the absolute lui 0x8008 form reported no writer. BSS zero-init does not establish it - the PS-X EXE header carries b_size = 0. The field-VM flag ops cannot reach it either: their index window is [0x80085758, 0x80086957] and the move-VM's signed operand reaches down only to 0x80084758, both above it. A from-scratch engine treats both flags as build-time constants.

JP retail uses build-shifted addresses (+0x1B90 for the debug-menu enable).

Cheat-database code-patch sites

0x2400 is the MIPS nop; a cheat that writes it is patching an instruction, which makes these useful Ghidra anchors.

AddressEffectCheat
0x800422F4Inventory-add count = 99Bought Any Item / Find Items You Will Get 99 Quantity
0x8004309EInventory count-decrement nopInfinite Items All Slots
0x80043910Vahn chest draw-call nopRemove Vahn's Chest
0x8007EA96HP-write branch nopMaxed HP for All Characters

The cheat-pinned mini-game cells (fishing tension 0x801D9168, Baka Fighter life 0x801DBFC4, dance points 0x801D53CC, slot-machine punch mode 0x801D3CAC) are on the cheats page.

PSX scratchpad (0x1F800000..0x1F8003FF)

The PSX has 1 KB of fast on-chip RAM here. Legaia uses the high end for per-frame state:

AddressTypePurpose
0x1F800314i16[] / ctxInverted-Y mirror table (op 0x4C nibble-9 sub-E); also the draw-context base whose +0x6A is the depth clip bound and +0x74..+0x7A the 2-D clip rect.
0x1F80037Eu16Near cutoff - a segment whose two transformed Z both fall inside it is rejected.
0x1F800393u8Per-frame tick byte - the global frame-time scalar read by WAIT_FRAMES, subtracted from the title-attract countdown, and exposed as World::tick_move_vms_with_delta in the port.
0x1F800394u32Field-VM transient flag word - not persisted, distinct from the saved story-flag bitmap. Set/clear/tested by ops 0x2E/0x2F/0x30; lower 16 bits re-seeded on every mode switch. Bit 0x40 is a scene-transition-pending flag, not a "dialog active" lock. Bit 0 is set exactly on the kingdom overworlds, where it gives the fog spawner its depth-tested, lifted arm.
0x1F8003A0ptrActive primitive/packet write cursor the POLY_* emitters allocate from.
0x1F80037Cu8Current walk-region kind; 0 disables the camera scroll clamp.
0x1F800384..874 × u8Current walk-region AABB in tiles.
0x1F8003E8..EB4 × i8Camera visible tile window [nearX, nearZ, farX, farZ], signed tile offsets from the camera tile; written by FUN_801DBC20 and op 0x46, read by the render library's cell emitters, the scroll clamp FUN_801DAA50, the ambient emitter and the dev menu.
0x801F2778..844 × i32Write-only mirrors of the window; no reader on the disc.
0x800846D0..DC4 × u32Button-mask config words; 0x800846DC = 0x48 (Cross | R1) is the field run button, seeded once by FUN_80034A6C and never rewritten.
0x1F8003ECu8[]Tile-flag bitmap base used by op 0x4C nibble-7 and the walkability grid at +0x4000 (field locomotion).
0x1F8003F8 / 0x1F8003FAi16Camera-scroll values used by the op 0x23 player path.

Overlay window (0x801C0000+)

The 256 KB overlay window is shared between several runtime overlays - only one is loaded at any time. Static analysis only sees what was loaded at the time of capture, which is why the repo keeps a separate import per overlay.

RAM rangeOverlaySubsystems
0x801C0000+Title screenMenu window-widget interpreter (FUN_801D6628); title-overlay tick FUN_801DD35C
0x801CE818+Town / field / dialog (PROT 0897)Field VM (FUN_801DE840), MES renderer, inventory hub, MAIN INIT
0x801CE818+Battle (PROT 0898)Per-actor state machine, battle main dispatcher, effect VM cluster
0x801CE818+Options / pause / save / shop menu (PROT 0899)In-game menu UI
0x801EF018Title-overlay state struct+0x154 = attract countdown (init 0x8000, underflow → mode 0x1A → MV1.STR); +0x158 = title frame counter
0x801F0000+Persistent bandSurvives overlay swaps: battle effect helpers (0x801F5D90, 0x801F5CF8, the particle cluster at 0x801F8004+), the world-map emitter gate and camera state 0x801F3518..0x801F3528, field-overlay effect descriptors from 0x801F291C
0x801F69D8Slot BStreamed sidecar modules - see battle globals

Each mini-game likewise gets its own slab of upper RAM, loaded fresh when entered. Menu-overlay cells worth knowing: 0x801E46B0 is the selected item id for the description box (<= 0 draws nothing) and 0x801E46D0 the packed toggle-state word for the options window.

History: the "PROT 0896 @ 0x801C5818" menu-overlay base

An earlier attribution placed the menu overlay at PROT 0896, base 0x801C5818. That base was an over-read artifact of the superseded entry-size expression: the menu overlay is PROT 0899 at 0x801CE818, and live field captures hold an ISO9660 directory cache at 0x801C5818. Catalogued in do not re-walk.

How we know

Ghidra's reference manager does not resolve MIPS lui+addiu pairs or gp-relative stores, so most of these rows were pinned by a writer hunt (Ghidra tooling), a save-state diff, or a cheat code that names the cell.

FunctionAddressWhat it provesDump
main()FUN_80015E90 @ 0x80015F08The one gp-relative store that sets the build-mode selector to 1ghidra/scripts/funcs/80015e90.txt
Pad readerFUN_8001822CThe packed held / changed / edge masks and the debug-mode gate on port 1funcs/8001822c.txt
Mode-switch prologueFUN_8001DCF8 @ 0x8001E17CSole non-RMW writer of the field-VM flag word's low 16 bitsfuncs/8001dcf8.txt
Mode-entry snapshotFUN_80016230Gates the field-state snapshot on 0x8007B7AC == 3funcs/80016230.txt
CONFIG screenFUN_800188C8Indexes the mode table at stride 24 - confirms the entry stridefuncs/800188c8.txt
Overworld curvature builderFUN_800271A8The two 0x8000-byte buffers: a drop ramp and the screen-Y curvature tablefuncs/800271a8.txt
TMD installerFUN_80026B4C @ 0x80026BA8Sole writer of the global TMD table; the hidden gp[+0x820] counter storefuncs/80026b4c.txt
Flag opsFUN_8003CE08 / _CE34 / _CE64The fourth flag bank's (idx >> 3, 0x80 >> (idx & 7)) addressingfuncs/8003ce08.txt
Inventory window installerFUN_8004313CThe only writer of the bag's active window (128 or 256 slots)funcs/8004313c.txt
Placement cloneFUN_801D5778dst[+0xA] = src[+0xA] - 0x140: the field is a screen Xfuncs/overlay_battle_action_801d5778.txt
Shop buy commitFUN_801DB7F4The Point Card accrual into 0x800845B4funcs/overlay_shop_save_801db7f4.txt
Monster AI pickerFUN_801E9FD4 @ 0x801EB73CSwitches on the formation cell - per-monster-id AIfuncs/overlay_battle_action_801e9fd4.txt
Cheat corpus557 GameShark / PAR codesNames the game-state cells directly; none targets the build-mode or debug-menu flagscheats
Save-state library60 captured states0x8007B8C2 reads 1 in all of them; the TMD table snapshots (dolk, geremi)mednafen automation

See also