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

Stable background

Stable background
by on (#134197)
I've tried to create a stable background, but it is not possible. It flickers and moves around.

I write to 0, 0 to $2005 and during the frame I update the background by writing to $2006 and $2007. Any help is appreciated!
Re: Stable background
by on (#134198)
$2005 and $2006 share an internal register inside the PPU. When you do updates through $2006/$2007, you overwrite this register. So after you update video memory, you need to set $2005 again before the next frame begins.
Re: Stable background
by on (#134199)
Reference material for tepples' statements:

http://wiki.nesdev.com/w/index.php/PPU_scrolling
http://wiki.nesdev.com/w/index.php/The_ ... _scrolling

The short version is: do your lda #0 / sta $2005 / sta $2005 after you do all of your $2006/$2007 updates, and before the start of the next frame (e.g. do all that within NMI).
Re: Stable background
by on (#134202)
To clarify, koitsu means before the start of rendering, which begins at the end of the vertical blank. Vertical blank starts at the beginning of NMI, and lasts for a short period of time, during which you need to make all needed writes to $2007, then write to $2005 twice to set your scroll position.

If all of this is not done before your reach the end of the vertical blank, you will have visual problems, i.e. some of the $2007 writes will go to unexpected addresses (nametable corruption), and the scroll will be wrong.
Re: Stable background
by on (#134221)
Thanks for your help!

Should I poll for the vertical blank? Or do the rendering in some other way?
Re: Stable background
by on (#134227)
piot wrote:
Should I poll for the vertical blank?

You can poll a flag that you set in the NMI, but not $2002. Reading bit 7 of $2002 is not advised is because when the register is read at the exact same time the flag gets set by the PPU, the flag gets cleared immediately and never returns a 1. This particular alignment has reasonably high chances of happening, since the register is read in a loop. This will cause you to miss VBlanks from time to time, which will affect the smoothness of animations and sounds.

Quote:
Or do the rendering in some other way?

The absolute simplest way is to keep NMIs always enabled and have the NMI handler only change a variable, nothing more:
Code:
NMI:
   inc FrameCount
   rti

Then, whenever you want to wait for Vblank, you do this:
Code:
   ;wait for VBlank
   lda FrameCount
Wait:
   cmp FrameCount
   beq Wait

The idea is that you put the current frame counter into the accumulator and keep comparing it to the memory location it was loaded from. The values will remain equal until the NMI fires and modifies the variable in RAM, which will cause the loop to end.

NMIs are 100% reliable, and you won't miss VBlanks with this technique as long as your game logic doesn't take longer than a full NES frame to execute.

The simplest NES game structure that's still versatile for a wide variaty of game types goes something like this:
Code:
InitializeModule:

   ;SET UP EVERYTHING FOR THE FOLLOWING LOOP;

ProcessFrame:

   ;READ CONTROLLERS;
   
   ;GAME LOGIC (PHYSICS, AI, SCROLLING, ETC.);

   ;WAIT FOR VBLANK;

   ;WRITE DATA TO THE PPU, RESET THE SCROLL, ETC;
   
   ;CALL MUSIC DRIVER;

   jmp ProcessFrame

You can have multiple blocks like this in your NES program, one for each different "module". For example, the title screen and the menus would use one loop like this where the logic is basically moving cursors around and updating options on screen according to user input. Once the game starts, another loop like this will take care of updating backgrounds, moving objects around and so on. You can freely navigate from module to module by simply jumping to the initialization code of another module at any time.
Re: Stable background
by on (#134243)
tokumaru wrote:
NMIs are 100% reliable, and you won't miss VBlanks with this technique as long as your game logic doesn't take longer than a full NES frame to execute.

There is one tiny caveat, which I don't see people mentioning very often. Even if you use NMIs, the NMI will be suppressed from time to time if you poll on $2002 (for whatever reason) while the vblank flag is getting set. This is in addition to the vblank flag not being returned correctly from the $2002 read. This is nothing a newcomer should worry about, though.
Re: Stable background
by on (#134245)
thefox wrote:
Even if you use NMIs, the NMI will be suppressed from time to time if you poll on $2002 (for whatever reason) while the vblank flag is getting set.

True. The NMI flag perfectly supresses the need for reading the VBlank flag in $2002, but $2002 reads are still common for resetting the $2005/$2006 first/second write state. Personally, I never use $2002 for that, because I believe I have to make my code stable enough to ALWAYS write to $2005 and $2006 in pairs, otherwise my code has a bug that should be fixed. Still, even if you do use $2002 for this purpose, that will most likely be AFTER the detection of VBlank, and since you'll have already detected it there's no chance of missing it, so this isn't such a big issue.