ppu palette reading through $2006/$2007

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

Post Reply
User avatar
krzysiobal
Posts: 1036
Joined: Sun Jun 12, 2011 12:06 pm
Location: Poland
Contact:

ppu palette reading through $2006/$2007

Post by krzysiobal »

Can you please confirm if I am right or wrong, but when trying to read (and save) the whole ppu address space, starting from address 0, by:
* reading PPUSTATUS (reseting latch)
* setting PPUADDR to 0 (two times),
* reading and discardring PPUDATA for the first time
* and then reading PPUDATA and saving it somewhere 16384 times

the bytes at destination buffer:
* $0000-$3EFF will have true content of whatever was mapped there (VRAM/CHR-ROM/RAM)
* $3F00 will have the SECOND palette byte
* $3F01 will have the THIRD palette byte
..
*$3F1E will have the LAST palette byte
* $3F20 will have the FIRST palette byte and so on..
..
*$3FFE will have the LAST palette byte
*$3FFF will have the LAST palette byte again?
Last edited by krzysiobal on Sat Oct 01, 2022 7:38 am, edited 1 time in total.
User avatar
Quietust
Posts: 1918
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: ppu palette reading through $2006/$2007

Post by Quietust »

Reads from PPU $3F00-$3FFF return the value from palette RAM instead of the VRAM buffer - thus, the byte you thought you were reading from $3EFF was actually the first palette byte.

If you want to read the actual value from $3EFF, then you need to change the VRAM address before reading $2007 a second time.

Also, the value you thought you were reading from $3FFF was actually the underlying VRAM value mirrored from $2FFF, because the PPU was still fetching bytes from external memory into the VRAM buffer even while you were looking at the palette, and once the VRAM address rolled back to $0000 it started returning the buffer again.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
Fiskbit
Posts: 890
Joined: Sat Nov 18, 2017 9:15 pm

Re: ppu palette reading through $2006/$2007

Post by Fiskbit »

In addition to the off-by-one Quietust mentioned where you'll switch from the buffered PPU bus value to the unbuffered palette value when reading from $3F00-3FFF, note that the memory at $3F00-3FFF that is shadowed by palette RAM is all still readable because it still gets buffered, so if you change the PPU address to a non-palette address after each read in this region and do one read, you get the underlying memory from the buffer. I'm not aware of any case where this actually matters, and GTROM is the only mapper I know of that actually has RAM here, but it can be done if you need it.
User avatar
krzysiobal
Posts: 1036
Joined: Sun Jun 12, 2011 12:06 pm
Location: Poland
Contact:

Re: ppu palette reading through $2006/$2007

Post by krzysiobal »

Oh thank you, that absolutely clears how it works. First reading the wiki made me think that the one byte lag depends whether you set ppu address to $0000-$3eff (lag) or $3f00-$3fff (no lag) and stays there until next change of $2006, but it depents on the current PPU address, not the value set by $2006.

According to the PPU memory map:
Address range Size Description
$0000-$0FFF $1000 Pattern table 0
$1000-$1FFF $1000 Pattern table 1
$2000-$23FF $0400 Nametable 0
$2400-$27FF $0400 Nametable 1
$2800-$2BFF $0400 Nametable 2
$2C00-$2FFF $0400 Nametable 3
$3000-$3EFF $0F00 Mirrors of $2000-$2EFF
$3F00-$3F1F $0020 Palette RAM indexes
$3F20-$3FFF $00E0 Mirrors of $3F00-$3F1F

So the PPU asserts /RD for every read cycle, no matter of the address, and full 14 bit address, set by the $2006?
So the region $3000-$3eFF can potentially be not a mirror, if the cartridge has its own 8 kB of RAM mapped at $2000-$3fff?

Also, does the PPU assert /WR for write cycles to $3f00-$3fff?
Fiskbit
Posts: 890
Joined: Sat Nov 18, 2017 9:15 pm

Re: ppu palette reading through $2006/$2007

Post by Fiskbit »

Yes, PPU /RD is asserted on every read regardless of address, and PPU /WR is only asserted for writes to $0000-3EFF.

Unlike the CPU bus, the cartridge has full control over what is mapped where on the PPU bus aside from palette RAM, since palette RAM is entirely internal to the PPU. The PPU reads from specific places for specific things, but the PPU doesn't use $3000-3FFF on the PPU bus for any reason. On most cartridges, this region ends up being a mirror of nametable memory, but that's only a generalization of cartridge behavior, not any sort of requirement, since the PPU simply doesn't use this region. $3000-3FFF are free for the cartridge to use as it pleases and indeed may be unique RAM, with the restriction that reading from $3F00-3FFF is very slow on G or H PPUs because of palette RAM and writing to $3F00-3FFF is impossible.
User avatar
Quietust
Posts: 1918
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: ppu palette reading through $2006/$2007

Post by Quietust »

krzysiobal wrote: Sun Oct 02, 2022 2:30 am So the PPU asserts /RD for every read cycle, no matter of the address, and full 14 bit address, set by the $2006?
So the region $3000-$3eFF can potentially be not a mirror, if the cartridge has its own 8 kB of RAM mapped at $2000-$3fff?

Also, does the PPU assert /WR for write cycles to $3f00-$3fff?
I wouldn't say that it "asserts /RD" - rather, it schedules a VRAM read which gets performed in the background after the $2007 read finishes.
Interestingly, when you write to the palette, the PPU still schedules a VRAM write but prevents /WR from going low (while still pulsing ALE at the usual time).
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
Post Reply