Page 1 of 1
Nintendo PPU-data format
Posted: Tue Nov 12, 2013 9:14 am
by oRBIT2002
I've discovered that Nintendo often uses the same way of storing PPU data into their NES-games. I was on my way writing some kind of ripper-tool but got a bit bored so I might never finish it, so perhaps someone else is interested in my findings.
The structure looks like this:
Code: Select all
dc.w PPUAddress (hi+lowbyte)
dc.b CONTROL
dc.b DATA (*CONTROL.LENGTH)
The structure can be repeated as a list (PPUAddress,Control,Data,PPUAddress,Control,Data etc.) and is terminated by a $0.
CONTROL has a few features:
bit 5-0 = LENGTH (number of bytes to insert).
bit 6 = RLE mode (1=Active)
bit 7 = PPU Write mode (0=Increment by 1, 1=Increment by 32)
When RLE mode is active (=1), DATA byte is inserted <CONTROL.LENGTH> number of times.
Re: Nintendo PPU-data format
Posted: Tue Nov 12, 2013 10:11 am
by Movax12
Slightly modified code from Super Mario Brothers to write such data to PPU: (using HL macros in ca65)
Note this is sub-optimal code: it's pretty slow compared to some techniques, but fast enough for many games:
Code: Select all
.proc WriteVRAMBufferToScreen
; Note: execution is to start at label: UpdateScreen
; register y is used to index the Buffer
; needed:
; define location for temp_word
; define Mirror_PPU_CTRL
.export ResetScroll, UpdateScreen
VRAM_Buffer_pointer = temp_word
repeat
; set PPU vram address:
mb PPU_ADDRESS := a
iny
mb PPU_ADDRESS := (VRAM_Buffer_pointer)[ y ]
iny
; load next third byte in stream, shift to the left and save in stack:
mb a := (VRAM_Buffer_pointer)[ y ] << 1
pha
; set ppu to increment by 32 by default
mb a := Mirror_PPU_CTRL | #%00000100
; if d7 of third byte was clear, ppu will increment address by 1 byte every write:
if carry clear
mb a := a & #%11111011
endif
; write contents of A to PPU_CTRL:
sta PPU_CTRL
; restore a
pla
; if d6 of third byte is set, repeat byte:
if a << 1 == carry set
; set d1, which will be shifted right and become carry
; and increment the index by one only
ora #%00000010
iny
endif
; shift back to the right twice to restore length value
; carry will be set now if repeat byte bit was set
mb a := a >> 2
; copy length into x
mb x := a
; loop and write data to vram:
repeat
; only increment index if this is not a repeating value:
if carry clear
iny
endif
mb PPU_DATA := (VRAM_Buffer_pointer)[ y ]
until dex == zero
; add end length plus one to the indirect at VRAM_Buffer_pointer
sec
; copy index to a
mb a := y
; add index to pointer base:
mb VRAM_Buffer_pointer := a +c VRAM_Buffer_pointer
mb VRAM_Buffer_pointer[ 1 ] := VRAM_Buffer_pointer[ 1 ] + C
; start here:
UpdateScreen:
; reset latch and load y with index zero
ldx PPU_STATUS
ldy #0
; if not zero, write to vram again:
until lda (VRAM_Buffer_pointer)[ y ] == zero
ResetScroll:
sta PPU_SCROLL
sta PPU_SCROLL
rts
.endproc
Re: Nintendo PPU-data format
Posted: Wed Nov 13, 2013 3:16 pm
by qbradq
That's pretty cool that they had some sort of shared libraries back in the day. When I was working on my NES software projects (before falling into the tool building trap

) I used a similar, all-be-it more simplistic format for my PPU updates.
Re: Nintendo PPU-data format
Posted: Thu Nov 14, 2013 7:02 am
by cpow
qbradq wrote:(before falling into the tool building trap

)
Ah yes..."I'd rather write programs that help write programs than write programs." Been there, living that!
The quote is referenced in a
wonderful book I wish everyone in software management and software development would read. Sadly, though, as the author mentions [in quoting Joel Spolsky], "most software engineers don't read enough [or anything] about their own field."
Re: Nintendo PPU-data format
Posted: Thu Nov 14, 2013 7:39 am
by tepples
Tool building has clearer requirements and needs less art.
Re: Nintendo PPU-data format
Posted: Thu Nov 14, 2013 7:49 am
by qbradq
tepples wrote:Tool building has clearer requirements and needs less art.
Word.
Plus, once I'm done with the tool I'll be able to pump out games lightning fast!
