Question about NES vectors and PPU

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Question about NES vectors and PPU
by on (#34042)
Alright, first time posting a question. Note that I'm not new to programming nor assembly, but I'm new to programming a game and new to the assembler, meaning that I don't know how the assemblers work.

Well, I knows the vectors present in the NES, and know what they are suposed to do, in the microprocessor view. But what's a bit unclear is what are their purpose in a NES game. NMIs are for updating the screen (graphics), very clear because it's its very first purpose due of the behavior of WRAM when rendering. NMIs are also for sound, because it is a great idea to update this at a precise timing interval, and also update any "internal timer" of the game (ex. decreasing time left) or any time-based routine. But waht's up with the code in the reset vetor??? Okay for any initialisation code, but what else in run-time? Also, does the IRQ can be used for anything else than for graphic FX (status bar remain at it place)?

PPU: it is another 65xx-based core unit, which is a CPU. It work in a kind of slave mode? What code it executes?

Please warn me if I "jargonize", and consider my apologies if it is the case.

Thanks

by on (#34044)
NMI: used to synchronize with VBL, also other things done every frame

Reset: tells where game code starts. Used when powering on and when reset button is pressed.

IRQ: BRK goes here, as well as APU interrupts and any mapper provides.

The PPU is a hardware state machine, not a processor.
Re: Question about NES vectors and PPU
by on (#34045)
~J-@D!~ wrote:
NMIs are for updating the screen (graphics), very clear because it's its very first purpose due of the behavior of WRAM when rendering. NMIs are also for sound, because it is a great idea to update this at a precise timing interval, and also update any "internal timer" of the game (ex. decreasing time left) or any time-based routine.


Yeah NMIs fire at a steady rate, so they can be used for timing mechanisms. Also note that they fire at the start of VBlank, which indicates it is now safe to make PPU accesses for a certain time period (and thus updating the screen).

Quote:
But waht's up with the code in the reset vetor??? Okay for any initialisation code, but what else in run-time?


Reset vector is the entry point for your program. It's only used at system startup and is not used at all at runtime (unless the user presses the reset button on the console). It's not like other interrupts because you don't RTI from a reset.

Quote:
Also, does the IRQ can be used for anything else than for graphic FX (status bar remain at it place)?


Well it can be used for whatever you want. Like for another timing mechanism... but usually it's used for raster effects (like splitting the screen).

Quote:
PPU: it is another 65xx-based core unit, which is a CPU. It work in a kind of slave mode? What code it executes?


The PPU does not run code... it is not a 65xx core unit. It is just a graphics processor. (EDIT: maybe I shouldn't say "processor" since I guess it technically isn't a processor? But I thought PPU stood for 'Picture Processing Unit'?)

The PPU is the part of the NES that transforms the palette, nametables, and CHR into visible on-screen pixels that get output to the TV. You do not program anything for the PPU, other than changing a few registers which change how the PPU renders.

All of the 6502 code you write for your game will be exeucted by the CPU. None of it is handled by the PPU.


EDIT - doh blargg posted too quick

by on (#34046)
It processes pictures, not code ;-)

Also re: NMI's being for sound, technically this isn't true. You can probably run sound at any time, it not being critical to be timed in vertical blank, although it's usually a good idea to run it in NMI if you're doing weird stuff like split-screen madness.

by on (#34050)
In fact if you want to get really technical, I suppose you could say it doesn't process a picture.......but data that it turns INTO a picture. (not sure if it actually processes the picture after that)

by on (#34051)
doppelganger wrote:
It processes pictures, not code ;-)

Also re: NMI's being for sound, technically this isn't true. You can probably run sound at any time, it not being critical to be timed in vertical blank, although it's usually a good idea to run it in NMI if you're doing weird stuff like split-screen madness.

The PPU processes bits from VRAM/palette and turns them into a video waveform which the TV turns into a picture. And the NMI is for whatever the Famicom hardware designers put it there for, which was probably for periodic graphic and sound operations; just because the beginning VBL triggers it doesn't mean it's meant only for synchronization to VBL. You don't want sound interrupting your NMI code, nor do you want sound code being delayed by the time spent in the NMI routine if the sound interrupt happens to occur during it.

To get really technical, the non-maskable interrupt (NMI) was meant for things which must interrupt the processor no matter what, like a "power is about to fail, so write critical state" or "break into low-level debugger" signal. The fact that the PPU can turn off off NMI shows that they are "misusing" it. The "proper" approach for the 6502 is to run all interrupts on IRQ, and differentiate them inside the interrupt handler by polling each possible interrupt source until the initiator is found. But since there's no other use for NMI, they use it as a second higher-priority interrupt, making interrupt handling faster since the routine doesn't need to poll as much, and ensuring that VBL code gets top priority.

by on (#34054)
blargg wrote:
To get really technical, the non-maskable interrupt (NMI) was meant for things which must interrupt the processor no matter what, like a "power is about to fail, so write critical state" or "break into low-level debugger" signal.

Can you quote any MOS Technology datasheet that recommends these as the intended uses for NMI?

by on (#34055)
tepples wrote:
Can you quote any MOS Technology datasheet that recommends these as the intended uses for NMI?

Hmmm, all I find is this:
MOS 6502 Manual wrote:
As is discussed, it is often desirable to have the ability to interrupt an interrupt with a high priority device which cannot afford to wait during the time interrupts are disabled. For this reason, the MCS650X has a second interrupt line, called a Non-Maskable Interrupt.

Maybe I was wrong, and NMI is simply a second less-flexible interrupt line that's unmaskable, thus minimizing response time. The unmaskability still has the advantage that there's no way for software to disable it (short of telling external hardware to disable it as on the NES with the PPU).

by on (#34163)
So many thanks for these fast answers.

The confusion with the PPU is because 2A03 and 2C02 were chips supplied by Ricoh and their name and pin package were so identical I thought they were actually 2 modified 6502s... But it was always clear to me that PPU doesn't read instructions back from the cartridge by its dedicated bus, but only graphic data. I only thought that, if it weren't a state machine but a modified 6502, it would have to run some code that would be inside the NES...

So, code pointed by the reset vector,except for initialisation of the PPU and memory and everything you want to initialize (mappers, perhaps), does nothing? It means that, in a game, when RTI'ing, the main code simply waits another interrupt? That is the whole point I want to clarify. When RTI'ing, what main code would be supposed to do? Or in other words: when RTI'ing, so when CPU is inactive, what it can do? Also, except processing picture and (hopefully) sound, and reading controller(s), what else NMI have to do?

@ doppelganger: of course NMIs are not for sound, but I knew it is very wise to use it in this way because Vblanks like you all said are a simple time base for it, and a fixed time base is crucial to sound to be played correctly (irregular notes or laggy music isn't cool)

@ blaarg: I admire your knowledge of µP and electronic in general, you stand here like an encyclopedia in this forum. As I mentioned in the beginning, I knew the purpose of each vectors in the microprocessor view. Reset is what's normally runs, IRQ contains a routine to perform when an external device want that the µP pays attention to it (timers are considered "devices") and NMI is the highest priority of IRQs that is non-maskable in software and generally dedicaced for critical events. I can't hide you that I found very funny that the NMIs on NES can be actually "masked", hence proving what you told about missusing the NMI.

By the way, have fun viewing this thingy making noise that I did ~6 month ago. ;) http://fr.youtube.com/watch?v=VJMtdfLtKCE&NR=1

by on (#34175)
~J-@D!~ wrote:
So, code pointed by the reset vector,except for initialisation of the PPU and memory and everything you want to initialize (mappers, perhaps), does nothing?


Not really.... Code pointed to by the reset vector is your game. It's the entry point. The reset vector simply tells the NES where the start of your program is.

Quote:
It means that, in a game, when RTI'ing, the main code simply waits another interrupt?


RTI simply jumps back to the code that was executing before the interrupt occured. Just like RTS jumps back from a subroutine you JSR'd to -- RTI returns back from a routined that was NMI'd/IRQ'd to.

You do not RTI from a reset... since nothing was happening before reset (the system was off) it would have nothing to return to. RTIing here would just cause the CPU to jump to garbage code, which would just execute random opcodes and probably eventually deadlock, with another reset (ie: power cycling the unit, or pressing the Reset button) being the only way to start it back up.

Quote:
That is the whole point I want to clarify. When RTI'ing, what main code would be supposed to do? Or in other words: when RTI'ing, so when CPU is inactive, what it can do? Also, except processing picture and (hopefully) sound, and reading controller(s), what else NMI have to do?


The CPU is never inactive. The only time it's inactive is when the system is powered off.

Anyway... what code goes where is really a preference thing. Many games do it different ways. One common setup is something like:

Code:
in NMI:
- update PPU ($2007 writes)
- update sprites ($4014 writes)
- set scroll ($2000,$2005,$2005 writes)
- JSR to music routine
- RTI


"Main game" (gets interrupted by NMI):
- poll joypads ($4016,$4017)
- update game logic (move objects, collision detection, etc)
- wait for NMI and repeat the process once NMI exits


Some games (SMB comes to mind, iirc) do everything inside NMI and simply have an infinite loop outside of it. Other games (Final Fantasy) do nothing in NMI (they exit it immediately) and simply use it to know when VBlank has started.

What you decide to do is completely your preference.

by on (#34201)
Disch wrote:
~J-@D!~ wrote:
So, code pointed by the reset vector,except for initialisation of the PPU and memory and everything you want to initialize (mappers, perhaps), does nothing?


Not really.... Code pointed to by the reset vector is your game. It's the entry point. The reset vector simply tells the NES where the start of your program is.

Quote:
It means that, in a game, when RTI'ing, the main code simply waits another interrupt?


RTI simply jumps back to the code that was executing before the interrupt occured. Just like RTS jumps back from a subroutine you JSR'd to -- RTI returns back from a routined that was NMI'd/IRQ'd to.

You do not RTI from a reset... since nothing was happening before reset (the system was off) it would have nothing to return to. RTIing here would just cause the CPU to jump to garbage code, which would just execute random opcodes and probably eventually deadlock, with another reset (ie: power cycling the unit, or pressing the Reset button) being the only way to start it back up.

Quote:
That is the whole point I want to clarify. When RTI'ing, what main code would be supposed to do? Or in other words: when RTI'ing, so when CPU is inactive, what it can do? Also, except processing picture and (hopefully) sound, and reading controller(s), what else NMI have to do?


The CPU is never inactive. The only time it's inactive is when the system is powered off.



I think I posted in the wrong section :wink: . I'm not newb that much ( "newb" here is not pejorative). I know every single 6502 instruction (the documented ones), I know what they do and how to use them. I also know that a CPU cannot be inactive, except if an instruction tells the CPU to "sleep" and wait an interrupt, which don't exist in the 6502. And it was far away from my mind to have a RTI in main code! Don't worry, I study in electronic, so I know this stuff already. :wink:

BUT, thank you Disch, thank you alot, because with this.......
Quote:
Anyway... what code goes where is really a preference thing. Many games do it different ways. One common setup is something like:


Code:
in NMI:
- update PPU ($2007 writes)
- update sprites ($4014 writes)
- set scroll ($2000,$2005,$2005 writes)
- JSR to music routine
- RTI


"Main game" (gets interrupted by NMI):
- poll joypads ($4016,$4017)
- update game logic (move objects, collision detection, etc)
- wait for NMI and repeat the process once NMI exits
 



Some games (SMB comes to mind, iirc) do everything inside NMI and simply have an infinite loop outside of it. Other games (Final Fantasy) do nothing in NMI (they exit it immediately) and simply use it to know when VBlank has started.

What you decide to do is completely your preference.

...you answered exactly to my question. :D
Maybe I wasn't clear. This is a known problem to me, and my apologies if it is the case. At least nobody tried to explain how interrupts work...

Interresting... the problem is that my first thought about how to make an NES game engine is that it was something close to SMB, according to what you said. Hmm, in you "code" section, I'll have to know how to do in NMI: update PPU, update sprites, set scroll and in main code: update game logic, which is something I have absolutely no idea how... :(

Hey, Thanks you all!.

by on (#34202)
Disch wrote:
Code:
"Main game" (gets interrupted by NMI):
- poll joypads ($4016,$4017)



Really? I'd think you would read the joypad in the NMI section, so it could happen once every frame, so you don't have a character moving at 100 pixels a frame or something like that. I suppose it depends on how long your game loop takes.

by on (#34203)
Celius wrote:
I'd think you would read the joypad in the NMI section, so it could happen once every frame, so you don't have a character moving at 100 pixels a frame or something like that.

My engines increment a retrace count on NMI and do nothing else (like FF1 does). The main code relies on this retrace count changing 60 times a second. It waits for the retrace count to change, then updates VRAM, reads the controller, and does game logic.

by on (#34207)
tepples wrote:
Celius wrote:
I'd think you would read the joypad in the NMI section, so it could happen once every frame, so you don't have a character moving at 100 pixels a frame or something like that.

My engines increment a retrace count on NMI and do nothing else (like FF1 does). The main code relies on this retrace count changing 60 times a second. It waits for the retrace count to change, then updates VRAM, reads the controller, and does game logic.

This is fine as long as you're sure your frame calculations won't go beyond the time at which the NMI fires. If the code takes longer than that, you'll misdetect the start of VBlank and will possibly mess with the PPU while the next frame is already rendering.

Of course it's not desirable to have your game lagging, but in some more complex designs (Kirby's Adventure, for example) this does happen once in a while, so you'd better be prepared.

And Celius, either way could work fine. In my game, I have a main loop processing input, scrolling, object AI and so on. Data to be sent to the PPU is calculated during that time, and when everything is ready, It sets a flag indicating so. When the NMI fires, it only updates the PPU if that flag is set. If by any chance the frame is not ready when the NMI fires, nothing is updated, but the sound code is still executed so that the music doesn't slow down. Anyway, after the main loop indicates that a frame is ready through the flag, it enters a loop that will only be broken when the NMI runs, because it clears that flag.

The flag prevents the game from reading the joypad many times in case frames are calculated too quickly, because the next frame is only processed after the NMI code has been executed, so everything runs at the steady rate of 60Hz (or less, in case a frame takes too long, but never more than that).

by on (#34210)
Celius wrote:
Really? I'd think you would read the joypad in the NMI section, so it could happen once every frame, so you don't have a character moving at 100 pixels a frame or something like that. I suppose it depends on how long your game loop takes.


Having joypad polling outside of NMI doesn't mean it will happen more than once a frame. The "main game" code will only run once, then wait for an NMI to happen -- so there will always be an NMI between joypad polls.

The reason I would leave it outside of NMI is because if there's slowdown, you don't poll the joypad more than necessary (unlike the music routine -- since even if there's slowdown, I wouldn't want the music to slow down).

Anyway, my approach would probably be something like this:

Code:
Main Game:
- poll joypads
- process game logic
- compile a list of PPU writes that need to be done so that NMI can quickly just dump the stuff from the list into VRAM, without having to really compute anything
- set a "waiting for NMI" flag
- wait for said flag to become clear
- repeat the process


NMI:
- Check "wait for NMI" flag, do the following only if set:
--- Sprite DMA
--- read from precompiled list and do necessary PPU writes
--- clear "wait for NMI" flag

(do the rest regardless of that flag's state)
- set scroll values appropriately
- set up whatever IRQs need to be set up (do this first if they're CPU cycle based -- here otherwise)
- JSR to music
- RTI


The reason for skipping over the chunk if the flag is clear is in case of multiple NMIs firing before game logic finishes (ie: slowdown). This will prevent frames from being "half drawn", parts of the frame being unnecessarily drawn multiple times, and/or potential VRAM corruption if the compiled list is still being compiled at the time the NMI fires.


If the game engine is designed so that it never attempts to draw too much in 1 frame's worth of processing time... skipping all the drawing and sprite DMA stuff for a frame will work just fine, since next frame it won't have to draw more than 1 frame's worth of work (despite it not drawing anything this frame).

by on (#34211)
Hey, I thought about something similar to tokumaru, to ensure that music will not lag. So I'm not dummy...

Do you think that it is even possible to design such a engine that calculate time to processing the current frame and if it is too big to be performed and ready in that frame, just calculate the next frame and then render it after the skipped frame (so the engine do frame skipping when necessary) ?

by on (#34212)
tokumaru wrote:
tepples wrote:
My engines increment a retrace count on NMI and do nothing else (like FF1 does). The main code relies on this retrace count changing 60 times a second. It waits for the retrace count to change, then updates VRAM, reads the controller, and does game logic.

This is fine as long as you're sure your frame calculations won't go beyond the time at which the NMI fires. If the code takes longer than that, you'll misdetect the start of VBlank and will possibly mess with the PPU while the next frame is already rendering.

This will synchronize to NMI just fine:
Code:
nmi:    inc nmi_count
        rti
       
wait_nmi:
        lda nmi_count
loop:   cmp nmi_count
        beq loop
        rts

The reason to poll nmi_count is that it simplifies code to a single thread, so you don't have to worry about NMI interrupting and reading half-updated data structures.

by on (#34215)
I suppose I never thought about having the main loop wait for the next NMI, so you're right, it would probably be best in the main loop, since it won't happen more than once a frame if you wait for the NMI.

by on (#34231)
blargg wrote:
This will synchronize to NMI just fine:
Code:
nmi:    inc nmi_count
        rti
       
wait_nmi:
        lda nmi_count
loop:   cmp nmi_count
        beq loop
        rts

The reason to poll nmi_count is that it simplifies code to a single thread, so you don't have to worry about NMI interrupting and reading half-updated data structures.

I see what you mean. You can only get out of this loop when the value is different from when you first read it. The only problem is that you can't, for example, prevent your music code from lagging in frames where the game logic takes too long. In practice, this is just an updated version of the old "wait for VBlank" used in the old days but has been proved unreliable. Works great for simpler games, but is not the perfect choice for games with occasional slowdowns.

Disch wrote:
Anyway, my approach would probably be something like this:

Code:
Main Game:
- poll joypads
- process game logic
- compile a list of PPU writes that need to be done so that NMI can quickly just dump the stuff from the list into VRAM, without having to really compute anything
- set a "waiting for NMI" flag
- wait for said flag to become clear
- repeat the process


NMI:
- Check "wait for NMI" flag, do the following only if set:
--- Sprite DMA
--- read from precompiled list and do necessary PPU writes
--- clear "wait for NMI" flag

(do the rest regardless of that flag's state)
- set scroll values appropriately
- set up whatever IRQs need to be set up (do this first if they're CPU cycle based -- here otherwise)
- JSR to music
- RTI

This is exactly what I do, even the IRQ stuff, I just wasn't clear enough in my last post.

EDIT: Just a note on how tricky the "set scroll values appropriately" step can be when frames haven't been fully processed yet. The scroll is one of the first things my main loop calculates (this probably happens in other engines as well), so the new scrolling values are always ready by the time the NMI fires, but if the rest is not, and the scroll is updated but no tiles or sprites are, you can get glitches or even that annoying effect where sprites that should be perfectly aligned to the background appear to shake a bit.

This happens in many commercial games (I've seen this on the Master System a lot, but also in some NES games), but is very annoying in my opinion. My solution was to, inside the part of the NMI that executes only when frames are complete, make a copy of the current scroll values. Then, in the part that is always executed, the copies are sent to the PPU. This means that while a frame is not completed, the PPU will keep using the old scroll values, until the frame is complete and they are updated with the new ones.

by on (#34232)
tokumaru wrote:
You can only get out of this loop [that changes the retrace count] when the value is different from when you first read it. The only problem is that you can't, for example, prevent your music code from lagging in frames where the game logic takes too long.

The music engine can store the current nmi_count, subtract the old nmi_count, and be able to reliably skip more than a second of missed vblanks. I'm pretty sure Pokemon Blue for GB uses this technique. But why is the game logic taking too long when games like Recca can run at 60 fps?

by on (#34234)
tepples wrote:
The music engine can store the current nmi_count, subtract the old nmi_count, and be able to reliably skip more than a second of missed vblanks.

That is one solution, true. I know I'm no sound guru, but wouldn't skipping sound worse than actually playing everything at a constant rate? I mean, there must be some perceptible distortion.

Quote:
I'm pretty sure Pokemon Blue for GB uses this technique. But why is the game logic taking too long when games like Recca can run at 60 fps?

Wow, it sure is hard to imagine a Pokemon game lagging... Maybe it happens when walking through the map and many character are walking around at once, I don't know.

by on (#34235)
tokumaru wrote:
tepples wrote:
The music engine can store the current nmi_count, subtract the old nmi_count, and be able to reliably skip more than a second of missed vblanks.

That is one solution, true. I know I'm no sound guru, but wouldn't skipping sound worse than actually playing everything at a constant rate? I mean, there must be some perceptible distortion.

Yes, it's perceptible, but just barely, like when a game slows from 60 fps to 30 fps and the game moves things twice as fast to keep up. When the audio update routine is delayed, all channels continue to play at their old pitch, timbre, and volume. Except for note-on or note-off events, most frames don't bring major changes to the PSG parameters.

Quote:
Quote:
I'm pretty sure Pokemon Blue for GB uses this technique. But why is the game logic taking too long when games like Recca can run at 60 fps?

Wow, it sure is hard to imagine a Pokemon game lagging... Maybe it happens when walking through the map and many character are walking around at once, I don't know.

Pokemon Blue lags mostly when it loads new CHR and maps into VRAM.

by on (#34239)
tokumaru wrote:
You can only get out of this loop [wait_nmi] when the value is different from when you first read it. The only problem is that you can't, for example, prevent your music code from lagging in frames where the game logic takes too long.

You can use a hybrid approach. Run the music engine off NMI, since it has very little communication with the game logic, thus making data synchronization easy (basically just "start music X" and "play sound effect Y" commands). If you had some mid-frame PPU operations, like split-screen for a status bar, that could also be done with NMI, since it involves little coordination with the game logic. This scheme still keeps things like sprites, tile updating, scroll position, etc. in the game thread, without the need for atomic updates.

by on (#34241)
blargg wrote:
You can use a hybrid approach. Run the music engine off NMI

You have to run graphics updates before everything else because they must fit in the roughly 2,270 cycles of vertical blanking. So if you move music to NMI, you have to move nametable, palette, and OAM updates to NMI too.

by on (#34245)
I would definitely run the music engine in the NMI, since like Blargg said, there is very little game logic involved. I really don't see any reason for the music not to be updated every frame.

Oh, and RPGs lagging might have something to do with RLE maps being decoded, since you can't mathematically predict where any tile is, you have to check every single byte in each row of the map to get to a specific tile. This can take thousands of cycles, especially when you have to update columns, in which case you have to decompress to one tile for 15 different rows, if you're using 2x2 metatiles, which many RPGs do. It's much easier/faster for games that compress maps into blocks to update, since you can calculate and not have to guess and check positions of tiles.