Hello. I have been working on my own NES emulator project, and thus far I've been able to make sense of the NES's behavior thanks to NES DEV's documentation. However, today I have been digging into Super Mario Bros in FCEUX in order to diagnose a bug in my emulator, where SMB freezes the first time the upper left corner of the screen moves into nametable 1. I eventually noticed that in some frames, SMB writes a 1 to the nametable select on scanline 247, but the status bar continues to be rendered from nametable 0 as normal. I've looked all over for an explanation of this, but I can't figure it out. I figure I must be misunderstanding how the PPU uses the nametable select bits, or else I'm just making some kind of silly mistake. Any insights into this problem would be much appreciated.
I don't know what SMB does specifically, but the nametable select bit can also be set by writing to $2006.
More info:
Wiki: PPU Scrolling
I just checked and the game does indeed write $00 to $2006 twice after the $2000 write.
Hmmm. Wouldn't v's nametable select bits be set to the expected value when it's reset during rendering? The way I'm doing it now is to directly set v's bit 10 to PPUCTRL's bit 0 on every horizontal reset, and set v's bit 11 to PPUCTRL's bit 1 on every vertical reset. It seems like this doesn't work, but something like this must be happening in order for the game to change nametables during rendering. My best guess is that it has something to do with how v, t, and PPUCTRL interact, but I haven't been able to find the fine details on this.
In any case, it was my assumption that changes to v during vblank are supposed to be overwritten at the start of rendering, but I might be missing something.
The timing for when and what parts of
t are copied to
v are in that article, but to summarize:
In response to CPU writes:
- Second write to $2006: immediately copies t to v.
- Read or write to $2007: increment appropriately.
If rendering is enabled:
- End of vblank: copies Y bits of t to v from pixels 280 to 304 of the pre-render scanline (i believe it redundantly executes the copy once per pixel in that range?)
- End of scanline, dot 256: increment Y bits in v
- End of scanline, dot 257: copy X bits of t into v (also happens on pre-render scanline)
- Throughout scanline: increment X bits of v as needed to fetch tiles
$2000 and $2005 only write to
t, they do not immediately affect
v.
There's a lot more detail about all of this in the article.
rainwarrior wrote:
$2000 and $2005 only write to t, they do not immediately affect v.
Aha. That's the part I was missing; I wrongly assumed that $2000 held onto the nametable select bits to be used later, rather than writing to t immediately. Thanks for the help!
Edit: I do feel a bit sheepish now that I finally spotted the explanation in the PPU scrolling article. I swear I looked for it several times. I guess that's what I get for skimming a bit too lightly. Thank you for being patient with me!
...and that's exactly why several of us wrote out the "long example", step-by-step, of what the PPU is doing (re: several internal variables/bits) alongside the relevant 6502 instructions. :-) It's very easy to get this wrong/mess it up (both from an emulation perspective and from a coding/game developer perspective).
Sarospa wrote:
I do feel a bit sheepish now that I finally spotted the explanation in the PPU scrolling article. I swear I looked for it several times. I guess that's what I get for skimming a bit too lightly. Thank you for being patient with me!
Stuff that you know most of the details of is often the hardest thing to read clearly.
koitsu wrote:
...and that's exactly why several of us wrote out the "long example", step-by-step, of what the PPU is doing (re: several internal variables/bits) alongside the relevant 6502 instructions.
It's very easy to get this wrong/mess it up (both from an emulation perspective and from a coding/game developer perspective).
I'm definitely grateful for all the documentation on NES DEV. I couldn't have gotten this far without it. It really is amazing to see Super Mario Bros running on my own emulator. So thanks for all the work you guys have put into documenting this stuff!
rainwarrior wrote:
End of vblank: copies t to v from pixels 280 to 304 of the pre render scanline (i believe it redundantly executes the copy once per pixel in that range?)
It should be noted that only the
Y bits get copied during those pixels, since the X bits get copied at dot 257.