いろいろな方法でZ80掛け算を実施してみます(乗算2)。
2018.11.12(org2017.1.1)
サイトマップ 、トップ < 訂正<< 乗算1<*
ちょっと趣味に走って、最速化を図ってみました。トータルループは高速化できますが、前の途中打ち切り案と比べると、データ依存で早くなったり、遅くなったりか
;A(8bit) * E(8bit) => HL(16bit) 8Dh * 45h = 2601hの演算(レジスタ設定)
コマンド
LD HL,0 | ;HL=Σ初期化 | |
LD A、8Dh | ;掛ける数(8bit) | |
LD DE,045H | ;掛けられる数(8bit) | |
LD B,8 | ;ビット長 8 | |
LOOP: | ADD HL,HL | ;Σを2倍 |
ADD A,A | ;掛ける数2倍(MSB->C) | |
JR NC,SKIP | ;加算可否 | |
ADD HL,DE | ;1がたっていたら加算 | |
SKIP: | DJNZ LOOP | ;8ビット分ループ |
END |
時間査定(CK数) | 加算実行 | |
有り | 無し | |
ADD HL,HL | 11 | 11 |
ADD A,A | 4 | 4 |
JR NC,SKIP | 7 | 12 |
ADD HL,DE | 11 | 0 |
DJNZ LOOP | 13 | 13 |
DJNZ (終了) | 8 | 8 |
1bit処理サイクル | 46 | 40 |
lastBit処理 | 41 | 35 |
8bitmax(xFF) | 363 | |
8bitmax(x00) | 315 |
下記のようにMSB側から加算していきます。途中で0を検出しても、HLレジスタを必要回数シフトしないと、桁数が合いませんが、単純にいってシンプル最速アルゴリズムかな?(DJNZより、DEC B;jR NZ,loopの方が若干早いけど、見やすさで妥協)。途中で加算ループを打ち切って、残りの必要なビットシフトだけ実行するようにすれば、本当に高速化。ADD A,Aの後、JR Z,owari、owariで、最後のADD,HL,DEのあと、DJNZでADDHL,HLだけ繰り返す。ループ前のZ判定も必要かな? 頭の中でデバック自信ないので書いてません。
16bit演算はフラグが立たないものがあります。学校の演習で16ビット演算の後フラグ確認コマンド追加していたら、指導教官にこんなことしない!8ビット演算が正しいと、難癖(と思う)つけられた思い出があります(だってこんなに遅いのに)。
コマンドリスト
L(8it:8Dh) * C(8bit:45H) => HL(16bit:2601H) | ||
XOR A | ;A=0 | |
LD H,A | ;Σ=(H*256+A)初期化 | |
LD L,8Dh | ;L(8bit)=8DH | |
LD C,045H | ;C(8bit)=45H | |
LD B,8H | B:8 bitLength | |
LOOP: | SLA A | ;Σ下位=Σ下位*2 |
RL H | ;Σ上位=Σ上位*2+CY | |
SLA C | ;CのLSBを取り出す | |
JR NC,NEXT | ;LSB=0だったら加算パス | |
ADD A,L | ;LSB=1⇒加算 | |
JR NC,NEXT | 上位へ繰上がり有無 | |
INC H | ;上位の繰上がり処理 | |
NEXT: | DJNZ LOOP | |
LD L,A | ||
END |
実行時間見積もり
時間査定(CK数) | 加算実行 | |
有り | 無し | |
SLA A | 23 | 23 |
RL H | 23 | 23 |
SLA C | 23 | 23 |
JR NC,NEXT | 7 | 12 |
ADD A,L | 4 | 0 |
JR NC,NEXT | 7 | 0 |
INC H | 4 | 0 |
DJNZ LOOP | 13 | 13 |
DJNZ (終了) | 8 | 8 |
1bit処理サイクル | 104 | 94 |
lastBit処理 | 99 | 89 |
8bitmax(xFF) | 827 | |
8bitmax(x00) | 747 |
そういえば、IC納入先でうまく動かないといわれ立ち合い、ソフトの60(75?)進掛け算間違えているの発見。直おそうとしたけど、久しぶりアセンブラで直しきれずに、ベテランプログラマのお出ましに。ちょっと悔しかった思い出。
遅いのを別にすとシンプルな(力づく)回答 掛け算とは、かける数回、かけられる数を足し続けること
ついでにいうと、汎用割り算というと繰り返し引き算になるんだろうなぁ。
H(8bit) * L(8bit) => HL(16bit) 8Dh * 45h = 2601h
もっと、簡単な掛け算は、ROM(テーブル)の使用かな?
8*8=16bitの巨大なROMを持って、単純に出力を求めるというものですが、ROMも実はかなり大きい。4*4のROMを圧縮ゲートレベルで作ろうと思ったけど、昔取った杵柄という訳にはいかず、悪戦苦闘で中断。 4*4のROMでも、ひっ算式にビットシフト(桁数)を含む2*2回のROMデータの加算で、8*8の乗算に拡張できます。
昔読んだプログラムの本に、参考書見ないで掛け算ソフトが書けるようになれば、初心者脱出だとか。 まあ、いろいろ遊んでください。
余談:掛け算回路大変といえば。
半導体メーカ入社1~2年目の話。研究所の設計したシステムのIC担当への説明会に、参加させてもらう機会があった(本来のターゲットはIC実担当者だけど、同じ課内の新人なので参考までに聴かせてもらった)。
ビデオ系なので10数MHzのシステムクロックだったと思う。ブロック図上DAC(デジタルtoアナログ変換器)と、ADC(アナログtoデジタル変換器)を内蔵したシステムでで、なんか変だと思ったら、アナログ系技術で培ったフィルタをアナログ演算回路で実現しているとのこと。 ”なぜわざわざアナログ領域で?”と立場をわきまえず質問したら、高速演算掛け算機を作るのが。(当時)大変だから、アナログ回路で実現するんだという回答でした。まあ掛け算を含む演算回路は(単純掛け算では無いし)大変なんですヨ。実に。