forked from Ports/goldeneye-pc-port
@
D131: restore truncated module ptr in seg_addr (Jungle -level_37) explosionRenderPropSmoke passes a compiled .bss matrix symbol (&dword_CODE_bss_8007A100) through osVirtualToPhysical() -- a u32-returning shim -- into gSPMatrix, truncating the 0x1_00000000 module high word. w1 lands as 0x40xxxxxx and seg_addr() returns it raw -> wild deref in gfx_sp_matrix when the first explosion draws (~frame 300). Fix: seg_addr() restores the module high word for any fallthrough w1 in [0x40000000, 0x70000000) (module fixed-based at 0x140000000, no ASLR; DRAM/KSEG0/segmented/phys are all handled in earlier branches). Covers the ~30 latent osVirtualToPhysical(<compiled matrix/vtx symbol>) sites in explosion/glass/blood/bondview2. Verified: Jungle renders to frame 1500-2400+ crash-free at 91.7% content; -level_20/-level_24 unregressed. Sweep 18->19/21 (note: -level_09 has a separate pre-existing boot crash regressed since M-18 -- see HANDOFF). @
This commit is contained in:
1 parent
1c4efdaaf2
commit
bb14baf3bf
6 files changed
+227
-14
No files matched your search
@@ -0,0 +1,74 @@
|
||||
# Local-agent handoff tasks (Qwen 27B)
|
||||
|
||||
Two self-contained, low-risk tasks that are **disjoint from the active Jungle
|
||||
`-level_37` G_MTX investigation** (that work is in `port/fast3d/gfx_pc.cpp`
|
||||
around `gfx_sp_matrix` / `seg_addr` / `gfx_run_dl` — do NOT touch that file).
|
||||
|
||||
Source: `docs/BACKLOG.md` "Technical cleanup" section.
|
||||
|
||||
---
|
||||
|
||||
## Task A — doc only, zero code risk (do this first)
|
||||
|
||||
**Goal:** add two entries to `docs/PORT-LEARNINGS.md`.
|
||||
|
||||
1. New bug class **"D24-implications — host-scheduling nondeterminism / fake
|
||||
priority semantics"**: the pthread kernel does not enforce N64's 0–31
|
||||
thread priorities (`osYieldThread` == `Sleep(0)`), so thread interleavings
|
||||
impossible on real hardware can occur, and frame timing carries host
|
||||
jitter. **How to apply:** when a flaky timing bug appears (especially
|
||||
Phase 3 audio underruns), reach first for host thread priorities
|
||||
(`SetThreadPriority`: scheduler thread time-critical, tick thread normal)
|
||||
and the deferred `GE_DETERM` fixed-tick mode (§F D117) — NOT for kernel
|
||||
changes. Link `[[d117]]`-style to the D117 finding.
|
||||
2. Watch item under the same class: **`osYieldThread` == `Sleep(0)`** is the
|
||||
one place the port fakes cooperative scheduling. If a level-sweep hot loop
|
||||
misbehaves under host load, inspect this shim first. Keep as-is until then.
|
||||
|
||||
Put both in section **E. Process / method notes** (or a new subsection if
|
||||
that reads better). Match the file's existing terse style. No code changes.
|
||||
|
||||
**Verify:** file still renders as markdown; `git diff` is docs-only.
|
||||
|
||||
**On expiry:** commit whatever is written; partial is fine.
|
||||
|
||||
---
|
||||
|
||||
## Task B — mechanical dead-code removal, single file
|
||||
|
||||
**Goal:** remove the closed-out **D63** debug scaffolding from
|
||||
**`port/src/libultra.c` ONLY** (leave `port/fast3d/gfx_pc.cpp`'s D63 code
|
||||
alone — that file is in use by the Jungle work; a separate cleanup later).
|
||||
|
||||
**FILES YOU MAY TOUCH:** `port/src/libultra.c` only.
|
||||
|
||||
D63 is a closed finding; this code is dead weight in the hottest function in
|
||||
the port. Remove, in `port/src/libultra.c`:
|
||||
|
||||
- the helper block around lines ~490–610: `d63WatchGunbarrelSlot`,
|
||||
`d63CheckSlot` (the "log only when the slot value changes" fn), the
|
||||
`D63Act` struct + `s_d63act` ring buffer + `D63_ACT_N`, `d63On`, `d63Tid`,
|
||||
`d63Act`, the watchdog thread fn + `d63WatchdogStart`, and the
|
||||
`D63 clobber-watch` block.
|
||||
- every call site marked `/* TEMP D63 */`: `d63WatchdogStart()` (~261),
|
||||
`d63Act("send")` + `d63WatchGunbarrelSlot()` (~617–618),
|
||||
`d63Act("recv")` + `d63WatchGunbarrelSlot()` (~658–659),
|
||||
`d63Act(...)` (~1110), and the two `getenv("GE_D63")` gfx-task logging
|
||||
blocks (~1117–1147).
|
||||
|
||||
Grep `D63` and `d63` in the file afterwards — should be zero hits.
|
||||
|
||||
**CONSTRAINTS:** no behavior change; deletion only; do not touch any other
|
||||
file; do not remove non-D63 code even if it looks unused.
|
||||
|
||||
**BUDGET:** <= 3 build cycles. `export PATH="/c/msys64/mingw64/bin:$PATH" &&
|
||||
./build-pc.sh ntsc-final` must stay green (240/240 link).
|
||||
|
||||
**Verify:** build green; `grep -in d63 port/src/libultra.c` empty;
|
||||
`./build-pc/ge007.x86_64.exe -level_09` still boots to frames (no crash in
|
||||
first ~15 s).
|
||||
|
||||
**On expiry:** `git checkout port/src/libultra.c` (revert) and write up which
|
||||
symbols were still entangled.
|
||||
|
||||
**REPORT:** list of removed symbols + line count delta + build result.
|
||||
+44
-11
@@ -128,19 +128,52 @@ Full workstream breakdown (WS1–WS6) in `docs/PLAN-linear-level-sweep.md`.
|
||||
§F/§H **D130**; PORT-LEARNINGS §A. Verified: -level_34 0/~14, -level_35
|
||||
0/4; -level_09/20/24 unregressed.
|
||||
|
||||
## Next task — Jungle `-level_37` (C2m, the last crash)
|
||||
## Done this session (M-19) — D131 (Jungle), D63 scaffolding removal
|
||||
|
||||
Jungle renders **~300 frames** then faults in `gfx_sp_matrix`
|
||||
(`gfx_pc.cpp:1046`, fault `0x401c68e0`) — an explosion / particle DL
|
||||
`G_MTX` with a bad matrix pointer. D75 / D124-Jungle matrix-family
|
||||
territory (compiled/global DL, NOT the per-level model-GDL path — that
|
||||
premise is dead, see D130). `docs/BRIEF-C2gdl-model-reloc.md` is now
|
||||
mostly obsolete. Likely near `port/src/gimgfixup.c` (D124-Jungle) /
|
||||
compiled `globalDL_0xNNN` matrix refs, or fast3d's `seg_addr` for a
|
||||
`G_MTX` w1. Then all 21 → hand `docs/LEVEL-PLAYTEST.md` to the user (WS6).
|
||||
- **D131** (`port/fast3d/gfx_pc.cpp`) — Jungle `-level_37` C2m crash.
|
||||
`explosionRenderPropSmoke` passes a compiled `.bss` matrix symbol
|
||||
(`&dword_CODE_bss_8007A100`) through `osVirtualToPhysical()` — a
|
||||
`u32`-returning shim — into `gSPMatrix`, truncating the `0x1_00000000`
|
||||
module high word → w1 = `0x401c68e0` → wild deref in `gfx_sp_matrix`
|
||||
when the first explosion draws (~frame 300). NOT `gimgfixup` / the
|
||||
model-GDL path (that premise was already dead per D130). Fix: `seg_addr`
|
||||
restores the module high word for a fallthrough w1 in
|
||||
`[0x40000000, 0x70000000)`. Covers ~30 latent `osVirtualToPhysical(<compiled
|
||||
matrix/vtx symbol>)` sites (explosion/glass/blood/bondview2). Verified:
|
||||
Jungle renders to frame 1500–2400+ crash-free; `-level_20`/`-level_24`
|
||||
unregressed. §F/§H **D131**, PORT-LEARNINGS §A.
|
||||
- **D63 scaffolding removed** — dead TEMP D63 probe calls stripped from
|
||||
`port/src/libultra.c` (watchdog thread + activity ring + slot watchers)
|
||||
and the `#ifdef PORT` probe blocks in `blood_animation.c`, `dyn.c`,
|
||||
`front.c`, `rsp.c`, `title.c`. All inert (env-gated / no side effects);
|
||||
build links clean. `port/fast3d/gfx_pc.cpp` D63 trail code left for a
|
||||
later pass. Bug class D24-implications + `osYieldThread` watch item added
|
||||
to PORT-LEARNINGS §E.
|
||||
|
||||
Everything else: hand `docs/LEVEL-PLAYTEST.md` to the user for the WS6
|
||||
completion pass (real input, per-level objective checklist).
|
||||
## Next task — two pre-existing regressions vs the M-18 handoff
|
||||
|
||||
Both reproduce on a **clean checkout of master `0a4b3bae`** (proven by
|
||||
`git stash` + rebuild), so they predate M-19's changes — a fast3d-only
|
||||
edit cannot cause a pre-first-frame boot crash.
|
||||
|
||||
1. **`-level_09` (BUNKER1) crashes at boot** — `frames=0`, PC
|
||||
`0x1400066fc`, fault `0x00a2fc68` (= stack ptr `0x0fa2fc68` with the top
|
||||
nibble masked → a 24/28-bit segment mask hitting a real pointer). The
|
||||
M-18 handoff's "`-level_09`/20/24 unregressed" is now false for 09.
|
||||
**Start here:** `git bisect` D125 (`a06eb364`) → HEAD against
|
||||
`./build-pc/ge007.x86_64.exe -level_9` (`frames=0` + crash = bad).
|
||||
Suspect D126 (objective sub-record relayout) or D128 (portal stride).
|
||||
2. **Intro renders mostly black** — legal/logo frames are 0–6% non-clear
|
||||
on clean master (`GE_PCDUMP="1-600:60"` + `pixcount.py`). The M-18
|
||||
handoff claims "the entire intro renders". Check `framediff.py` vs
|
||||
`tools_pc/golden/`.
|
||||
3. **Silo intro fly-down cinematic hang** (user report M-19) —
|
||||
intermittent; one `-level_20` run went 300 frames clean. May be the
|
||||
same class as #2 or D117 nondeterminism under load.
|
||||
|
||||
After those: all 21 load+render → hand `docs/LEVEL-PLAYTEST.md` to the
|
||||
user for the WS6 completion pass (real input, per-level objective
|
||||
checklist).
|
||||
|
||||
**Regen gotcha:** `d69_emit.py` rewrites `data/pccg-<r>/pccg.bin` from
|
||||
scratch with only the 52 bg/stan rows — you MUST follow it with
|
||||
|
||||
@@ -12,7 +12,7 @@ Build = `f2beae4b` + `tools_pc/d88_propdefs.py` (D123) + `port/src/gimgfixup.c`
|
||||
|
||||
| Level | # | Status | Crash site | Class |
|
||||
|---|---|---|---|---|
|
||||
| Bunker1 | 09 | **PASS** 91.7% | — | — |
|
||||
| Bunker1 | 09 | **CRASH (regressed since M-18)** | boot crash `frames=0`, PC `0x1400066fc`, fault `0x00a2fc68` (stack ptr, top nibble masked). Reproduces on clean master `0a4b3bae` → pre-existing, not D131. Bisect D125→HEAD. | **new** |
|
||||
| Silo | 20 | **PASS** 91.7% | — | — |
|
||||
| Archives | 24 | **PASS** 91.1% | — | — |
|
||||
| Train | 25 | **PASS** 87.0% | — | — |
|
||||
@@ -26,7 +26,7 @@ Build = `f2beae4b` + `tools_pc/d88_propdefs.py` (D123) + `port/src/gimgfixup.c`
|
||||
| Cradle | 41 | **PASS** 55.4% (low — partial render, no crash) | — (C1 fixed, D123) | — |
|
||||
| Runway | 35 | **PASS** | — (D130: `romdataFixupFont` glyph-relayout aliasing) | — |
|
||||
| Facility | 34 | **PASS** | — (D130: `romdataFixupFont` corrupted glyph `#`/`"` pixeldata → fast3d AV) | — |
|
||||
| Jungle | 37 | CRASH | `gfx_sp_matrix` gfx_pc.cpp:1046 (fault 0x401c68e0) — renders ~300 frames then explosion-DL `G_MTX` (D75/matrix family); separate from D130 | **C2m** |
|
||||
| Jungle | 37 | **PASS** 91.7% (frame 1500–2400+ crash-free) | — (D131: `osVirtualToPhysical()` truncated a compiled `.bss` matrix ptr in `explosionRenderPropSmoke` → `seg_addr` now restores the module high word) | — |
|
||||
| Aztec | 28 | **PASS** 90.8% | — (C3 fixed, D125) | — |
|
||||
| Bunker2 | 27 | **PASS** 91.5% | — (C3r fixed, D126) | — |
|
||||
| Depot | 30 | **PASS** 79.8% | — (C4 fixed, D126) | — |
|
||||
@@ -34,7 +34,12 @@ Build = `f2beae4b` + `tools_pc/d88_propdefs.py` (D123) + `port/src/gimgfixup.c`
|
||||
| Surface2 | 43 | **PASS** 70.4% | — (C6 fixed, D126) | — |
|
||||
| Surface1 | 36 | **PASS** 77.5% | — (C7 guarded, D127) | — |
|
||||
|
||||
**20 / 21 PASS** (M-18). D130 cleared C2 Facility + Runway — the crash was
|
||||
**19 / 21** (M-19). D131 cleared C2m Jungle (explosion-DL `G_MTX` truncated
|
||||
compiled-symbol pointer). **But `-level_09` (Bunker1) regressed to a boot
|
||||
crash sometime between M-18 and now** — reproduces on clean master, so it
|
||||
is not an M-19 change; bisect D125→HEAD. Net 20→19 until 09 is refixed.
|
||||
|
||||
**(M-18) 20 / 21 PASS.** D130 cleared C2 Facility + Runway — the crash was
|
||||
`romdataFixupFont` corrupting fontchar glyphs 0/1/2 (in-place 24→32B relayout
|
||||
aliases for low indices), NOT the model-GDL relocation the D124-Facility
|
||||
addendum suspected. Only Jungle (C2m, explosion-DL `G_MTX`, ~frame 300)
|
||||
|
||||
@@ -821,6 +821,7 @@ covers D24–D69; the log continues in §H (D32 procedure, D70–D121).
|
||||
| D125 | crash classes C3+C6 (Aztec/Bunker2/Surface2): **root cause found (M-16)** — `tools_pc/d88_emit.py:374` assigns a 4-byte literal to an 8-byte slice (`out[dst_o+0x30:dst_o+0x38] = b"\x00…"`, the stan zero-fill in `emit_pad`); every pad/boundpad record silently shrinks the output bytearray by 4 B, and once the tail falls below the boundpad plink string blob, later verbatim leaf writes hit Python out-of-range slice semantics (insert at current end, not relocated offset) → boundpad names drift/truncate (Aztec pad33 `p138d2`→`8d2`) → `stanPackId()` reject → `getposstan()` NULL stan → `setupDoor` leaves door `model=NULL` → crash `propobj.c:13601`. M-14's "propDefs zeros in RAM" was a misread; sidecar propdefs were always correct (M-15) and post-load RAM matches the sidecar byte-for-byte (M-16) | **resolved (M-16b)** — line 374 → 8 NULs; all 21 sidecars regen'd; **Aztec `-level_28` now PASSES** (was C3 CRASH). Bunker2 falls through to a separate DOOR-tail `linkedDoor` layout bug (C3 residual) |
|
||||
| D126 | crash classes C3r/C4/C6 (Bunker2 `-level_27` `door7F054FB4` propobj.c:13523, Depot `-level_30` prop.c:902, Surface2 `-level_43` loadobjectmodel.c:393): the objective sub-records `criteria_picture` (30), `criteria_roomentered` (32), `criteria_deposit` (33), `setup_objective_text` (35) each end in a `T *next` list pointer that the setup walk (`set_parent_cur_obj_*` / `setup_briefing_text_entry_parent`) writes unconditionally. On PC that pointer widens 4→8B and lands 8-aligned at offset 16 → struct is 24B/6w (N64 16/20). `d88_propdefs.py` emitted them at N64 size via the generic arm → the runtime 8-byte `->next` write clobbered the *next* record's header → propdef walk desynced, command indices drifted ~100, `linkedDoorOffset + arg2` resolved to the wrong record → door `linkedDoor` chain walked into garbage. | resolved — `d88_propdefs.py` PROPDEF_PC_BYTES[30/32/33/35]=24 + typed handler; `loadobjectmodel.c` sizepropdef PORT returns 6. Bunker2/Depot/Surface2 now PASS (13→16/21) |
|
||||
| D124 | crash class C2: fast3d bad texture pointer. **Jungle** (`0xabcd0824`): `gimgSyncCompiledGlobalDLs()` slot-detect keyed on the post-fixup marker, which `texLoad()` had already overwritten → compiled `globalDL_0xNNN` explosion DLs kept link-time `IMAGESEG` words → latent on every level, tripped by the first explosion-DL draw. **Facility** (`0x72181ee8`): see **D130** — the model-GDL-relocation hypothesis (M-14 addendum) was WRONG; real cause was `romdataFixupFont` | Jungle fixed (`port/src/gimgfixup.c`); Facility → D130 |
|
||||
| D131 | crash class C2m (Jungle `-level_37`): fast3d `gfx_sp_matrix` AV on a wild matrix pointer `0x401c68e0` (`gfx_pc.cpp:1046`) ~frame 300, when the first explosion/smoke prop renders. `explosionRenderPropSmoke` builds `gSPMatrix(gdl++, osVirtualToPhysical((void*)&dword_CODE_bss_8007A100), …MODELVIEW)` (+ `applyRoomMatrixToDisplayList`). `osVirtualToPhysical()` is a `u32`-returning shim (`libultra.c:1207`) → truncates the compiled `.bss` symbol's `0x1_00000000` module high word → w1 = `0x40xxxxxx` → `seg_addr()` returns it raw. Same class as D94 (chraction 32-bit ptr truncation), but in a GBI DL word. The projection matrix in the same DL is fine (`get_BONDdata_field_10E0()` is a runtime `0x70xxxxxx` ptr, fits u32); the `gSPDisplayList(&globalDL_0xNNN)` refs are fine (port `Gwords.w1` is 64-bit `uintptr_t`, no macro truncation). ~30 `osVirtualToPhysical(<compiled matrix/vtx symbol>)` sites exist (`explosion.c`, `glass*.c`, `blood_animation.c`, `bondview2.c`) — all latent until that effect first draws. | resolved — `seg_addr()` restores the module high word for any fallthrough w1 in `[0x40000000, 0x70000000)` (module fixed-based at `0x140000000`, no ASLR; DRAM/KSEG0/segmented/phys all handled earlier). Jungle renders to frame 2400+ clean; `-level_20`/`-level_24` unregressed. **18→19/21.** (`-level_09` has a separate pre-existing boot crash, see below.) |
|
||||
| D130 | crash class C2 (Facility `-level_34`, Runway `-level_35`): `import_texture_i8` AV on a wild texture pointer (`0x72181ee8`), baked into the HUD glyph DL by `gDPLoadTextureBlock(gdl, curchar->pixeldata, …)` when the level-title string ("Chemical Warfare Facility #2") renders `#`/`"`. Root cause: `romdataFixupFont` (`port/src/romdata.c`) converts the N64 24B fontchar array to the PC 32B array **in place**, forward-field, backward-glyph. PC−N64 stride = 8, so for glyphs 0/1/2 `d` overlaps `s` by less than the 24B read span and an early field write clobbers a later field's source mid-`for k<5` loop → glyph 1's `width` = `bswap(index)` = `0x01000000`, glyph 2's `pixeldata` = `pcPixOff+(index−pixStart)` ≈ `0x020002e8` → `+= font_base` → wild → fast3d AV. On N64 the array is read-only rodata, never re-laid-out, so no bug there. NOT the model-GDL relocation (`sub_GAME_7F0762E0` / `texLoadFromGdl`) the D124-Facility addendum suspected — `gdl` there is still a segmented `0x05xxxxxx` value so the `& 0x00ffffff` masks are correct, and `texLoadFromGdl` never copies a `G_SETTIMG` for these levels. | resolved — stage all 6 N64 fields in a local `f[6]` before writing any. Facility + Runway now PASS (16→18/21). Probes reverted. |
|
||||
|
||||
Phase 2 replaced the Phase-1 demo loop with the real `mainproc()` on real OS
|
||||
@@ -4390,6 +4391,63 @@ unregressed. Sweep 13 → 16/21. Generalisable quirk appended to
|
||||
align), C2m Jungle (`G_MTX`), C5 Control (BG portal), C7 Surface1
|
||||
(`sndSetupSound`).
|
||||
|
||||
**D131 (session M-19) — Jungle `-level_37` C2m crash: `osVirtualToPhysical()`
|
||||
truncates a compiled-symbol pointer inside a GBI matrix command.** Jungle
|
||||
renders ~300 frames then AVs in `gfx_sp_matrix` (`gfx_pc.cpp:1046`,
|
||||
`int32_t int_part = addr[…]`) with `addr = 0x401c68e0`. Caller is the `G_MTX`
|
||||
case of `gfx_run_dl` → `seg_addr(cmd->words.w1)`.
|
||||
|
||||
Probe (`GE_MTXPROBE`, reverted) dumped the faulting DL — a well-formed model
|
||||
render sequence in a per-frame DRAM GDL: `gSPMatrix(PROJECTION,LOAD)` w1 =
|
||||
`0x700d8070` (valid), `gSPMatrix(MODELVIEW,LOAD)` w1 = `0x401acbe0` (bad),
|
||||
`gSPMatrix(MODELVIEW,MUL)` w1 = `0x401c68e0` (bad, the fault), `gSPVertex`
|
||||
w1 = `0x700da350` (valid). All lens `0x40`, opcodes sane — the walk is *not*
|
||||
desynced, only the modelview-matrix pointers are wrong.
|
||||
|
||||
`0x401c68e0` == `(u32)(0x1_401c68e0)` — a compiled-module address with the
|
||||
`0x1_00000000` high word dropped (module fixed-based at `0x140000000`, cf.
|
||||
D94 `chraction.c:1243` comment). Source: `explosionRenderPropSmoke`
|
||||
(`explosion.c:1501`) does
|
||||
`gSPMatrix(gdl++, osVirtualToPhysical((void*)&dword_CODE_bss_8007A100),
|
||||
G_MTX_NOPUSH|G_MTX_MUL|G_MTX_MODELVIEW)` — `&dword_CODE_bss_8007A100` is a
|
||||
compiled `.bss` matrix; `osVirtualToPhysical()` is `(u32)(uintptr_t)va`
|
||||
(`libultra.c:1207`), so the store truncates. The `[-1]` LOAD matrix is the
|
||||
room matrix from `applyRoomMatrixToDisplayList` (same truncation path).
|
||||
Why the projection matrix is fine: `get_BONDdata_field_10E0()` returns a
|
||||
runtime `0x70xxxxxx` pointer that survives the `u32` cast. Why
|
||||
`gSPDisplayList(&globalDL_0xNNN)` is fine: the port's `Gwords.w1` is a
|
||||
64-bit `uintptr_t` (`include/PR/gbi.h:1730`) and `gDma1p` stores the full
|
||||
pointer — only `osVirtualToPhysical` truncates.
|
||||
|
||||
~30 sites pass a compiled matrix/vtx symbol through `osVirtualToPhysical`
|
||||
(`explosion.c`, `glass.c`/`glass2.c`, `blood_animation.c`, `bondview2.c`) —
|
||||
each latent until that effect first draws, which is why only Jungle (an
|
||||
early scripted explosion) tripped it in the no-input sweep.
|
||||
|
||||
**Fix** (`port/fast3d/gfx_pc.cpp` `seg_addr`): at the final fallthrough,
|
||||
if `w1 ∈ [0x40000000, 0x70000000)` restore the module high word
|
||||
(`(mod_hi | w1)`, `mod_hi` read from this TU's own load address). Everything
|
||||
legit that reaches the fallthrough is either DRAM V1 (`≥0x70000000`), KSEG0
|
||||
(`≥0x80000000`), an LSB-set / low-nibble segmented address, or a
|
||||
sub-`0x800000` physical offset — all handled in earlier branches — so the
|
||||
range is unambiguous. Narrow, ABI/pointer-width class (same as D94/D3x).
|
||||
Verified: Jungle renders to logic-frame 2400+ crash-free at 91.7% non-clear;
|
||||
`-level_20` (Silo) + `-level_24` (Archives) unregressed. **Sweep 18→19/21.**
|
||||
|
||||
Not fixed this session: **`-level_09` (BUNKER1) now crashes at boot**
|
||||
(`frames=0`, PC `0x1400066fc`, fault `0x00a2fc68` — a stack pointer
|
||||
`0x0fa2fc68` with the top nibble masked, i.e. another 28/24-bit segment-mask
|
||||
applied to a real pointer). Reproduced on a **clean `git stash` checkout of
|
||||
master `0a4b3bae`** → pre-existing regression, not caused by D131 (a
|
||||
fast3d-only change cannot affect a pre-first-frame boot crash). Contradicts
|
||||
the M-18 handoff's "`-level_09` unregressed" claim; likely fallout from a
|
||||
D126/D128 propdef/portal change or an environmental sidecar/ROM mismatch.
|
||||
Next session: `git bisect` D125→HEAD against `-level_09`. Silo also shows an
|
||||
intermittent hang in the intro fly-down-to-Bond cinematic (user report;
|
||||
not always reproducible — ran 300 frames clean here).
|
||||
|
||||
---
|
||||
|
||||
**D130 (session M-18) — Facility + Runway C2 crash was `romdataFixupFont`,
|
||||
NOT the model-GDL relocation.** `-level_34` (and `-level_35`) fault in
|
||||
`import_texture_i8` (`gfx_pc.cpp:821`) on `loaded_texture.addr = 0x72181ee8`,
|
||||
|
||||
@@ -62,6 +62,22 @@ state.
|
||||
a level actually feeds a control byte to the HUD text (none do yet; D130
|
||||
was a font-relayout bug, not this).
|
||||
|
||||
- **D131 corollary — `osVirtualToPhysical()` truncates a compiled-symbol
|
||||
pointer to 32 bits.** The port shim is `(u32)(uintptr_t)va` (`libultra.c`).
|
||||
For a runtime DRAM pointer (`0x70xxxxxx`) the cast is lossless; for a
|
||||
**compiled module symbol** (`.bss`/`.rodata` matrix, e.g.
|
||||
`&dword_CODE_bss_8007A100` in `explosionRenderPropSmoke`) it drops the
|
||||
`0x1_00000000` module high word, so the GBI w1 becomes `0x40xxxxxx` and
|
||||
`seg_addr()` hands fast3d a wild pointer → AV in `gfx_sp_matrix` /
|
||||
`gfx_sp_vertex`. Same class as D94 (`chraction.c:1243`), but in a DL word.
|
||||
~30 latent sites (`grep 'osVirtualToPhysical(' src/game/{explosion,glass,glass2,blood_animation,bondview2}.c`),
|
||||
each armed only when that effect first draws. Fixed once in `seg_addr()`:
|
||||
restore the high word for a fallthrough `w1 ∈ [0x40000000, 0x70000000)`
|
||||
(module is fixed-based at `0x140000000`; DRAM/KSEG0/segmented/phys are all
|
||||
handled in earlier branches). `gSPDisplayList(&globalDL_0xNNN)` is NOT
|
||||
affected — the port's `Gwords.w1` is 64-bit and `gDma1p` stores the full
|
||||
pointer; only `osVirtualToPhysical` truncates.
|
||||
|
||||
## B. 16-byte PC `Gfx` / `Vtx` vs 8-byte N64
|
||||
|
||||
Any buffer reservation, `memcpy` size, slot stride, or pool budget
|
||||
@@ -214,3 +230,13 @@ deprioritised below level-progression / crash work. See
|
||||
fixed-tick mode was assessed not-narrow (redesigns retrace/tick
|
||||
semantics); design is in §F D117 if someone picks it up, after which
|
||||
`framediff.py --exact` becomes usable.
|
||||
- **D24-implications — host-scheduling nondeterminism / fake priority
|
||||
semantics:** the pthread kernel does not enforce N64's 0–31 priorities
|
||||
(`osYieldThread` = `Sleep(0)`), so interleavings impossible on console can
|
||||
occur, and frame timing has host jitter. When a flaky timing bug appears
|
||||
(especially Phase 3 audio underruns), reach first for host thread
|
||||
priorities (`SetThreadPriority`: scheduler thread time-critical, tick
|
||||
normal) and the deferred `GE_DETERM` mode (D117) — not for kernel changes.
|
||||
- **Watch item: `osYieldThread` = `Sleep(0)`.** The one place we fake
|
||||
cooperative behavior. If a level-sweep hot loop misbehaves under host load,
|
||||
this shim is the first thing to inspect. Keep as-is until then.
|
||||
@@ -2405,6 +2405,23 @@ static inline void *seg_addr(uintptr_t w1) {
|
||||
if (w1 < 0x800000) {
|
||||
return (void *)(w1 + 0x80000000);
|
||||
}
|
||||
// D131: a GBI DL built by game code can reference a COMPILED symbol via
|
||||
// osVirtualToPhysical() (a u32-returning shim), which truncates the
|
||||
// module's 0x1_00000000 high word. Seen in explosionRenderPropSmoke:
|
||||
// gSPMatrix(gdl++, osVirtualToPhysical((void*)&dword_CODE_bss_8007A100),
|
||||
// ..MODELVIEW) -> w1 == 0x40xxxxxx -> wild deref in gfx_sp_matrix. The
|
||||
// module is based at 0x140000000 (fixed, no ASLR), and nothing legit
|
||||
// reaches this fallthrough with a value in [0x40000000, DRAM_V1): DRAM
|
||||
// (>=0x70000000), KSEG0 (>=0x80000000), segmented addrs and sub-0x800000
|
||||
// physical offsets are all handled above. Restore the high word from
|
||||
// this TU's own load address.
|
||||
{
|
||||
static const uintptr_t mod_hi =
|
||||
((uintptr_t)(void *)&segmentPointers[0]) & 0xffffffff00000000ULL;
|
||||
if (mod_hi && w1 >= 0x40000000 && w1 < 0x70000000) {
|
||||
return (void *)(mod_hi | w1);
|
||||
}
|
||||
}
|
||||
return (void *)w1;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user