掛け算
1~100 を足すプログラムの比較ルールを示した際に、「n*(n+1)/2 の公式を使えば速い」というのは無し、と書きました。
ただし、別の例題として、両者同じ条件で比較する、という前提であればありだと思います。
目次
Z80 vs 6502 トップページ(別ページ)
概要
Z80 と 6502 で、n * (n+1) / 2 をやってみましょう。
…と言っても、ほとんど掛け算ルーチンを作るだけですが。
8bit * 8bit = 16bit が必要になります。
実は、これも 16bit レジスタを持つ Z80 に有利な問題。
n の範囲は、1~254 とします。(n+1 で 8bit に収まるように)
クロック計測は、先の問題と同じく、n=100 で行うものとします。
・ローカルルール
2014.8.8 追記
8bit 掛け算なので、筆算にして8段、8回以上のループ展開は存在しないと思います。
ただ、8回はあまりに多いので、半分の4回までは展開を許すことにします。
ただし、展開されるループ1回分は、5命令を超えないことを条件にします。(あまり巨大なループを展開するのはおかしいので)
改良案は、ページ下部のコメント欄や、メールで送って下さい。待っています。(SPAM対策アドレス表記使用)
Z80基本
HL = BC * A / 2 を計算します。
LD HL,0 ; 10 (11)
LD A,100 ; 7 (8)
LD B,L ; 4 (5)
LD C,A ; 4 (5)
INC C ; 4 (5)
LOOP:
SRL A ; 8 (10)
JR NC,SKIP ; 12 / 7 (13 / 8)
ADD HL,BC ; 11 (12)
SKIP:
JR Z,END ; 12 / 7 (13 / 8)
SLA C ; 8 (10)
RL B ; 8 (10)
JP LOOP ; 10 (11)
END:
SRL H ; 8 (10)
RR L ; 8 (10)
基本的な 8bit 掛け算のプログラムです。2進数の筆算をやっています。
もっと高速な最適化ができそうな気もしますが、やっていません。(投稿お待ちしています)
最終的な結果は HL に入ります。
前処理が 34 クロック
LOOP 以下が、加算が生じた場合 69クロック、生じない場合 62 クロック。
ただし、乗数を2進数で示したときに、一番左の 1 の桁を計算した時点で終了します。
この際、次のループの準備は行わないので、26 クロック速くなります。
ここでは、乗数を 100 で計算しています。2進数では 0110 0100 。
なので、7回ループして、加算が3回生じます。
69*3 + 62*4 - 26 = 429 で、計算部分で 429クロックということですね。
最後に、後処理として 2 で割っています。これが 20クロック。
総計で、483 クロックです。
構造整理
2014.8.4 午後追記
先のプログラムのループ部分を整理したプログラムが投稿されました。ありがとうございます。
・SRL A ではなく RRA を使ったほうが速い。ただし、前提として前処理でキャリーをクリアしなくてはならない。
・ループ構造の後半を前に持っていき、無条件分岐を無くしている。
主にこの二つの工夫で、ループ内の処理を軽減しています。
LD HL,0 ; 10 (11)
LD A,100 ; 7 (8)
LD BC,101 ; 10 (11)
OR A ; 4 (5)
JP START ; 10 (11)
LOOP:
SLA C; 8 (10)
RL B; 8 (10)
START:
RRA ; 4 (5)
JR NC,LOOP ; 12 / 7 (13 / 8)
ADD HL,BC ; 11 (12)
JP NZ,LOOP ; 10 / 10 (11 / 11)
END:
SRL H ; 8 (10)
RR L ; 8 (10)
前処理が 46クロック、後処理が 20 クロック、ループ内は加算有りが 56クロック、加算無しが 38クロックで、最後は 20 クロック速くなります。
46 + 56*3 + 38*4 - 20 + 20 = 366 クロックです。
かなり高速化されました。