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.
where x is from 0 to 7.
|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.
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
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