Newbie Question: What is the recommended way to display and switch between a title page and a single level page? I have a fair amount of the code for the actual gameplay done, so I thought it was be easy to add a title page. Converted over to using nesicide during this time. I don't plan on doing scrolling for the title page or the gameplay page. Currently set to vertical mirroring too.
It appears I have the following two options:
1) Populate name table 1 and 2, then after player hits starts, set $2000 bit 0 to switch which is viewable
2) Populate just name table 1, then 'overwrite' that area after start button
Tried number 1, but it didn't work, I suspect my timing may be wrong. Do I need to disable the NMI before doing this, or since these are in the same register does it make it a moot point?
Tried number 2, got a cpu jam. I figured this was because I didn't disable the NMI. But when that was done it didn't appear to do anything and just sit on the title page.
I look forward to the RTFM comments, but each technical doc I've looked at for the PPU doesn't clear explain this and the ones that do don't go deep enough on how to switch back and forth without doing scrolling and offsets.
darkowl wrote:
What is the recommended way to display and switch between a title page and a single level page?
[...]
It appears I have the following two options:
1) Populate name table 1 and 2, then after player hits starts, set $2000 bit 0 to switch which is viewable
2) Populate just name table 1, then 'overwrite' that area after start button
Most games appear to use #2.
Quote:
Tried number 2, got a cpu jam.
Then perhaps your code isn't doing what you expect. Have you tried tracing through your level page loading code in an emulator with a debugger?
Quote:
I figured this was because I didn't disable the NMI.
That shouldn't affect anything unless your NMI handler fails to properly save and restore the A, X, and Y registers, or unless it corrupts the stack or the stack pointer.
I've switched it to do the equivalent of #2 (overwrite)
As for the cpu jam, I wasn't doing a good job of using the stack in my nmi handler. That solved some oddness from occurring.
My main problem turned out to be my flag that was set based off of user input was still 0 when read in the nmi portion. This confused me for the longest time, but apparently if you define a .space after .org $C000 it is not accessible to the nmi handler. Defining it after .org $2000 corrected it. I didn't think there could be a scope problem, but maybe this is related to page boundaries? So thank you for your debugger suggestion, I would have never found it otherwise.
Its still not completely working, but at least on 'A' it displays the bottom of NT1 and top of NT1 (in that order) on the screen. I want NT2, but at least I'm getting closer. I'll avoid putting all the code up here, but if that sounds familiar let me know.
The one outstanding question I have is this:
In the nmi handler if I know a fairly large number of cycles needs to execute (like writing a new nametables worth to $2007) even when I turn off the ppu bg rendering, can't another nmi occur before I get to my rti? I know most places say don't turn off the "generate an nmi on vblank" for anything, but isn't this almost necessary in this case? I know its a race before the next vblank, but since when exactly that will occur is unknown, unless you turn of the interrupt then how can you guarantee your 2007 writes will actually finish and not get interrupted?
darkowl wrote:
but apparently if you define a .space after .org $C000 it is not accessible to the nmi handler. Defining it after .org $2000 corrected it. I didn't think there could be a scope problem, but maybe this is related to page boundaries? So thank you for your debugger suggestion, I would have never found it otherwise.
Disregard that part. while it gave the appearance of things working it was really creating aliases for $2002,2003, etc. that had nothing to do with the ppu.
Disclaimer: still a relative newbie, so if I spew any nonsense please correct me:
This thread by Celius I think can help address this issue:
http://nesdev.com/bbs/viewtopic.php?t=3971
Recently I've been thinking about the same thing. The vblank is really quite short and it is easy to make it go longer and keep writing to the PPU during a frame update...causing ugly scramblies.
Just the other day I wrote a partial map decoding routine which draws a single meta-meta-tile from my map data, and stuck it all in vblank. Guess what? it was too long (caused scrambling) So what I did was I put all the decoding in my main loop, after a wait for vblank to complete---this dumps into a buffer, which is in turn read by a routine called from vblank (this is what actually updates the PPU). Not only did it perform better it was actually simpler to code! (I had to keep changing the VRAM address in my first attempt...)
For a game title, I'd probably do something where I change the palette and then fill the nametable in "slices" for a few frames, where the vblank just fills up one slice at a time or something like that. I think it should be possible to fill one nametable during a single vblank though. *edit* but I have a vague memory of an experiment where this failed, so take that with a grain of salt lol. I know the "slice" idea would work great though.
Initially I assumed the length of the NMI up to the rti == the length of vblank. I know that completely wrong. I came across some good explainations of nmi,vblank, and the timing involved since then. I'll reread that thread you mentioned though.
For some reason, I still assumed that vblank would last long enough to do a full nametable transfer. That could be the case, but I guess I need to do some more testing. One doc suggested for these bulk writes to the ppu, not to use 'buffering' as a nametables worth of data would be too much to make buffering it efficient. He suggested to actually do (the bulk writes) outside of the nmi handler, being sure to toggle the bg rendering. then I guess during vblank nothing needs to happen (well at least in regards to that bulk write). But if I definately needed to do it inside of the magic vblank window, I can see how slicing it up might be needed.
Mastering the nmi/vblank/ppu timing seems to be the biggest challenge so far.
Maybe you could set a "disableVblank" flag or something, right before you disable bg rendering and write to the PPU? The vblank would keep firing but it would not execute your PPU code because disableVblank would be set. I know in a lot of my early experiments I actually fill a nametable as the first thing that happens, then I turn on bg rendering. Also, I save/restore all registers in my vblank routine.
That has been working so far but for a game engine, I intend to develop some kind of state-switching logic which can swap out pointers to various update routines for game logic/PPU updates. I want it to be able to do something like (pseudo code):
set game state to Title
*main loop and vblank routines update the title screen and get input blah blah blah*
main loop: "I'm done! On the next update, the state shall now be LOADING LEVEL 1."
*level loader routines from the main loop and vblank fill the nametable, set up initial sprites locations, game object states, etc.*
level loader: "I'm done! On the next update, the state shall now be PLAYING LEVEL 1."
*level playing code starts running! all the fun game stuff happens*
etc.
I have an NMI routine that always runs (NMIs are always enabled), it updates video and audio. But I also have 2 flags, which indicate whether said updates should take place, so I virtually enable/disable video/audio through those flags.
So, in order to perform a big PPU update, I'd disable video through that flag and wait for the next NMI to happen, at which time rendering will be disabled (because of the flag) and I'll have all the time in the world for PPU writes. When I'm done, I change the state of the flag and rendering will be switched back on during the next NMI.
I decided to do things like that because I have a fairly general NMI routine that should be enough for most types of updates required during a game, but I wanted to have the option to skip those standard updates altogether and have direct access to the PPU for bulk/non-standard writes.
I'm happy to say after a ton of changes, I've finally got it working exactly as expected! Thanks to everyone that commented, I can sleep easy tonight.
I keep the 'nmi on vblank' enabled the entire time and ended up using a series of flags (levelchanged, disablevideo, readyforchange, and inprocess) like mentioned in the recent posts. This way at any point I can be sure its safe to touch $2006. Thanks again.