I've been working on switching between endless loops and NMIs. In my NMI routine, I'll do everything that must be done at the maximum speed of 60hz. If I did many of these things in the endless loop, they'd occur at a speed that may be undesirable, depending on how long it takes to execute everything in the endless loop. I do game logic related things in the endless loop. I don't want the NMI to be enabled when I'm in the endless loop. And after the endless loop is finished doing it's thing, I will turn the NMI back on, and just wait in the endless loop until the flag that tells it to update game logic is set again.
So I tried this, and I got some results I wasn't expecting. I was expecting the NMI to start at Vblank, not right after I set bit 7 of $2000. In my NMI routine, I had a variable increasing by 1 for every time the NMI was executed. At the end of the NMI, I'd set the flag that tells the endless loop to update game logic. After the loop was over, the NMI was turned back on, and the flag was cleared. But the NMI seemed to start right back up again in the same frame. The variable being increased by one was not increasing at 60hz. It was almost double that.
Is this a game-related bug, or does the NMI really start right when you set bit 7 of $2000?
If a write to $2000 just set bit 7 (when it was clear before) and the VBL flag is already set, an NMI will occur immediately. So the solution is to just clear the VBL flag first, which will have the next NMI occur on the start of the next VBL:
bit $2002 ; clear VBL flag
lda #$80
sta $2000 ; enable nmi
Thanks! I guess I don't know as much as I really should about this kind of stuff. Yeah, my previous solution had me polling $2002 to wait for Vblank, and if it was in Vblank, I'd then turn the NMI's on. Obviously, this is not a very reliable solution. I was worried I was going to have to stick with it. Thanks again!
i tried a loop in Main that didnt work in NMI. that could set appropriate delays with key presses or store values at the end of a loop once your current event ends. then using lookup tables to to enter a desired amount of timing.
Code:
CHANGE_TIME
LDX INC_B_BUTTON ; or event
LDA TIME,x
STA OUTLOOP1
LDA TIME2,x
STA OUTLOOP2
RTS
LOOP
LDX OUTLOOP1
LDY #$ff
DECY DEY
BNE DECY
DECX DEX
BNE DECX
DEC OUTLOOP2
BNE DECY
RTS
TIME
.db FF,87,32, 40
TIME2
.db E3,80,20, 10
Filling the OutLOOP2 with larger number would yeild some loog delays around 30 secs or less and more depending on the value. And could prove using as setuping introduction screens at start up.
i got this off 6502 Software Book by Blacksburg and then made some appropriate changes. Hope it helps some one.
I don't know why it didn't work inside the NMI routine, but I know that is not a good place for this kind of code. The NMI routine on the NES exists so that we can keep our programs sync'ed to the refresh rate of the screen, so, ideally, you should return from the current "instance" of the NMI routine before it's time for the next one to start.
However, you are trying to run some code that will keep the CPU inside the NMI for many many frames. I don't think that an NMI will fire while another one is still running (that'd be pretty bad because it'd fuck up the stack big time), but it still feels very wrong to keep you NMI routine running for so long.
Also, I don't see many uses for this kind of delay. As I said when I replied to your other post, this kind of delay freezes everything, and is very imprecise. In order to know the duration of the delay you have to go through some serious cycle counting (that's pretty hard) or guess until you get it right, which is just as annoying.
Most, if not all, the timing in NES games should be frame-based, because the system provides us means of staying in sync with the 60Hz refresh rate of the TV (I'm talking about the NMI routine here). Also, delays should be specic to individual events or groups of events, and not freeze the whole program.
For example, you may want to display your title screen for 10 seconds. But if you think about it, this is not the only thing you are doing. You are also reading the controllers (after all, you must know when the player presses start in order to start a new game), playing some music, and so on. You are also free to do some animations, such as changing the palette. This is only possible with event-specific delays, because you only want to delay the title screen, not any of the other things that are also going on.
The correct way to do this is with frame counters. Each second has 60 frames, so 10 seconds have 600 frames. The math is pretty easy (as opposed to the other method). All you need to do is set up a variable with the value 600 (it must be a 16-bit variable to hold a value this big) as soon as you first display the title screen. Then, every frame (the NMI helps you detect the start of a frame), decrement this variable. When it reaches 0, you know that the time is up and you can fade out and do whatever comes after that. Notice that you only delayed the fade-out, but all other events were free to run normally.
i used the delay to move sprite that changed everytime time i made a button press and increased or decreased in speed. the presses where made in the NMI and would update apprioately with event. while movements where in the MAIN. the falisy with this is that there can be nothing else in the Main. but it will run it spearate course apart from the NMI waiting patiencly awaiting for a press. but now after your last post i know how to NMI time and will those instead. thanks again