Direct Memory Access

The GBA has four Direct Memory Access (DMA) units that can be utilized. They're mostly the same in terms of overall operation, but each unit has special rules that make it better suited to a particular task.

Please Note: TONC and GBATEK have slightly different concepts of how a DMA unit's registers should be viewed. I've chosen to go by what GBATEK uses.

General DMA

A single DMA unit is controlled through four different IO Registers.

  • Source: (DMAxSAD, read only) A *const pointer that the DMA reads from.
  • Destination: (DMAxDAD, read only) A *mut pointer that the DMA writes to.
  • Count: (DMAxCNT_L, read only) How many transfers to perform.
  • Control: (DMAxCNT_H, read/write) A register full of bit-flags that controls all sorts of details.

Here, the x is replaced with 0 through 3 when utilizing whichever particular DMA unit.

Source Address

This is either a u32 or u16 address depending on the unit's assigned transfer mode (see Control). The address MUST be aligned.

With DMA0 the source must be internal memory. With other DMA units the source can be any non-SRAM location.

Destination Address

As with the Source, this is either a u32 or u16 address depending on the unit's assigned transfer mode (see Control). The address MUST be aligned.

With DMA0/1/2 the destination must be internal memory. With DMA3 the destination can be any non-SRAM memory (allowing writes into Game Pak ROM / FlashROM, assuming that your Game Pak hardware supports that).

Count

This is a u16 that says how many transfers (u16 or u32) to make.

DMA0/1/2 will only actually accept a 14-bit value, while DMA3 will accept a full 16-bit value. A value of 0 instead acts as if you'd used the maximum value for the DMA in question. Put another way, DMA0/1/2 transfer 1 through 0x4000 words, with 0 as the 0x4000 value, and DMA3 transfers 1 through 0x1_0000 words, with 0 as the 0x1_0000 value.

The maximum value isn't a very harsh limit. Even in just u16 mode, 0x4000 transfers is 32k, which would for example be all 32k of IWRAM (including your own user stack). If you for some reason do need to transfer more than a single DMA use can move around at once then you can just setup the DMA a second time and keep going.

Control

This u16 bit-flag field is where things get wild.

  • Bits 0-4 do nothing
  • Bit 5-6 control how the destination address changes per transfer:
    • 0: Offset +1
    • 1: Offset -1
    • 2: No Change
    • 3: Offset +1 and reload when a Repeat starts (below)
  • Bit 7-8 similarly control how the source address changes per transfer:
    • 0: Offset +1
    • 1: Offset -1
    • 2: No Change
    • 3: Prohibited
  • Bit 9: enables Repeat mode.
  • Bit 10: Transfer u16 (false) or u32 (true) data.
  • Bit 11: "Game Pak DRQ" flag. GBATEK says that this is only allowed for DMA3, and also your Game Pak hardware must be equipped to use DRQ mode. I don't even know what DRQ mode is all about, and GBATEK doesn't say much either. If DRQ is set then you must not set the Repeat bit as well. The gba crate simply doesn't bother to expose this flag to users.
  • Bit 12-13: DMA Start:
    • 0: "Immediate", which is 2 cycles after requested.
    • 1: VBlank
    • 2: HBlank
    • 3: Special, depending on what DMA unit is involved:
      • DMA0: Prohibited.
      • DMA1/2: Sound FIFO (see the Sound section)
      • DMA3: Video Capture, intended for use with the Repeat flag, performs a transfer per scanline (similar to HBlank) starting at VCOUNT 2 and stopping at VCOUNT 162. Intended for copying things from ROM or camera into VRAM.
  • Bit 14: Interrupt upon DMA complete.
  • Bit 15: Enable this DMA unit.

DMA Life Cycle

The general technique for using a DMA unit involves first setting the relevent source, destination, and count registers, then setting the appropriate control register value with the Enable bit set.

Once the Enable flag is set the appropriate DMA unit will trigger at the assigned time (Bit 12-13). The CPU's operation is halted while any DMA unit is active, until the DMA completes its task. If more than one DMA unit is supposed to be active at once, then the DMA unit with the lower number will activate and complete before any others.

When the DMA triggers via Enable, the Source, Destination, and Count values are copied from the GBA's registers into the DMA unit's internal registers. Changes to the DMA unit's internal copy of the data don't affect the values in the GBA registers. Another Enable will read the same values as before.

If DMA is triggered via having Repeat active then only the Count is copied in to the DMA unit registers. The Source and Destination are unaffected during a Repeat. The exception to this is if the destination address control value (Bits 5-6) are set to 3 (0b11), in which case a Repeat will also re-copy the Destination as well as the Count.

Once a DMA operation completes, the Enable flag of its Control register will automatically be disabled, unless the Repeat flag is on, in which case the Enable flag is left active. You will have to manually disable it if you don't want the DMA to kick in again over and over at the specified starting time.

DMA Limitations

The DMA units cannot access SRAM at all.

If you're using HBlank to access any part of the memory that the display controller utilizes (OAM, PALRAM, VRAM), you need to have enabled the "HBlank Interval Free" bit in the Display Control Register (DISPCNT).

Whenever DMA is active the CPU is not active, which means that Interrupts will not fire while DMA is happening. This can cause any number of hard to track down bugs. Try to limit your use of the DMA units if you can.