Correct usage of PPUSTATUS

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

User avatar
DRW
Posts: 2225
Joined: Sat Sep 07, 2013 2:59 pm

Correct usage of PPUSTATUS

Post by DRW »

When writing data to PPUADDR, we need to reset the high/low latch by writing LDA PPUSTATUS first.

Now, I've also seen the version BIT PPUSTATUS.

So, I have three questions:

1. Is there any advantage of using BIT over using LDA?

2. And can both versions be used for both, PPUADDR and PPUSCROLL?

3. Are there other PPU addresses where I have to reset the high/low latch by using PPUSTATUS? Or are PPUADDR and PPUSCROLL the only ones?
My game "City Trouble":
Gameplay video: https://youtu.be/Eee0yurkIW4
Download (ROM, manual, artworks): http://www.denny-r-walter.de/city.html
AWJ
Posts: 433
Joined: Mon Nov 10, 2008 3:09 pm

Re: Correct usage of PPUSTATUS

Post by AWJ »

DRW wrote:When writing data to PPUADDR, we need to reset the high/low latch by writing LDA PPUSTATUS first.

Now, I've also seen the version BIT PPUSTATUS.

So, I have three questions:

1. Is there any advantage of using BIT over using LDA?
Using BIT preserves the previous contents of A.
2. And can both versions be used for both, PPUADDR and PPUSCROLL?
Yes, the effect on the PPU is identical with either instruction. Both instructions do a read from memory, the difference is whether they put the data into A or not.
3. Are there other PPU addresses where I have to reset the high/low latch by using PPUSTATUS? Or are PPUADDR and PPUSCROLL the only ones?
PPUADDR and PPUSCROLL are the only write-twice registers that have a high/low latch.
User avatar
DRW
Posts: 2225
Joined: Sat Sep 07, 2013 2:59 pm

Re: Correct usage of PPUSTATUS

Post by DRW »

Thanks for the information.
My game "City Trouble":
Gameplay video: https://youtu.be/Eee0yurkIW4
Download (ROM, manual, artworks): http://www.denny-r-walter.de/city.html
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Correct usage of PPUSTATUS

Post by rainwarrior »

The other thing BIT does that LDA doesn't is it reads bit 6 (sprite 0 hit) into the V (overflow) flag, so for sprite 0 hit testing it's usually the best choice.

For bit 7 (vblank) both LDA and BIT put it in the N (sign) flag, so both are equally good unless you want to preserve A.

For bit 5 (sprite overflow) there's no convenient flag load. The best choice here is BIT, but after loading A with %00100000. (Because BIT does an AND operation without destroying A you can keep testing it in a loop.)


BIT's non-destructive AND is also useful for combination tests, e.g. if you want to test for sprite 0 and vblank together (for backup in case the hit fails unexpectedly?), you can load A with %11000000 and do a BIT test loop. (Take note: BIT's AND only updates the Z flag, the N/V flags are loaded directly from $2002 and not part of the AND operation.)


I just have a habit of using BIT with that register even if I don't need to preserve A. There's just such a strong correlation in practice between BIT and $2002 on the NES, it feels like the "natural" way to read it. (BIT does have some other uses, but they're relatively rare compared to seeing it as a $2002 read.)
tschak909
Posts: 142
Joined: Mon Jul 03, 2017 4:37 pm
Contact:

Re: Correct usage of PPUSTATUS

Post by tschak909 »

Yes, BIT was literally designed for situations, like this.

-Thom
Pokun
Posts: 2681
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: Correct usage of PPUSTATUS

Post by Pokun »

I see why BIT can be used to get bit 6 and 7, but I don't get why LDA misses bit 5 and 6?
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Correct usage of PPUSTATUS

Post by rainwarrior »

Pokun wrote:I see why BIT can be used to get bit 6 and 7, but I don't get why LDA misses bit 5 and 6?
tschak909 sort of answered that:
tschak909 wrote:BIT was literally designed for situations, like this.
The purpose of BIT is to use A as an AND mask to test an arbitrary bit (or any 8-bit mask) from a memory location. As an added bonus, it also has a direct fetch of bits 6 and 7 so that they could be used even more easily without having to prepare A. (I wonder if they were greedy enough whether they could have used the carry flag as well?)

LDA on the other hand is a general purpose load instruction. It only sets a minimum number of flags (zero flag and sign flag) becauase it needs to be unobtrusive. LDA gets interleaved with other instructions; think about how a 16-bit addition needs to have LDA in between two ADC instructions, etc. They weren't going to cram in extra "free bit test" stuff into assorted flags, that's very specific to BIT.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Correct usage of PPUSTATUS

Post by tokumaru »

Just wanted to point out that, from my own experience, that you don't *have* to reset the $2005/6 latch all the time, as long as your code is well behaved and never does any stray $2005/6 accesses. Clearing the latch can be seen as a safety measure, so if you feel more comfortable doing it, that's fine, but you don't *need* to do it. I never do it and never had any problems, and a lot of commercial games I debugged don't do it either.
User avatar
DRW
Posts: 2225
Joined: Sat Sep 07, 2013 2:59 pm

Re: Correct usage of PPUSTATUS

Post by DRW »

tokumaru wrote:Just wanted to point out that, from my own experience, that you don't *have* to reset the $2005/6 latch all the time, as long as your code is well behaved and never does any stray $2005/6 accesses.
That's exactly the reason why "City Trouble" still works despite me not using it for scrolling.

But here's a question: What if you don't use the latch and someone presses the reset button exactly between two STA PPUADDR? Wouldn't the following game be misaligned until you power it off?
My game "City Trouble":
Gameplay video: https://youtu.be/Eee0yurkIW4
Download (ROM, manual, artworks): http://www.denny-r-walter.de/city.html
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Correct usage of PPUSTATUS

Post by rainwarrior »

DRW wrote:But here's a question: What if you don't use the latch and someone presses the reset button exactly between two STA PPUADDR? Wouldn't the following game be misaligned until you power it off?
Yes, you must clear it once on startup, at the very least.

Though standard startup also polls $2002 for two frames to wait for the PPU to warm up anyway, so you've probably already cleared the latch doing that.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Correct usage of PPUSTATUS

Post by tokumaru »

DRW wrote:What if you don't use the latch and someone presses the reset button exactly between two STA PPUADDR? Wouldn't the following game be misaligned until you power it off?
The correct reset procedure requires you to wait a few frames for the PPU to initialize, and during this time we usually count frames by reading $2002 repeatedly and checking the vblank flag, so the latch is guaranteed to be cleared after resets.

EDIT: Like rainwarrior said.
User avatar
DRW
Posts: 2225
Joined: Sat Sep 07, 2013 2:59 pm

Re: Correct usage of PPUSTATUS

Post by DRW »

Oh, right: BIT PPUSTATUS in the wait for vblank function. I forgot about that.

Does anybody know of any other possible conceivable situation where the stuff can somehow misalign, even if I always read or write PPUADDR and PPUSCROLL in pairs?
My game "City Trouble":
Gameplay video: https://youtu.be/Eee0yurkIW4
Download (ROM, manual, artworks): http://www.denny-r-walter.de/city.html
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Correct usage of PPUSTATUS

Post by rainwarrior »

I think it's perfectly good practice to clear the latch at the start of an NMI handler's upload session, or when you're about to load a nametable, etc.

You don't strictly have to, but a few bytes/cycles of redundant latch clears in your game could make the difference between a latent bug that causes a hard fail vs. one that the program can recover from. I actually think they're worth putting in, personally.

There are a lot of ways bugs can arise that end up being completely benign with just a little bit of redundant code. Looking back at some code you shipped later on and thinking "that shouldn't have worked?", and then you realize that extra little bit of protection you'd written that you didn't expect to matter was actually doing its job. I've seen that enough times to think it's worth doing.
User avatar
DRW
Posts: 2225
Joined: Sat Sep 07, 2013 2:59 pm

Re: Correct usage of PPUSTATUS

Post by DRW »

O.k., I'll keep it then.
My game "City Trouble":
Gameplay video: https://youtu.be/Eee0yurkIW4
Download (ROM, manual, artworks): http://www.denny-r-walter.de/city.html
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Correct usage of PPUSTATUS

Post by tokumaru »

BTW, about a year ago I found out I could slightly abuse the way the high/low latch and $2005/6 writes work in order to speed up the updating of columns in the attribute tables in one of my engines: Change only low byte of VRAM address (good for attributes)
rainwarrior wrote:I think it's perfectly good practice to clear the latch at the start of an NMI handler's upload session, or when you're about to load a nametable, etc.
I'm not strongly against clearing the latch as a safety measure, just like I'm not against clearing all RAM during reset as a safety measure, but when done during development, these procedures could end up hiding bugs that'd be easy to catch otherwise. You should NOT have stray writes to $2005/6 in your game, ever, but how will you detect these bugs if you're clearing the latch left and right?
You don't strictly have to, but a few bytes/cycles of redundant latch clears in your game could make the difference between a latent bug that causes a hard fail vs. one that the program can recover from. I actually think they're worth putting in, personally.
My advice is, by all means, cover your ass by clearing whatever you can as much and as often as it takes for you to feel comfortable, but save such safety measures for the end of development, because while having bugs manifest themselves in the final product is a BAD thing, having them manifesting themselves during development is a GOOD thing.

Anyway, the reason I don't personally clear the latch is because I always find myself in situations where every cycle matters. I try to code my systems to be as dynamic as possible, and after the overhead of switching banks and deciding it does indeed have to process VRAM updates, my vblank handlers only have so much time left for the actual updates. The updates are scheduled dynamically according to the available time, and there are a few of them that I absolutely need to happen in the same frame, such as a row and a column of metatiles when the screen scrolls diagonally. I kid you not, the 4 cycles taken by a BIT $2002 were preventing me from fitting those 2 updates together. Between refactoring the more complex systems in hopes of shaving those cycles off from somewhere else or just removing the BIT $2002, the choice was easy. Ever since that happened, it has always made more sense to me to claim those 4 cycles as useful vram update time than using them for a safety measure I probably won't ever need. I guess I could clear the latch *after* the vram updates, but... meh.
Post Reply