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

Best vBlank Wait with $2002?

Best vBlank Wait with $2002?
by on (#145967)
Someone on the Nesdev IRC Channel said : "Don't spin around $2002, because it is unrealabe and there is a chance to miss a frame"
Someone else said : "My code is very fishy!" :

****************************************************

Here is my warm up routine :

Code:
   LDX #$04            ; 4 Times vblank period will come and go

warmup_loop:           ; Do loop until vblank starts
   BIT $2002           ; It is not vblank period / 7th bit of $2002 is 0 / BIT, Clear the negative sign
   BPL warmup_loop     ; The result is Plus / BPL, Continue the loop!

; Vblank period has just started / 7th bit of $2002 is 1 / BIT, Set the negative sign / The result is Negative / BPL, Don't continue the loop!

vbend_loop:            ; Do loop until current vblank ends
   BIT $2002           ; It is vblank period / 7th bit of $2002 is 1 / BIT, Set the negative sign
   BMI vbend_loop      ; The result is Negative / BMI, Continue the loop!

; Vblank period has just ended / 7th bit of $2002 is 0 / BIT, Clear the negative sign / The result is Plus / BMI, Don't continue the loop!

   DEX
   BNE warmup_loop


****************************************************

Here is my vblank wait routine :

Code:
vblank_wait:           ; Do loop until current vblank ends
   BIT $2002           ; It is vblank period by sheer chance! / 7th bit of $2002 is 1 / BIT, Set the negative sign
   BMI vblank_wait     ; The result is Negative / BMI, Continue the loop!

; Vblank period has just ended / 7th bit of $2002 is 0 / BIT, Clear the negative sign / The result is Plus / BMI, Don't continue the loop!

vbstart_loop:          ; Do loop until a new vblank starts
   BIT $2002           ; It is not vblank period / 7th bit of $2002 is 0 / BIT, Clear the negative sign
   BPL vbstart_loop    ; The result is Plus / BPL, Continue the loop!      

; Vblank period has just started / 7th bit of $2002 is 1 / BIT, Set the negative sign / The result is Negative / BPL, Don't continue the loop!

   RTS                  ; Now the screen can be updated!


****************************************************

So, is it really fishy?! Or will I miss any frame?! :?
Re: Best vBlank Wait with $2002?
by on (#145969)
A BIT $2002 / BMI loop is never useful. Use BPL only. It's fine to use it during warm-up. But using it for timing will always result in some frames being missed. Reading the flag resets it, and the NES also resets it at a certain time every frame. If the register is read at the same time the NES resets it, then you'll miss that frame. Whenever correct timing is needed, you must enable NMI and set a flag there, then check that flag in your wait loop.

Read this:
http://wiki.nesdev.com/w/index.php/NMI
Re: Best vBlank Wait with $2002?
by on (#145972)
I put that BIT $2002 / BMI in the vblank wait routine to skip any vblanks which is on its halfway and then wait for a new vblank to get a full vblank period.
Is it useless for that purpose?
Also NMI is disabled all the time.
Re: Best vBlank Wait with $2002?
by on (#145973)
Quote:
Is it useless for that purpose?

Yes. Just a bit $2002 with no BMI will have the same purpose.
Re: Best vBlank Wait with $2002?
by on (#145974)
FARID wrote:
I put that BIT $2002 / BMI in the vblank wait routine to skip any vblanks which is on its halfway and then wait for a new vblank to get a full vblank period.
Is it useless for that purpose?
Also NMI is disabled all the time.

To rephrase what was said already: BIT $2002 / BMI is useless because reading $2002 has the side-effect of clearing the vblank flag. So, if the BIT $2002 happened to return the vblank flag as set, it would also clear it at the same time, and the next iteration of loop would return it as unset, exiting the loop. And if BIT $2002 returned the vblank flag as already being cleared, then of course the BMI branch would never be taken. In any case, the end result is the same, the vblank flag is cleared.
Re: Best vBlank Wait with $2002?
by on (#145976)
Memblers wrote:

I was the one reviewing Farid's code. He's using it for a multicart, and the NMI handler is that of one of the games. In order to use NMI, he'd have to understand what variables the NMI handler uses and how to disable their game-related function so that it doesn't interfere.
Re: Best vBlank Wait with $2002?
by on (#145978)
Trying to avoid NMI for a menu? Try putting sprite 0 at the bottom of the screen, then you can wait for a sprite 0 hit, then delay some cycles after that so you know you're in vblank time.

Before you display your first frame though, you'll probably need to do repeated 2002 polling for vblank, which can miss frames. Then you can display a frame with the correct scroll values and sprite contents, then sprite 0 hit will work after that.

But if the intent isn't true 60FPS, and is just to wait for vblank to update a menu or something, then does it really matter if you miss frames?
Re: Best vBlank Wait with $2002?
by on (#145980)
For a menu I wouldn't bother to miss frames. The game Portopia, which is entirely menu based, relies on $2002 polling only and doesn't use interrupts ever.
Re: Best vBlank Wait with $2002?
by on (#145981)
Bregalad wrote:
For a menu I wouldn't bother to miss frames.

Unless you have music/sound, right?
Re: Best vBlank Wait with $2002?
by on (#145996)
If you are concerned about the missed frames, you can dramatically decrease their frequency by adding more cycles to your wait loop.

Code:
; 7-cycle loop has 1/7 chance of waiting an extra frame
:
    bit $2002
    bpl :-

; 13-cycle loop has 1/13 chance of waiting an extra frame
:
    nop
    nop
    nop
    bit $2002
    bpl :-


Like, the naive loop has 14% slowdown because of the missed frames, but every cycle you add to the loop decreases your chances. If your loop had 100 cycles in it (and this is not unreasonable to do), it would go down to 1% slowdown.
Re: Best vBlank Wait with $2002?
by on (#146000)
Thanks for everyone for the great info.
So BIT $2002 clears Negative sign, and as a result BMI will never branch, so it is useless.
But what about the BIT $2002, I feel that it is needed for skipping any halfway vblank periods, no?

Image
Re: Best vBlank Wait with $2002?
by on (#146002)
Yes, an extra BIT $2002 before you enter your wait loop will clear the bit if you are already within vblank. Very useful if you need to avoid accidentally exiting the wait loop in mid-vblank (but not important if you don't).