Sprite RAM (Object Attribute Memory) Access

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Sprite RAM (Object Attribute Memory) Access
by on (#52889)
Hey all! I wanted to post this question that I originally posted on the Emuversal Bulletin Board (here). I posted it there by mistake before I knew about this awesome NESdev forum!! Anyway, I wanted to put it here so that more people could benefit from the question and the great answer that Disch provided.

Following is my original post:
=======================================================

I've got a question regarding access to the PPU's object attribute memory (OAM) (a.k.a. Sprite RAM) via $2003 and $2004. There is very conflicting information on these registers from various documentation sources. For example:

- 2C02 Tech Reference by Brady Taylor states register $2004 is read/write and either a read or a write will increment the address stored in $2003.

- http://nesdevwiki.org/wiki/NES_PPU states register $2004 is read/write but _only_ writes will increment the address in $2003.

- Still other documentation (e.g. NEStech by Jeremy Chadwick) states that $2004 is write-only and cannot be read from at all!

- I tested some code in NEStopia and it clearly increments the address in $2003 only on writes and _not_ on reads.

- I tested the same code in VirtuaNES and it clearly increments on writes and reads!

- I tested the same code on the FCEUX and JNES emulators and I don't think they even allow you to read from sprite RAM as far as I can tell.

Seeing as how there are so many different implementations in the software emulator world I'm beginning to wonder if there are any games out there that actually care about this...??? Haha.

But does anyone *KNOW* what a real NES does to $2003 when reading from $2004? Or have a way that they can test it on a real NES for me to find out?? I would like my NES implementation to be as accurate as possible. If I don't get any responses then I will go with the way that NEStopia implements it (i.e. increment $2003 on writes but not on reads).

=======================================================
Following is the answer that Disch provided (along with some followup details that aren't in the Emuversal post):

how it works:

1) writes to $2004 increment $2003

2) reads from $2004 do not increment $2003

3) $4014 simply reads from the given address and copies the data to $2004. It does this 256 times. So any side-effects of $2004 writes apply to $4014 as well.

4) during rendering, $2003 is changed by the PPU in order to fetch OAM (much like how the PPU address [$2006] is changed during rendering to fetch tiles). To my knowledge no emulators accurately simulate this, as exact details are not yet fully known.

5) Since $2003 is changed by the PPU during rendering -- at the end of rendering (provided the PPU was not disabled via $2001), $2003 finds its way back to $00. Some games (Akira comes to mind) rely on this.

jwdonal's followup question to item (5): You state, "$2003 finds its way back to $00". Can you please elaborate on this a bit more? Do you mean that $2003 is automatically reset to $00 at the end of rendering?

Disch's followup answer to item (5): Provided you leave the PPU on, yes, $2003 is reset to 0 at the end of rendering. However if you turn the PPU off before the end of rendering, $2003 will be semi-random. It exact value will depend on what sprites were are on screen and when in the frame you turned the PPU off.

6) If you turn off the PPU during rendering, $2003 will be scrambled (due to it being in whatever state the PPU was last using it as).

7) writing to $2004 during rendering "screws up". Exact results are unknown/unreliable, but probably result in OAM corruption and possibly mangling of $2003 resulting in incorrect sprites being rendered on the next scanline.

8) reading from $2004 during rendering exposes internal OAM fetches (this is outlined on the nesdev wiki). Some commercial games rely on this to find HBlank.

9) I'm not sure what happens when writing to $2003 during rendering. I'd wager it either the write has no effect (somewhat unlikely) or it jumbles up sprites for the next scanline (more likely).
Re: Sprite RAM (Object Attribute Memory) Access
by on (#52898)
jwdonal wrote:
Seeing as how there are so many different implementations in the software emulator world I'm beginning to wonder if there are any games out there that actually care about this...??? Haha.

I'm not aware of a single commercial game that uses $2003/$2004 for updating sprites, all of them use DMA, AFAIK. A handful of games rely on $2004 reading, and they work correctly in very few emulators (try the game Super Cars, for example).
Re: Sprite RAM (Object Attribute Memory) Access
by on (#53160)
tokumaru wrote:
A handful of games rely on $2004 reading, and they work correctly in very few emulators (try the game Super Cars, for example).


Excellent! I will make a note for the future to try Super Cars to make sure that my $2003/$2004 accesses are working correctly. It's always cool to know the name of a game or two that will stress particular aspects of the NES! Thanks!