Probably should have mentioned this is the NES =P But I gathered that from 2006 and Zelda 2.
What puzzles me is, what exactly is V-Blank? What exactly is NOT V-Blank? Isn't anything within a NMI call V-Blank by definition?
To answer your last question first: no. NMI is triggered at the start of VBlank, but that doesn't mean any code that runs in it is in VBlank.
VBlank is a period of time. The NES is constantly rendering frames -- 60 of them per second. Between each frame is a period of time where the raster gun on the display is resetting for the next frame, and therefore the system is not outputting any video. This time is "VBlank". Since there's no video being output, it is safe to mess with video settings.
If you want more detail -- each frame on the NES consists of 262 scanlines. Each scanline is exactly 113.66667 CPU cycles*... so they all last for a fixed length of time. The scanlines are broken down as follows (note the number system may be different depending on what emu or doc you're referring to, but this numbering is pretty common):
- scanlines 0 to 239 are "rendered". This is when the PPU is drawing pixels to the screen.
- scanline 240 is "idle" ... this is REALLY where VBlank starts, but NMI hasn't happened yet
- scanlines 241 to 260 (or -21 to -2 depending on your numbering) is where VBlank officially starts. NMI triggers at the very start of scanline 241.
- scanline -1 (or 261) is "pre-render"... this is where VBlank has officially ended (no longer safe to access PPU), and the PPU has begun doing work in preparation for rendering the next scanline.
Not counting the idle line, there are 20 scanlines of VBlank. Each scanline is 113.66667 cycles, meaning you have 2273.3333** cycles of VBlank time.
Note it's a WINDOW OF TIME
. Each instruction that executes consumes some of these cycles (see any 6502 doc for how many cycles each instruction uses). Once you run out of that time... you are no longer in VBlank... regardless of whether or not you are still in the NMI routine.
* Technically there's one exception to this rule, but don't worry about it.
** Keep in mind there might be some latency between the start of VBlank and the NMI trigger. And remember the NMI itself consumes 7 cycles, so you probably have closer to 2260 CPU cycles of VBlank time by the time your NMI code starts running. And to make things worse, games will almost always need to spend vblank time doing a sprite DMA (a write to $4014 to update all on-screen sprites) which consumes a whopping 513 cycles! So REALLY, you have closer to 1747 cycles.
and I still get a glitchy mess.
FCEUX tells you what scanline the PPU is currently on, so you can gauge your timing. Step through your code in the FCEUX debugger and keep an eye on the "Scanline" marker:https://i.imgur.com/vimpWYj.png
<- see this image
If the scanline is 240 to 260, you are safely in VBlank. If it's anything else, you're in the middle of rendering.
Also if it's 260 you are REALLY close to running out of time, as all drawing code should probably be done a bit before VBlank ends.