Z80で乗算するには?

Z80には乗算命令が無いので、乗算を行いたい場合は、他の命令の組み合わせで乗算を行うことになります。

(1) ループで実現する
A * B を実施したい場合に、B が例えば 0〜7 の範囲とか、乗数・被乗数のいずれかが小さいことが明白な場合は、
その回数加算してしまえば良いです。Aレジスタに Aレジスタ * Bレジスタを格納するサンプルです。
Bレジスタは 1〜7 程度を想定しています。B = 0 は想定外です。オーバーフローも考慮しません。
  LD    C,A
  XOR   A
LOOP:
  ADD   A,C
  DJNZ  LOOP
		
この方法は、実装が簡単な反面、Bレジスタに設定した値が大きいほど、それに比例して遅くなります。
安定した処理時間を望むゲームなどには使いにくいですね。

(2) シフトと加算の組み合わせで実現する
A * B で、A 及び B の両方に大きな値が入る可能性がある場合、(1) の方法は遅すぎます。
そこで、かけ算の筆算の要領でシフトと加算だけで乗算を実現する方法を紹介します。
下記は、HL = A * B を実現するルーチンです。HL, A, B いずれも符号無しを想定。
B,DE,HL,フラグ が破壊されます。
  LD    D,0
  LD    E,B
  LD    L,D
  LD    H,D
  LD    B,8
LOOP:
  SLA   L
  RL    H
  RLCA
  JP    NC,SKIP_ADD
  ADD   HL,DE
SKIP_ADD:
  DJNZ  LOOP
		

かけ算の筆算を二進数でやることを考えてください。桁ごとに計算して、桁位置に対応する重み分だけ左シフトした値を
加算することで結果を得る仕組みなので、二進数でも通用します。
そして、二進数の場合、一桁には 0 か 1 しか入ってませんから、0 なら足さない、1 なら足す、を選択すれば良いことになります。


しかし、シフトする量が着目している Bレジスタの桁 によって変わってしまうと、プログラムが複雑になることは想像に難くありません。
複雑になると遅くなりますので、ここはもう一つ工夫します。
加算の順序は入れ替えても同じなので、下の桁からでは無く、上の桁から計算していくことにします。


これを上から順に処理しています。

2020年8月15日 更新
[戻る]