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 registers

      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 code

      Loading Palettes

      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
      
      ↑Jump back a section

      Loading VRAM

      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
      
      ↑Jump back a section
      Last modified on 26 November 2010, at 18:35