Files
goldeneye-pc-port/AGENTS.md
T
James Dansereau d3b3fe53ce Docs: track open issues D75-D77 (3D render, 2D partial draw, no audio)
Carry over the logo-pixel session's handoff state: D75-D77 recorded as
OPEN in PCPortResearch.md §F with candidate causes + verification steps,
prioritization guidance (D69 stays primary; render before audio unless a
shared root cause is found - Q1), and matching AGENTS.md phase-status line.
HANDOFF also drops the stale scratch-file list from Task 3 and points at
the relocated N64 reference screenshots.
2026-08-27 19:26:57 -04:00

12 KiB
Raw Blame History

AGENTS.md — GoldenEye 007 PC Port

What this is

  • n64decomp/007: WIP decompilation of GoldenEye 007 (N64), byte-matches US/EU/JP ROMs.
  • Active work: PC port modelled on the Perfect Dark PC port (same Rare "Indy" engine family).
  • Read docs/PCPortResearch.md first — architecture, GE-specific RSP deltas, phased plan, and review findings (A1–D33 in §11; current handoff + plan in §H).
  • Starting a fresh session? Read docs/HANDOFF.md — the paste-ready brief with the immediate task, standing procedure, and environment gotchas.

Non-negotiables

  1. N64 build untouched. Makefile, tools/, rsp/, ld/ belong to the N64 build. Never modify them for the PC port.
  2. Game logic is unmodified. The decomp's control flow and behavior are ground truth for 1:1 fidelity — never change them. All N64 hardware dependencies are satisfied by the port/ layer; if a game file seems to need a behavioral change, stop — the fix belongs in port/. Narrow exception (ABI/layout only): the 32→64-bit transition forces a small class of mechanical, semantics-preserving edits that cannot be isolated in port/ — chiefly pointer-width reconciliation in ROM-serialized structs (a struct with a 32-bit-pointer field misaligns when read as 64-bit). These follow the PD ground-truth pattern (store the embedded address as u32, cast to a real pointer at the use site), change no logic or behavior, and are each documented in docs/PCPortResearch.md §F/D3x. No other game-code edits are permitted.
  3. Region macros mirror the Makefile. CMakeLists.txt REGION_DEFS must match the N64 Makefile's per-region macro set exactly (finding A1). Divergence = silent branch divergence + link failures.
  4. src/libultrare/Makefile.libultrare is ground truth for original-vs-Rare libultra files (finding B3). The PC build compiles: libultra/audio, libultrare/audio (drvrNew/env/reverb), libultra/gu, and libultrare/io/vitbl.c only. All other io/ + os/ files are excluded and shimmed in port/src/libultra.c.
  5. rsp/graphics/gmain.s is the RSP ground truth — the authoritative reference for which GBI commands GE emits (modified fast3d, 1545 lines). We do not run it on PC; port/fast3d/ replaces it. Use it to validate the software RSP's command decoding and the custom CC/RM modes.

Critical files

File Role
docs/PCPortResearch.md Research + plan + findings (A1–C2). Read first.
CMakeLists.txt PC build (parallel to the N64 Makefile). Source list + REGION_DEFS live here.
port/src/ Shims: libultra.c (OS API), gesched.c (scheduler), n64stubs.c (boot/TLB/FPU/rmon), random.c (PRNG ported verbatim from random.s), ucode.c (microcode segment markers), main.c, video.c, …
port/fast3d/ Software RSP (adapted from the PD port). The main Phase 2 work.
rsp/graphics/gmain.s GE's RSP ucode — ground truth for GBI/CC/RM.
PD_PORT_CHECKOUT Perfect Dark PC port checkout — standing reference for this project: consult it whenever a remaining work item has a PD analogue (same Rare engine family). Port-layer ground truth (port/fast3d/, crash/system/video), plus copy candidates: port/src/preprocess/ (N64→PC asset conversion at load; filemodel.c is the D43 near-analogue, same vma 0x5000000) and mixer.c/input.c/fs.c (Phase 3/4 — our stubs were scaffolded to be replaced by these). Caveats: port-layer files only; same family ≠ identical format — validate per field. Full audit: docs/PCPortResearch.md §2.4.

Build

./build-pc.sh ntsc-final   # or pal-final / jpn-final

Needs CMake + SDL2 + zlib + OpenGL (MSYS2 packages: see build-pc.sh header). ROM goes in ./data/ (not distributed).

Verification ritual (after any build-affecting change)

  1. Undefined symbols. Every symbol referenced by the compiled set (see CMakeLists.txt: SRC_GAME, SRC_ENGINE, SRC_LIBAUDIO, SRC_LIBULTRARE_AUDIO, SRC_LIBULTRARE_DATA, SRC_GU, SRC_PORT*) must be defined exactly once in the compiled set or in port/. Symbols that live in EXCLUDED files (libultra/io/*, libultrare/io/* except vitbl.c, libultra/os/*, libultrare/os/*, sched.c, rmon.c, vi.c, src/*.s) must be provided by port/src/libultra.c, gesched.c, n64stubs.c, random.c, or ucode.c.
  2. Duplicates. No symbol defined twice across the compiled set (watch sp_* stacks, rmon*, os* shims, segment markers).
  3. Syntax. Every touched file must parse; once the toolchain is installed, ./build-pc.sh is the final word.

Run /linkcheck for this sweep. Record new findings in docs/PCPortResearch.md §11 style (next label after the last used).

Phase status

  • Phase 0 (scaffolding): done, committed.
  • Compile+link milestone: all ~235 TUs compile and ge007.x86_64.exe links clean (ninja ge007 -k 0, 236/236). Findings D7–D17 in docs/PCPortResearch.md §11; asset stubs in port/src/assetstubs.c, fast3d no-ops in port/src/gfxstub.c (delete when real fast3d lands).
  • Phase 1 (boot to window): done — ROM loads/validates/maps at cart base 0x10000000 (romdata.c), SDL2 window + GL clear loop (video.c), absolute asset symbols from scripts/gen_romassets.py → port/src/romassets_<r>.s (findings D18–D23).
  • Phase 1.5 (boot to first frame): DONE — boot chain complete AND real frames render ([NOTE] frame N rendered in … us). D34–D42 closed the blockers on top of D31–D33: ANIM_DATA lvalues, music seq-table ABI+endianness, music-heap sizing, libaudio bank-tree re-layout, implicit-declaration prototype shim (D38), Globalimagetable rebasing + true segment size (D39), ModelHitEntry pool sizing (D40), cross-thread GL context release (D41), rsp task-settings toggle (D42). ROM dump verified against the No-Intro good dump (byte-identical, header CRCs re-checked — tools_pc/romverify.c).
  • Phase 2 (rendering): IN PROGRESS — fast3d integrated + real frames render. Plan B EXECUTED (D50, committed): all 512 NTSC model files converted offline by tools_pc/d43_emit.py → data/pcmodels-ntsc-final/pcmodels.bin + manifest.csv (single concatenated RZ image; regenerate per region with the script — sidecars are gitignored), served through the existing load path via a port-layer table patch (port/src/pcmodels.c, romdata cart-extension, one-shot pcmodelsPatchTable() + poolRemaining reset hook in load_object_fill_header); runtime C fixups for language-bank BE offset tables + font re-layout (D50.3/D50.4); legal-screen UB seed (D50.5); D50.6 fixed the first model-render crash — texCopyGdls copied only w0 of each 16-byte Gfx slot on PC (the union's trailing long long is 8 bytes), leaving stale mempool w1s in the compacted GDLs; byte-proven against PlegalpageZ, fixed with a full-slot copy under #ifdef PORT. Model GDLs now execute to completion (PlegalpageZ sub-DLs). D51 RESOLVED (font pixeldata fixup wrote the pointer at the wrong offsets — frame-5 import_texture_i8 crash gone; GE opcode space decoded along the way, G_TEXRECT=0xE4/0xE5 non-F3DEX numbering), D52 RESOLVED (osGetCount now advances at the N64 RSP counter rate ≈ 46.5525 ticks/µs — fixed the non-deterministic post-frame-2 hang), D53 RESOLVED (model RW-data pool addressing: D53.1 Model.datas word-stride → u32 * under PORT + casts; D53.2 ModelSlot/AnimModelSlot re-laid on top of the PC struct Model — in-use@0x10 / pool@0x20, slot size = sizeof(Model) = 0xE8 — plus PORT-guarded heap-fallback bumps in model.c), D54 RESOLVED (cseq ALCMidiHdr BE header: port-layer romdataFixupCseq bswap32 of the first 17 u32s, called from music.c after each decompress), D54b RESOLVED (synth param slots sized for ALStartParamAlt = 0x28 in synthesizer.c alSynInit under PORT), D55 RESOLVED (RLE folder-menu background BE w/h header: bswap32 of the first word at (u32 *)&unknown2 at cart-map time in romdataInit, guarded). Build GREEN; game boots, plays intro music, renders through logo/gun-barrel, instantiates Brosnan, and executes the gun-barrel hole DL clean to ENDDL. D56 RESOLVED (watch Model/RW-pool raw offsets: field-name Model access + static 0xC8-byte pool under PORT in bondview2.c), D57 RESOLVED (pointer-grown rwdata records overflowed N64-sized spare pools — Brosnan PC numRecords 153 > 140: capacities grown in initunk_005520.c + dynamic slot+pool fallback in model.c), D58 RESOLVED (gun-barrel DL: vertex-pointer K0 idiom rebuilt via OS_K0_TO_PHYSICAL(…) | 0x80000000 in title.c + DL reserve 0x100→0x200 because sizeof(Gfx) is 16 on PC). D59–D68 RESOLVED (committed): the "GL DLL" crash was D64's unbounded blood-RLE write (sentinel section-adjacency lost on PC) clobbering the gun-barrel sub-DL; then D60–D62 (DMA target validation, OSMesgQueue layout), D65/D65b (HEADS/BODIES enum signed sentinels under PORT), D66 (romCopyAligned + ramrom replay 64-bit pointer width), D67 (struct image_entry N64 layout), D68 (Globalimagetable BE→LE fixup — port/src/gimgfixup.c bswaps IMAGESEG Gfx w1 words + sImageTableEntry.index after texReset's romCopy; compiled globalDL shadows synced for explosion.c). The game now renders the entire intro (logo → gun barrel w/ Brosnan → cast; ~frame 2100, ≈2 min wall-clock at the current ~20 fps clean-run rate). Current blocker D69: load_bg_file (bg.c:830) faults on first stage load — BG-file headers/records are N64 big-endian segment-0x0F offsets, read LE on PC; the bg .seg + Tbg_*_stanZ format work is next (decode from bg.c/stan.c → offline sidecar conversion per the D43 pattern or runtime port-layer fixup; PD preprocess/filebg.c is approach-reference only — its BG format differs). D70–D74 (intro-logo pixels, RESOLVED): D70 env-gated PPM frame capture (GE_PCDUMP → ./ppm/, gitignored — kept as permanent dev tooling); D71 C-array texture sources (the four rarewarelogo.c RGBA16 images) byte-swapped on LE PC → port-layer per-source bswap in import_texture; D72 the UV path (GE always uses authored tc[] UVs; lookat_enabled defaults false); D73 = root cause of old D72.3 — sinf/cosf du double constants are big-endian word pairs, garbage on LE PC → guMtxF2L emitted −32768 for every sin/cos entry → logo triangles projected off-screen; fixed with the PORT-only DVAL() macro in src/libultra/gu/guint.h (sinf.c/cosf.c .d reads replaced; N64 build untouched); D74 texture import fallback no longer truncates valid gDPLoadBlock data (was dropping letter mip chains + reducing D_02005FF0 to 32×3), TextureCacheKey gained size_bytes, and the VBO path wraps UVs by tile size for WRAP sub-tiles (N64 semantics). The Rareware logo now renders its four gold letters on the dark-blue plate (PPM-verified ~frame 555; final pixel-perfect check vs N64 footage optional). D69 remains the milestone blocker. Committed through D74. Recurring sub-task: ABI/layout fixes per the D32 procedure (§H) as more asset types are first touched (PD's preprocess/ module already solves most of them; prefer the offline pattern for format work — D48; full-struct Gfx copies on PC — D50.6; audit struct type-puns after pointer-width changes — D53.2; raw byte offsets into pointer-containing structs shift on PC — D56; N64-sized reservations must be re-checked against 16-byte Gfx/Vtx widths — D58). Open this session (tracked in §F as D75–D77, lower priority than D69): D75 3D rendering still wrong (Nintendo logo misplacement + intro player models absent); D76 2D disclaimer screen only partially drawn; D77 no audible music on PC. Prioritization: rendering over audio unless a shared root cause is found (Q1).
  • Phase 3 (audio + input): libaudio → SDL — largely copy-and-adapt from PD (mixer.c 722 lines vs our 31-line stub; input.c SDL_GameController backend; §2.4); decide the ASP strategy (C2: aspMain* dummies in ucode.c).
  • Phase 4 (saves + polish): file-backed EEPROM — build on PD's fs.c (file-backed save dir); PFS/motor already no-op stubs.