CASL U - 乗算の計算 |
a×bのような乗算を計算する副プログラムとして作成する。データa, bはそれぞれGR1, GR2に格納しておき、副プログラムを呼び出す。計算結果はGR0に格納することとする。もちろん、データa,
bは整数である。
方法は2通り考えられる。
@ データa(GR1)をデータb(GR2)回、加算する。
A シフト命令を利用する。
方法@
手順は次のとおりである。
- GR0を0で初期化する。
- データa(GR1)をGR0に加算する。
- データb(GR2)から1を減算する。
- データb(GR2)が0でなければ 2. へ移動する。0ならば次へ。
- 呼出し元へ戻る。
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演算の後、ジャンプ命令で分岐すれば良い。
手順は次のとおりである。
- GR0を0で初期化する。
- GR3にデータb(GR2)を記憶する。
- GR3の最下位ビットを調べる。(1とAND演算する。)
- 0であれば 6. へ移動する。0でなければ次へ。
- データa(GR1)をGR0に加算する。
- データa(GR1)を1ビット左シフトする。
- データb(GR2)を1ビット右シフトする。
- データb(GR2)が0でなければ 2. へ移動する。0ならば次へ。
- 呼出し元へ戻る。
ポイントは、データ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,2017 Hiroshi Masuda |