Correct usage of PPUSTATUS
Moderator: Moderators
Re: Correct usage of PPUSTATUS
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"?
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"?
Re: Correct usage of PPUSTATUS
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.
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.
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.rainwarrior wrote:tschak909 sort of answered that: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?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?)tschak909 wrote:BIT was literally designed for situations, like this.
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.
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.
Re: Correct usage of PPUSTATUS
Correct. It's just a lot easier to test bit 6 in a tight-as-possible loop through BIT than through LDA.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?
Re: Correct usage of PPUSTATUS
I see, I was just overthinking it. Thanks!
Re: Correct usage of PPUSTATUS
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?
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!
Re: Correct usage of PPUSTATUS
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)
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)
- rainwarrior
- Posts: 8732
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: Correct usage of PPUSTATUS
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.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.
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.
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.tokumaru wrote:how will you detect these bugs if you're clearing the latch left and right?
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!
Of course, yes. If you need 4 cycles or 3 bytes, it's something you can cut.tokumaru wrote:situations where every cycle matters...the 4 cycles taken by a BIT $2002 were preventing me from fitting those 2 updates together
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.
Re: Correct usage of PPUSTATUS
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.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.
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.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.
Sounds like a good compromise.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.
- GradualGames
- Posts: 1106
- Joined: Sun Nov 09, 2008 9:18 pm
- Location: Pennsylvania, USA
- Contact:
Re: Correct usage of PPUSTATUS
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?
Re: Correct usage of PPUSTATUS
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.
GradualGames: If you haven't experienced an unpaired write, there shouldn't be a problem.
- GradualGames
- Posts: 1106
- Joined: Sun Nov 09, 2008 9:18 pm
- Location: Pennsylvania, USA
- Contact:
Re: Correct usage of PPUSTATUS
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?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.
This is comforting. (since I don't do this)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?
Last edited by GradualGames on Thu Aug 03, 2017 12:03 pm, edited 1 time in total.
Re: Correct usage of PPUSTATUS
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.
Re: Correct usage of PPUSTATUS
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.GradualGames wrote:What could cause an unpaired write except for improper locking of nmi vs. main thread?
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.
- GradualGames
- Posts: 1106
- Joined: Sun Nov 09, 2008 9:18 pm
- Location: Pennsylvania, USA
- Contact:
Re: Correct usage of PPUSTATUS
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.tokumaru wrote: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.GradualGames wrote:What could cause an unpaired write except for improper locking of nmi vs. main thread?
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.
Re: Correct usage of PPUSTATUS
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.
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).GradualGames wrote: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)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.