My game is a simple NROM puzzle game. The only scrolling is when I transition from the title screen, to the puzzle screen. I wait for VBLANK, then scroll a bit, (looping until its all in).
Then I go to my game loop which:
waits for VBLANK
polls for input
does updates
repeat...
Everything I've done so far works, but I am not using NMI.
I'm not "running long" and running out of cycles
I guess my questions are:
Should I be using NMI?
Is it considered bad form to code it this way?
Do some games do what I've done, or do they all sync using NMI?
I'd just like to hear peoples opinions. After all, I plan on doing other games so I'll have to learn other techniques eventally.
Thanks,
Al
There is two ways to wait on VBlank :
- Poll $2002
- Use NMIs
If you do the first method, you're sure you'll get a VBlank when your polling loop exits, however you don't know how many VBlanks you missed before, and it IS possible to miss VBlanks.
If you do it the second method, using NMIs, a NMI will trigger every VBlank no matter what (assuming they are enabled), so yeah, that method is better. The other is good only if you don't need smooth timing, so when the screen isn't used anyway. It is NO good for gameplay.
There is at least one Famicom game that does it all with $2002 polls : Portpia Renzoku Satsujin Jiken. However, since it's stricly an investigation game (so it doesn't scroll nor require any precise timing, it just have a blinking cursor that won't blink at constant rate on real hardware, but most user won't see that), and used frame IRQs for sound anyway, then it could rely on that method. That it still not recommanded.
You should use NMIs, you need it for all the PPU and sound stuff. My main loop is timed by incrementing a variable in NMI and waiting for it to be non-zero.
Code:
nmi_count = $10 ; one byte in zero-page, location up to you
nmi: inc nmi_count
rti
wait_nmi:
lda nmi_count
loop: cmp nmi_count
beq loop
rts
By not modifying nmi_count outside of NMI, other code can use it for timing, i.e.
Code:
lda nmi_count
cmp next_count
beq one_second_passed
...
one_second_passed:
clc ; update next_count
adc #60
sta next_count
...
I know this is an old topic, but I think I probaby didn't do things correctly when I converted over to using NMIs.
All my code works and looks fine, but I might have just gotten lucky. 2 wrongs (or 20) making a right (so to speak).
When I converted my code from polling 2002 to using NMIs I got everything working. But I did it by creating a very large and complicated NMI routine.
Within the NMI routine I was checking my state machine, processing input, moving sprites, invoking sprite DMA, updating backgrounds, etc..
Should the actual "work" be done in the main loop and just the NMI timing or sync-ing (like the counter or flag variables mentioned by blargg) be all I maintain in the NMI?
Al
That is a style preference. There's no "right" or "wrong" way. SMB (I think?) and Final Fantasy simply has NMI return right away like blargg's example... while several other games do their work in the actual NMI routine.
The only thing I recommend is do drawing related stuff FIRST. Anything that has to be done in VBlank should be done before you do other stuff. Sprite DMA and any PPU writes should have top priority. Only after all that stuff is done should you start doing other things, like polling joypads, calling the music routine, etc.
I don't know what you're talking about, but Super Mario Bros. runs the entire game as an NMI handler. After the init code, SMB's main thread is running the following code, which emulators running on handhelds (e.g. PocketNES and PocketNES) will usually automatically detect as a speed hack:
Code:
:
jmp :-
The easiest way to convert $2002 spinning code to NMI based code uses a variable in RAM:
Code:
.segment "ZEROPAGE"
retraces: .res 1
.segment "CODE"
nmiHandler:
inc retraces
rti
; In main loop:
lda retraces
:
cmp retraces
beq :-
SMB and Final Fantasy are on opposite ends of the spectrum. SMB lives and breates in NMI (the only piece of code that doesn't run in NMI is the reset code, which is very short), while Final Fantasy's NMI routine exits immediately and lets the main program resume execution.
My opinion is that if you already got hte program working by polling $2002, the quickest way to make use of NMI's is to just set a flag in the NMI code, and poll that flag instead of $2002, bacause that will need no modification in the structure of your code, and can be done in, what, 5 minutes? Anyway, this is a very quick modification.
But with more complex games, where computing a frame may take more than a NES frame (if there are too many active enemies, for example), I think it'd be better to do the opposite. Have the main loop process everything and buffer the data to be written to the PPU, and set a flag when that data is ready. The NMI routine would then check that flag, and if a frame is ready for rendering, the data is sent to the PPU, but if it's not, you could still do other timed stuff that does not depend on graphic updates, such as music.
That way, even if the game did slow down because of the complexity of current events, the music would still play normally. If you used the polling method and the processing took more than a frame, you'd miss the Vblank, and everything, including the music, would be delayed by one frame. Even worse, if the game logic finished in the middle of Vblank, you wouldn't be able to detect that (unless you only detect the start of Blank, by first waiting the flag to be clear and then set), and the PPU drawing code could very well spill out of Vblank time, causing very visible glitches.
Polling should just be used with simple programs, where you know the processing time of each frame will fit nicely in a NES frame. Having all the code inside the NMI is already better than that, just do the graphical stuff first, game logic later.
Crap
I knew about Final Fantasy, but got mixed up with SMB. My mistake!
You can hear the music slow down in Zelda when the game overloads, and you can hear the music slow down AND the status bar flicker in SMB where there is many enemies. That is very bad programming from Nintendo, because they did everything in their NMI and disabled NMIs at all until it's finished (without the disabling, the game would crash).
Bregalad wrote:
That is very bad programming from Nintendo, because they did everything in their NMI and disabled NMIs at all until it's finished
Yeah, this sure causes music slowdown, because each NMI has to wait for the previous one to end, and if that takes longer than the time of a frame, a full frame will be lost.
Quote:
(without the disabling, the game would crash).
Do you mean if an NMI fired while the previous one was still running? From a hardware point of view, does that even happen? Can an NMI fire while the previous one hasn't finished yet? I once read about IRQ's not firing before the previous IRQ routine finished, but I'm not sure.
If this is possible (NMI's firing before the previous one ended), and you read a flag right at the begining of the routine it could still work well... if a flag indicates that the previous NMI hasn't finished yet, only do the music, then return. If the previous NMI has finished, do all the graphics, sound, and game logic last. It would work just as well as well as if the game logic was outside of the NMI routine.
For IRQs, they will never fire while one is executing if you do nothing special, because the I flag is automatically set on all interupts, disabling IRQs. The flag is automatically returned when you return from the IRQ, wich is normally clear in all cases, exept if the IRQ was caused by a brk opcode. Nothing prevent the IRQ routine to clear the I flag once the source of the IRQ has been acknownledged, allowing new IRQ to occurs before the first finishes. If the I flag is clear befor the IRQ source is acknownledged, the IRQ won't stop firing as soon as the cli (or possibly plp) opcode is met, and then you'll get a never-ending chain of IRQs, crashing the processor.
For NMIs, it's pretty much the same, the I flag is automatically set, unallowing IRQs to fire until the NMI returns or the flag is cleared by hand. The difference is that NMIs can still be triggered at anytime, regardless of the I flag, so the only way to disable NMIs is to clear $2000.7. If a game is programmed to have the NMI routine not clearing $2000.7, and if the NMI holds longer than a frame, it's unavoidable that the programm will crash, until you do some tricks.
Quote:
If this is possible (NMI's firing before the previous one ended), and you read a flag right at the begining of the routine it could still work well... if a flag indicates that the previous NMI hasn't finished yet, only do the music, then return.
Yes, this would work well, unless the music code itself is very slow and slow downds things even more (wich is unlikely to be the case). I even think many Konami games does something like that (I haven't checked in details).
Thanks for the info.
Quote:
If a game is programmed to have the NMI routine not clearing $2000.7, and if the NMI holds longer than a frame, it's unavoidable that the programm will crash, until you do some tricks.
I guess the NMI routine can take longer than a frame to execute, as long as this doesn't happen too often, or the stack will definitely overflow.
Quote:
Quote:
If this is possible (NMI's firing before the previous one ended), and you read a flag right at the begining of the routine it could still work well... if a flag indicates that the previous NMI hasn't finished yet, only do the music, then return.
Yes, this would work well, unless the music code itself is very slow and slow downds things even more (wich is unlikely to be the case).
Yeah, I doubt any regular music code would take a significant ammount of time of the frame, as the rest of the game logic is more complicated and also has to run every frame. Anyway, I think this is a valid option, since the music code can execute quickly, NMI's won't pile up and overflow the stack.
I prefer not to do this for my game, since I'll be using multiple NMI routines at different parts of the game, and I'd rather have the main code control what routines execute at what times, instead of the routines themselves doing that.
Quote:
Do you mean if an NMI fired while the previous one was still running?
Yes, that's why it's called the Non-Maskable Interrupt (NMI). The 6502 has no concept of an NMI routine, just that of the NMI being asserted and causing the code to vector to the handler address. Once it's there, the NMI is over in the 6502's eyes. NMI is meant for things which must be reliably responded to, and why it's edge-triggered (once NMI line is asserted, it can be de-asserted and NMI will still occur, unlike IRQ).
The IRQ, on the other hand, has an inhibit flag which serves as a "still executing IRQ handler routine" flag, though there's no requirement that it be left set (inhibited) until the end of the IRQ handler.