DMA
DMAはVDPに搭載された機能で、下記のメモリ間転送を行います。
- 68000のメモリ(RAMかROM)から、VDPのメモリ(VRAMかCRAMかVSRAM)へ転送
- VRAMからVRAMへ転送
- VRAMを指定値で埋める(VDPデータレジスタからVRAMへ転送)
DMA転送手順
- DMA有効フラグを1にします。 (VDPレジスタ1で設定)
- 自動アドレス加算値を指定します。 (VDPレジスタ15で設定)
- 転送サイズを指定します。 (VDPレジスタ19〜20で設定)
- 転送モードと転送元アドレスを指定します。 (VDPレジスタ21〜23で設定)
- VDP CTRL (アドレス 0xC00004) で転送先アドレスを指定します。
- VDP DATA (アドレス 0xC00000) に埋める値を設定します。
転送モードが 「VRAMを指定値で埋める」 の場合は6番目が終わると自動で転送が始まります。
それ以外の転送モードでは5番目が終わると自動で転送が始まり、6番目は不要です。
転送中は68000は停止しています。
転送モードによる設定内容の違い
転送モード | 自動アドレス加算値 | 転送サイズ | 転送元アドレス のアラインメント | 転送先アドレス のアラインメント |
68000のメモリからVDPのメモリへ転送 | WORD単位 | WORD単位 | WORD単位 | BYTE単位 |
VRAMからVRAMへ転送 | BYTE単位 | BYTE単位 | BYTE単位 | BYTE単位 |
VRAMを指定値で埋める | BYTE単位 | BYTE単位 | - | WORD単位 |
68000のメモリはワード(16bit)単位、VRAMはバイト(8bit)単位、VDP DATAはワード(16bit)単位 でアクセスすると覚えておけば良いでしょう。
68000のRAMかROMから、VRAMかCRAMかVSRAMへ転送
ワード単位で転送します。
自動アドレス加算値と転送元アドレスに奇数を指定すると正常に動作しません。
つまり自動アドレス加算値も転送元アドレスも偶数になります。
転送サイズには、例えば4bytes転送したいなら転送サイズに 2 を指定します。
VRAMからVRAMへ転送
バイト単位で転送します。
VRAMを指定値で埋める(VDPデータレジスタからVRAMへ転送)
ワード単位で転送します。
転送先アドレスに奇数を指定すると正常に動作しません。
転送モードと状況による転送容量の違い
転送種別 | 横解像度 (Pixel) |
HBlank期間中 (Byte) |
VBlank期間中 1ライン当り (Byte) |
VBlank期間中 NTSC (Byte) |
VBlank期間中 PAL(224Lines) (Byte) |
VBlank期間中 PAL(240Lines) (Byte) |
68000のメモリからVDPのメモリ(VRAM)へ転送 | 320 | 18 | 205 | 7380 | 17835 | 14555 |
68000のメモリからVDPのメモリ(VRAM)へ転送 | 256 | 16 | 167 | 6012 | 14529 | 11857 |
VRAMからVRAMへ転送 | 320 | 17 | 204 | 7344 | 17748 | 14484 |
VRAMからVRAMへ転送 | 256 | 15 | 166 | 5976 | 14442 | 11786 |
VRAMを指定値で埋める | 320 | 9 | 102 | 3672 | 8874 | 7242 |
VRAMを指定値で埋める | 256 | 8 | 83 | 2988 | 7221 | 5893 |
コード例
68000のRAMかROMから、VRAMへのDMA転送
/* sourceAddress から destinationAddress へ autoIncSize 分アドレス加算しながら transfersLength バイト転送する */ void dma() uint autoIncSize; /* 自動加算サイズ */ uint transfersLength; /* 転送サイズ */ ulong sourceAddress; /* 転送元アドレス */ uint destinationAddress; /* 転送先アドレス */ { register ulong *ctrl32; register uint *ctrl16; ctrl16 = (uint *)VDP_CONTROL_ADDRESS; ctrl32 = (ulong *)VDP_CONTROL_ADDRESS; *ctrl16 = REGISTER_WRITE(1) + ((0 << R_9918) | (1 << R_DISP) | (1 << R_IE0) | (1 << R_M1) | (0 << R_M2) | (1 << R_SMS)); /* R_M1 = 1 = DMA有効 */ *ctrl16 = REGISTER_WRITE(15) + (autoIncSize); /* 自動アドレス加算値(2bytes単位) */ *ctrl16 = REGISTER_WRITE(19) + (transfersLength & 0x00FF); /* 転送サイズ(2bytes単位) */ *ctrl16 = REGISTER_WRITE(20) + (transfersLength >> 8 & 0x00FF); *ctrl16 = REGISTER_WRITE(21) + (uchar)((ulong)sourceAddress >> 1 & 0x000000FF); /* 68000の転送元アドレス(2bytes単位) */ *ctrl16 = REGISTER_WRITE(22) + (uchar)((ulong)sourceAddress >> 9 & 0x000000FF); *ctrl16 = REGISTER_WRITE(23) + (uchar)((ulong)sourceAddress >> 17 & 0x000000FF); *ctrl32 = VRAM_WRITE(destinationAddress) + 0x00000080; /* VRAMの指定アドレスへDMA転送開始 */ }