パッド入力
VRAM アクセスを想定したプログラムで、ゲームの「出力」は見られたので、次は「入力」を考慮したプログラムを作ってみようと思います。
いろいろやってみようと思ったのですが、長いプログラムになってしまうため、「入力パッドの読み取り」「キャラクター座標の移動」「コマンド入力」の3つに分けて考えます。
目次
Z80 vs 6502 トップページ(別ページ)
概要
入力パッドを読み取って、「新たに押されたボタン」を簡単に読み取れるようにします。
パッドの読み取りは、MSX でもファミコンでも面倒だったのですが、ここでは GAMEPAD という1バイトのメモリにすでに読み取られたものが入っているものとします。
今はデータ内容について考える必要はありませんが、BIT ごとにスイッチに対応していて、入力があった BIT が 1 になるものと考えてください。
GAMEPAD の値は「現在の」状態です。これを元に、「新たにボタンが押された」部分だけがすぐに読み取れる PAD_NEW を作り出してください。
1回前の状態の GAMEPAD を PAD_OLD に保存してあれば
PAD_NEW = (GAMEPAD XOR PAD_OLD) AND GAMEPAD
で作り出せます。
作りだした PAD_NEW が 0 ではない場合(なにか新たな入力があった場合)には、過去 16回分の入力を PADHIST に記録してください。
記録方式は自由とします。これは、後にコマンド入力の検査に使うためのものです。
・ローカルルール
分岐がある場合「一番時間がかかる」ルートのクロック数を計測します。
入力はゲームの基本処理であり、最悪の状況で速いプログラムが良いためです。
Z80 基本
LD HL,(GAMEPAD) ; 16 (17)
LD A,L ; 4 (5)
XOR H ; 4 (5)
AND L ; 4 (5)
LD H,A ; 4 (5)
LD (PAD_OLD),HL ; 16 (17)
JR Z,END ; 12 / 7 (13 / 8)
LD B,H ; 4 (5)
LD A,(BUFPTR) ; 13 (14)
INC A ; 4 (5)
AND 0FH ; 7 (8)
LD (BUFPTR),A ; 13 (14)
LD E,A ; 4 (5)
LD D,0 ; 7 (8)
LD HL,PADHIST ; 10 (11)
ADD HL,DE ; 11 (12)
LD (HL),B ; 7 (8)
END:
GAMEPAD: DB 0
PAD_OLD: DB 0
PAD_NEW: DB 0
BUFPTR : DB 0
PADHIST:
GAMEPAD と PAD_OLD を並べることで、処理に必要な2つのデータを1回の 16bit アクセスで取り出しています。
そして、PAD_OLD と PAD_NEW を並べることで、処理結果と次のために必要なデータの2つを、1回の 16bit アクセスで書きこんでいます。
あとは基本に忠実な形でリングバッファに書き込んでいるだけです。
リングバッファ書き込み時に一番時間がかかります。
総計で 152 クロックです。
ポインタアクセス
2014.8.28追記
僕のプログラムでは、16bit アクセスで速度を稼ごうとしたのですが、HL を介して連続アクセスした方が速い、と言うプログラムが投稿されました。
LD HL,GAMEPAD ; 10 (11)
LD B,(HL) ; 7 (8)
DEC L ; 4 (5)
LD A,(HL) ; 7 (8)
LD (HL),B ; 7 (8)
DEC L ; 4 (5)
XOR B ; 4 (5)
AND B ; 4 (5)
LD (HL),A ; 7 (8)
JR Z,END ; 12 / 7 (13 / 8)
DEC L ; 4 (5)
LD D,H ; 4 (5)
LD E,(HL) ; 7 (8)
INC E ; 4 (5)
RES 4,E ; 8 (10)
LD (HL),E ; 7 (8)
LD (DE),A ; 7 (8)
END:
PADHIST: DS 16
BUFPTR: DB 0
PAD_NEW: DB 0
PAD_OLD: DB 0
GAMEPAD: DB 0
投稿プログラムでは、プログラムの最後の1命令がありませんでした。入力をリングバッファに納める大事な部分。でも、実行に必要なクロック数はちゃんと計算されていたので、投稿時にコピーミスがあっただけのようです。
PADHIST は、アドレスの下位 8bit が 00H のメモリから始まっている、という前提があります。
これにより、他のメモリも含めてすべてのアドレスの上位 8bitは同じとなり、アドレス計算を下位8 bitだけで済ませています。
その上で、GAMEPAD から初めて、PADHIST に近づく方向に HL を動かしながら連続アクセスしています。僕のプログラムではアドレスを直接指定していましたが、HL による間接指定の方が、メモリアクセスが少なく高速動作します。
BUFPTR は PADHIST 内の位置を意味しますが、PADHIST がアドレスの下位が 00H から始まる、としているため、BUFPTR がそのままアドレスの下位 8bit となります。
BUFPTR を 0~15 で維持するのは、増加後、BIT 4 (16 の位) をリセットすることで行っています。ビットリセット命令は少し遅いのですが、AND 計算は A レジスタでしかできないため、A に移して計算して戻して…などとやるよりはずっと速いです。
こうした工夫で高速化されています。計算は、一番遅い分岐を辿ってクロックを全て足し合わせるだけです。
総計は、120クロックです。