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

calima
Posts: 1745
Joined: Tue Oct 06, 2015 10:16 am

Re: Correct usage of PPUSTATUS

Post by calima »

Unrelated, but it always annoys me how none of the easily googlable 6502 sources tell how BIT works with a partial match.

0xf & 0x1 = 0x1
But what is the Z flag? Zero or one? Ie, for which case is it useful, testing everything or testing "is at least one bit set"?
Pokun
Posts: 2681
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: Correct usage of PPUSTATUS

Post by Pokun »

I think this 6502 reference page is the best one. It clearly explains that the Zero Flag is set if the result of A & M results in 0 (and cleared otherwise), and the Overflow and Negative Flags always gets a copy of bit 6 and 7 respectively.
rainwarrior wrote:
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.
I'm probably misunderstanding something but I still don't understand. I understand that BIT makes things easier, but I don't understand why LDA technically wouldn't work. If all bits in $2002 are fully readable, you should get a copy of them in the accumulator after LDA $2002 no? Then you could test the flags in the accumulator after doing that.
Or is it just that LDA would technically work but not practically in a game? I've never tested any of these flags in my NES programs yet, save for the vblank flag tests in the init code.
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Correct usage of PPUSTATUS

Post by tepples »

Pokun wrote:I understand that BIT makes things easier, but I don't understand why LDA technically wouldn't work. If all bits in $2002 are fully readable, you should get a copy of them in the accumulator after LDA $2002 no?
Correct. It's just a lot easier to test bit 6 in a tight-as-possible loop through BIT than through LDA.
Pokun
Posts: 2681
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: Correct usage of PPUSTATUS

Post by Pokun »

I see, I was just overthinking it. Thanks!
User avatar
Dwedit
Posts: 4924
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Re: Correct usage of PPUSTATUS

Post by Dwedit »

Okay stupid question...
There's also undocumented instruction 0C, NOP abs. Does that do a memory read then discard it with no changes to flags or register A?
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Correct usage of PPUSTATUS

Post by tepples »

Yes, as far as I'm aware. (Source)

But I'd use it and other unofficial opcodes only for reading MMIO ports or some other NES-specific task, not game logic that you expect to port to a machine using one of the 6502's successors. On the 65C02, HuC6280, and 65816, $0C is TSB, a read-modify-write instruction that's like ORA but writes the result back to memory rather than to A. (Source)
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Correct usage of PPUSTATUS

Post by rainwarrior »

tokumaru wrote: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.
Sorry that I've tread back on our old argument, but no, I would definitely not want to suddenly add in extra safety code at the END of development. That has far too much potential to add NEW bugs, and invalidates all of the testing you were doing up until that point. I think doing this would be worse than no safeties at all. If you've gone without them up until that point, just stay the course and ship that way.

Like I said in the other thread, I think "safeties off" tests are a great thing to do, just not as something you alter so late in the project. E.g. every sunday night turn off all the redunant checks (helps if you put 'em in a .define) and do some smoke testing, then after this testing session turn them back on and get back to normal. Spend as much time as is practical testing the way you will deploy. That by itself is much more important than having a redundant safety feature.
tokumaru wrote:how will you detect these bugs if you're clearing the latch left and right?
I would once again suggest the debugger can do a much better job than working safeties-off. The game failing is neither the only way, nor the best way to detect a bug. Using appropriate debug tools you can detect this with complete reliability without even removing the safety code.

If you wrote a LUA script to catch any $2002 reads where the latch isn't already at 0, you would catch a mismatch error whether or not it resulted in crashing the game or gave any easy visual indications, and wouldn't require any modification of the game's code. Setup breakpoints on unexpected reads/writes, fabricate some sort of assert mechanism, use thefox's nintendulator that automatically catches uninitialized memory use, etc. there's lots of very good tools for this kind of thing!

tokumaru wrote:situations where every cycle matters...the 4 cycles taken by a BIT $2002 were preventing me from fitting those 2 updates together
Of course, yes. If you need 4 cycles or 3 bytes, it's something you can cut.

There's also a compromise between "never do it" and "always do it", like nobody is advocating clearing $2002 more than once during an NMI handler (pointless), but even if you only put a redundant $2002 read between screens or levels (i.e. timing not an issue, rendering off), that by itself is still a recovery point. Maybe the game goes visually haywire for whatever reason, but if they can just make it to the next screen... they're back in business!

Even if your code is perfect (it isn't) there is such a thing as hardware failures, bad catridge connector, vibrations in the room, crummy power supply, etc. You could write these cases off as "well it should crash and I don't care what happens", but if someone's been playing your game for an hour they'd probably really appreciate being able to recover if it's possible. Such a miracle has happened to me a lot of times while playing NES and it's always been a moment of extreme relief.


Overall I don't think $2002 latch mismatch in particular is a case with high potential for error, really. It's just one of many things I think usually worth doing redundantly as a matter of practice.
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 »

rainwarrior wrote:I would definitely not want to suddenly add in extra safety code at the END of development. That has far too much potential to add NEW bugs, and invalidates all of the testing you were doing up until that point.
You have a good point, and I did in fact think of this. I didn't really mean "put the safeties in, assemble and ship", but rather "put the safeties in when the core engine is mostly stable, so there's still plenty of testing ahead as the rest of the game is developed", but I see your point.
I think doing this would be worse than no safeties at all. If you've gone without them up until that point, just stay the course and ship that way.
That's probably the reason I don't put the safeties in at all: I think they hide bugs during development, and putting them in late may change things too much. You're right, that was bad advice on my part.
every sunday night turn off all the redunant checks (helps if you put 'em in a .define) and do some smoke testing, then after this testing session turn them back on and get back to normal.
Sounds like a good compromise.
User avatar
GradualGames
Posts: 1106
Joined: Sun Nov 09, 2008 9:18 pm
Location: Pennsylvania, USA
Contact:

Re: Correct usage of PPUSTATUS

Post by GradualGames »

I have never done a read of $2002 except for the two (recommended) vblank waits when the ppu starts up on reset and have never had a problem...should I be concerned?
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Correct usage of PPUSTATUS

Post by tepples »

Or limit haywire operation to one frame by doing the BIT $2002 right after enabling rendering. This way your Lua breakpoint catches the unpaired write even sooner.

GradualGames: If you haven't experienced an unpaired write, there shouldn't be a problem.
User avatar
GradualGames
Posts: 1106
Joined: Sun Nov 09, 2008 9:18 pm
Location: Pennsylvania, USA
Contact:

Re: Correct usage of PPUSTATUS

Post by GradualGames »

tepples wrote:Or limit haywire operation to one frame by doing the BIT $2002 right after enabling rendering. This way your Lua breakpoint catches the unpaired write even sooner.

GradualGames: If you haven't experienced an unpaired write, there shouldn't be a problem.
I only do writes to $2006 and $2005 either within nmi or, outside of nmi with graphics disabled (and the portion of nmi which uses these registers locked out by a condition)...so I don't think I can get the latch into the opposite state from what I expect. What could cause an unpaired write except for improper locking of nmi vs. main thread?
tokumaru wrote: 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?
This is comforting. (since I don't do this) :)
Last edited by GradualGames on Thu Aug 03, 2017 12:03 pm, edited 1 time in total.
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 »

If you had unpaired $2005/6 writes, you'd probably have noticed some sort of graphical corruption by now. Like we've been saying, clearing the high/low latch is an extra layer of protection you may want to include in your programs, so they can recover from software bugs or possible hardware malfunctions, but it isn't mandatory, and several commercial games don't do it.
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 »

GradualGames wrote:What could cause an unpaired write except for improper locking of nmi vs. main thread?
I can't think of many things... Even improper locking would still execute an even amount of $2005/6 writes, so the latch would remain consistent afterwards, even if those specific writes we're botched.

One thing I can think of are mid-screen horizontal scroll changes... I seem to remember some games not bothering to do a second $2005 write since they only needed to change the X scroll, so this could end up resulting in an inconsistent state of the latch.
User avatar
GradualGames
Posts: 1106
Joined: Sun Nov 09, 2008 9:18 pm
Location: Pennsylvania, USA
Contact:

Re: Correct usage of PPUSTATUS

Post by GradualGames »

tokumaru wrote:
GradualGames wrote:What could cause an unpaired write except for improper locking of nmi vs. main thread?
I can't think of many things... Even improper locking would still execute an even amount of $2005/6 writes, so the latch would remain consistent afterwards, even if those specific writes we're botched.

One thing I can think of are mid-screen horizontal scroll changes... I seem to remember some games not bothering to do a second $2005 write since they only needed to change the X scroll, so this could end up resulting in an inconsistent state of the latch.
Hmm...so in my experiments with Split X/Y scrolling using an irq, sometimes I've seen an odd little dotted pattern in the last 8 pixel wide column of a given screen split (I'm not talking about the flickery/bouncy scanline artifact at the very left of the screen that some games have, say smb3 status bar. I've found it's pretty easy to hide that particular artifact by adjusting timing. This is a more consistent looking pattern). With enough fiddling with the waits that push code into hblank I was able to get it to go away. But I'm wondering if there's any possibility that reading $2002 first in these irqs would also help with that problem or if that is more likely to be purely a timing problem where I may have written something just outside of hblank, perhaps. I'm guessing it may be the latter because it's just this tiny tiny little section of the topmost row of pixels of the last column of a split in some cases, the rest of the split scrolling area looks as expected.
Pokun
Posts: 2681
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: Correct usage of PPUSTATUS

Post by Pokun »

With noise and hardware malfunctions anything could happen that is supposed to be fail-proof in software. NESes and Famicoms often have old and dirty cartridge connectors nowdays which can make the game hang just by a slight bump. My SMB3 cart's pins have very high oxidation, so too much vibration in the floor is enough to make the game hang, and this is a large game without backup RAM. Last time I beat the game, I did it without warping ...or breathing for that matter.
GradualGames wrote:
tepples wrote:Or limit haywire operation to one frame by doing the BIT $2002 right after enabling rendering. This way your Lua breakpoint catches the unpaired write even sooner.

GradualGames: If you haven't experienced an unpaired write, there shouldn't be a problem.
I only do writes to $2006 and $2005 either within nmi or, outside of nmi with graphics disabled (and the portion of nmi which uses these registers locked out by a condition)
Exactly like I do it. I also BIT $2002 in my NMI but within the same condition that allows rendering that frame (as per advice).
Post Reply