Questions about Vblank, NMI, DMA

Discussion of hardware and software development for Super NES and Super Famicom. See the SNESdev wiki for more information.

Moderator: Moderators

Forum rules
  • For making cartridges of your Super NES games, see Reproduction.
Post Reply
Esns68
Posts: 31
Joined: Tue Jan 07, 2020 2:03 pm

Questions about Vblank, NMI, DMA

Post by Esns68 »

As I'm in the beginner stages of learning to program the SNES in assembly, I'm hearing a lot about the importance of Vblank, NMI, and DMA in rendering graphics, and I am trying to understand how this whole thing works.

I was mostly wondering, in what order do these things have to happen, and how do you keep things up throughout the program?
It seems like you just load the graphics first with functions that use DMA, turn on the screen, turn on NMI to trigger Vblank, something like this.
What would you have to do from then on next time you want to do something? Do you turn off NMI then just repeat this process? Repeat for each from
Basically, how are they all connected?

In project source codes I also see things like labels of Sprite init, video setup.
What would be the purpose of these things?
I see these things in projects from both Neviksti's Snes Starterkit, and Bazz's sprite tutorial, involved their own LoadGraphics.asm includes.

How do you know when your in Vblank or not? How long does a Vblank last? (This is assuming an NTSC system)
So I hear you have to be in Vblank to do anything graphicly. How do you make sure you do something during a Vblank?
Also do you "create" (or set) the Vblank to begin with?

About DMA. So I understand you write to certain bytes of the DMA channel, and I think you write to the last byte of the DMA channel after all that to, to start the DMA transfer. So just making sure, right after you do that, is the DMA transfer done?
Also, do you have to write to it again right after to turn it off?

How do you set NMI on and off? And do you basically just have to track of when it's on or off?

I swear I thought I had other questions about this, and more meaningful and specific ones.
I'll probably update in replies if they return to my mind, which will probably happen as I study this more.

But I generally what I'm trying to ask what is the general, basic process/order you do all these things, to load graphics to the screen?
I'm trying to understand this for future reference so I don't write things that conflict with NMI, Vblank and the display process.
I want to make sure to write everything the right way, and in the right order, both the data and NMI Vblank related processes.
Last edited by Esns68 on Sun Feb 07, 2021 3:24 am, edited 1 time in total.
User avatar
aa-dav
Posts: 220
Joined: Tue Apr 14, 2020 9:45 pm
Location: Russia

Re: Questions about Vblank, NMI,

Post by aa-dav »

First of all - CPU executes program instruction by instruction. But it can be interrupted in the process what is called 'interrupt' by external signal.
NES/SNES have two interrupts: maskable IRQ (CPU has instructions which enables or disables this) and non-maskable NMI (CPU cannot ignore this signal).
Then interrupt happens CPU saves flags register and current program counter to the stack and goes to the address of interrupt handler.
There are two addresses of IRQ handler and NMI handler in the end of the (first for SNES) 64Kb of CPU address space, so programmer can choose where interrupt handlers (both of them) resides.
Interrupt handler must save all other registers, do it's work, restore registers and execute RTI instruction (return from interrupt) which restores PC and flags from stack. So main program continues as if nothing happened.
So, PPU just emits interrupt to CPU then it enters VBlank, so CPU can react and feed PPU with new data.
DMA in SNES is complex thing and could be programmed to feed PPU with new data automatically even during VDraw (during HBlank). It complex subject.
Pokun
Posts: 2681
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: Questions about Vblank, NMI, DMA

Post by Pokun »

I feel it's necessary to understand a bit what vblank and hblank are. An NTSC TV is made to (by the PPU) draw the frame 60 times a second which is done by an electron gun line by line, from left to right, top to bottom. After finishing drawing a line it briefly turns off and goes back (called "tracing") to the left edge to draw the next line under it. Turning the electorn gun off is called blanking, and in this case horizontal blanking (hblank). Once it has drawn all lines on the TV it should be pointing at the bottom right it blanks again and traces back up to the top left part of the TV. This blanking is the vertical blanking (vblank).
The PPU is using the PPU memory (VRAM, OAM, CGRAM and certain PPU registers) when drawing the screen, and accessing them when doing this could cause problems and isn't allowed (if you try the screen will just turn black I think). But when the electron gun is blanking, the PPU memory is open for access by the CPU (you). This all means that you should never write to PPU memory when the TV is being drawn, only when blanking. You don't need to do anything to "set" vblank, the PPU is handling this.
Aside from hblank and vblank, there is also forced blanking which is a mode the PPU can be set to by setting bit 7 of $2100.

Vblank is a short period so you can't update the whole screen during this time. You use the vblank period to make general PPU updates, like updating the edge of screen for scrolling, sprite or palette updates. Hblank is even shorter period (as it happens between every single line) that can be used for advanced techniques like screen-splitting and other raster effect. You don't need to worry about hblank now. Forced blanking lasts until you turn it off (by clearing bit 7 of $2100), so you have unlimited time to do updates (but the screen will turn black during this time). You use this when you want to make large PPU updates, like drawing an entirely new screen. You are already using it in your init code for drawing the very first screen.

How do you know that the PPU/TV is in the vblank period? Like Aa-dav said, the NMI pin on the CPU is wired by Nintendo to the PPU which triggers it at the start of every vblank period. So to make sure your PPU updates happens within the vblank period, you just put all the PPU update codes at the beginning of the NMI handler. You also need to enable NMI's on the PPU side by setting bit 7 of $4200. Also as Aa-dav said, there is no need to enable NMIs on the CPU side as they are always enabled (that's the meaning of "Non-Maskable" in Non-Maskable Interrupt). You are probably already disabling NMIs on the PPU side in your init code and then enabling it at the end of the init code.


Program structure example:

Code: Select all

;Constant and variable definitions:
;...

RESET:  ;reset handler starts here
[init code here]
[code for drawing the first screen here]
  lda #%00001111
  sta $2100          ;turn off forced blanking, brightness max (15)
  lda #%10000000
  sta $4200          ;turn on NMI on PPU side
  
main:
[all program logic code here]
  loop main

NMIn:  ;NMI handler starts here
[all PPU updates here]
[anything else you want to happen each NMI here]
  rti

;Unused interrupt handlers:
IRQn:
COPn:
ABORTn:
COPe:
ABORTe:
NMIe:
IRQ_BRKe:
  rti

;Header:
[header here]

;Interrupt vectors:
;Native mode vectors (65816 mode):
  .byte $00,$00,$00,$00
  .word <>COPn          ;COP opcode interrupt, unused on Super Famicom/NES
  .word <>BRKn          ;BRK opcode interrupt
  .word <>ABORTn        ;unused on Super Famicom/NES
  .word <>NMIn          ;Vertical blanking interrupt
  .byte $00,$00         ;65816 mode has no RESET vector
  .word <>IRQn          ;H/V-Timer or external interrupt
  
;Emulation mode vectors (6502 mode):
  .byte $00,$00,$00,$00
  .word <>COPe          ;emulation mode version of COP
  .byte $00,$00         ;6502 mode has no separate BRK vector
  .word <>ABORTe        ;unused on Super Famicom/NES
  .word <>NMIe          ;NMI vector for 6502 mode
  .word <>RESET         ;CPU is always in 6502 mode on boot/reset
  .word <>IRQ_BRKe      ;emulation mode IRQ/BRK vector
The program starts at RESET when you turn on the SNES and it will run the init code. You will also need to upload all VRAM, OAM, CGRAM etc and draw your first screen here. After that you turn on the screen (by turning off forced blanking) and enable NMIs. Now it's important to keep all game logic in the main thread (which loops forever or until you turn off the SNES) and all PPU updates in the beginning of the NMI. Also you can't have too much PPU updates, or you will run out of vblank time before the NMI code is finished (this is why it's a good idea to buffer all PPU updates like I did with sprites in the other thread). If you keep logic and PPU updates cleanly separate like this, you should have enough time to DMA all sprites, do some palette updates and part of the background for scrolling though, so it's not that short of a period.

Again this is 64tass syntax. The <> are needed in this assembler for 16-bit addresses but not in WLA-DX. Also WLA-DX optionally has directives for setting up the header and interrupt vectors automatically for you. In this example I set them up manually using .byte and .word directives. You can ignore that part if you want, as long as you understand where they go.


As for DMA you better check examples in the superfamicon.org wiki (also check my OAM-DMA example in the other thread). Basically there are registers for setting the source address, destination address, data length (how many byte you want to copy) and increment mode for the DMA.
The CPU can't execute any instructions while DMA is running (because the DMA is a hardware part of the CPU) so you don't have to worry about knowing when it's done, you can't do anything anyway. DMA is much faster than manually copying data with the LDA and STA instructions or even the block copy instructions MVN and MVP, so this isn't wasted time or anything. The reason there are more than one DMA channel has to do with HDMA which you don't have to worry about now.
User avatar
dougeff
Posts: 3079
Joined: Fri May 08, 2015 7:17 pm

Re: Questions about Vblank, NMI, DMA

Post by dougeff »

viewtopic.php?t=18643#p236624

And according to this, you can transfer between 5000 and 6000 bytes to the PPU during an NTSC v-blank in 224 pixel high mode (with a DMA).

http://forums.nesdev.com/viewtopic.php? ... 72#p215654
nesdoug.com -- blog/tutorial on programming for the NES
Oziphantom
Posts: 1565
Joined: Tue Feb 07, 2017 2:03 am

Re: Questions about Vblank, NMI, DMA

Post by Oziphantom »

Esns68 wrote: Sun Feb 07, 2021 2:55 am As I'm in the beginner stages of learning to program the SNES in assembly, I'm hearing a lot about the importance of Vblank, NMI, and DMA in rendering graphics, and I am trying to understand how this whole thing works.

I was mostly wondering, in what order do these things have to happen, and how do you keep things up throughout the program?
Hard to know what things you keep up, but programmer skill usually ;)
It seems like you just load the graphics first with functions that use DMA, turn on the screen, turn on NMI to trigger Vblank, something like this.
well people tend to get annoyed or think it is broken if all they see is a black screen, so its best to put something on it as soon as you can.
What would you have to do from then on next time you want to do something? Do you turn off NMI then just repeat this process? Repeat for each from
Basically, how are they all connected?
There is the graphics chip, it is the master it rules the roost as you are now its slave. the CPU and you will dance to its beat, it will not stop, it will not slow, it will not pause the raster marches at constant pace and you are now its slave.
So every 1/60th of a second, VBlank will happen and it will happen for 38 scan lines.
If you have NMI on VBlank enabled then you will get an NMI on the first cycle of the first line of VBlank. IF you don't you get nothing.

DMA is the entire other system over here that has nothing to do with the other things in anyway at all.
You are free to DMA when ever you want. However the PPU only permits you to access any of its RAM (VRAM, CGRAM, OAM etc ) during a Blank period, of which VBlank is basically the only real access point.
DMA has nothing to do with graphics at all its just the fastest way to move bytes from one place to another, and basically those places can be anywhere in the system.
In project source codes I also see things like labels of Sprite init, video setup.
What would be the purpose of these things?
I see these things in projects from both Neviksti's Snes Starterkit, and Bazz's sprite tutorial, involved their own LoadGraphics.asm includes.
Well Sprite Init will Initlilize the Sprites to a default state, i.e all off screen, small size and showing tile 0 with pallete 0. If you don't do this you could end up with random sprites showing on the screen. The contents of RAM at power up is Random and depends on how much the sun flared 8seconds ago. So you need to set it to a known value or unexpected things will happen.
Video setup, like wise the register state of the SNES is not fixed and will have random bits set or cleared, and then if you have hit reset and not power on it will have the old state mostly. So again there is a InitVideo or InitSNES step that will set all the registers to a known "turn everything off" state. InitVideo may setup and enable a particular video mode with maps and tiles and palletes set at particular addresses as the programmer wants them to be.
How do you know when your in Vblank or not?
because you just got an NMI or you read the state of bit7 of $4212
How long does a Vblank last? (This is assuming an NTSC system)
38 scan lines which gives you 50,312 Master Clocks, to which then how many fast/slow/xslow cycle clocks you get depends on your code and what you do when.
So I hear you have to be in Vblank to do anything graphicly. How do you make sure you do something during a Vblank?
You can modify any PPU register at any time, although it is not wise to do so for most of them. But to access any of the RAMs must be during VBlank.
Also do you "create" (or set) the Vblank to begin with?
You don't the PPU controls it. Although you can turn the screen off, which is then "all blank" or "Forced Blank".
About DMA. So I understand you write to certain bytes of the DMA channel, and I think you write to the last byte of the DMA channel after all that to, to start the DMA transfer. So just making sure, right after you do that, is the DMA transfer done?
Also, do you have to write to it again right after to turn it off?
DMA takes place instead of the CPU, not along side the CPU, while DMA is happening the CPU will be stalled. So
Enable DMA
CPU is stalled and .. DMA starts..
..DMA Ends..
Control is returned to the CPU
You do not need to turn off the DMA it will stop itself once it has complete and it will return control back to the CPU which will continue where it left off.
How do you set NMI on and off? And do you basically just have to track of when it's on or off?
You don't control a Non Maskable Interrupt. But you can stop them from being generated by clearing bit 7 of $4200, or enable to be triggered by setting it. You must also then read $4210 to clear the flag so it can trigger next time.
I swear I thought I had other questions about this, and more meaningful and specific ones.
I'll probably update in replies if they return to my mind, which will probably happen as I study this more.

But I generally what I'm trying to ask what is the general, basic process/order you do all these things, to load graphics to the screen?
I'm trying to understand this for future reference so I don't write things that conflict with NMI, Vblank and the display process.
I want to make sure to write everything the right way, and in the right order, both the data and NMI Vblank related processes.
There is no right way, there is no standard there is just a bare metal machine and however you structure things is how they are structured. But you will want most dealings with the PPU in a NMI handler that happens on VBlank and then you put your game logic in the main thread. If you have an NMI handler and a Main thread is, well depends on the project and the needs. For example Mario and Zelda on the NES just have the NMI thread and no main. But then other games will have NMI, IRQ and Main threads.

You would be well advised to look up all of koitsu's posts and read them. Surprised he has popped up here or in the GameJam posts, anybody heard from him? Is he ok, my vague understanding of where he is puts him in a major danger zone of the US.
Last edited by Oziphantom on Tue Feb 09, 2021 12:12 am, edited 1 time in total.
93143
Posts: 1717
Joined: Fri Jul 04, 2014 9:31 pm

Re: Questions about Vblank, NMI, DMA

Post by 93143 »

Oziphantom wrote: Mon Feb 08, 2021 10:44 pmThere is the graphics chip, it is the master it rules the roost as you are now its slave. the CPU and you will dance to its beat, it will not stop, it will not slow, it will not pause the raster marches at constant pace and you are now its slave.
Well said. Understanding the PPU's operation and how the whole scheme works in terms of the steady march of dots, scanlines and frames adds a lot of structure to thinking about the SNES.
to access any of the RAMs must be during VBlank.
You can access CGRAM safely during HBlank. Of course, HBlank is far too short to update the whole thing, so this is mostly useful for raster effects. I believe VRAM will ignore writes outside VBlank or forced blank, and OAM I think puts the write wherever the PPU last looked, which is not generally where you want it.
You must also then read 4201 to clear the flag so it can trigger next time.
Don't you mean $4210?

Same goes for the IRQ handler, but it's $4211.
creaothceann
Posts: 611
Joined: Mon Jan 23, 2006 7:47 am
Location: Germany
Contact:

Re: Questions about Vblank, NMI, DMA

Post by creaothceann »

This is explained in video form here: https://www.youtube.com/playlist?list=P ... _lvGwfn6GV
My current setup:
Super Famicom ("2/1/3" SNS-CPU-GPM-02) → SCART → OSSC → StarTech USB3HDCAP → AmaRecTV 3.10
Oziphantom
Posts: 1565
Joined: Tue Feb 07, 2017 2:03 am

Re: Questions about Vblank, NMI, DMA

Post by Oziphantom »

93143 wrote: Mon Feb 08, 2021 11:34 pm
Oziphantom wrote: Mon Feb 08, 2021 10:44 pmThere is the graphics chip, it is the master it rules the roost as you are now its slave. the CPU and you will dance to its beat, it will not stop, it will not slow, it will not pause the raster marches at constant pace and you are now its slave.
Well said. Understanding the PPU's operation and how the whole scheme works in terms of the steady march of dots, scanlines and frames adds a lot of structure to thinking about the SNES.
to access any of the RAMs must be during VBlank.
You can access CGRAM safely during HBlank. Of course, HBlank is far too short to update the whole thing, so this is mostly useful for raster effects. I believe VRAM will ignore writes outside VBlank or forced blank, and OAM I think puts the write wherever the PPU last looked, which is not generally where you want it.
He doesn't understand how the AND opcode works, I think its best not to confuse the issue with * cases ;)
You must also then read 4201 to clear the flag so it can trigger next time.
Don't you mean $4210?

Same goes for the IRQ handler, but it's $4211.
I did, good catch, I will update the original.
Post Reply