HDMA(HBlank DMA) は 各スキャンラインの HBlank1 でちょっとしたデータ転送2を行い、PPUレジスタを書き換えて画面効果を実現するためのDMAです。
スキャンラインごとにPPUの内容を変更できるため、
- スキャンラインごとに色を設定することで、クロノトリガーのメニューのようなグラデーション塗りや、
- スキャンラインごとにウィンドウレジスタを変更することで、魔獣王のオプション画面のピンクのボーダー
といった画面効果を実現できます。
HDMAのテーブルアドレスレジスタは H-IRQ中 に変更できるため、うまく使えればより高度な画面効果も実現可能です。
HDMAテーブルは、どのデータをいつ転送する必要があるかについての指示を記したテーブルです。
直接モード:
1 byte ヘッダ(リピートフラグ(bit7) & 転送行数)
00h HDMAテーブル終了 (until it restarts in next frame)
01h..80h 1ユニット転送して、後の"X-01h"行だけ停止
81h..FFh "X-80h"行かけて、"X-80h"ユニット転送を行う (1行、1ユニット)
N bytes 転送データ
nを転送ユニットとすると、
ヘッダが
01h..80h: N = n バイト
81h..FFh: N = (X-80h) * n バイト
例(1ユニット=2バイト):
$11 ; エントリ0
$0000, $0000 ; 転送(y=n)
$02 ; エントリ1
$0100, $0040 ; 転送(y=n+16)
$82 ; エントリ2
$0104, $0041 ; 転送(y=n+17)
$0108, $0042 ; 転送(y=n+18)
$64 ; エントリ3
$0114, $0045 ; 転送(y=n+19)
$00 ; 終了(y=n+118)
間接モードのHDMAテーブルは、生データの代わりに、データへのポインタを含むようにします。
間接モード:
1 byte ヘッダ (直接モードと同じ)
2 bytes Nバイトの転送データへのポインタ (ポインタが指すデータの内容は直接モードと同じ)
例(1ユニット=2バイト):
$11
$E502 --> $0000, $0000 (y=n)
$02
$E506 --> $0100, $0040 (y=n+16)
$82
$E60E --> $0104, $0041 (y=n+17)
$0108, $0042 (y=n+18)
$64
$E50A --> $0114, $0045 (y=n+19)
$00 (y=n+118)
転送データ数(N
, GDMA) または 転送データへのポインタ(HDMA) の値は常にテーブルからREADされます。データ値は転送方向によって READ または WRITTEN になります。
HDMAでは、テーブル自体も間接的にアドレス指定されたデータブロックも、転送ステップは常にインクリメンタルです。
(H, V)=(6, 0)
のときに、アクティブなHDMAチャネルのHDMAレジスタに対して、リロードが起きます。
リロード中はCPUが停止します。まず1つでもアクティブなHDMAチャネルがあれば、18サイクル停止します。さらにアクティブなHDMAチャネルごとに、直接HDMAなら 8サイクル、間接HDMAなら 24サイクル 停止します。3
リロードの内容
A2Ax に A1Tx の値をコピー
NTRLx に 現在のテーブルの内容をコピー
間接HDMAの場合は間接アドレスをロード
1: 転送は FBlank中 でも実行されます。
2: 1回のHBlankで、最大4バイトまでです。
3: マスターサイクルです。