ランダムアクセス
目次
6502基本
DATA は、縦座標が 64 個分並んだあと、横座標が 64個、キャラクタ番号が 64 個並びます。
各配列の先頭からの位置が同じものが1組となっています。
LDX #>DATA ; 2
LDA #0 ; 2
STA >0 ; 3
CLC ; 2
LOOP:
; 縦位置を考慮して VRAM の上位バイトを計算
LDY DATA,X ; 4
BMI END ; 3 / 2
LDA SHIFT,Y ; 4
AND #$03 ; 2
ADC #<VRAM ; 2
STA >1 ; 3
; VRAM 下位バイトを計算
LDA SHIFT,Y ; 4
AND #$E0 ; 2
ADC DATA+64,X ;4
TAY; 2
; キャラを書き込む
LDA DATA+128,X ; 4
STA (0),Y ; 6
INX ; 2
BCC LOOP ; 3 / 2
END:
SHIFT:
DB 00, 20, 40, 60, 80, A0, C0, E0
DB 01, 21, 41, 61, 81, A1, C1, E1
DB 02, 22, 42, 62, 82, A2, C2, E2
SHIFT から、24バイトのデータテーブルがあります。
これは、0~24 の数値を、5bit ローテートした値が入っています。
これにより、縦座標の 5bit shift の計算を高速化しています。
ローテートした値の「下位2bit」に VRAM アドレスの上位 8bit を足し、>1 に入れています。
ちなみに、>0 は前処理で 0 を入れた後、常に 0 のままです。
「上位3bit」が、VRAM アドレスの下位バイトに当たります。
こちらはさらに横座標を足して、VRAM アドレスの下位 8bit が完成。
最後に、STA (0),Y でキャラクターの書き込みを行っています。
これは、ゼロページの 0 の値を下位、1 を上位とした 16bit アドレスに、さらに Y を足したアドレスに、A レジスタの値を書き込む命令です。
VRAM の下位アドレス(Yに入れてある)はここで足してしまうため、下位アドレスの >0 は常に 0 にしてあるのです。
ループ内の計算は、一切キャリーを発生しません。
そのため、前処理でキャリーをクリアした後は、足し算前にもキャリーをクリアしていません。
ループ最後の分岐も、「キャリーがクリアなら」を使用していますが、条件分岐ではなく必ずジャンプします。(実行速度は変わらないが、コードが短縮できる)
1キャラクタの書き込みに 44クロック。これを 48回繰り返します。
前処理は 9クロックで、終了時には条件分岐で 7クロック必要です。
44 *48 +9+7 = 2128
総計 2128 クロック。
ちなみに、SHIFT テーブルのサイズを倍増し、48バイトにすると、さらに高速化できます。
詳細は書きませんが総計 1840 クロックになります。
ただ、現時点でも Z80 よりずっと速いので、テーブルを肥大化させるのは自粛しています。
(Z80 に負けそうになった時には 1840 クロック版にします(笑))
速度判定
6502 は 2128 クロック。周波数を考慮して倍にすると、MSX での 4256 クロック相当の実時間になります。
Z80 は 8248 クロックなので、ファミコンの倍も遅いです。
…まだ試作した程度なので、僕の作り方も悪いかもしれない。
でも、こういうメモリアクセスの多いプログラムは、Z80 の苦手なところなんです。
そして、ゲームを作るならメモリアクセスは避けられない。
いくら Z80 がレジスタをたくさん持っていると言っても、動き回る多数の敵キャラクターを全て記憶できるほどではないのだから。