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

Order of things in the NMI

Order of things in the NMI
by on (#152236)
What is the correct order of the things that are done when the NMI interrupt hits?

Let's take these things:

- Reading the controller
- Saving the current sprite data to the CPU RAM address for DMA
- Making the address for sprite DMA known to the PPU
- Saving the current background and attribute data somewhere in the CPU RAM
- Drawing the background and attributes to the PPU
- Saving the current palette data somewhere in the CPU RAM
- Drawing the palettes to the PPU
- Setting the PPU parameters (intensify red, gren, blue etc., enabling sprites)
- Saving the current scrolling value somewhere in the CPU RAM
- Setting the scrolling value (+ nametable swap if necessary)
- Game logic (setting the game status according to the current input and the general variables)

In what order in the NMI do these steps have to be processed, so that everything works correcly?

And which ones of them only need to be done once at startup? (I assume "Making the address for sprite DMA known to the PPU" is only necessary once, right?)
Re: Order of things in the NMI
by on (#152241)
Six of those items don't need to be in the NMI at all:

- Reading the controller
- Saving the current sprite data to the CPU RAM address for DMA
- Saving the current background and attribute data somewhere in the CPU RAM
- Saving the current palette data somewhere in the CPU RAM
- Saving the current scrolling value somewhere in the CPU RAM
- Game logic (setting the game status according to the current input and the general variables)

The remaining five items are already in a good order:

- Making the address for DMA known to the PPU
- Drawing the background and attributes to the PPU
- Drawing the palettes to the PPU
- Setting the PPU parameters (intensify red, gren, blue etc., enabling sprites)
- Setting the scrolling value (+ nametable swap if necessary)

These five items must all finish before vblank ends. It's good to do OAM DMA first, because it runs in parallel with the rest of the NMI code, and it's good to set the scroll last, because other PPU accesses will modify the scroll. If you have anything else you want to put in the NMI, it has to go after those five things.
Re: Order of things in the NMI
by on (#152242)
For the non NMI required tasks the order is: read controller, do game logic based on past state and controller, render scene from resulting state.

Joe wrote:
It's good to do OAM DMA first, because it runs in parallel with the rest of the NMI code...

OAM DMA Takes 513 cycles and does not run in parallel. The rest is true.
Re: Order of things in the NMI
by on (#152243)
Here are the constraints:
- On a PAL PPU, OAM DMA must be started (if it's going to happen at all) no later than 1617cy after NMI. This cannot be improved. (Correspondingly, OAM DMA is often one of the first things done in NMI)
- On a PAL PPU, accesses to OAMADDR ($2003) and OAMDATA ($2004) must finish no later than 2131cy after NMI
- On an NTSC PPU, OAM DMA must* be started (if it's going to happen at all) no later than 1759cy after NMI
- Starting a DMA transfer is equivalent to writing to OAMDATA 256 times.
- On an NTSC PPU, accesses to OAMADDR shouldn't be used, unless one immediately starts an OAM DMA transfer.
- On an NTSC PPU, accesses to PPUSCROLL, PPUADDR, and PPUDATA should* finish no later than 2273cy after the NMI
- On a PAL PPU, accesses to PPUSCROLL, PPUADDR, and PPUDATA should* finish no later than 7672cy after the NMI
-- Accesses to PPUADDR and PPUDATA are used to update nametables (background) and attribute tables and update the palette, if anything is going to be changed.

* Unless one increases the blank time at the top of the picture in order to increase bandwidth. Additionally, changing PPUADDR and/or PPUSCROLL allow for split scroll and other raster effects

All other actions can happen at any time. (Anything in CPU RAM, controller reading, changing emphasis).

Most games that I've looked at use some structure like
- Use a jump table or indirect jump to select which NMI handler to use depending on game state (e.g. pause, title screen, main game play, &c)
- OAM DMA
- upload new data to nametables and attribute tables
- set PPUCTRL, PPUMASK, and scrolling
- all other housekeeping
Re: Order of things in the NMI
by on (#152245)
43110 wrote:
OAM DMA [...] does not run in parallel.

Whoops! I must've been thinking about APU DMA, which does run in parallel.
Re: Order of things in the NMI
by on (#152246)
Quote:
And which ones of them only need to be done once at startup?

This "Setting the PPU parameters (intensify red, gren, blue etc., enabling sprites)", can be done only once if your game never actually needs to change them during the game. You generally only need to write changes, so you can update palette information only once if that never changes in your game. (Or do it once on level load, but never in your NMI if it's always going to be the same at any given point during a level.) It's wise to write scrolling things ($2005/$2000) every frame even if your game never scrolls, just because other registers affect it.

Edit: Heck, you could even write the background and attributes only once if that never changes. But that's a rare case outside of a demo.
Re: Order of things in the NMI
by on (#152247)
Quote:
- Drawing the background and attributes to the PPU
- Drawing the palettes to the PPU

Just to be clear (I'm being picky here) you don't "draw anything to" the PPU, but you send data to VRAM through the PPU. This is usually called "VRAM update(s)".

As the palette it is directly inside the PPU so you'd "update the (PPU's) palette". Because there's no other palette in the NES, there is no need to specify that it's the PPU's you're talking about.
Re: Order of things in the NMI
by on (#152250)
Thanks for all the information.

I've got one more question, though: In the following Code, do I put the game logic before the RTI command or somewhere outside?
Code:
NMI:
  ; 1. All NMI-specific stuff: Sprites, backgrounds, palettes, scrolling
  ; 2. Game logic: Here?
  RTS


In case I have to put it outside: Where exactly do I have to put it? Where does the program jump to when NMI is left?

The actual starting code is at the reset interrupt. But this one ends with an infinity loop:
Code:
Reset:
  ; 1. Disable NMI
  ; 2. All the initialization stuff.
  ; 3. Enable NMI.
Forever:
  JMP Forever

Therefore, I assume whenever the NMI is left, the program simply jumps back to that infinity loop. So, if the game logic has to be outside "NMI: ... RTS", where do I have to put it?
Re: Order of things in the NMI
by on (#152252)
I'd recommend you put the game logic somewhere else. Anything that doesn't NEED to be in the NMI is usually best left outside it.

And your text is right, but your code is wrong. RTI is what ends your NMI, not RTS.

Quote:
In case I have to put it outside: Where exactly do I have to put it? Where does the program jump to when NMI is left?

You don't need to put it outside, it's just a good idea. You could have a program with no NMI, or a program that runs entirely in the NMI. But I don't recommend it.

My recommendation is outside, and if you go with that recommendation, literally anywhere outside. It doesn't matter. When the NMI fires, it saves the address of whatever the CPU was doing, (as well as the processor status flags). When an RTI is hit, it returns to that address, and restores the processor status flags. Basically, no matter what the CPU was doing when the NMI started, that's where it would go when the RTI is hit.

(Just for reference RTS only returns to the address, and doesn't restore the flags. Using RTS to end an interrupt, or RTI to end a subroutine means the wrong number of bytes is pulled from the stack, which is very bad.)

One thing: While RTI returns to what the program was doing and restores the flags, it doesn't restore A, X and Y. So most people push them to the stack at the beginning of the NMI and pull them at the end so the program has the same values in A, X, and Y as when the NMI fired when it returns, rather than whatever the NMI used.

Code:
NMI:
  pha
  tya
  pha
  txa
  pha
;Standard NMI stuff here
  pla
  tax
  pla
  tay
  pla
  rti


Edit:
Quote:
So, if the game logic has to be outside "NMI: ... RTS", where do I have to put it?

In between jmp Forever and Forever.
Re: Order of things in the NMI
by on (#152254)
Yeah, these are two possible program structures. Having the game logic is often considered simpler (newbie tutorials usually do it this way - but make the mistake of putting the game logic before PPU updates), because the programmer doesn't have to keep track of different threads and how the PPU switches between them.

The second option you presented would indeed have the game logic inside the "forever loop". This is the most versatile way because you can mix and match different game loops and NMI handlers in a more organized way.

There's a third possibility, which is having everything outside the NMI handler, with the NMI merely setting a flag to indicate that VBlank has started. It also has the advantage of being a single thread, but its main drawback is not being able to handle lag frames properly (it completely misses VBlanks during lag frames). On the other hand, it makes it easier to have different game loops and VBlank handlers for the different parts of the game.
Re: Order of things in the NMI
by on (#152257)
The RTS was just an error in the forum post. My actual sample program indeed used RTI.

I'm still a bit confused about how to do this outside of the NMI interrupt:
Code:
Reset:
  ; Init stuff
Forever:
  JSR ProcessNextGameLogicFrame
  JMP Forever

NMI:
  ; Graphics stuff
  RTI


In this code, I would need a variable to tell the game logic function if it is actually supposed to run.
NMI sets the variable to true in the end.
And ProcessNextGameLogicFrame sets the variable to false in the end.

On the other hand, if I do this:
Code:
Reset:
  ; Init stuff

Forever:
  JMP Forever

NMI:
  ; Graphics stuff
  JSR ProcessNextGameLogicFrame
  RTI

I don't need such a variable.

So, why is the above version better? What does it mean when tokumaru says that you can mix and match different game loops and NMI handlers in a more organized way. Where would I have different game loops and different NMI handlers?


By the way, is it possible that an NMI interrupt gets started while the program is still inside the previous NMI interrupt?
Re: Order of things in the NMI
by on (#152263)
DRW wrote:
Where would I have different game loops and different NMI handlers?

Title vs. options menu vs. game vs. end credits, for example.

Quote:
By the way, is it possible that an NMI interrupt gets started while the program is still inside the previous NMI interrupt?

Yes. If you're running everything in NMI, you might need to set a "reentrant lockout" variable saying you're already in NMI and then check it at the start of the NMI handler so that you don't run most of the NMI handler.
Re: Order of things in the NMI
by on (#152265)
DRW wrote:
In this code, I would need a variable to tell the game logic function if it is actually supposed to run.

Yes, the game loop has to wait for the NMI to finish before processing another frame. Similarly, the NMI needs to know whether the frame processing has indeed finished in time, otherwise it has to deal with a lag frame. The same flag can be used for both purposes.

Quote:
On the other hand, if I do this:
Code:
Reset:
  ; Init stuff

Forever:
  JMP Forever

NMI:
  ; Graphics stuff
  JSR ProcessNextGameLogicFrame
  RTI

I don't need such a variable.

This kinda defeats the purpose of separating the game logic, doesn't it?

Quote:
So, why is the above version better? What does it mean when tokumaru says that you can mix and match different game loops and NMI handlers in a more organized way.

I meant you can simply JMP to other game loops in order to change game modes, and independently select an NMI handler by having a variable indicating its address and having JMP (NMIPointer) under your NMI label.

Quote:
By the way, is it possible that an NMI interrupt gets started while the program is still inside the previous NMI interrupt?

Yes, that would constitute a lag frame. This means you still need a flag to know whether frame calculations have finished, or you need to disable NMIs while doing the game logic, but enabling NMIs back midframe could couse a graphical glitch (it happens in SMB, for example).
Re: Order of things in the NMI
by on (#152294)
O.k., so it looks like the game logic should rather be put outside the NMI.

Out of curiosity: How do the popular commercial games handle it? And is there a difference between old games ("Donkey Kong", "Kung Fu", "Super Mario Bros.") and newer ones ("Mega Man" and newer)?


About NMI hitting before the previous NMI is done:

So, I assume this can happen at any time. Which means we have to save the status of all registers.

At first glance, I would do it like this:
Code:
NMI:
  STA BackupA
  STX BackupX
  STY BackupY

  ; If not ready (ready = 0), go to end.
  LDA NmiIsReady
  BEQ NmiNotReadyYet

  ; If ready, set ready to false (0), so that no other NMI jumps in.
  LDA #$00
  STA NmiIsReady

  ; The regular NMI stuff
  ; ...

  ; After everything is done, the next NMI is allowed to hit.
  LDA #$01
  STA NmiIsReady
  JMP NmiEnd
  ; Restoring the original register values isn't necessary here since this time,
  ; the interrupt happened when the game was in a clean state anyway.

  ; Restore the original register values if NMI is not ready.
NmiNotReadyYet:
  LDA BackupA
  LDX BackupX
  LDY BackupY

NmiEnd:
  RTI


Is this the correct way to do?
Which one is better? Using three global variables like in the above example? Or using Kasumi's version with PHA, PLA, TAX, TAY, TXA and TYA?

Another thing that might be a problem: How do I save the status register?
Let's say the NMI hits in the middle of some complicated calculation or comparison where the carry flag or that zero flag etc. were used. Then I have to backup and restore this as well, right?

Also: What happens if the next NMI hits right after the NmiIsReady variable was set to 1 again, but before JMP NmiEnd or before RTI? Can this cause a glitch or something like that?
Re: Order of things in the NMI
by on (#152295)
DRW wrote:
Which one is better? Using three global variables like in the above example? Or using Kasumi's version with PHA, PLA, TAX, TAY, TXA and TYA?

If you want to have any code outside NMI, you have to save and restore the registers every time NMI occurs, not just when NMI happens during another NMI. With global variables, you'll clobber the saved state from the first NMI when the second NMI occurs. Kasumi's example using the stack prevents that from happening.

DRW wrote:
Another thing that might be a problem: How do I save the status register?

The CPU saves it for you. You restore it by using RTI to return.

DRW wrote:
Also: What happens if the next NMI hits right after the NmiIsReady variable was set to 1 again, but before JMP NmiEnd or before RTI? Can this cause a glitch or something like that?

If it happens enough times, the stack will overflow and eventually something will pull garbage from the stack.
Re: Order of things in the NMI
by on (#152296)
Joe wrote:
If you want to have any code outside NMI, you have to save and restore the registers every time NMI occurs, not just when NMI happens during another NMI. With global variables, you'll clobber the saved state from the first NMI when the second NMI occurs. Kasumi's example using the stack prevents that from happening.

Yes, those two things make sense.

Joe wrote:
DRW wrote:
Also: What happens if the next NMI hits right after the NmiIsReady variable was set to 1 again, but before JMP NmiEnd or before RTI? Can this cause a glitch or something like that?

If it happens enough times, the stack will overflow and eventually something will pull garbage from the stack.

So, is there a way to prevent it? And is this even a likely problem? Especially if you put the registers back from the stack?
I mean, there are lots of possibilities where the NMI could fire again:
Code:
  PLA
  TAX
  PLA
  TAY
  PLA
  RTI

There must be a way to ensure that the thing doesn't destroy the whole status when the new NMI tries to save the registers to the stack in the time frame when getting the registers back from the stack in the old NMI is only partly done.
Re: Order of things in the NMI
by on (#152298)
Quote:
; Restoring the original register values isn't necessary here since this time,
; the interrupt happened when the game was in a clean state anyway.

That's not necessarily a safe assumption to make. Even if so, the speed penalty for being safe is quite small. Also, anytime you find yourself jumping to an RTI or an RTS, you can just use another RTI or RTS.

Code:
jmp label
lda whatever
;Other Stuff
label:
rts

to
Code:
rts
lda whatever
;Other Stuff
rts


The NMI isn't crazy and random. It fires every ~29780 cycles, or once per frame. That's what it's used for... keeping the game updates at a fixed frame rate.

For reference, the longest instructions take only 7. If your NMI is separated from your game logic, it's not going to take that long. If your NMI doesn't take that long, it will never interrupt itself making this a nonproblem. Maybe a reason to separate the game logic from the NMI is to keep that impossible.

The only way I thought of that is 99% failsafe is also checking the stack pointer, and forcing a return if it's below a certain value like $C0. This value can be made lower if your program happens to be particularly stack heavy, or not... since if the NMI is interrupting during something particularly stack-heavy, it's probably not a good time to run anyway.
Re: Order of things in the NMI
by on (#152300)
Hm. You're right. Until now, I always put the game logic into the NMI and that's why I always had that issue in mind that the NMI can be called when another NMI is still active.

But now that I know that I better put the game logic into the infinite loop at the end of the Reset interrupt, it's of course all much safer:
The NMI might fire when the game logic is still processed and therefore, we still have to save A, X and Y when the NMI starts and puts it back when it ends, but we don't have to care for the situation that an NMI fires during another NMI since the stuff that is done in the NMI is basically always the same.

I assume for updating the whole screen at once (for example between the title screen and the first level), I would disable the NMI first, write the whole screen, and enable it again, right?

But now that we've established that the NMI might interrupt the game logic, but that it never interrupts the NMI: What is better: Putting A, X and Y on the stack or using my version with the three global variables?
Re: Order of things in the NMI
by on (#152303)
Quote:
I assume for updating the whole screen at once (for example between the title screen and the first level), I would disable the NMI first, write the whole screen, and enable it again, right?

Yes, this is one way to update a whole screen without the game crashing on NTSC.

A single nametable is 1024 bytes. Even assuming you were just writing the same byte in the fastest way, you'd get nowhere near 1024. sta $2007 is 4 cycles. 4*1024 would use slightly less than double the time you have to safely write to $2007 on NTSC. If lidnariq's post is correct, you could totally do it in PAL, which is a surprise to me.

You could also fade the palettes to black, update portions of the screen, then fade back in if you wanted to keep NMIs active the whole time. This would make the updates slower than just disabling rendering while the screen is black. The advantage is that you could keep your music playing properly (timed in the NMI) in between screens.

Quote:
But now that we've established that the NMI might interrupt the game logic, but that it never interrupts the NMI: What is better: Putting A, X and Y on the stack or using my version with the three global variables?

If you don't know which to use, use the stack one. It's less likely to break, and you're not using RAM you could use for something else. Typically things that aren't safe have other types of advantages. If you don't see the advantages, the safe route is best.
Re: Order of things in the NMI
by on (#152305)
Kasumi wrote:
If lidnariq's post is correct, you could totally do it in PAL, which is a surprise to me.

It might or might not be possible, but I don't care for PAL. I program my game for NTSC and that's it. (Even though I'm from Germany.)

Kasumi wrote:
You could also fade the palettes to black, update portions of the screen, then fade back in if you wanted to keep NMIs active the whole time.

Meh. I'll just take the easy way and disable NMI.
In my game, screen transitions will only happen between levels. So, we don't have scenes like where you walk through a door and stand somewhere else.
This also means that no music plays during that time anyway.
Re: Order of things in the NMI
by on (#152326)
Kasumi wrote:
A single nametable is 1024 bytes. Even assuming you were just writing the same byte in the fastest way, you'd get nowhere near 1024. sta $2007 is 4 cycles. 4*1024 would use slightly less than double the time you have to safely write to $2007 on NTSC. If lidnariq's post is correct, you could totally do it in PAL, which is a surprise to me.
70 scanlines is a lot of time, even at the slower PAL CPU clock.

Unrolling 1024 STA $2007s occupies 3KiB of your PRG, so it's a dubious investment just to be able to clear the nametable in a single vblank.
Re: Order of things in the NMI
by on (#152328)
lidnariq wrote:
Unrolling 1024 STA $2007s occupies 3KiB of your PRG

Well, 1024 STA $2007s would use 4096 cycles, out of 7459.375 (did I calculate that correctly?) of the PAL VBlank. What's left may not be enough to loop after every byte, but you could totally loop every 4 bytes, so you'd barely waste any ROM. I still don't see why clearing a name table in one frame would be particularly useful, though.
Re: Order of things in the NMI
by on (#152331)
I totally wasn't trying to say it was useful. It was just very surprising that you actually could. Obviously it's not practical.
Re: Order of things in the NMI
by on (#152669)
Another question:
Kasumi wrote:
Code:
NMI:
  pha
  tya
  pha
  txa
  pha
;Standard NMI stuff here
  pla
  tax
  pla
  tay
  pla
  rti

Is the order of the X and Y register important here? Does the Y register have to be put into the stack first or is this just an arbitrary order? (If I can choose, I would always use the order of A, X and Y, not A, Y, X.)
Re: Order of things in the NMI
by on (#152670)
And something else. A stylistic question:

Where should the background be updated during gameplay? Inside the NMI or in the game logic, before the NMI starts?

With update, I mean stuff like drawing the next column in the offscreen memory in scrolling games.

The very first initialization of a complete background is done outside the NMI. So, what about the updates that happen during the gameplay?

Instant palette changes also count: In the game logic loop or inside NMI?
Re: Order of things in the NMI
by on (#152673)
The order of X and Y is not important. (You still have to reverse whichever order you choose when pulling from the stack of course.) A just has to be first because the transfer instructions destroy A.

To update the screen/palettes during gameplay, you write the updates you want to make to a RAM buffer in your main loop. You read that data from the buffer and write it to PPU registers in the NMI.

The reason you don't just write them in the NMI without setting up a buffer is because there is a limited amount of time to do so safely. Finding out what data to write to the palette or background involves decision making with takes CPU time. Ideally your NMI should make almost no decisions, just read/write from the buffer.

Imagine a scrolling game with compressed tiles. To get the data to write for the PPU, you have to go through the compression. This is not something you want to be using valuable "safe draw" time. The buffer would just contain the uncompressed column which could be written with a simple loop, or even something unlooped for certain kinds of updates.

Edit: Lidnariq's post covers exactly how much safe time you have. You can see how many cycles each instruction takes here: http://www.obelisk.demon.co.uk/6502/reference.html
Re: Order of things in the NMI
by on (#152676)
Order of pushing X and Y doesn't matter, so long as they're pushed in one order and pulled in the reverse order (last in, first out).
Re: Order of things in the NMI
by on (#152679)
O.k., I get the fact that the NMI has a limited time to do everything.

But why can't I just do the whole background update before the NMI hits at all?

Your suggestion is this:

Before NMI:
1. Set up an array in RAM.
2. Run the algorithm to decompress the data with all its ifs and elses.
2.1. Store the decompressed data into the array.

During NMI:
Read the array in RAM and copy the values 1:1 into the PPU.


So, why not just do this?

Before NMI:
1. Run the algorithm to decompress the data with all its ifs and elses.
1.1. Store the decompressed data directly into the PPU. No intermediate array.

During NMI:
0. Do nothing with the background. (Do the sprite DMA and the scrolling, i.e. stuff that would be done anyway.)


In this case, I wouldn't need an extra array in RAM.
Re: Order of things in the NMI
by on (#152680)
Quote:
But why can't I just do the whole background update before the NMI hits at all?

Writing to the $2007 (and some other PPU registers) while the screen is being drawn will crash the game at worst and corrupt the visuals on screen at best. This is why I said there is a limited amount of time to do so safely.

The NMI triggers during a very small period in between frames being drawn. You could do everything in your NMI, so long as you don't use more than the CPU cycles written in lidnariq's post.
Re: Order of things in the NMI
by on (#152684)
You can read and write video memory at will during forced blanking. If the background never changes during a level, such as if sprites are the only moving things, you can just load the background before the level starts. Then your NMI handler only needs to perform sprite DMA.
Re: Order of things in the NMI
by on (#152686)
Of course I'm talking about a level that has to be updated live during gameplay. I'm aware that non-scrolling or two-screen-games can just be updated before the level.

Kasumi wrote:
Writing to the $2007 (and some other PPU registers) while the screen is being drawn will crash the game at worst and corrupt the visuals on screen at best.

But how is this possible with the following setup (shown as pseudo code)?

Code:
InitializeNes();

NmiIsNext = true;

GameLogic:

if (NmiIsNext)
  goto GameLogic;

DoTheGameLogic();

// This is the code that this thread is about:
UpdateThePpuForBackground();

NmiIsNext = true;

goto GameLogic;

//////////

interrupt Nmi:

SaveRegisters();

if (not NmiIsNext)
  goto NmiEnd;

DoTheNmiStuff();

NmiIsNext = false;

NmiEnd:

RestoreRegsiters();

return from interrupt;

In this scenario, the NMI should never do anything while the game logic and other stuff is still processed.
Re: Order of things in the NMI
by on (#152693)
DRW wrote:
But why can't I just do the whole background update before the NMI hits at all?

Because befote the NMI hits, VBlank hasn't started yet, and you can't write to the PPU outside of VBlank.

If you really have to update VRAM during gameplay, you can only do it during VBlank. The only option you have for eliminating the need for buffers is to also generate the data during VBlank, but like it's been said, that's not recommended at all, because it wastes too many precious VBlank cycles. Even if you used forced blanking to extend VBlank (which can be tricky to setup, specially if you're a newbie), you'd still have to waste a lot of time, because different types of updates depend on each other (for example, you scroll and have to draw a new column of tiles, and the new position of the camera affects the position of the sprites), and this will have you putting huge parts of your game logic into the NMI and stealing VBlank time, which could even be impossible depending of how complex your engine is.

The correct thing to do is let your engine generate the data at the appropriate speed, and in the correct order so that when VBlank starts and the NMI hits, the buffers are in a consistent state.

It's not like these buffers will steal a huge amount of RAM, since the time of a VBlank is barely enough to write 180 or so bytes, so that's as big as your buffer's gonna get.
Re: Order of things in the NMI
by on (#152694)
There are ~2273 cycles you have to write to $2007 every frame without some magic. The NMI lets you know when this time starts. Say this was your NMI:

Code:
NMI:
inc vblankcounter
rti

And this was your main loop.
Code:
main:
lda vblankcounter
waitnmiloop:
cmp vblankcounter
beq waitnmiloop
SCREENUPDATES:

You could totally do screen updates under the screen updates label. What's important is not the NMI specifically. It's the 2270 cycles you have to safely write to $2007. As long as SCREENUPDATES doesn't take too long, it's fine there.

And if you mean how it's possible to write an entire screen before the game starts, that's because the screen is not currently being drawn then. Again, you can't write to $2007 while the screen is being drawn. If nothing is being drawn you can write to $2007 at any time. While something IS being displayed, the NMI lets you know when the PPU has just stopped rendering it, and you have X time before it starts to render again.

If you mean something else, you will need to clarify the question.
Re: Order of things in the NMI
by on (#152794)
tokumaru wrote:
Because befote the NMI hits, VBlank hasn't started yet, and you can't write to the PPU outside of VBlank.

O.k., that's the detail that I wasn't aware of.
Re: Order of things in the NMI
by on (#152796)
That's a VERY important detail. The whole point of the NMI is to let you know that VBlank has started, so that you don't miss any of it.