Z80 vs 6502

目次

概要

比較ルール

1~100を足すプログラム

6502基本

繰り上がり高速化カウンタレジスタ化条件省略

Z80 基本

ループ展開条件省略さらに展開

速度判定


Z80 基本

つづいて Z80 。

6502 の改良プログラムを移植する形で、あえて 8bit 演算にして速度を稼ぐ、というプログラムもありました。

しかし、最終的には 16bit 演算をスマートに使ったプログラムが速いようです。


まず、基本系。


	LD HL,0 ; 10 (11)
	LD BC,100 ; 10 (11)
LOOP:
	ADD HL,BC ; 11 (12)
	DEC C ; 4 (5)
	JP NZ,LOOP ; 10 / 10 (11 / 11)

最初に僕が作ったプログラムに似ていますが、DE レジスタを使わなくなりました。

ループも、DJNZ ではなく DEC C ; JP NZ で回しています。


DJNZ では ループ変数として暗黙に B レジスタを使うのですが、これを C レジスタに変えているわけです。

局所的には遅くなりますが、これでループ変数と「足す数」を共通に出来るため、DE レジスタの操作がいらなくなって全体として高速化しています。


LOOP より前の前処理が 22 クロック、LOOP 後が 28 クロックで、100回繰り返すので 2800 クロック。

合計、2822 クロックで計算を終わります。


僕が最初に作ったプログラムは 3325 クロックでしたから、少し早くなりました。

しかし、これだとクロック周波数(ファミコンは MSX の半分)を考慮しても、速度でファミコンに負けています。


(6502 は、この時点で 1395 クロックでした。MSX の速度に合わせると、この値を倍にして 2790 クロック。2822 クロックではまだ遅いです)


ループ展開

そこで、「6502 のプログラムは結構長い(28バイト)ので、同程度のサイズまでループ展開させてもらった」というのが次のプログラム。


	LD HL,0 ; 10 (11)
	LD BC,100 ; 10 (11)

LOOP:
	ADD HL,BC ; 11 (12)
	DEC C ; 4 (5)
	JR Z,EXIT ; 12 / 7 (13 / 8)

	ADD HL,BC ; 11 (12)
	DEC C ; 4 (5)
	JR Z,EXIT ; 12 / 7 (13 / 8)

	ADD HL,BC ; 11 (12)
	DEC C ; 4 (5)
	JR Z,EXIT ; 12 / 7 (13 / 8)

	ADD HL,BC ; 11 (12)
	DEC C ; 4 (5)
	JR Z,EXIT ; 12 / 7 (13 / 8)

	ADD HL,BC ; 11 (12)
	DEC C ; 4 (5)
	JP NZ,LOOP ; 10 / 10 (11 / 11)
EXIT:

全体としては 27バイトで、6502 のプログラムよりは短いです。

基本形としては先に挙げたものと同じなのですが、見て判る通り、ループ内のプログラムを繰り返しています。


「ループ展開」というテクニックです。

今の CPU では、キャッシュにプログラムが収まっているのが最速なので、プログラムは小さいほうが速いです。

しかし Z80 の時代にはキャッシュなどないため、ループ回数を減らしてオーバーヘッドを無くす、というのが高速化手法として有効でした。


とはいえ、このプログラムでは、どこで終了条件が来るかわからないため、条件分岐を多数入れています。

ループの条件判断より高速化されるようになっていますが、このオーバーヘッドが結構大きい。


前処理が 22 クロック。

ループ内が、基本単位 25 クロックを5回繰り返しているのですが、最後だけ 28 クロックなので 25*4 + 28 = 103 クロック。

これを 25 回繰り返すので、 103 * 25 = 2575 クロック。


合計で、2582 クロック。ファミコンより速くなりました。




条件省略

…もう一ひねりしてみます。これは投稿されたものではなく、僕の方で作ったもの。(作成後、総計で3クロック減る局所的な改良案を頂き反映しています)


	LD BC,100 ; 10 (11)
	LD HL,0 ; 10 (11)
	BIT 0,C ; 8 (10)
	JR NZ,MOD1 ; 12 / 7 (13 / 8)

LOOP:
	ADD HL,BC ; 11 (12)
	DEC C ; 4 (5)
MOD1:
	ADD HL,BC ; 11 (12)
	DEC C ; 4 (5)
	JP NZ,LOOP ; 10 / 10 (11 / 11)

前処理が長くなったのでループ展開が2回に減ってしまった…でも、これで 17byte 。


17byte ならまだ展開できる! というコード量ですが、実は僕が計算を間違えまして、各命令のコード量を集計する際に暗算でやって繰り上がりを間違え、27byte だと思い込むという大ミスを…
後で指摘され、さらに展開したバージョンが投稿されました。(この次のプログラム)


前処理の中で「端数」が出るかどうかを確認し、端数がある場合はループの途中に飛び込んでいます。

なので、ループの最後以外では終了条件の確認が不要になっています。


これも、不定回ループを展開するときの基本テクニックでした。


前処理が 40 クロック。ループ内が 45クロックで、50回繰り返しますから 45*50 = 2250 クロック。

合計で、2290 クロックです。


次ページ: さらに展開


前ページ 1 2 3 4 5 次ページ

(ページ作成 2014-08-03)
(最終更新 2014-08-05)
第2版 …他の版 初版

戻る     次記事:掛け算
トップページへ

-- share --

92000

-- follow --




- Reverse Link -