At a glance

Main RAM
2 MB at 0x80000000..0x801FFFFF. Nothing above it: 0x80200000+ only mirrors RAM on a retail console.
Executable
SCUS_942.54 loads at 0x80010000 and is 0x6B800 bytes (430 KB): tables, then code from main() at 0x80015E90, then data. It ends at 0x8007B800.
gp
0x8007B318 - most globals are reached as imm(gp), which an absolute-address search never sees.
Save block
0x80084140..0x80085B57, the 0x1A18 bytes a save copies: character records at 0x80084708 + n*0x414, flag bank 0x80085758, item bag 0x80085958.
Heap
0x80091800..0x801C5FFF (InitHeap(0x80091800, 0x134800)): scene bundles, models, the battle context and actor pool.
Overlays
Slot A at 0x801CE818 (field, battle, menu, minigames - one at a time); slot B at 0x801F69D8 (summon / cast modules, world-map render).
Stack
Starts at 0x80200000 (the startup code replaces the header's 0x801FFFF0) and grows down.
Full table
docs/reference/memory-map.md - every row, in the same region order; grep it for your address

The address space

Drawn to scale, low addresses on the left. Click a region to jump to its section.

0x800000002 MB main RAM0x801FFFFF

0x801C6000top 232 KB, zoomed0x80200000

The heap dominates the machine; the executable is about a fifth of it. In the zoom, every slot-A image starts at the same 0x801CE818, which is why an address there means nothing without the mode - and the battle image's extent runs 0x640 bytes into slot B, so a module paged during battle and the battle overlay share that sliver.
Starts atSizeHolds
0x8000000064 KBKernel RAM: exception vectors and the BIOS's own tables. The game never addresses it.
0x8001000024 KBSCUS_942.54 image head: jump tables, constant matrices, strings - no code.
0x80015E90357 KBSCUS_942.54 code: the game plus the statically linked PsyQ libraries.
0x8006F18050 KBSCUS_942.54 data segment: static game tables, then the gp small-data block.
0x8007B80088 KBStatic work area: uninitialised globals, the save block, the sound-driver work area.
0x800918001234 KBHeap.
0x801C600034 KBResident buffers: PROT TOC, XA clip table, libcd / SsAPI state, battle actor table.
0x801CE818≤ 162 KBOverlay slot A - one per-mode image at a time.
0x801F69D8≤ 16 KBOverlay slot B - small paged modules.
0x801FA9D822 KBFree RAM, then the stack from 0x80200000 down.
0x1F8000001 KBScratchpad - separate on-chip RAM.
0x1F801000+-Hardware I/O registers.
Where these boundaries come from

The executable's own header fixes the bottom half: t_addr = 0x80010000, t_size = 0x6B800, initial PC 0x80026C28, initial sp = 0x801FFFF0 (which the startup code at 0x80026C74 replaces with 0x80200000), and no BSS (b_addr = b_size = 0) - so nothing above the image end is cleared by the loader. The first jr ra in the image is at 0x80016228 and the last at 0x8006F178, which is what places the code between the table head and the data. main() sets the heap from DAT_8007B414 = 0x80091800 with size 0x134800 (0x200000 on the 8 MB development console), so the heap ends at 0x801C6000. The overlay bases are recovered from each image's own call graph (static overlay pipeline).

The previous version of this map split the executable at 0x80060000, gave it ~960 KB, placed a 256 KB overlay window at 0x801C0000 with a title overlay at its base and an "extended overlay region" past 0x80200000. None of that survives the header and the overlay bases: the title screen is PROT 0899 code at 0x801CE818, 0x801C0000..0x801C5FFF is heap, and there is no RAM past 0x801FFFFF.

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 holds the persistent state, but most game logic lives in overlays streamed off the disc per game mode.
  • An overlay address is ambiguous on its own. Every slot-A image links at 0x801CE818 and only one is resident, so the same address means different things in field, battle and menu mode. The overlay rows below say which image they belong to.
  • A heap address is a snapshot. It depends on the allocation order; the ones listed are those that stay put across the captured states.
  • 0x1F800000 is not main RAM. It is the scratchpad, and a flag a script tests may live there.

Kernel and executable

The first 64 KB belong to the BIOS - exception vectors at 0x80000080, the kernel's tables and work area - and the game only reaches them through the BIOS call vectors. One kernel word is game state all the same: 0x80009010 is the BIOS rand() seed every random draw in the game steps, so a save state's word there is where the game's one random stream stands. SCUS_942.54 follows at 0x80010000: 24 KB of tables, the code from main() up, then the data segment.

AddressTypePurpose
0x80010778u32[71]Move-VM opcode jump table (move VM).
0x80010B84MATRIXThe constant base matrix the non-field view build folds in: 16384 * I, a 4x scale (the field uses 0x8007BF10, 6x).
0x800111C4u32CD / XA transport state word - the 11 states FUN_8003D764 walks.
0x80014FA0u32[132]Battle-applier selector jump table: 116 of 132 slots point at the shared epilogue; slot 0x82 is the Incense top-up.
0x80015E90codemain() - the first function in the image; the entry stub FUN_80026C28 sets gp and calls it.
Cheat-code patch sites in the code

A GameShark code that writes 0x2400 to an instruction's upper halfword (address % 4 == 2) turns it into addiu $zero, $zero, imm - a no-op. These make useful Ghidra anchors.

AddressEffectCheat
0x800422F4Writes 0001 over the branch inside the inventory-add clamp, shortening it so the clamp always runs: every add stores 99Bought Any Item / Find Items You Will Get 99 Quantity
0x8004309ENo-ops the inventory count decrementInfinite Items All Slots
0x8004390ENo-ops a draw-call siteRemove Vahn's Chest

The fourth code-patch-shaped cheat, Maxed HP for All Characters, writes 0x2400 to 0x8007EA96 - past the image's end, so whatever it patches is not executable code. The field overlay's Walk Thru Walls sites are below.

Data segment and gp block

The executable's initialised data: the static game tables, then the gp small-data block from 0x8007B318, which runs past the image end into the work area. These mean the same thing in every mode.

AddressTypePurpose
0x8006F4C8i16[2049]Arctangent table for the bearing resolver FUN_80019B28.
0x8007050Cchar[]Resident scene-name string - an output of the scene loader, not an input.
0x8007078C24 B × 28Game-mode dispatch table (boot).
0x80070A2Ci16[5120]Shared trig LUT, 4096 * sin - one revolution plus the quarter turn the cosine view needs.
0x8007326C8 B × 6TMD per-mode descriptor table (TMD).
0x80073F00i16Dialog pager auto-press countdown: op 4C 89 sets it, and the waiting box presses confirm when it runs out.
0x80073F14u8[8]Compass axis bitmasks for the motion VM's eight-direction walk: 1 +Z, 2 -Z, 4 +X, 8 -X, combined for diagonals.
0x80074358u32[4]Global ability bitmask; the party's per-character ability blocks are ORed into it.
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.
0x80077828u8[2] per monsterPer-monster steal table, 1-based id, each entry [chance, item] - chance first. Not in the monster record (steal table).
0x80077998u8[5] per characterRot limb object ranges: which mesh objects the battle draw dims for each Rot bit.
0x80078630u8[6] per characterRot CLUT windows: three [lo, hi) palette ranges per character that the status CLUT pass tints blue for each Rot limb bit (battle).
0x800788B8u16[0x110]Streamed-voice clip durations (arts shout, Seru cast voice); neither reader bounds the index.
0x8007B450ptr / u32Op-0x49 submode cell: 0 idle, 1 done, otherwise the active submode descriptor's address. The cheat database's "menu-request register" - poking a record pointer opens a submode.
0x8007B5FCu32Encounter step counter, one word across doors. Outside the saved window: it holds its SCUS_942.54 file value 0x3CE (974) after power-on and a card load, so the first battle after a cold load in a rate-18 region is rolled on step 55.
0x8007B6A8u8Save-anywhere allow flag (scene header bit); the same bit raises the field-fog cap on every overworld.
0x8007B6F4u16GTE H projection register (focal length / zoom). The cheat database's "small maps" / "camera mode" labels are this word.
0x8007B790u16[3]Live camera rotation trio - pitch, yaw, roll (12-bit angles).
0x8007B7C0u32Previous frame's held pad mask (the pad reader keeps it to form the edge masks).
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

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_ui_formats::screen_elements; packet evidence on battle.

Static work area and the save block

From the image end at 0x8007B800 to the heap base is uninitialised global storage - the executable declares no BSS, so a cell here holds only what the code stores. It holds, in order, the rest of the gp block, the actor and mesh tables, the save block and the work buffers above it.

Mode, pad and battle globals

AddressTypePurpose
0x8007B83Cu16Next game-mode index, the master mode selector: 0x02/0x03 field INIT/MAIN, 0x14/0x15 battle, 0x16/0x17 the menu and title (CARD), 0x1A STR FMV. The front end writes it six times on the way from the logo to the field, each store in the handler that hands off.
0x8007B850u32Per-frame held button mask, packed (face/shoulder byte in bits 0-7, d-pad/system byte in bits 8-15).
0x8007B868u32Dev/dual-mode gate (retail 0); the developer screens it gates are unreachable on a retail disc.
0x8007B874u32Newly-pressed edge mask, held & ~prev - what most menus test.
0x8007B8A0s16Failed actor-spawn counter behind WORK ERR%d: cleared by the per-stage init, incremented when the actor pool is empty, printed every frame it is non-zero (WORK ERR on Mt. Rikuroa).
0x8007B8C2u16Dev/retail loader-path selector: 40 reads, written once at cold boot to 1. Details.
0x8007B98Fu8In-game debug menu enable - byte 3 of the debug-mode word 0x8007B98C. Poking it to 1 brings up the debug menu on SELECT+Triangle.
0x8007BAC0u32Special-battle restriction word: bit 0x100 bars Item, 0x200 forbids Ra-Seru; any set bit suppresses the spoils.
0x8007BAC8u16BGM request id; the scene loader clears it and the script installs it (audio).
0x8007BD0Cu8[4]Formation cell - per-slot monster id (monster m is actor slot m + 3); the AI picker switches on it.
0x8007BD10u8[]Per-seat character id, 1-based (1 Vahn, 2 Noa, 3 Gala, 4 the AI companion).
0x8007BD24ptrBattle context pointer (0x800EB654 in battle, 0 in the field): +0x07 action-state cursor, +0x13 active slot, +0x276 the side-band applier's stage byte, +0x279 cast-module phase, +0x28A battle-mode counter.
0x8007BD71u8Battle run state: 0xFF running, 0xFE ending, low values the loader's step counter.
0x8007BD74ptrSide-band streaming buffer: one summon.dat / readef.DAT slot at a time (summon / readef).
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 header declares no BSS. 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).

Actor and mesh tables

AddressTypePurpose
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. Its counters and bases (0x8007B774, 0x8007BB38, 0x8007B824, 0x8007B6F8) sit in the gp block.
0x8007C348u32Actor allocator free-stack top; seven list sentinels follow.
0x8007C34Cu32[7]Actor-list heads the per-frame walk dispatches through node[+0x0C]; five are separate render passes.
0x8007C364ptrPlayer field ctx pointer (0x80083794 in the captures; +0x10 carries the encounter-active flag).
0x80083E58ptr[N]VDF sub-entry pointer table, consumed for actor bring-up.
0x800840B8i32[3]Camera eye-space translation trio, uploaded as the GTE TR.
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).

The save block (0x80084140..0x80085B57)

The live game state a save is composed from - the save write copies these 0x1A18 bytes, so a save-block offset is VA - 0x80084140 (save screen).

AddressTypePurpose
0x8008444Cu32Persistent fishing points; the lure row, rod stat and point-exchange purchase mask sit beside it.
0x80084540u16The loaded scene's raw CDNAME define - two above the extraction-frame index (town01 3). The cheat database's "Map Modifier".
0x80084570u32Play-time counter - advances per frame (~60/s), not per second.
0x800845DCu32Records-page play time: zero until the ending scene's op 4C EE copies the live counter into it.
0x80084594 / 0x80084598u8 / u8[]Party member count / member ids (sorted insertion, cap 4).
0x8008459C / 0x800845A4u32Party gold / casino coin bank.
0x800845A0u324C D3 clock, remaining ticks; its duration (0x800845B8, non-zero = running), threshold (0x800845BC) and flag pair (0x800845C0: expiry flag high half, below-threshold flag low half) follow (MENU_CTRL).
0x800845B4u32Point Card counter (unmapped by every public cheat archive): the shop buy commit accrues price/20 * qty while the card is held, capped at 9,999,999.
0x800846D0u32[4]Button-mask config words; 0x48 (Cross | R1) is the field run button.
0x80084708 + n*0x414u8[0x414]Character records, four slots; display name at +0x2A7. Slot 3 (Terra) ends exactly where the flag bank begins (save record).
0x80085758bitsFourth flag bank (save block +0x1618) - the bitfield field-VM SET / CLEAR / TEST address as (idx >> 3, 0x80 >> (idx & 7)); indices run past 256, so it is not a fixed 256-bit array.
0x80085958(id, count)[256]Item bag (save block +0x1818); the active window is 128 or 256 slots - never 72, which is a cheat's page span (inventory).

Work buffers

AddressTypePurpose
0x80085B58bufferlibsnd sound-driver work area, handed over at boot - the first byte past the save block.
0x80088758record[]Resident CDNAME define table (16-byte records), what the travel arts scan for a destination.
0x80089118i32[3]Camera focus trio, stored negated; in the field only X and Z are written.
0x80089128u32[32]Held-mask history ring, one entry per vsync; its AND drives the menus' auto-repeat.
0x800917B0u32 per VAB idThe fixed SPU address each VAB slot opens at (audio).

Heap

main() hands 0x80091800..0x801C5FFF to InitHeap, and the allocator serves scene bundles, model packs, sound banks and the battle structures out of it. A heap address belongs to the allocation order, not to the program; these are the ones that stay put across the captured states.

AddressTypePurpose
0x800EB654structThe battle context 0x8007BD24 points at while a battle is resident.
0x800EC9E8 + n*0x2D4u8[0x2D4]Battle actor pool; HP at +0x14C. The actors are reached through the pointer table at 0x801C9370 (cheat citations).

Resident buffers

The 34 KB between the heap and the overlay base are fixed buffers that survive every mode change - which is why an overlay can hand data to its successor here.

AddressTypePurpose
0x801C6220rowsShop buy-list staging array, written by the SCUS row builder; the hoisted band is the Platinum Card stock (shop).
0x801C6EA4ptrCurrent world / scene struct pointer; +0x40 is a write-only parked return state.
0x801C6ED8[CdlLOC, u32] × 34CD-XA clip table, slot i = file XA<i+1>.XA; built at boot by ISO9660 lookup, so it survives disc relayout (cutscene).
0x801C70F0TOCIn-RAM PROT.DAT TOC, filled at boot (PROT.DAT).
0x801C8980tableResident monster.snd bank index (PROT 0891), staged by init.pak.
0x801C8FE0u32[]Steal result band and element-cycling counter - scratch two slot-B cast modules address independently.
0x801C9370ptr[8]Battle actor pointer table: party in slots 0-2, monsters in 3-7.
0x801CB408record[128]libcd directory-entry cache.
0x801CD2B8 / 0x801CD2C0u16 / ptr[16]SsAPI slot-allocation bitmap / per-slot sequence-state pointers.

Overlay slot A (0x801CE818)

The per-mode code window. Every image links at 0x801CE818, each mode's INIT handler streams its PROT entry in, and only one is resident - the same address is a dialog routine in the field and the battle state machine in battle. The pause menu replaces the field overlay at the same base.

PROTEnds atImageLoaded by
08950x801F4017Boot init.pak - publisher logos, front-end hand-offboot, mode 16
08970x801F3817Field / town / dialog / world mapmode 2
08980x801F7017Battlemode 20
08990x801F3817Menu: title screen, pause menu, save, shop, casino prizesmode 22
09700x801F3017STR / MDEC movie playermode 26
09710x801D0017Debug menumode 0
0972..0980≤ 0x801DC817Minigames: fishing, slot machine, Baka Fighter, Muscle Dome hub, dance; dev modulesmode 24 warp
0902 / 0979 / 0981smallGame over (unreachable), field-to-battle intro, world-map top-view debugmodes 18 / 8 / 12

Field overlay (PROT 0897)

AddressTypePurpose
0x801D065C … 0x801D078CcodeWalk Thru Walls cheat sites: four beq instructions in the player movement controller's collision path, whose branch displacement the cheat rewrites - a code patch, not collision-state bytes.
0x801F21B4tablesHead of the overlay's data: the actor-collision, wall and interact-facing probe tables.
0x801F2738cellsThe dialog pager's row window - scroll, reveal, collapse, rows on the page, pending text (MES).
0x801F2B98record[17]Panel-window descriptors the world-map panel sizer and dev-menu panels index.
0x801F3518u32World-map batch emitter state: running angle, one-shot gate 0x801F351C, scale, step, OT layer. Field-overlay data - reloaded with the overlay, not preserved across a swap (world map).
0x801F3580structCamera staging descriptor - the composer's output and the ease's input.

Battle overlay (PROT 0898)

AddressTypePurpose
0x801CED44u32[]Battle action-SM jump table, indexed by ctx[+0x07] (battle action).
0x801F6950u32Overlay PRNG state - its draws never perturb the SCUS rand() stream.
0x801F6980u8[8]Multi-cast value-readout window; PROT 0915 writes it from slot B, reaching down into the battle image.
0x801F6990u32[16]The arts queue-builder's per-token marks (accepted starter, Super tail-replace).

Menu and title overlay (PROT 0899)

AddressTypePurpose
0x801E46B0i32Selected item id for the description box (<= 0 draws nothing).
0x801E46B4 / 0x801E46B8u32Shop quantity under edit and its cap, min(gold / price, 99, 99 - held).
0x801E46D0u32Packed toggle-state word for the options window.
0x801EF018structTitle state: +0x154 attract countdown (underflow → mode 0x1A → MV1.STR), +0x158 frame counter; +0x204 / +0x208 the sub-mode and previous sub-mode.

Boot, movies and minigames

AddressImagePurpose
0x801F369C0895 bootinit.pak's own globals: logo sprite descriptors, memory-card driver state, fade level.
0x801D0D58 / 0x801D0E600970 moviesThe two MDEC command packets and the hardware-register pointer block (DMA, MDEC, DPCR).
0x801D9168 / 0x801D92980972 fishingTension gauge / fish life (cheat-pinned); the lure triple is at 0x801D9174.
0x801D3CAC0975 slot machinePunch-mode unlock (cheat-pinned).
0x801DBFC4 / 0x801DC06C0976 Baka FighterPlayer / computer life (cheat-pinned).
0x801D1A78 / 0x801D1AE00977 Muscle DomeContest hub arm word / ringside-still latch.
0x801D53CC0980 danceDance-points counter (cheat-pinned).

PROT 0896 links at 0x801D4DF0, not at the slot base, and nothing on this disc loads it.

Overlay slot B (0x801F69D8)

One small module at a time above slot A: PROT 0900 (screen-effect widgets), 0901 (world-map render), 0967..0969 (battle tutorial and boss stages), 0978 (the staged background loader) and the 64 summon / cast images 0903..0966, the largest 0x4000 bytes. The band starts inside the battle image's extent, so a module loaded in the field has its head overwritten when the battle overlay comes in (cast module).

AddressTypePurpose
0x801F69D8u32 + codeSlot-B link base: the resident module's first word (0x001000E2 when empty).
0x801F6AA8 / 0x801F6AD8tablesPROT 0978's two dispatchers - field restore and int.tim panel still.
0x801F7A9CcodePROT 0900's sprite, iris-mask and letterbox widgets that field-VM op 0x43 drives (move VM).
0x801F9D28u32PROT 0955's per-arm frame countdown - one example of the module-local cells each cast image keeps.

Free RAM and the stack

Above the largest slot-B image nothing is loaded. The stack starts at 0x80200000 and grows down; interrupt callbacks run on their own stack at 0x8007A7F0, and the render pass moves onto the scratchpad, so only the main thread's own calls land here. A canary fill over the band measures how deep they go: 0x801FE420 (7,136 bytes) once at boot, while FUN_8001D8FC reads CDNAME.TXT into a 4 KB stack buffer, and never below 0x801FF138 after it - the FMV decoder, which reserves a per-frame macroblock table on the stack. Battles stay above 0x801FFD30, scene loads and card saves above 0x801FFA20, the minigames above 0x801FFA88 bar the dance contest, whose hall load reaches 0x801FF9E0. 0x801FD000..0x801FE000 is therefore free, which is why the disc patcher parks injected code there (randomizer).

No code on the disc builds an address from 0x801FA9D8 up; the stack top comes from a data word. The loader reads exactly as many sectors as the PROT table of contents gives, so a larger PROT 0900 / 0901 would carry its extra bytes into this space on every field load, and they would stay until power-off. The catch is that those two entries have no spare room on the disc, so growing them means moving every later PROT entry, which a same-size patch cannot do. In the same way, while the field or menu overlay is loaded, the range 0x801F3818..0x801F69D7 only holds leftovers from whichever image last used it.

Scratchpad (0x1F800000..0x1F8003FF)

1 KB of fast on-chip RAM outside the 2 MB. Most cells from 0x1F80035C up are displacements off 0x1F800314 (lui 0x1F80; ori 0x314), so an absolute-address scan never sees them.

AddressTypePurpose
0x1F800038u32IR0 the world-map decoration handlers load before their depth cue.
0x1F800314baseBase the cells below are reached from.
0x1F80035Ci16[16]Scene floor-elevation ladder - the sixteen heights a collision byte's low nibble indexes (field locomotion).
0x1F80037Cu8Current walk-region kind; 0 disables the camera scroll clamp. The region's AABB follows at 0x1F800384..87.
0x1F80037Du8Game-speed rate scalar; elapsed time is always the product of this and the tick byte.
0x1F80037Eu16Near cutoff - primitives with an OTZ below it are dropped.
0x1F800388u16[4]Draw-context 2-D clip rect.
0x1F800393u8Per-frame tick byte - how many display frames the last loop took; every timer subtracts it.
0x1F800394u32Field-VM transient flag word - not persisted. Ops 0x2E/0x2F/0x30 set/clear/test it; the low 16 bits are re-seeded on every mode switch. Bit 0x40 is scene-transition-pending; bit 0 is set exactly on the kingdom overworlds.
0x1F8003A0ptrActive primitive / packet write cursor the POLY_* emitters allocate from.
0x1F8003E8..EBi8[4]Camera visible tile window [nearX, nearZ, farX, farZ], set per camera region and by op 0x46.
0x1F8003ECptrTile-flag bitmap base; the walkability grid is at +0x4000.
0x1F8003F4ptrOrdering-table base the overworld ground and fog emitters index.

Above the scratchpad are the hardware registers - DMA at 0x1F801080..0x1F8010F0, GPU at 0x1F801810, MDEC at 0x1F801820, SPU from 0x1F801C00. The game reaches them through the PsyQ libraries; only the movie player keeps a pointer block to them in its own data.

How we know

Ghidra's reference manager does not resolve MIPS lui+addiu pairs or gp-relative stores, so most rows were pinned by a writer hunt (Ghidra tooling), a save-state diff, or a cheat code that names the cell. The region boundaries come from the executable's header and the overlays' own call graphs.

EvidenceWhereWhat it proves
PS-X EXE headerSCUS_942.54 +0x10Load address, image size, initial PC and sp, no BSS
Heap initFUN_8002B3D4(2, 0x80091800, 0x134800)The heap's base and end
Static overlay mapcrates/asset/data/static-overlays.tomlEvery overlay's base and extent, recovered from its own jal graph
main()FUN_80015E90 @ 0x80015F08The one gp-relative store that sets the build-mode selector to 1
Pad readerFUN_8001822CThe held / previous / changed / edge masks
Mode-switch prologueFUN_8001DCF8 @ 0x8001E17CSole non-RMW writer of the field-VM flag word's low 16 bits
TMD installerFUN_80026B4C @ 0x80026BA8Sole writer of the global TMD table
Flag opsFUN_8003CE08 / _CE34 / _CE64The flag bank's addressing
Bag window installerFUN_8004313CThe only writer of the bag's active window
Save write0x801DFA98The save block is 0x1A18 bytes from 0x80084140
Cheat corpus557 GameShark / PAR codesNames the game-state cells directly (cheats)

See also