diff --git a/docs/HANDOFF.md b/docs/HANDOFF.md index 9c002093..525012ec 100644 --- a/docs/HANDOFF.md +++ b/docs/HANDOFF.md @@ -30,21 +30,24 @@ no longer hits `Bad size for RGBA texture` — BUNKER1 renders multiple full frames (5 rooms drawn, frame GDL advances cleanly). The stream-decode + texture-pool layers of D85 are done. -**Now a fresh, NON-DETERMINISTIC crash cluster** (newly reachable — the -render loop + guard AI run in-level now; 4-run sample = 3 distinct -faults): -1. `bgScissorCurrentPlayerView` frame-GDL overrun (`bg.c:1355`, fault - `0x70800000` = end of 8 MB DRAM) — ~1/4 runs. -2. `chrlvInitActAttack` bad pointer (`chraction.c:1316`, fault - `~0x4012xxxx`, looks like a hi-word-truncated 64-bit ptr, D86/D92 - class) — ~2/4 runs. -3. `gfx_sp_matrix` unrelocated seg addr `0x90000000` (`gfx_pc.cpp:1077`) - — a room-GDL `gsSPMatrix` w1 not remapped by the widen — ~1/4 runs. +**D94 fixed (`63204a27`)** the one deterministic pointer bug in that +cluster — `chrlvInitActAttack`'s `(s32)`-truncated anim-table index. -Full triage + the `data/`-deletion recovery note in `PCPortResearch.md` -§F ("D85 texture wall CLEARED", "`data/` deletion + recovery"). -**Sidecars were regenerated this session** — if `data/` looks wrong, -rerun all three (`d43_emit.py`, `d69_emit.py`, `d88_emit.py --regen`). +**The remaining blocker is D95 (OPEN): the `-mgfx` master-DL buffer is +half-capacity on PC** (16-byte `Gfx` vs N64 8-byte, same byte budget). +The frame GDL overruns → non-deterministic fault at `0x70800000` (top of +8 MB DRAM), corrupting other GDLs on the way (the run-to-run "Unknown GBI +opcode" / seg-9 `0x90000000` faults are all downstream of this). Doubling +`g_GfxBuffers` stops the overrun (90 s+ clean) **but OOMs `MEMPOOL_STAGE`** +(zbuf alloc spins in `mempAllocBytesInBank` `while(1)`, `frames=0`). +Committed `70784f80`, reverted `2a506284`. Fix options in +`PCPortResearch.md` §F "D95" — the cleanest is likely to `malloc` +`g_GfxBuffers` on PC (pure CPU-side GBI scratch, outside the N64 pool). + +`data/` was accidentally deleted + fully regenerated this session — if it +looks wrong, `cp baserom.u.z64 data/ge007.ntsc-final.z64` then rerun +`d43_emit.py` / `d69_emit.py` / `d88_emit.py --regen` (§F "`data/` +deletion + recovery"). - Build: `export PATH="/c/msys64/mingw64/bin:$PATH" && ./build-pc.sh ntsc-final` - Sidecar regen (REQUIRED after this session — D88.5/D88.6 changed the diff --git a/docs/PCPortResearch.md b/docs/PCPortResearch.md index b04deeed..f630848e 100644 --- a/docs/PCPortResearch.md +++ b/docs/PCPortResearch.md @@ -3124,6 +3124,48 @@ fault sites). Treat as a fresh crash-chain, not D85: write fault ~`0x70800000`). Timing-dependent, masked behind #1. Prop/character render path (D75-adjacent), newly reachable. +**D94 (RESOLVED — truncating `(s32)` pointer cast in `chrlvInitActAttack`).** +Committed `63204a27`. `chraction.c:1221`/`1231` compute the firing-anim +table entry as `(s32)arg1[anim_index]->table + (s32)(idx*sizeof(...))` — +`table` is `weapon_firing_animation_table (*)[]`, and the `(s32)` cast +truncates the 64-bit pointer, then the cast back zero-extends, dropping +the `0x1_00000000` module-base bit → `panim_float ≈ 0x4012xxxx` → +`panim_float->anim.anim` faults there when a guard starts an attack +in-level. Replaced both with plain array indexing (`&(*table)[idx]`) under +`#ifdef PORT` — the code's own comments say that's the intent. + +**D95 (OPEN — the `-mgfx` master-DL buffer is half-capacity on PC; the +naive fix OOMs `MEMPOOL_STAGE`).** `dyn.c:56` sizes `g_GfxBuffers` from +`-mgfx` (a byte budget from `boss.c`'s per-level `memallocstringtable`, +sized for N64 8-byte `Gfx`). On x86-64 a `Gfx` is 16 bytes, so the master +display list holds **half** the commands for the same budget. Every +render fn appends with a bare `gdl++` and **no bounds check**, so once +BUNKER1 emits real room geometry the list overruns `g_GfxBuffers[1]`/`[2]`, +runs off the stage mempool, and faults writing a GBI command at the top +of the 8 MB emulated DRAM (`0x70800000`) — **non-deterministically**, and +scribbling GBI across DRAM on the way (the run-to-run `Unknown GBI opcode +0x3f/0xffffb9` and `gfx_sp_matrix` seg-9 `0x90000000` faults were all +downstream corruption from this one overrun). Doubling the `g_GfxBuffers` +allocation (`* sizeof(Gfx)/8`) under PORT **stops the overrun** (verified: +`-level_09` then runs 90 s+ / 5000+ VI posts, no crash) **but** the extra +~100 KB starves `MEMPOOL_STAGE` so `zbufAllocate` → +`mempAllocBytesInBank` (`memp.c:204`) spins in its OOM `while(1)` and no +frame ever renders (`kernel heartbeat: frames=0`; mainThread stuck in +`lvlRender`→`viClearZBufCurrentPlayer`→`zbufInit`). Committed as +`70784f80` then **reverted (`2a506284`)**. Real fix options, in rough +order of cleanliness: (a) allocate `g_GfxBuffers` (and only that — it is +pure CPU-side GBI scratch that `gfx_run` walks by raw pointer) with plain +`malloc` on PC instead of from `MEMPOOL_STAGE` — verify nothing does +`osVirtualToPhysical` on a `gdl` pointer first (`rspGfxTaskStart` PORT +path sets `task->t.data_ptr = firstGdl` directly, looks safe); (b) enlarge +the emulated DRAM (`port/src/dram.c` `DRAM_SIZE 0x00800000`) and move the +`tlbmanageGetTlbAllocatedBlock` ceiling so `MEMPOOL_STAGE` (bounded +`_bssSegmentEnd .. TLB block`, `boss.c:218`) gains the room; (c) a +safety-net cap in the append path (a lot of call sites — least clean). +Also: `struct tex` headers are 24 B vs 16 B on PC (texpool-triage finding) +— same class, same pool pressure; a real memory-budget pass for the PC +port would address both. + **`data/` deletion + recovery (session M-3).** `git worktree remove --force` on an agent worktree that had a directory *junction* `worktree/data → main/data` followed the junction and deleted the real