VRAM question

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
User avatar
zanto
Posts: 57
Joined: Sun Mar 07, 2021 11:15 pm
Location: Rio de Janeiro, Brazil

VRAM question

Post by zanto »

I was debugging some code that is supposed to load tiles into a PPU nametable when I noticed something weird on the debugger. The video below shows it.
https://www.youtube.com/watch?v=yxfQaq5olgA

Basically, the VRAM address keeps changing even when I'm not making any reference to it. Also, when I send the nametable address I want to store the tiles at (using PPUADDR), the address changes right after the instructions. And when I store a tile in the PPU, the address goes up by like $1000. Is that normal? If not, what could I have done to cause such behavior?
User avatar
Controllerhead
Posts: 314
Joined: Tue Nov 13, 2018 4:58 am
Location: $4016
Contact:

Re: VRAM question

Post by Controllerhead »

zanto wrote: Thu Apr 08, 2021 7:06 pm Basically, the VRAM address keeps changing even when I'm not making any reference to it ... what could I have done to cause such behavior?
It's drawing the screen =p

Turn off sprite and background rendering bits in PPU_MASK to keep it still.
Image
User avatar
zanto
Posts: 57
Joined: Sun Mar 07, 2021 11:15 pm
Location: Rio de Janeiro, Brazil

Re: VRAM question

Post by zanto »

Oh >_< Of course, that makes sense. This code isn't executed during NMI. I interrupted NMI interrupts before executing this code because I don't want the screen to be drawn while it's running. But I guess it's not enough to make the screen not be drawn. Is there any way to make it happen? So, basically what I want to do is:

- Disable NMI and wait until there's no drawing (so vram isn't updated)
- Draw all bg stuff (I already have a code that makes this happen)
- Re-enable NMI

I can enable and disable NMI using bit 7 on $2000, but how do I wait until there's no more drawing? Will this wait for vblank routine work even with disabled NMI?

Code: Select all

WAITFORVBLANK:	; subroutine that waits for vblank. Wait until we're ready for the next screen redraw
	BIT PPUSTATUS
	BPL WAITFORVBLANK
	RTS
User avatar
Controllerhead
Posts: 314
Joined: Tue Nov 13, 2018 4:58 am
Location: $4016
Contact:

Re: VRAM question

Post by Controllerhead »

Disabling the NMI bit in $2000 won't stop the screen from drawing: It will stop the code from jumping to the NMI vector when vBlank starts at the beginning of scanline 241 (or later possibly). It's still a good idea, but, it's not enough.

PPU_MASK is what you're looking for: Store 0 in bits 4 and 5 of $2001: #%xxx00xxx
https://wiki.nesdev.com/w/index.php/PPU ... _.3E_write

You may also want to read PPU_STATUS ($2002) before re-enabling drawing and NMI: This will clear the "vBlank is happening status bit" and stop your code from jumping away if the middle of vBlank is happening: Depending on how your code is structured, or how far you are into vBlank, this could cause problems.
Image
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: VRAM question

Post by tokumaru »

Rather than disable NMIs, many programmers prefer to make VRAM, OAM and scroll updates conditional in the NMI handler and keep NMIs always on. The most obvious benefit of doing this is that you don't stop the other tasks that also run in the NMI handler, such as the audio driver, meaning that you can keep the music going even during screen transitions or other big VRAM updates if you wish.

Another benefit of keeping NMIs always on is that you can have a spot you NMI handler that takes care of enabling and disabling rendering always in vblank (during the main loop you update the copy of PPUMASK, and the NMI handler writes that to the actual register during vblank), avoiding screen jumps and explicit waits for vblank.

The final reason for keeping NMIs always on is that you get to easily avoid some hardware quirks, such as the occasional scroll glitches caused by mid-screen PPUCTRL or the unwanted NMIs fired by enabling NMIs during vblank. There are workarounds for these, but you can simply avoid these problems altogether by keeping NMIs always on.

I've been doing this for a long time now: I have a copy of PPUMASK in RAM that my NMI handler copies to the actual PPUMASK (this doesn't disrupt any VRAM operations that might be happening in the main thread), and then I check the rendering bits - if both are off, I simply skip all PPU operations in the NMI handler.
User avatar
zanto
Posts: 57
Joined: Sun Mar 07, 2021 11:15 pm
Location: Rio de Janeiro, Brazil

Re: VRAM question

Post by zanto »

Ah, thanks for the information. I didn't know disabling the NMI would have that many side effects. Your idea of keeping the ppumask bits in RAM is similar to what I've been doing with ppuctrl, so I guess I'll do that too!
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: VRAM question

Post by tokumaru »

zanto wrote: Thu Apr 08, 2021 10:40 pmAh, thanks for the information. I didn't know disabling the NMI would have that many side effects.
It's not as bad as it seems, after all there are workarounds for all of the drawbacks. I do think that keeping NMIs always on is a much cleaner approach, though.
Your idea of keeping the ppumask bits in RAM is similar to what I've been doing with ppuctrl, so I guess I'll do that too!
Yeah, it's very common to buffer this pair of registers, since most of the time you only want them to change between frames, during vblank.
Post Reply