Killing NMI by polling $2002?
Moderator: Moderators
Killing NMI by polling $2002?
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!
I'd just like to have a confirmation that this illogical and stupid behaviour also happens on the real hardware. Thanks!
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.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)
Thanks for the confirmation!
-
tomaitheous
- Posts: 592
- Joined: Thu Aug 28, 2008 1:17 am
- Contact:
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.tomaitheous wrote: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.Disch wrote:yes, it's a quirk in the real hardware.
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.
-
Celius
- Posts: 2159
- Joined: Sun Jun 05, 2005 2:04 pm
- Location: Minneapolis, Minnesota, United States
- Contact:
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.
-
tomaitheous
- Posts: 592
- Joined: Thu Aug 28, 2008 1:17 am
- Contact:
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?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.
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: Select all
01 N-
02 N-
03 N-
04 --
05 -V
06 -V
07 NV
08 NV
09 NVThanks for the clarification, blargg!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: Select all
01 N- 02 N- 03 N- 04 -- 05 -V 06 -V 07 NV 08 NV 09 NV
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.
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.