パッド入力

目次

概要

Z80 基本

ポインタアクセス自己書き換え

6502 基本

速度判定

余談


自己書き換え

2015.4.27 追記

昨年11月29日には投稿いただいていたのですが、忙しくて本文に追記してませんでした。申し訳ありません。

基本は「基本のプログラム」なのですが、2つの工夫を盛り込むことで、ポインタアクセスより高速化されています。


	LD HL,(PAD_OLD) ; 16 (17)
	LD A,L ; 4 (5)
	XOR H ; 4 (5)
	AND H ; 4 (5)
	LD L,A ; 4 (5)
	LD (PAD_NEW),HL ; 16 (17)
	JR Z,END ; 12 / 7 (13 / 8)
	LD HL,PADHIST ; 10 (11)

BUFPTR EQU *-2
	LD (HL),A ; 7 (8)
	LD A,L ; 4 (5)
	ADD A,16 ; 7 (8)
	LD (BUFPTR),A ; 13 (14)
END:

PADHIST:	DS 256

PAD_NEW:	DB 0
PAD_OLD:	DB 0
GAMEPAD:	DB 0

▼高速化の工夫、その1。


BUFPTR EQU *-2 という見慣れぬ命令があります。

これは擬似命令で、「この位置の2バイト前に BUFPTR という名前を与える」です。


前の命令 LD HL,PADHIST が3バイト命令なので、後半2バイトの先頭に BUFPTR という名前を与えたことになります。実はこれ、PADHIST のアドレスを記してある部分。

そして、プログラムの最後に、ここに「次のアクセス位置」を書き込んでいます。常に、アクセス位置が直接 HL に読み込まれることになる。


基本のプログラムでは、BUFPTR として「PADHIST のアクセス位置」を保存していました。これだと、命令を読み込んだ後に、命令を解釈して、またメモリアクセスしないといけない。

ところが、自己書き換えによって、アクセス位置を「命令の一部」にすれば、メモリアクセスが減ります。この工夫で高速化しているのです。


▼高速化の工夫、その2。


PADHIST に16回分のデータを記録、としていましたが、同時に「記録形式は自由」ともしました。

そこで、思い切って 256バイトを確保してしまうことで高速化を図っています。


256バイト確保していますが、PADHIST としては 16バイトごとに飛び飛びにしか使いません。

間のメモリは、不連続になりますが別の用途にも使えますので「無駄遣い」ではないでしょう。


そして、次の書き込みメモリの計算は、下位 8bit のみを 16足すことで行っています。

16回足すと 255 を超えて 0 に戻りますから、データ端のチェックなしに、データ16個のリングバッファが実現されています。


合計、108クロックです。


6502 基本


	LDA GAMEPAD ; 4
	TAX ; 2
	EOR PAD_OLD ; 4
	AND GAMEPAD ; 4
	STA PAD_NEW ; 4
	STX PAD_OLD ; 4
	BEQ END ; 3 / 2

	LDX BUFPTR ; 4
	STA PADHIST,X ; 5
	INC X ; 2
	TXA ; 2
	AND #$0F ; 2
	STA BUFPTR ; 4
END:

ゼロページを使っていません。GAMEPAD や PAD_NEW は重要な情報なのでゼロページに持ってもいいように思うのだけど、6502 の方が速そうなので、Z80 に対するハンデです。

(Z80 が劇的に高速化されることがあったら、ゼロページ使用を解禁しようかと思います)


Z80 とほぼ同じプログラム内容ですが、メモリの読み書きは 8bit づつです。(16bit は扱えないので)

やはりリングバッファ書き込み時に一番時間がかかり、43クロックです。


速度判定

6502 は 43クロック。周波数を考慮して倍にすると、MSX での 86クロック相当の実時間になります。

Z80 は 108クロックなので、差は 22クロック、20% ファミコンが速いです。


単純でメモリ参照が多いプログラムなので、メモリ操作の苦手な Z80 にはかわいそうな例題かもしれません。


余談

MSX ではジョイスティックの読出しは、BIOS を使用することが推奨されていました。

でも、I/O アクセス4回ほどで直接知ることができます。



	LD A,0FH ; 7 (8)
	OUT (A0H),A ; 11 (12)
	LD A,2FH ; 7 (8)
	OUT (A1H),A ; 11 (12)
	LD A,0EH ; 7 (8)
	OUT (A0H),A ; 11 (12)
	IN A,(A2H) ; 11 (12)

72クロックで PAD の状態がわかります。BIOS はこの後に、結果を使いやすくする変換処理が入るのでもっと遅かったろうけど。

(A の必要なところだけ AND で取り出して、テーブルアドレスに足してテーブルの値取り出して…たぶん、BIOS コールで 150クロックくらいは行くのではないかと思う。BIOS 読んだわけではないけど。)


これに対し、ファミコンではジョイパッドは 1bit づつ読み出す必要がありました。


	LDA #$01 ; 2
	STA $4016 ; 4
	LDA #$00 ; 2
	STA $4016 ; 4

	LDX #8 ; 2
LOOP:
	LDA $4016 ; 4
	ROR A; 2
	ROL >0 ; 5
	DEX ; 2
	BNE LOOP ; 3 / 2

141 クロックです。まぁ、8回ループ展開すれば 100 クロックです。


今回は CPU 勝負なので実際の I/O 速度は想定していませんが、これを足せばファミコンは 150クロック程度、MSX は BIOS 使用で 300 クロック程度だったかな、と思っています。


つまり、周波数を考慮すれば、ここでの勝負も互角。I/O アクセスってかなり遅い処理なので、実際にゲームを作る際も GAMEPAD のようにメモリに一旦置いといて、必要な際にはメモリを参照するようにするのが普通でした。


次はの例題は…ユーザー操作


前ページ 1 2

(ページ作成 2014-08-10)
(最終更新 2015-04-27)
第2版 …他の版 初版

前記事:ランダムアクセス     戻る     次記事:ユーザー操作
トップページへ

-- share --

0000

-- follow --




- Reverse Link -