This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

Killing NMI by polling $2002?

Killing NMI by polling $2002?
by on (#45009)
Hi, I have a short question: is it correct that by continuously polling $2002 in a very tight loop, it may happen that NMI's won't occur? Because that's exactly how Nintendulator and Nestopia behave, but not FCE Ultra.

I'd just like to have a confirmation that this illogical and stupid behaviour also happens on the real hardware. Thanks!

by on (#45011)
yes, it's a quirk in the real hardware.

Which is exactly why you should never poll $2002 when an NMI might occur (never use $2002 to wait for VBlank except when waiting for PPU warm-up)

by on (#45013)
Disch wrote:
yes, it's a quirk in the real hardware.

Which is exactly why you should never poll $2002 when an NMI might occur (never use $2002 to wait for VBlank except when waiting for PPU warm-up)


I am using Sprite 0 hit detection in my main game loop to split the screen, and I was just wondering why NMI's were occasionally not happening, until I found out that on the NES, the NMI flag apparantly can be cleared before the actual NMI is happening... Of course I already have implemented a workaround for it, but I was just wondering if this stupid behaviour is actually correct. From a hardware designer's standpoint, it absolutely makes no sense at all.

Thanks for the confirmation! ;)

by on (#45017)
Disch wrote:
yes, it's a quirk in the real hardware.


Why do you call it a quirk though? Many systems hold the IRQ line active until a port is read (or sometimes written to) to acknowledge the interrupt.

by on (#45018)
Because it's a race condition. The NMI should fire and THEN the acknowledgment should happen.

by on (#45020)
tomaitheous wrote:
Disch wrote:
yes, it's a quirk in the real hardware.


Why do you call it a quirk though? Many systems hold the IRQ line active until a port is read (or sometimes written to) to acknowledge the interrupt.


On the NES, either there seems to be a significant delay between setting bit#7 of $2002 and pulling the NMI line (so that it can be cleared before), or reading $2002 sometimes prevents bit#7 to be set at all. Since this behaviour doesn't make any sense, it seems to be a hardware bug which Nintendo did not fix.

I really wonder if the designers were really sure what Sprite 0 hit detection was supposed to accomplish. For collision detection, it's quite useless. And for mid-screen changes, there are lots of factors which make it unnecessarily complex. For example, why doesn't Sprite 0 hit generate an NMI? It wouldn't have cost much extra logic. Or why does the Sprite pixel have to overlap with the background, instead of just setting the flag when Sprite 0 is in range?

They probably did implement this weird method because there are some patents from Commodore and Atari involved for methods of synchronizing the raster beam with the CPU.

Enough ranting. ;)

by on (#45021)
I've always wondered why they couldn't just make a sprite 0 hit when it was drawn. I agree it's overly complex that it has to be a solid sprite pixel on a solid BG pixel. I actually have used it for sprite to BG collision in my REALLY newbie crap demos. In real, professional game design this is just plain sloppy. It's great for split screen effects though, assuming you know that the NMI has already happened in the current frame.

by on (#45038)
6502freak wrote:
On the NES, either there seems to be a significant delay between setting bit#7 of $2002 and pulling the NMI line (so that it can be cleared before), or reading $2002 sometimes prevents bit#7 to be set at all.


Oh, so you're saying there's an instance where you won't get the corret status of BIT #7 *and* you'll cause the bit to clear - causing a miss of the interrupt?

by on (#45052)
Yes, exactly. Here's the output of a test ROM which reads $2002 every frame, each time one PPU clock (1/3 CPU clock) later. The first column shows an N if NMI occurred normally for that frame, and the second shows a V if the high bit of $2002 was set when read. The test first starts reading a little before VBL, so the high bit isn't set yet. Note how for row 04, NMI doesn't occur AND the VBL flag reads back as clear (reading $2002 again still reads it back as clear). This can only occur every third frame, due to a CPU cycle being 3 PPU clocks.
Code:
01 N-
02 N-
03 N-
04 --
05 -V
06 -V
07 NV
08 NV
09 NV

by on (#45081)
blargg wrote:
Yes, exactly. Here's the output of a test ROM which reads $2002 every frame, each time one PPU clock (1/3 CPU clock) later. The first column shows an N if NMI occurred normally for that frame, and the second shows a V if the high bit of $2002 was set when read. The test first starts reading a little before VBL, so the high bit isn't set yet. Note how for row 04, NMI doesn't occur AND the VBL flag reads back as clear (reading $2002 again still reads it back as clear). This can only occur every third frame, due to a CPU cycle being 3 PPU clocks.
Code:
01 N-
02 N-
03 N-
04 --
05 -V
06 -V
07 NV
08 NV
09 NV


Thanks for the clarification, blargg!

by on (#45160)
Here is a textbook example of what happens if you poll $2002 to wait for vblank:

http://robertlbryant.com/gaming/download/ttxo_demo.nes

This was the first completed program that I made, and it shows... alot! haha I haven't booted it up in awhile, but I'm pretty sure you can notice it when making a move... or the computer makes a move. I can't remember. Just play it, and you'll be able to hear where the music drags in spots. That is from polling $2002 to wait for vblank, in which you can hear the frames being missed.