// Visit https://github.com/ethteck/splat/wiki/Adding-Symbols for documentation about this file
entrypoint = 0x80070C00; // type:func
main = 0x8007F880; // type:func

// OB64 libultra address->name table (see docs/LIBULTRA-BRIDGING.md).
// Batch 1 (2026-08-24): boot-critical functions, identified from the
// disassembly (MMIO/cop0 fingerprints, standard libultra call patterns) and
// verified against N64Recomp's reimplemented_funcs / the N64ModernRuntime
// osXxx_recomp implementations. Each name must exist in the runtime or the
// recompiled output won't link.

osInitialize = 0x80098050;          // type:func
osCreateThread = 0x80094860;        // type:func
osStartThread = 0x80094A20;         // type:func
osSetThreadPri = 0x80094950;        // type:func
osGetThreadPri = 0x80094930;        // type:func
osCreateMesgQueue = 0x80093570;     // type:func
osCreateViManager = 0x80095220;     // type:func
osCreatePiManager = 0x8008B8C0;     // type:func
osCartRomInit = 0x8008BD30;         // type:func
// CORRECTION (2026-09-12, session 32): 0x80095820 was named osViSetMode, but it
// is `__osViSwapContext` (it reads __osViNext->modep/framep from its own context
// and writes the VI hardware registers; it never uses $a0). The REAL
// osViSetMode is func_800955C0: it stores the mode pointer into __osViNext
// (offset 0x8) and copies modep->comRegs.ctrl into the context, exactly like
// libultra. Because the real one was never named, the runtime never learned the
// game's VI mode, so the 640x480 "Licensed by Nintendo"/ATLUS/QUEST screens were
// scanned out with the dummy 320x240 VI geometry - the top-left quarter of the
// RDP's 640x480 framebuffer, stretched over the screen.
__osViSwapContext = 0x80095820;     // type:func  (stubbed - the runtime's VI thread does the swap)
osViSetMode = 0x800955C0;           // type:func
// func_80095B30 is osViBlack (tests/sets __osViNext->state bit 0x20). The game
// blanks the screen around a mode switch (func_80093CB0: osViSetMode + blank,
// then osViBlack(0) + osViSwapBuffer when the new frame is ready); without the
// bridge the runtime kept scanning out the stale/partially-drawn framebuffer, so
// the 320x240 -> 640x480 switch showed ~0.2s of noise before the "Licensed by
// Nintendo" still.
osViBlack = 0x80095B30;             // type:func
osViSetSpecialFeatures = 0x80095610; // type:func
osDpSetNextBuffer = 0x8009A630;     // type:func
osGetCount = 0x8009A6E0;            // type:func
__osSetFpcCsr = 0x8009A710;         // type:func
osVirtualToPhysical = 0x80090780;   // type:func

// Batch 2 (2026-08-24): message queues, audio, and framebuffer swap - needed to
// get past the first game threads (which block on osRecvMesg/osSendMesg and
// drive the audio + VI state). Identified from standard libultra patterns.
//
// CORRECTION (2026-08-25): osSendMesg was initially assigned to 0x800935A0,
// but that function does a FRONT insert (mq->first = (first+msgCount-1) %
// msgCount) which is osJamMesg. The game's actual back-insert osSendMesg is
// func_80093810 (36 call sites, used by the audio/event request system). Naming
// func_80093810 = osSendMesg is what lets the runtime's osSendMesg (which wakes
// blocked threads) handle the audio-request responses. Both are in
// N64Recomp::reimplemented_funcs and defined in the runtime.
osJamMesg = 0x800935A0;             // type:func  (front insert)
osSendMesg = 0x80093810;            // type:func  (back insert, primary send)
osRecvMesg = 0x800936E0;            // type:func
osAiGetLength = 0x8008C410;         // type:func
osAiGetStatus = 0x8008C420;         // type:func
osAiSetFrequency = 0x8008C430;      // type:func
osViSwapBuffer = 0x800957D0;        // type:func
osViGetCurrentFramebuffer = 0x800951A0; // type:func
osViGetNextFramebuffer = 0x800951E0;    // type:func

// Batch 3 (2026-08-24): interrupt mask, audio buffer submission, and the RSP
// task family. Naming these makes the remaining verbatim MMIO helpers
// (osSpGetStatus/osSpSetStatus/__osAiDeviceBusy) unreachable dead code.
osSetIntMask = 0x8008B820;          // type:func
osAiSetNextBuffer = 0x8008C550;     // type:func
osSpTaskLoad = 0x80093A00;          // type:func
osSpTaskStartGo = 0x80093C0C;       // type:func
osSpTaskYield = 0x80093C40;         // type:func
osSpTaskYielded = 0x80093C60;       // type:func

// Batch 4 (2026-08-25): osCont (controller) family + timers. The game boots
// through osContInit (called from the game thread via func_80089C60) and polls
// controllers from func_8008A3A4/func_8008A42C. Identified from the
// disassembly: the SI-touching cluster at 0x800900C0..0x800906C0 (the
// 0x80096B90 cluster is the PFS/Controller-Pak family, NOT osCont*).
//
// NOTE: osSetTimer is func_80094D40, not func_80094E34 (that is the timer
// interrupt handler __osSetTimerIntr). osContInit calls func_80094D40 with the
// 8-arg OSTimer layout the runtime's osSetTimer_recomp expects (value in
// a2:a3 hi:lo, interval/mq/msg on the stack).
osContInit = 0x80090470;            // type:func
osContStartQuery = 0x800901F0;      // type:func
osContGetQuery = 0x80090270;        // type:func
osContStartReadData = 0x80090290;   // type:func
osContGetReadData = 0x80090318;     // type:func
osGetTime = 0x80094C90;             // type:func
osSetTime = 0x80094D20;             // type:func
osSetTimer = 0x80094D40;            // type:func

// Batch 7 (2026-09-17, session 65): the Controller Pak's SI-touching functions.
// OB64 saves to a Controller Pak, and its PFS filesystem (osPfsInitPak,
// osPfsAllocateFile, osPfsFindFile, osPfsReadWriteFile, osPfsChecker, ...) is
// libultra that the ROM already contains and the port already recompiles — it
// needs no porting. Only these three functions talk to the SI/PIF hardware,
// which the port does not emulate (KSEG1 MMIO is aliased to a scratch page in
// recomp.h), so they are bridged to the host 32 KiB pak image in
// `librecomp/src/pak.cpp`. Identified from the disassembly:
//   __osContRamRead 0x80097BD0 — 23 call sites, `do { ... } while (retry-- >= 0)`,
//     `__osSiGetAccess`, PIF ram 0x800F86C0, the `addr >> 3` / `addr << 5`
//     address pair, a `__osContDataCrc` verify, `bcopy(ptr + 6, data, 32)`.
//   __osContRamWrite 0x80097DC0 — same shape plus the ROM's own label-area guard
//     (`address < 7 && address != 0` unless `force == 1`); called by
//     `__osPfsSelectBank` (0x800970D0) with block 1024 = the bank register.
//   __osPfsGetStatus 0x80096EC0 — `__osPfsInodeCacheBank = 250`, a one-channel
//     status query, and the only other raw-SI user on the PFS path.
__osContRamRead = 0x80097BD0;       // type:func
__osContRamWrite = 0x80097DC0;      // type:func
__osPfsGetStatus = 0x80096EC0;      // type:func

// Batch 5 (2026-08-25): event registration. The boot trace shows the game
// thread (thread 3) blocking in func_8008A1B0 -> func_80089AB0 ->
// func_80089A30 on an audio request response that never arrives. The audio
// thread (func_80088F08) is triggered by a 0x29A mesg sent from the **VI
// retrace event**, which the game registered through its VERBATIM osViSetEvent
// (func_80095560). Because it was never named, the runtime's VI thread never
// delivered the retrace event to the game's audio queue, so the request was
// never processed. Naming osViSetEvent + osSetEventMesg routes event
// registration through the runtime (ultramodern/src/events.cpp).
osViSetEvent = 0x80095560;          // type:func
osSetEventMesg = 0x80093940;        // type:func

// Batch 6 (2026-08-25): SP status. The game's RSP task threads (func_80089358,
// func_80089200) busy-wait on the SP status register (0xA4040010) before loading
// each task via a verbatim reader (func_800939F0). Named osSpGetStatus so the
// runtime's osSpGetStatus_recomp (reports SP halted/idle) replaces the MMIO read.
osSpGetStatus = 0x800939F0;         // type:func

