Symptom
Across matrix/vertex/texture commands, w1 consistently has low 3 bits set:
- Matrix:
seg=0x00264503 (low 3 = 0x3 = exactly the params byte 0x03)
- Vertex:
seg=0x0026450B (low 4 = 0xB)
- Texture:
seg=0x00264503 (same)
After mask & 0x00FFFFF8, address resolves to 0x00264500 — but bytes there are a DL command stream (opcodes E7, BA, B9, BB, FC, FD, F5), not matrix/vertex/texture data.
What we know
- F3D_Gold ucode is tolerant of low 3 bits in w1 — DMA hardware truncates them, ucode never reads them as flags. Per gmain.s line 612-621.
- C-side macros (
gSPMatrix, gSPVertex, gSPSetTextureImage) put raw addresses in w1, no OR with flags.
- Yet observed bytes at masked address are NOT what they should be.
Hypothesis
Heap aliasing in the bump allocator at /tmp/ge_decomp/src/game/dyn.c:85 (g_GfxMemPos):
dynAllocateMatrix() returns g_GfxMemPos then g_GfxMemPos += sizeof(Mtx)
- Same allocator backs
dynAllocate(size) for arbitrary blocks AND DL chunks
- DL chunks emitted via
gSPDisplayList(rodata->BaseAddr) reference addresses inside the same heap region
- Possible: a
gSPMatrix(addr_X) actually receives a pointer to a sub-DL chunk because field_10E0 was set wrong upstream
Try next
- Read
gmain.s more carefully — find the EXACT instruction that consumes w1 in matrix/vertex/texture handlers. Confirm low-bits truly are masked vs extracted as flags.
- Trace
g_CurrentPlayer->field_10E0 — find ALL writers and verify they only ever set it to a Mtx pointer.
- Add runtime assertion in
dynAllocateMatrix that g_GfxMemPos & 0x3F == 0 (64-byte aligned).
Files
n64decomp/007 rsp/graphics/gmain.s (RSP asm — 1545 lines)
lib/rt64/src/hle/rt64_rsp.cpp::matrix (current decoder)
lib/rt64/src/hle/rt64_rsp.cpp::setTextureImage:1160
/tmp/ge_decomp/src/game/dyn.c:85 (allocator)
/tmp/ge_decomp/src/game/bondview.c:11882 (set_BONDdata_field_10E0 caller)
Acceptance criteria
Matrix calls decode to sensible affine/projection values (m[3] = [0,0,0,1] or m[*][3] = [0,0,0,1]).
Symptom
Across matrix/vertex/texture commands,
w1consistently has low 3 bits set:seg=0x00264503(low 3 = 0x3 = exactly the params byte 0x03)seg=0x0026450B(low 4 = 0xB)seg=0x00264503(same)After mask
& 0x00FFFFF8, address resolves to0x00264500— but bytes there are a DL command stream (opcodes E7, BA, B9, BB, FC, FD, F5), not matrix/vertex/texture data.What we know
gSPMatrix,gSPVertex,gSPSetTextureImage) put raw addresses in w1, no OR with flags.Hypothesis
Heap aliasing in the bump allocator at
/tmp/ge_decomp/src/game/dyn.c:85(g_GfxMemPos):dynAllocateMatrix()returnsg_GfxMemPostheng_GfxMemPos += sizeof(Mtx)dynAllocate(size)for arbitrary blocks AND DL chunksgSPDisplayList(rodata->BaseAddr)reference addresses inside the same heap regiongSPMatrix(addr_X)actually receives a pointer to a sub-DL chunk becausefield_10E0was set wrong upstreamTry next
gmain.smore carefully — find the EXACT instruction that consumes w1 in matrix/vertex/texture handlers. Confirm low-bits truly are masked vs extracted as flags.g_CurrentPlayer->field_10E0— find ALL writers and verify they only ever set it to a Mtx pointer.dynAllocateMatrixthatg_GfxMemPos & 0x3F == 0(64-byte aligned).Files
n64decomp/007 rsp/graphics/gmain.s(RSP asm — 1545 lines)lib/rt64/src/hle/rt64_rsp.cpp::matrix(current decoder)lib/rt64/src/hle/rt64_rsp.cpp::setTextureImage:1160/tmp/ge_decomp/src/game/dyn.c:85(allocator)/tmp/ge_decomp/src/game/bondview.c:11882(set_BONDdata_field_10E0 caller)Acceptance criteria
Matrix calls decode to sensible affine/projection values (m[3] = [0,0,0,1] or m[*][3] = [0,0,0,1]).