DMA registers: Difference between revisions

From SNESdev Wiki
Jump to navigationJump to search
(Add register names to some bit diagrams)
(Some clarity improvements. (Using n with a range instead of x for registers to make it clear there are 8 unique registers of each type, not 16 and not with any mirroring. Using x for readable unused bit and specifying it's unused, not open bus. Trying to make even more clear that the multi-address unused byte is just one byte at both addresses. Improving the pattern table.))
Line 52: Line 52:


==DMA channel registers==
==DMA channel registers==
=== DMAPx - DMA/HDMA parameters ($43x0 read/write) ===
=== DMAPn - DMA/HDMA parameters ($43n0 read/write) (n = 0..7) ===
----
----


  7  bit  0
  7  bit  0
  ---- ----
  ---- ----
  DI.F FPPP
  DIxA APPP
  |||| ||||
  |||| ||||
  || | |+++- Pattern
  |||| |+++- Transfer pattern (see below)
  || +-+---- 0:  Increment A bus address after copy
  |||+-+---- Address adjust mode (DMA only):
  ||        1/3: Fixed
|||        0:  Increment A bus address after copy
  ||        2:  Decrement A bus address after copy
  |||        1/3: Fixed
  ||         (These two bits affect DMA only, not HDMA)
  |||        2:  Decrement A bus address after copy
  ||+------- Unused
  |+-------- Indirect (HDMA only)
  |+-------- Indirect (HDMA only)
  +--------- Direction: 0=Copy from A to B, 1=Copy from B to A
  +--------- Direction: 0=Copy from A to B, 1=Copy from B to A


The "pattern" affects how many bytes are transferred each scanline in HDMA. For DMA, it allows copying to VRAM, which requires writing to two alternating addresses.
The "transfer pattern" affects how many bytes are transferred each scanline in HDMA. For DMA, it allows copying to VRAM, which requires writing to two alternating addresses.


{| class="wikitable"
{| class="wikitable"
|+ DMA patterns
|+ DMA transfer patterns
|-
|-
! Number !! Number of bytes !! B Bus address !! Usage example
! Pattern !! Number of bytes !! B Bus address !! Usage example
|-
|-
| 0 || 1 || xx || WRAM, Mode 7 graphics/tilemap
| 0 || 1 || xx+0 || WRAM, Mode 7 graphics/tilemap
|-
|-
| 1 || 2 || xx xx+1 || VRAM
| 1 || 2 || xx+0 xx+1 || VRAM
|-
|-
| 2 || 2 || xx xx || OAM, CGRAM
| 2 || 2 || xx+0 xx+0 || OAM, CGRAM
|-
|-
| 3 || 4 || xx xx xx+1 xx+1 || Scroll positions, Mode 7 parameters
| 3 || 4 || xx+0 xx+0 xx+1 xx+1 || Scroll positions, Mode 7 parameters
|-
|-
| 4 || 4 || xx xx+1 xx+2 xx+3 || Window  
| 4 || 4 || xx+0 xx+1 xx+2 xx+3 || Window  
|-
|-
| 5 || 4 || xx xx+1 xx xx+1 ||
| 5 || 4 || xx+0 xx+1 xx+0 xx+1 ||
|-
|-
| 6 || 2 || xx xx || Same as 2
| 6 || 2 || xx+0 xx+0 || Same as 2
|-
|-
| 7 || 4 || xx xx+1 xx xx+1 || Same as 3
| 7 || 4 || xx+0 xx+1 xx+0 xx+1 || Same as 3
|}
|}


=== BBADx - B-bus address ($43x1 read/write) ===
=== BBADn - B-bus address ($43n1 read/write) (n = 0..7) ===
----
----


Line 100: Line 101:
  ++++-++++- Selects a hardware register to read or write from, in the $2100-$21ff range
  ++++-++++- Selects a hardware register to read or write from, in the $2100-$21ff range


=== UNUSEDx - Unused byte ($43xB and 43xF read/write) ===
=== UNUSEDn - Unused byte ($43nB and $43nF read/write) (n = 0..7) ===
----
----


Line 107: Line 108:
  NNNN NNNN
  NNNN NNNN
  |||| ||||
  |||| ||||
  ++++-++++- Unused byte available at two different addresses
  ++++-++++- One unused byte available through two different addresses


Seems to have no effect on DMA or HDMA, and this register cannot be used as a source for a DMA fill.
Seems to have no effect on DMA or HDMA, and this register cannot be used as a source for a DMA fill.
Line 113: Line 114:
==Configuration registers (DMA) ==
==Configuration registers (DMA) ==


=== A1TxL, A1TxH, DMA Current Address ($43x2, $43x3 read/write) ===
=== A1TnL, A1TnH - DMA Current Address ($43n2, $43n3 read/write) (n = 0..7) ===
----
----
   A1TxH       A1TxL
   A1TnH       A1TnL
   $43x3       $43x2
   $43n3       $43n2
  7  bit  0  7  bit  0
  7  bit  0  7  bit  0
  ---- ----  ---- ----
  ---- ----  ---- ----
Line 125: Line 126:
These registers change as the DMA happens.
These registers change as the DMA happens.


=== A1Bx -  DMA Current Address (bank) ($43x4 read/write) ===
=== A1Bn -  DMA Current Address (bank) ($43n4 read/write) (n = 0..7) ===
----
----


Line 136: Line 137:
This register does not change during DMA. DMA can not cross banks.
This register does not change during DMA. DMA can not cross banks.


=== DASxL, DASxH - DMA Byte-Counter ($43x5, $43x6 read/write) ===
=== DASnL, DASnH - DMA Byte-Counter ($43n5, $43n6 read/write) (n = 0..7) ===
----
----


   DASxH       DASxL
   DASnH       DASnL
   $43x6       $43x5
   $43n6       $43n5
  7  bit  0  7  bit  0
  7  bit  0  7  bit  0
  ---- ----  ---- ----
  ---- ----  ---- ----
Line 156: Line 157:
== Configuration registers (HDMA) ==
== Configuration registers (HDMA) ==


=== A1TxL, A1TxH, A1Bx - HDMA Table Start Address ($43x2, $43x3, $43x4 read/write) ===
=== A1TnL, A1TnH, A1Bn - HDMA Table Start Address ($43n2, $43n3, $43n4 read/write) (n = 0..7) ===


   A1Bx       A1TxH       A1TxL
   A1Bn       A1TnH       A1TnL
   $43x4       $43x3       $43x2
   $43n4       $43n3       $43n2
  7  bit  0  7  bit  0  7  bit  0
  7  bit  0  7  bit  0  7  bit  0
  ---- ----  ---- ----  ---- ----
  ---- ----  ---- ----  ---- ----
Line 166: Line 167:
  ++++-++++---++++-++++---++++-++++- 24-bit little-endian address on the A bus
  ++++-++++---++++-++++---++++-++++- 24-bit little-endian address on the A bus


These registers control where the channel's HDMA table is. This address gets copied into $43x8 and $43x9 every frame.
These registers control where the channel's HDMA table is. This address gets copied into $43n8 and $43n9 every frame.


== Other HDMA registers ==
== Other HDMA registers ==
These keep track of each channel's state as HDMA is happening.
These keep track of each channel's state as HDMA is happening.


=== DASxL, DASxH - Indirect HDMA Address ($43x5, $43x6 read/write) ===
=== DASnL, DASnH - Indirect HDMA Address ($43n5, $43n6 read/write) (n = 0..7) ===
----
----


   DASxH       DASxL
   DASnH       DASnL
   $43x6       $43x5
   $43n6       $43n5
  7  bit  0  7  bit  0
  7  bit  0  7  bit  0
  ---- ----  ---- ----
  ---- ----  ---- ----
Line 184: Line 185:
With indirect HDMA, if the repeat bit is set in the table entry, then the SNES will continue to read increasing addresses starting from the one given in the table, using these registers to keep track of where it currently is.
With indirect HDMA, if the repeat bit is set in the table entry, then the SNES will continue to read increasing addresses starting from the one given in the table, using these registers to keep track of where it currently is.


=== DASBx - Indirect HDMA Address (bank) ($43x7 read/write) ===
=== DASBn - Indirect HDMA Address (bank) ($43n7 read/write) (n = 0..7) ===
----
----
  7  bit  0
  7  bit  0
Line 194: Line 195:
This register must be set manually by the program.
This register must be set manually by the program.


=== A2AxL, A2AxH - HDMA Table Current Address ($43x8, $43x9 read/write) ===
=== A2AnL, A2AnH - HDMA Table Current Address ($43n8, $43n9 read/write) (n = 0..7) ===
----
----


   A2AxH       A2AxL
   A2AnH       A2AnL
   $43x9       $43x8
   $43n9       $43n8
  7  bit  0  7  bit  0
  7  bit  0  7  bit  0
  ---- ----  ---- ----
  ---- ----  ---- ----
Line 205: Line 206:
  ++++-++++---++++-++++- Low 16 bits of the current address within the HDMA table
  ++++-++++---++++-++++- Low 16 bits of the current address within the HDMA table


Bank byte is taken from $43x4 as it does not change.
Bank byte is taken from $43n4, as it does not change.


=== NTRLx - HDMA Line-Counter ($43xA read/write) ===
=== NTRLn - HDMA Line-Counter ($43nA read/write) (n = 0..7) ===
----
----
  7  bit  0
  7  bit  0
Line 213: Line 214:
  RLLL LLLL
  RLLL LLLL
  |||| ||||
  |||| ||||
  |+++-++++- Number of scanlines left  
  |+++-++++- Number of scanlines left
  +--------- Repeat flag
  +--------- Repeat flag


Line 228: Line 229:
  N bytes - Data
  N bytes - Data


The number of bytes in each Data section is determined by the pattern chosen for the channel in register $43x0.
The number of bytes in each Data section is determined by the pattern chosen for the channel in register $43n0.


* If repeat mode is off, one pattern's worth of bytes are written, then the SNES waits for the specified number of scanlines before continuing onto the next table entry.
* If repeat mode is off, one pattern's worth of bytes are written, then the SNES waits for the specified number of scanlines before continuing onto the next table entry.

Revision as of 17:25, 13 May 2022

The SNES's DMA (Direct Memory Access) unit allows a game to copy graphics, palettes, OAM and more at a much higher speed than the CPU can accomplish alone. This allows a game to make better use of the limited amount of time it has in vblank to change graphical memory.

The SNES has two address buses - consisting of the A bus (which contains cartridge ROM, cartridge RAM, and the SNES's RAM) and the B bus (anything in the $2100-$21ff range, including PPU registers and APU registers). DMA always involves copying something from one of these two buses to something on the other bus.

DMA cannot copy from one area of the SNES's RAM to another, even if RAM is specified as both the source and destination. For that, the MVN and MVP instructions are probably the best available choice.

The SNES also features HDMA which runs in the background and can be set up to automatically write values to hardware registers at specific scanlines, allowing for effects.

These registers are always accessed at 3.58 MHz! That means that any channels that are not currently in use can have their registers repurposed for a small amount of fast RAM.

DMA channels

The SNES contains 8 separate DMA "channels" - each one contains a set of parameters to configure a DMA transfers. They are configured with registers in the $4300-$437f range, where the first 16 addresses correspond to the first register, the second 16 addresses correspond to the next, and so on.

MDMAEN - Start DMA transfer ($420B write)


7  bit  0
---- ----
7654 3210
|||| ||||
|||| |||+- Channel 0 select
|||| ||+-- Channel 1 select
|||| |+--- Channel 2 select
|||| +---- Channel 3 select
|||+------ Channel 4 select
||+------- Channel 5 select
|+-------- Channel 6 select
+--------- Channel 7 select

Upon writing to this register, a DMA transfer is started for each bit that was set, starting with the lowest selected channel number up toward the highest. The CPU is stopped until all transfers have completed. If an HDMA transfer happens while the DMA transfer is going, the DMA transfer will be temporarily paused to allow the HDMA transfer to happen.

HDMAEN - Enable HDMA transfers ($420C write)


7  bit  0
---- ----
7654 3210
|||| ||||
|||| |||+- Channel 0 HDMA enable
|||| ||+-- Channel 1 HDMA enable
|||| |+--- Channel 2 HDMA enable
|||| +---- Channel 3 HDMA enable
|||+------ Channel 4 HDMA enable
||+------- Channel 5 HDMA enable
|+-------- Channel 6 HDMA enable
+--------- Channel 7 HDMA enable

This register enables HDMA for the selected channels.

DMA channel registers

DMAPn - DMA/HDMA parameters ($43n0 read/write) (n = 0..7)


7  bit  0
---- ----
DIxA APPP
|||| ||||
|||| |+++- Transfer pattern (see below)
|||+-+---- Address adjust mode (DMA only):
|||         0:   Increment A bus address after copy
|||         1/3: Fixed
|||         2:   Decrement A bus address after copy
||+------- Unused
|+-------- Indirect (HDMA only)
+--------- Direction: 0=Copy from A to B, 1=Copy from B to A

The "transfer pattern" affects how many bytes are transferred each scanline in HDMA. For DMA, it allows copying to VRAM, which requires writing to two alternating addresses.

DMA transfer patterns
Pattern Number of bytes B Bus address Usage example
0 1 xx+0 WRAM, Mode 7 graphics/tilemap
1 2 xx+0 xx+1 VRAM
2 2 xx+0 xx+0 OAM, CGRAM
3 4 xx+0 xx+0 xx+1 xx+1 Scroll positions, Mode 7 parameters
4 4 xx+0 xx+1 xx+2 xx+3 Window
5 4 xx+0 xx+1 xx+0 xx+1
6 2 xx+0 xx+0 Same as 2
7 4 xx+0 xx+1 xx+0 xx+1 Same as 3

BBADn - B-bus address ($43n1 read/write) (n = 0..7)


7  bit  0
---- ----
AAAA AAAA
|||| ||||
++++-++++- Selects a hardware register to read or write from, in the $2100-$21ff range

UNUSEDn - Unused byte ($43nB and $43nF read/write) (n = 0..7)


7  bit  0
---- ----
NNNN NNNN
|||| ||||
++++-++++- One unused byte available through two different addresses

Seems to have no effect on DMA or HDMA, and this register cannot be used as a source for a DMA fill.

Configuration registers (DMA)

A1TnL, A1TnH - DMA Current Address ($43n2, $43n3 read/write) (n = 0..7)


  A1TnH       A1TnL
  $43n3       $43n2
7  bit  0   7  bit  0
---- ----   ---- ----
HHHH HHHH   LLLL LLLL
|||| ||||   |||| ||||
++++-++++---++++-++++- Low 16 bits of the address on the A bus

These registers change as the DMA happens.

A1Bn - DMA Current Address (bank) ($43n4 read/write) (n = 0..7)


7  bit  0
---- ----
BBBB BBBB
|||| ||||
++++-++++- Bank byte for the A bus address

This register does not change during DMA. DMA can not cross banks.

DASnL, DASnH - DMA Byte-Counter ($43n5, $43n6 read/write) (n = 0..7)


  DASnH       DASnL
  $43n6       $43n5
7  bit  0   7  bit  0
---- ----   ---- ----
HHHH HHHH   LLLL LLLL
|||| ||||   |||| ||||
++++-++++---++++-++++- 16-bit number that indicates how many bytes to transfer

A byte count of zero means 65536 bytes.

This byte count is not affected by the DMA pattern. The SNES will stop before a pattern is completed if it runs out of bytes.

Once the DMA finishes, these registers will be zero.

Configuration registers (HDMA)

A1TnL, A1TnH, A1Bn - HDMA Table Start Address ($43n2, $43n3, $43n4 read/write) (n = 0..7)

  A1Bn        A1TnH       A1TnL
  $43n4       $43n3       $43n2
7  bit  0   7  bit  0   7  bit  0
---- ----   ---- ----   ---- ----
BBBB BBBB   HHHH HHHH   LLLL LLLL
|||| ||||   |||| ||||   |||| ||||
++++-++++---++++-++++---++++-++++- 24-bit little-endian address on the A bus

These registers control where the channel's HDMA table is. This address gets copied into $43n8 and $43n9 every frame.

Other HDMA registers

These keep track of each channel's state as HDMA is happening.

DASnL, DASnH - Indirect HDMA Address ($43n5, $43n6 read/write) (n = 0..7)


  DASnH       DASnL
  $43n6       $43n5
7  bit  0   7  bit  0
---- ----   ---- ----
HHHH HHHH   LLLL LLLL
|||| ||||   |||| ||||
++++-++++---++++-++++- Low 16 bits of the current indirect DMA address.

With indirect HDMA, if the repeat bit is set in the table entry, then the SNES will continue to read increasing addresses starting from the one given in the table, using these registers to keep track of where it currently is.

DASBn - Indirect HDMA Address (bank) ($43n7 read/write) (n = 0..7)


7  bit  0
---- ----
BBBB BBBB
|||| ||||
++++-++++- Bank number used for all indirect DMA addresses on this channel

This register must be set manually by the program.

A2AnL, A2AnH - HDMA Table Current Address ($43n8, $43n9 read/write) (n = 0..7)


  A2AnH       A2AnL
  $43n9       $43n8
7  bit  0   7  bit  0
---- ----   ---- ----
HHHH HHHH   LLLL LLLL
|||| ||||   |||| ||||
++++-++++---++++-++++- Low 16 bits of the current address within the HDMA table

Bank byte is taken from $43n4, as it does not change.

NTRLn - HDMA Line-Counter ($43nA read/write) (n = 0..7)


7  bit  0
---- ----
RLLL LLLL
|||| ||||
|+++-++++- Number of scanlines left
+--------- Repeat flag

Automatically loaded from the table. Scanline count is decremented every scanline until it hits zero.

HDMA table format

HDMA tables specify what values to write to the selected B bus register, as well as which scanlines to write the values on. The tables can either directly contain the values (Direct mode) or specify 16-bit pointers that are then used to get the values (Indirect mode).

Direct HDMA table entries


1 byte - Line count, and repeat mode
N bytes - Data

The number of bytes in each Data section is determined by the pattern chosen for the channel in register $43n0.

  • If repeat mode is off, one pattern's worth of bytes are written, then the SNES waits for the specified number of scanlines before continuing onto the next table entry.
  • If repeat mode is on, then the total size of the data section is the number of scanlines multiplied by the number of bytes in the pattern. One pattern's worth of bytes are written for however many scanlines indicated in the table.

Indirect HDMA table entries


1 byte - Line count, and repeat mode
2 bytes - Pointer to access the data through
  • If repeat mode is off, one pattern's worth of bytes are written from an address starting from the pointer given.
  • If repeat mode is on, the SNES continues to progress through the bytes that the pointer points to, for however many scanlines are indicated in the table.

Line count, repeat mode byte


Possible values for the "Line count, and repeat mode" byte are as follows:

  • $00: Stop processing HDMA on that channel for the rest of the frame.
  • $01-$80: Write once, then wait for X-1 scanlines
  • $81-$FF: Write every scanline for X-$80 scanlines, repeat mode