Last modified on 26 November 2010, at 18:35

Super NES Programming/DMA tutorial

Direct memory access is a process whereby memory is dynamically copied to another location, independently of the CPU. In any modern computer, DMA is an essential requirement. Relating to the SNES, DMA can be used to quickly copy tile and palette data to the video RAM. Knowledge of DMA is a requirement for creating larger SNES programs, so this tutorial will cover just that.

DMA is used for copying graphics data, such as 8x8 tiles and tile maps, to the video RAM(VRAM), and palette data to the CGRAM. These locations can only be accessed by reading or writing to certain registers repeatedly. Note that while this could more easily be accomplished without using DMA, it would be several times slower.

When the DMA process is initialized, the CPU is halted until the DMA is complete. There are in total 8 DMA channels, but for the purposes of simply loading palette or graphics data, only one channel is necessary.

NOTE: This tutorial is incomplete and untested.

DMA registersEdit

where x is from 0 to 7.

size address description
Byte $420B DMA Control Register
Byte $43x0 DMA channel x control register
Byte $43x1 DMA channel x destination($21xx)
Word $43x2 DMA channel x source address offset(low)
Word $43x3 DMA channel x source address offset(high)
Byte $43x4 DMA channel x source address bank
Word $43x5 DMA channel x transfer size(low)
Word $43x6 DMA channel x transfer size(high)

NOTE: A DMA channel's transfer size, when set to #$0000, is read as a transfer of 65536 bytes, not 0 bytes.

some codeEdit

Loading PalettesEdit

Here is a macro for loading a palette data into the CGRAM(the place where palettes are stored):

;macro for loading palette data into the CGRAM
;only use if SIZE is less than 256 bytes
;syntax SetPalette LABEL CGRAM_ADDRESS SIZE
.macro SetPalette
pha
php

rep     #$20            ; 16bit A
lda     #\3
sta     $4305           ; # of bytes to be copied
lda     #\1             ; offset of data into 4302, 4303
sta     $4302
sep     #$20            ; 8bit A

lda     #:\1            ; bank address of data in memory(ROM)
sta     $4304   
lda     #\2
sta     $2121           ; address of CGRAM to start copying graphics to

stz     $4300           ; 0= 1 byte increment (not a word!)
lda     #$22
sta     $4301           ; destination 21xx   this is 2122 (CGRAM Gate)

lda     #$01            ; turn on bit 1 (corresponds to channel 0) of DMA channel reg.
sta     $420b           ;   to enable transfer

plp
pla
.endm

Loading VRAMEdit

Here is a macro for loading a data into the VRAM(the place where tiles and tile maps are stored):

;macro for loading graphics data into the VRAM
;only use if SIZE is less than 256 bytes
;syntax LoadVRAM LABEL  VRAM_ADDRESS  SIZE
.macro LoadVRAM
pha
phy
php

rep     #$20            ; 16bit A
sep     #$10            ; 8bit Y
ldy     #$80
sty     $2115           ; VRAM address increment value designation
lda     #\2
sta     $2116           ; address for VRAM write(or read)
lda     #\3
sta     $4305           ; number of bytes to be copied
sep     #$20            ; 8bit A
lda     #\1             
sta     $4302           ; data offset in memory

ldy     #:\1            ; bank address of data in memory
sty     $4304   
ldy     #$01
sty     $4300           ; 1= word increment
ldy     #$18
sty     $4301           ; 2118 is the VRAM gate

ldy     #$01            ; turn on bit 1 (channel 0) of DMA
sty     $420b
 
plp
ply
pla
.endm