CASL U - 乗算の計算
 前へ 目次へ 次へ

乗算の計算

 a×bのような乗算を計算する副プログラムとして作成する。データa, bはそれぞれGR1, GR2に格納しておき、副プログラムを呼び出す。計算結果はGR0に格納することとする。もちろん、データa, bは整数である。
 方法は2通り考えられる。
  @ データa(GR1)をデータb(GR2)回、加算する。
  A シフト命令を利用する。

方法@

 手順は次のとおりである。

  1. GR0を0で初期化する。
  2. データa(GR1)をGR0に加算する。
  3. データb(GR2)から1を減算する。
  4. データb(GR2)が0でなければ 2. へ移動する。0ならば次へ。
  5. 呼出し元へ戻る。

 GR1とGR2のデータが変わらないように最初にPUSH命令、戻る前にPOP命令を追加する。
 プログラムは次のとおりである。

MAIN1    START
         LD      GR1, DATA1
         LD      GR2, DATA2
         CALL    MULT1
         ST      GR0, ANS
         RET
DATA1    DC      10
DATA2    DC      5
ANS      DS      1
         END
MULT1    START
         PUSH    0, GR1
         PUSH    0, GR2
         LAD     GR0, 0    ;1.
LOOP     ADDA    GR0, GR1  ;2.
         SUBA    GR2, =1   ;3.
         JNZ     LOOP      ;4.
         POP     GR2
         POP     GR1
         RET               ;5.
         END

方法A

 GR1=10(=0000 1010)× GR2=5(=0000 0101)をひっ算で書くと次のようになる。先頭の0は省略する。

×0000001010.
×0000000101.
+0000001010.   …    1010×101
+000000000.    …   10100×101
00001010.     …  101000×101
+0000110010

 GR1が左に1ビットずつシフトされていることがわかる。GR2は最下位ビットから使われている。GR2を右に1ビットずつシフトすると常に最下位ビットだけを調べれば良いことになる。
 特定のビットが0か1かを調べるにはAND命令を使う。今、調べたいビットは最下位ビットであるから最下位ビットだけが1のデータとAND演算を行う。
    101 AND 001 = 1,    10 AND 01 = 0
 AND演算の後、ジャンプ命令で分岐すれば良い。

 手順は次のとおりである。

  1. GR0を0で初期化する。
  2. GR3にデータb(GR2)を記憶する。
  3. GR3の最下位ビットを調べる。(1とAND演算する。)
  4. 0であれば 6. へ移動する。0でなければ次へ。
  5. データa(GR1)をGR0に加算する。
  6. データa(GR1)を1ビット左シフトする。
  7. データb(GR2)を1ビット右シフトする。
  8. データb(GR2)が0でなければ 2. へ移動する。0ならば次へ。
  9. 呼出し元へ戻る。

 ポイントは、データb(GR2)をGR3に記憶させてからGR3と1をAND演算するところである。GR2をそのままAND演算すればよいと思われるが、AND命令は  AND   GR2, 1  のように書くわけで演算結果がGR2に格納される。このようにGR2をそのまま使うと乗算する値のGR2の内容が変わってしまう。これを防ぐために一度GR2をGR3に記憶させ、GR3を使ってAND演算している。

 GR1, GR2とGR3のデータが変わらないように最初にPUSH命令、戻る前にPOP命令を追加する。
 プログラムは次のとおりである。3つずつあるPUSH, POP命令はRPUSH, RPOP命令に置き換えても良い。

MAIN2    START
         LD      GR1, =10    ;リテラルを使用
         LD      GR2, =5
         CALL    MULT2
         ST      GR0, ANS
         RET
ANS      DS      1
         END
MULT2    START
         PUSH    0, GR1
         PUSH    0, GR2
         PUSH    0, GR3
         LAD     GR0, 0        ;1.
LOOP     LD      GR3, GR2      ;2.
         AND     GR3, =1       ;3.
         JZE     SHIFT         ;4.
         ADDA    GR0, GR1      ;5.
SHIFT    SLA     GR1, 1        ;6.
         SRA     GR2, 1        ;7.
         JNZ     LOOP          ;8.
         POP     GR3
         POP     GR2
         POP     GR1
         RET                   ;9.
         END

 GR1=10(1010), GR2=5(101)のとき、プログラムを順番に追っていき、レジスタなどの値の変化を見てみよう。PUSH, POPは省略する。
 次の表のようにプログラムを追跡していくことをトレースという。↑印は上と同じ値(変化なし)という意味である。

命令 GR0 GR1 GR2 GR3 動作
    LDA  GR0, 0 0 1010 101 ? 1. GR0を0で初期化する。
LOOP  LD  GR3, GR2 101 2. GR3にデータb(GR2)を記憶する。
    AND  GR3, =1 1 3. GR3の最下位ビットを調べる。(1とAND演算する。)
    JZE  SHIFT 4. 0であれば 6. へ移動する。0ならば次へ。
    ADDA  GR0, GR1 1010 5. データa(GR1)をGR0に加算する。
SHIFT  SLA  GR1, 1 10100 6. データa(GR1)を1ビット左シフトする。
    SRL  GR2, 1 10 7. データb(GR2)を1ビット右シフトする。
    JNZ  LOOP 8. データb(GR2)が0でなければ 2. へ移動する。0ならば次へ。
LOOP  LD  GR3, GR2 10 2. GR3にデータb(GR2)を記憶する。
    AND  GR3, =1 0 3. GR3の最下位ビットを調べる。(1とAND演算する。)
    JZE  SHIFT 4. 0であれば 6. へ移動する。0でなければ次へ。
SHIFT  SLA  GR1, 1 101000 6. データa(GR1)を1ビット左シフトする。
    SRL  GR2, 1 1 7. データb(GR2)を1ビット右シフトする。
    JNZ  LOOP 8. データb(GR2)が0でなければ 2. へ移動する。0ならば次へ。
LOOP  LD  GR3, GR2 1 2. GR3にデータb(GR2)を記憶する。
    AND  GR3, =1 1 3. GR3の最下位ビットを調べる。(1とAND演算する。)
    JZE  SHIFT 4. 0であれば 6. へ移動する。0でなければ次へ。
    ADDA  GR0, GR1 110010 5. データa(GR1)をGR0に加算する。1010+101000
SHIFT  SLA  GR1, 1 1010000 6. データa(GR1)を1ビット左シフトする。
    SRL  GR2, 1 0 7. データb(GR2)を1ビット右シフトする。
    JNZ  LOOP 8. データb(GR2)が0でなければ 2. へ移動する。0ならば次へ。
    RET 110010 1010 101 ? 最終結果。GR1〜GR3はPOPで元に戻る。 9. 呼出し元へ戻る。


 副プログラムにエラー処理を考える。

 1語で扱えるデータの範囲は−32768〜32767までであるから計算結果がこの範囲以外であればエラーである。計算の過程で、GR0及びGR1が範囲内にあるかどうかを調べればよい。GR0は ADDA GR0, GR1 の後、GR1は SLA  GR1, 1 の後で調べる。
 正数の場合、GR0とGR1は範囲を超えるとOF(オーバーフローフラグ)が1になるので、判定できる。負数の場合、例えば-1×3を行うと-1を左シフトするとOFが1になる。正数と負数の場合に分ける必要があるようである。

 正数用、負数用と用意するのもうまい方法とはいえない。
 そこで、計算は正数だけを対象とする。事前に負数は整数に変換し、負数であったことを記憶しておけば良い。
   正数×正数=正数
   負数×負数=正数
   正数×負数=負数
   負数×正数=負数
の4パターンだけである。まず、GR1を調べ負数であればGR4を1にする。GR2が負数ならGR4を0に、正数なら1のままとする。同じようにGR1を調べ正数であればGR4を0にする。GR2が負数ならGR4を1に、正数なら0のままとする。

A  B Y
0  0
0  1
1  0
1  1
0
1
1
0

 難しいようだが、XOR命令で実現できる。すなわち、1を0に、0を1にする計算である。真理値表は左のとおりである。

 GR1が負数のときGR4を1にする。 GR4=1
 GR2が負数のとき、 XOR  GR4, =1 の計算をする。GR4(=1) XOR 1 は0となる。
 GR2が正数のとき、 XOR  GR4, =0 の計算をする。GR4(=1) XOR 0 は1となる。

 GR1が正数のときGR4を0にする。 GR4=0
 GR2が負数のとき、 XOR  GR4, =1 の計算をする。GR4(=0) XOR 1 は1となる。
 GR2が正数のとき、 XOR  GR4, =0 の計算をする。GR4(=0) XOR 0 は0となる。

 このように、GR1が正数のときは LD GR4, =0 、負数のときは LD GR4, =1を行い、次に、GR2が正数のときは XOR GR4, =0 、負数のときは XOR GR4, =1 を計算すれば良い。

 GR1, GR2とも正数として乗算を行い、GR4が1のときだけ計算結果を負数(2の補数)に戻す。


 前へ 目次へ 次へ
 CASL U Copyright © 2003  Hiroshi Masuda

 

 

inserted by FC2 system