Is there any real reason for acknowledging NMIs?

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Is there any real reason for acknowledging NMIs?
by on (#47536)
I mean, none of my programs so far read $2002 to acknowledge an NMI, but all worked fine. My writes to $2006 and $2005 are always done in pairs, so I don't really need to reset the write count either. Is there any reason I would want to read $2002 in my NMI routine?

by on (#47538)
Maybe you're polling 2002 to wait for the screen to turn on. (waiting for sprite 0 to become unset)

Anyway, if you disable and enable NMIs without clearing VBL, you'll get another NMI. I think games DO rely on this.

by on (#47540)
Dwedit wrote:
Maybe you're polling 2002 to wait for the screen to turn on. (waiting for sprite 0 to become unset)

This is useful, but not actually related to acknowledging the NMI (clearing the VBlank flag).

Quote:
Anyway, if you disable and enable NMIs without clearing VBL, you'll get another NMI.

OK, but assuming NMIs are always enabled there is no actual need to acknowledge each one of them, is there? Any real reason for clearing the VBlank flag? It will be cleared automatically after 20 scanlines, won't it?

by on (#47545)
If you really need those 12 ppu pixels, you can get away with not reading PPU status.

by on (#47550)
The way you say it makes this look frowned upon. Sometimes I'll take all the VBlank time I can get, and those 12 pixels might make a difference, yes. Why do you think not reading $2002 is such a big deal?

by on (#47560)
Well... if you're certain you don't need to read it, then don't.

Acknowledging NMIs is not necessary. The only practical reason I can think of for reading it, is if you're afraid 2005/2006 writes might get interrupted and you need to reset that latch. Probably a good defensive programming practice, but there's no rule that says you have to do it.

by on (#47561)
I always first read $2002 before doing anyting in my NMIs routine. That's a principle, in any interrupt routine the first thing to do is save the registers and acknownledge the interrupt.

However, in this very particular case, since there is only one NMI source and that they are edge-triggered (not state triggered), and if you're absolutely sure about your $2005/6 writes being in pairs, then you may try to not doing it and test it extensively on real hardware, if it works then fine.

If you read Dish's NMI doccument, he says it's better to never disable NMIs even when rendering is off, this implies that you should skip the $2002 reading part else it may randomly screw up the PPU work you're doing when a NMI happens between 2 $2006 writes. I however have a different technique who is to disable NMIs at the same time you disable rendering, and enable them in reverse order (NMIs, and at VBlank rendering). This works fine as long as no music is playing, and I'm pretty sure most commercial games does this.

by on (#47568)
Even if a pair of $2005 or $2006 writes got interrupted by an NMI (which assumes that your MAIN code (outside of nmi) has writes to them, and thus, you had to read $2002 to fix it so your nmi code could execute its pair of writes correctly, how would you even go about restoring the state of the latch, when you exit nmi? It seems like if you're trying to squeeze every bit of performance out of the cpu, it'd be better to not even have to deal with it in the first place.

In the end, if you have *good* management in your code, you shouldn't even need to read $2002 at all, ever. (Maybe once in the reset routine, but that's it)

but in all honesty, when are you ever going to need to write to $2005 or $2006 outside of the NMI while the game is running? Only when the screen is turned off, yes, but when the screen is turned off, theoretically, your ppu-writing pipeline manager thingy (the method you theoretically are using to buffer your ppu writes so that they are written during the next vblank) should also be turned off, which means that the nmi wouldn't be messing with 2005/2006 while the main code is, so there's really no time where a pair of 2005/2006 writes would get interrupted.

Ok, maybe you change 2005/2006 during a scanline interrupt, but even then, do these scanline irqs ever fire in such a way that an nmi would interrupt them? Usually not, unless your code isn't structured well. And since you're 99% likely not messing with 2005/2006 in your main code while the screen rendering is turned on (as I explained above), it just seems that these write pairs would never be interrupted. Everything is just naturally organized such that it never happens.

Thus, I'd think you're safe not reading $2002 in your nmi. :P

by on (#47574)
Oh yeah Drag you are right, you may definitely write to $2005 or $2006 during rendering to modify the scroll midframe, but never staright during when a NMI is firing (unless you coded a PAL programm running on NTSC or vice-versa, causing the timing to be off, in that case it's likely that your game won't be playable anyway).

However, I admit when doing only horizontal scroll changes I write to $2005 only once, there is no reason to write a second value when it will be ignored (this waste bytes). So if someone does that it will have to read $2002 in it's NMI before the scroll update. If you don't do that then fine, but remember to be carefull with that.

by on (#47575)
Drag wrote:
when the screen is turned off, theoretically, your ppu-writing pipeline manager thingy (the method you theoretically are using to buffer your ppu writes so that they are written during the next vblank) should also be turned off, which means that the nmi wouldn't be messing with 2005/2006 while the main code is, so there's really no time where a pair of 2005/2006 writes would get interrupted.

Exactly. My NMI routine only performs graphical updates if a flag tells it to. So I just keep this flag cleared when I'm rendering stuff outside of NMI and the NMI won't mess with $2005/$2006, it will just handle the sound and return, not interfering with whatever was interrupted.

Thanks everyone.