ダイレクトメモリアクセス(DMA)は、CPUを介さずにデータを高速に転送する方法です。データのコピー(転送)だけでなく、メモリ埋め(Fill)にも使用できます。
DMAを有効にすると、転送時にはCPUが一時停止して、DMAコントローラが必要な転送を行い、転送が終わるとCPUが動作を再開します。
GBAには4つのDMAチャンネルがあり、優先度は DMA0 > DMA1 > DMA2 > DMA3
となっています。優先度の低いDMAチャンネルは、優先度の高いチャンネルがアクティブな時は一時停止します。
DMA転送がアクティブなときはCPUは一時停止しますが、Sound/Blanking DMA転送
が一時停止している間はCPUは動作しています。
DMA0: (優先度が最も高いため) HBlank期間内のデータ転送(HBlank DMA)など、時間にシビアな転送をしたいときに向いている
DMA1, 2: サウンド再生時のFIFOにデータを転送するとき。内部メモリ・外部メモリから内部メモリへの転送が可能。
DMA3: (後述のDADの指定可能範囲が広いため)唯一、Game Pak ROM/FlashROMに書き込みをするができる(SRAMは除く)
加えて、全部のDMAチャンネルは汎用的なデータ転送用途にも使うことができます。(DMA3がよく使われる印象です)
DMA転送で転送するデータが始まるアドレスを指定します。
0x0400_00B0: DMA0SAD - DMA0ソースレジスタ (内部メモリのみ)
0x0400_00BC: DMA1SAD - DMA1ソースレジスタ
0x0400_00C8: DMA2SAD - DMA2ソースレジスタ
0x0400_00D4: DMA3SAD - DMA3ソースレジスタ
DMA0の場合は0x07FF_FFFF
(内部メモリのみ)まで、DMA1,DMA2,DMA3の場合は0x0FFF_FFFF
まで指定することが可能です。
DMA転送でデータ転送先のアドレスを指定します。
0x0400_00B4: DMA0DAD - DMA0ターゲットレジスタ (内部メモリのみ)
0x0400_00C0: DMA1DAD - DMA1ターゲットレジスタ (内部メモリのみ)
0x0400_00CC: DMA2DAD - DMA2ターゲットレジスタ (内部メモリのみ)
0x0400_00D8: DMA3DAD - DMA3ターゲットレジスタ
DMA0, DMA1, DMA2の場合は0x07FF_FFFF
まで、DMA3の場合は0x0FFF_FFFF
まで指定することが可能です。
0x0400_00B8: DMA0CNT
0x0400_00C4: DMA1CNT
0x0400_00D0: DMA2CNT
0x0400_00DC: DMA3CNT
DMAnCNT.0-15
は DMAnCNT_L
、DMAnCNT.16-31
は DMAnCNT_H
と呼ぶ場合もあります。
Bit
0-15 W 転送サイズ(bit26で指定するワードの数)
DMA0,1,2 は bit0-13 のみが使用(つまりbit14-15は無視される)
0にすると 0x4000ワード (DMA3は 0x10000ワード)
16-20 - 未使用
21-22 R/W ターゲットアドレス制御; (0: +1, 1: -1, 2: ±0, 3: +1/Reload)
23-24 R/W ソースアドレス制御; (0: +1, 1: -1, 2: ±0, 3: 指定禁止(指定した場合は、+1?))
25 R/W DMAリピート
0b0: 転送終了後、DMA有効フラグ(bit31)をクリア
0b1: 転送終了後もDMA有効フラグはセットされたままで、転送開始タイミング(例:HBlank)になるたびに転送が再開 (毎回ワードカウントレジスタで指定された分のデータを転送しゲーム側で停止するまで永遠に繰り返す)
26 R/W ワードサイズ(0=16bit, 1=32bit)
27 R/W Game Pak DRQ(DMA3のみ); 0=Normal, 1=DRQ from Game Pak, DMA3
28-29 R/W モード (0: 即座に, 1: VBlankDMA(VBlank開始時), 2: HBlankDMA(HBlank開始時), 3: チャンネル固有)
CH0: 使用禁止
CH1,2: サウンドFIFO
CH3: ビデオキャプチャ
30 R/W 転送終了時にIRQを発生させるかどうか
31 R/W このDMAチャンネルが有効かどうか
転送が完了、つまり転送サイズ分の転送を完了すると自動的にクリア(bit25が0なら)
このbitを手動でクリアすることで転送を停止させることも可能
DMA有効フラグ(bit15)を0から1に変更した後、DMA関連レジスタにアクセスする前に2クロックサイクル待つ必要があります。
モード2(HBlankDMA)でOAM(0x0700_0000
)やOBJ VRAM(0x0601_0000
)にアクセスする場合は、DISPCNTレジスタの "H-Blank Interval Free"ビットをセットする必要があります。
ソースレジスタ、ターゲットレジスタ、ワードカウントレジスタは初期開始アドレスと初期長を保持しています。ハードウェアは転送中または転送後にこれらのレジスタの内容を変更することはありません。
実際の転送は、プログラムからは触れない、内部ポインタと内部カウンタレジスタを使用して行われます。初期値は次の2つの場合に内部レジスタにコピーされます
DMAnCNT.31
を0から1に変更したとき: SAD, DAD, CNT_L がリロードされます。- DMAリピート時: CNT_Lがリロードされます。DADは
Increment/Reload
のときにリロードされます。
サウンド再生用のFIFOへのDMA転送のことをサウンドDMAと呼びます。
サウンドDMAを行う場合は上述のリピートビットをONにし、転送先アドレスをFIFO_A(0x0400_00a0
)またはFIFO_B(0x0400_00a4
)に設定する必要があります。
サウンドコントローラからのDMA要求により、32bitを4回(合計16バイト)転送します。 このとき、ワードカウントレジスタとDMA転送タイプビット(CNT_H.10
)は無視されます。サウンドDMAでは転送先アドレスはインクリメントされません。
DMA0のような、サウンドDMAより優先度の高いDMAチャンネルの動作中は、サウンドDMAが一時停止されることに注意してください。例えば、サウンドのサンプルレートが64kHzの場合、16バイトのサウンドDMAデータが 0.25ms(4kHz)ごとに要求されます。よって0.25ms経過するまでに次の16バイトをサウンドDMAでFIFOに転送する必要があります。 つまり、サウンドDMAより優先度の高いDMA転送は、0.25ms以内に終わるのが望ましいです。とはいえ、HBlankの時間は16.212usに制限されているため、DMA0をHBlank時のデータ転送として使う限り問題にはなりません。
Warning 信頼性低
DMA3 のみが Game Pak ROM または Flash ROM との間のデータ転送に使用されます。1
通常モードでは、ワードカウントが0になるまでDMAがリクエストされます。
Game Pack DRQビットを設定する場合、カートリッジには/DREQ信号を出力する外部回路が必要です。
DREQと/IREQのピンは1つしかないため、DRQモードを使用している間はカートリッジから/IREQが供給されない可能性があります。
Warning 信頼性低
メモリ(または外部ハードウェア/カメラ)から VRAM にビットマップをコピーすることを目的としています。
この転送モードを使用する場合は、リピートビットを設定し、ワードカウントレジスタにスキャンラインあたりのデータ単位数を書き込みます。
キャプチャは HBlank DMA と同様に動作しますが、VCOUNT=2 で転送が開始され、スキャンラインごとに繰り返され、VCOUNT=162 で停止します。
最初のデータ単位をのぞいて、すべてのデータ単位はシーケンシャルな読み書きによって転送されます。
n個のデータ単位があるとき、DMA転送全体に要する時間は、2N+2(n-1)S+xI
です。
このうち、1N+(n-1)S
がReadサイクル、残りの1N+(n-1)S
がWriteサイクルとなりますが、実際のサイクル数は転送元エリアと転送先エリアのWaitStateとバス幅に依存します(CPU命令サイクルタイムの章で説明します)。
さらに、毎回のDMA転送ごとに、 2I
(通常) か 4I
(転送元と転送先がGamePakメモリのとき)がかかるので、(基本的に)x
は 2n
か 4n
です。
1: データバスが8bit単位に制限されているため、SRAMにはアクセスできません。