Navigation Log - なびろぐ -
1999/09/02

...X680x0 spirit inside...

この日記はGNSで生成しています。
この日記の画像はOPTPiX webDesigner Ver.4で生成しています。

hauN
Go amazon.co.jp

■ご注文リストから■ [一覧]
■Amazonギフト券■ [購入]
幼女戦記 3 [Blu-ray] [DVD]
幼女戦記 3 [Bl...
Amazonほしい物リスト


1999/09/02 (木)

Z80そろそろしめくくり

_ ということで、メールでZ80コードアンケートは24通。投稿作品が届いたので掲載しませう。この乗算ルーチンは初見でしたわ・・・。


; A*BC = BC*DE = HL が全て成立するかどうかをチェックする
;     by <A HREF="http://www.yuasa.kuis.kyoto-u.ac.jp/ylab/koyama/">koyama</A>
;
;    結果は Z flag に反映される。(真なら 1、偽なら 0)
;    フラグ以外のレジスタは全て元の値を維持。 (A も元のまま)
; 
; 基本的な流れ:
;    A ≠ DE のときは (BC=0 and HL=0) なら真、さもなくば偽。
;    A = DE のときは (A=0 and HL=0) なら真、さもなくば乗算して調べる。
; 値の退避:
;    まず DE をスタックに退避、
;    そして E を使って A を退避。
;    乗算に入ったら DE を使って HL を退避する。
;    PUSH/POP するのは結局一回だけで済む。
; その他:
;    JR より JP が速いのはわかっているが
;    ここではコードサイズの最適化を意識しているのと
;    Position Independent になることを意識してみた。

COMPARE:
   PUSH DE                ; DE の退避
   CP   E                 ; A=E かどうか
   LD   E, A              ; A の退避 (フラグは変化しない)
   JR   NZ, BC_HL_0_CHECK ; if (A≠E) goto BC_HL_0_CHECK;
   XOR  A                 ; D と E のチェックのため A ← 0
   CP   D                 ; D が 0 かどうか
   JR   NZ, BC_HL_0_CHECK ; if (D≠0) goto BC_HL_0_CHECK;
   OR   E                 ; E (退避された A) が 0 かどうか
                          ; 比較ついでに A ← E もやってるのがミソ
   JR   Z, HL_0_CHECK     ; if (A=0) goto HL_0_CHECK;
;
; ここに辿りついた時は、 D=0, A=E になっている。
; 逆に言うと、 POP DE すれば LD A, E で全て戻るので
; A,D,E は全部こわしてよい。
;
; ここから乗算
; 以下、 A の各ビットを stuvwxyz と表現することにする。
;
   LD   E, D          ; 既に D=0 だから、これだけで DE = 0 になる
   EX   DE, HL        ; HL = 0, DE = 元のHL
   SCF                ; Cflag = 1 (この 1 が最終的に End Mark になる)
   ADC  A, A          ;CF=s,A= tuvwxyz1, HL = 0
   JR   NC, MUL_LOOP2 ; s が 0 なら飛ばすので、
                      ;             結局 HL = BC * s になる
MUL_LOOP1:            ; 以下同様の理屈で、
   ADD  HL, HL        ; ループを繰り返すごとに、以下のように変化する↓
   ADD  HL, BC        ;    A = tuvwxyz1, HL = BC *   s
MUL_LOOP2:            ;    A = uvwxyz10, HL = BC *( 2s+  t)
   ADD  A, A          ;    A = vwxyz100, HL = BC *( 4s+ 2t+  u)
   JR   Z, MUL_END    ;    A = wxyz1000, HL = BC *( 8s+ 4t+ 2u+  v)
   JR   C, MUL_LOOP1  ;    A = xyz10000, HL = BC *(16s+ 8t+ 4u+ 2v+ w)
   ADD  HL, HL        ;    A = yz100000, HL = BC *(32s+16t+ 8u+ 4v+2w+ x)
   JR   MUL_LOOP2     ;    A = z1000000, HL = BC *(64s+32t+16u+ 8v+4w+2x+ y)
                      ;    A = 10000000, HL = BC*(128s+64t+32u+16v+8w+4x+2y+z)
                      ;    A = 00000000 で抜ける
                      ;     (ループ回数を数えるためのレジスタが不要なのがミソ)
MUL_END:              ;       これで結局 HL = BC * A となる。
   OR   A             ; Cflag = 0  (SUB HL,DE っていう命令が無いんだもん…)
   SBC  HL, DE        ; (乗算結果 - 元のHL) で、一致してれば Z flag が立つ。
   EX   DE, HL        ; HL を復帰
   POP  DE            ; DE を復帰
   LD   A, E          ; 元は A=E なので、これで A も復帰することになる。
   RET
;
; あとは HL が 0 かどうかが関わるやつ (最初の方のチェックで分岐してくる)
;
BC_HL_0_CHECK:            ; B,C,H,L が「全部 0」かどうか調べればいいので、
   LD   A, B              ; B から始めて
   OR   C                 ; ひたすら OR を取っていくわけですな。
HL_0_CHECK:               ;      (←ここから入ってくる場合は A が 0 なので、
   OR   H                 ;         この OR が LD A, H と等価になるのがミソ)
   OR   L                 ; この時点で、 OR 取った分が全部 0 なら Z flag = 1
   LD   A, E              ; 退避されていた A の値を戻す
   POP  DE                ; 退避されていた DE の値を戻す
   RET


[URL] [View Log()] [Trackback]
Name: Comment:



メールはこちらへ...[後藤浩昭 / Hiroaki GOTO / GORRY / gorry@hauN.org]

「表紙へ戻る」
「会議室」 「最新版」 「なびろぐindex」 「GNSソースを読む」