1
0
Fork 0
mirror of https://github.com/imjasonh/nescript synced 2026-07-08 08:55:38 +00:00

runtime: reset PPU scroll after VRAM buffer drain

Each $2006 write inside __vram_buf_drain updates the PPU's `t`
(scroll) register, so leaving it pointing at the last buffer
entry's address shifted the next frame's rendering up/right by
however many cells we wrote past $2000. Reset by writing $00 to
$2006 twice (clears `t` and resets the write-toggle to high)
followed by $00 to $2005 twice (zero X/Y scroll). The HUD demo
golden flips from "smileys offset by ~16px" to the intended
red bar with white hearts and a yellow score digit.

https://claude.ai/code/session_01F7dHsgh7UX7SAK3wZ7JiKc
This commit is contained in:
Claude 2026-04-18 22:57:46 +00:00
parent a806bfd3bd
commit 1c00d20121
No known key found for this signature in database
5 changed files with 16 additions and 0 deletions

Binary file not shown.

Binary file not shown.

View file

@ -2045,6 +2045,22 @@ pub fn gen_vram_buf_drain() -> Vec<Instruction> {
out.push(Instruction::new(LDA, AM::Immediate(0))); out.push(Instruction::new(LDA, AM::Immediate(0)));
out.push(Instruction::new(STA, AM::Absolute(VRAM_BUF_HEAD))); out.push(Instruction::new(STA, AM::Absolute(VRAM_BUF_HEAD)));
out.push(Instruction::new(STA, AM::Absolute(VRAM_BUF_BASE))); out.push(Instruction::new(STA, AM::Absolute(VRAM_BUF_BASE)));
// Reset the PPU's internal scroll/address state. Each `$2006`
// write during the drain updated the PPU's `t` register
// (which holds the next scroll value); leaving it pointing
// at our last buffer entry's address would cause the next
// frame's rendering to start from a non-zero offset and the
// visible image would shift up/right by however many cells
// we wrote past `$2000`. The standard fix is to write `0` to
// `$2006` twice (resetting `t` to nametable 0 / cell 0) and
// then `0` to `$2005` twice (zero X / Y scroll). Two `$2006`
// writes also reset the `$2006`/`$2005` write-toggle latch
// to "high" so the next frame's drain sees a clean state.
out.push(Instruction::new(LDA, AM::Immediate(0)));
out.push(Instruction::new(STA, AM::Absolute(0x2006)));
out.push(Instruction::new(STA, AM::Absolute(0x2006)));
out.push(Instruction::new(STA, AM::Absolute(0x2005)));
out.push(Instruction::new(STA, AM::Absolute(0x2005)));
out.push(Instruction::implied(RTS)); out.push(Instruction::implied(RTS));
out out
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Before After
Before After