アセンブリ言語 CASL2 加算・減算命令
アセンブリ言語CASL2では足し算と引き算の方法が、3種類づつもあるのをご存じですか?
なぜ、足し算や引き算みたいな単純な計算に、3種類も命令が存在するのか。
今回は、加算命令と減算命令について情報を共有したいと思います。
加算命令
CASL2では加算命令は「算術加算」と「論理加算」の2種類あります。
算術加算
名称 | オペコード | 第1オペランド | 第2オペランド | 第3オペランド |
ADD Arithmetic | ADDA | レジスタ | アドレス or レジスタ | --- |
レジスタ | アドレス | レジスタ |
使用例1: ADDA GR0, A
汎用レジスタGR0の値とメモリA番地の値を加算して、汎用レジスタGR0に転送(ロード)せよ。
使用例2: ADDA GR0, 1
汎用レジスタGR0の値とメモリ1番地の値を加算して、汎用レジスタGR0に転送せよ。
使用例3: ADDA GR0, 1, GR1
汎用レジスタGR0の値とメモリ「汎用レジスタGR1の値 + 1」番地の値を加算して、汎用レジスタGR0に転送せよ。
使用例4: ADDA GR0, GR1
汎用レジスタGR0の値と汎用レジスタGR1の値を加算して、汎用レジスタGR0に転送せよ。
論理加算
名称 | オペコード | 第1オペランド | 第2オペランド | 第3オペランド |
ADD Logical | ADDL | レジスタ | アドレス or レジスタ | --- |
レジスタ | アドレス | レジスタ |
使用例1: ADDL GR0, A
汎用レジスタGR0の値とメモリA番地の値を加算して、汎用レジスタGR0に転送(ロード)せよ。
使用例2: ADDL GR0, 1
汎用レジスタGR0の値とメモリ1番地の値を加算して、汎用レジスタGR0に転送せよ。
使用例3: ADDL GR0, 1, GR1
汎用レジスタGR0の値とメモリ「汎用レジスタGR1の値 + 1」番地の値を加算して、汎用レジスタGR0に転送せよ。
使用例4: ADDL GR0, GR1
汎用レジスタGR0の値と汎用レジスタGR1の値を加算して、汎用レジスタGR0に転送せよ。
実は、算術加算と論理加算を実行すると同じ計算結果になります。
それでは算術加算と論理加算はいったい何が違うのでしょうか。
算術加算・論理加算の違い
算術加算・論理加算の違いは、フラグレジスタの示す値で判断することができます。
以下に具体的例を示します。
例1:5 + (-1) の計算
① ADDA(算術加算)で計算した場合1 | ADD | START | |
2 | LAD | GR0, 5 | |
3 | LAD | GR1, -1 | |
4 | ADDA | GR0, GR1 | |
5 | RET | ||
6 | END |
答え: (0004)16
② ADDL(論理加算)で計算した場合
1 | ADD | START | |
2 | LAD | GR0, 5 | |
3 | LAD | GR1, -1 | |
4 | ADDL | GR0, GR1 | |
5 | RET | ||
6 | END |
答え: (0004)16
①と②の答えはどちらも4です。また、レジスタにも全く同じ値が格納されています。
一見するとADDA(算術加算)とADDA(算術加算)の違いがないようですが、実はフラグレジスタの状態に違いがあります。
①はオーバーフローフラグが0のままであるのに対し、②はオーバーフローフラグが1というな違いがあります。
①・・・OF(オーバーフローフラグ)= 0
【フラグレジスタ】ZF | SF | OF |
0 | 0 | 0 |
②・・・OF = 1
【フラグレジスタ】ZF | SF | OF |
0 | 0 | 1 |
算術加算・論理加算は同じ答えでもフラグが違う
算術加算・論理加算においてフラグに違いがある理由は、算術と論理では16進数の扱いに違いがあるためです。
ここで、10進数「-1」は16進数「FFFF」ですが、この16進数「FFFF」は10進数「65535」でもあります。
- -1 = (FFFF)16
- 65535 = (FFFF)16
どちらも同じFFFFであるため、算術加算・論理加算ともに同じ答えを導き出してしまうのです。
しかし、-1と65535の区別を行わないと、加算する際にCOMET2が混乱してしまいます。
COMET2さん「このFFFFは -1なの? 65535なの? わかるか!」
このような理由から、16進数FFFFはADDAにおいては-1としてADDLにおいては65535として扱う決まりになっています。
- ADDAのとき
・・・(FFFF)16を-1として扱う - ADDLのとき
・・・(FFFF)16を65535として扱う
このように、似たような命令を2種類用意することで、(FFFF)16の区別を行いたいということなんですね。
当然、16ビットにおいて65535に4を加えれば数値がオーバーフローしてしまうのでオーバーフローフラグが1になります。
それでは、なぜ、16進数では-1と65535が同じ表現になってしまうのか?それについては16進数の性質が関係しています。
減算命令
減算命令も「算術減算」と「論理減算」に分けることができます。
加算命令と同じく算術と論理の2種類の命令を用意することで、数値の扱い方に違いを持たせるためです。
算術減算
名称 | オペコード | 第1オペランド | 第2オペランド | 第3オペランド |
SUBtract Arithmetic | SUBA | レジスタ | アドレス or レジスタ | --- |
レジスタ | アドレス | レジスタ |
使用例1: SUBA GR0, A
汎用レジスタGR0の値とメモリA番地の値を減算して、汎用レジスタGR0に転送(ロード)せよ。
使用例2: SUBA GR0, 1
汎用レジスタGR0の値とメモリ1番地の値を減算して、汎用レジスタGR0に転送せよ。
使用例3: SUBA GR0, 1, GR1
汎用レジスタGR0の値とメモリ「汎用レジスタGR1の値 + 1」番地の値を減算して、汎用レジスタGR0に転送せよ。
使用例4: SUBA GR0, GR1
汎用レジスタGR0の値と汎用レジスタGR1の値を減算して、汎用レジスタGR0に転送せよ。
論理減算
名称 | オペコード | 第1オペランド | 第2オペランド | 第3オペランド |
SUBtract Logical | SUBL | レジスタ | アドレス or レジスタ | --- |
レジスタ | アドレス | レジスタ |
使用例1: SUBL GR0, A
汎用レジスタGR0の値とメモリA番地の値を減算して、汎用レジスタGR0に転送せよ。
使用例2: SUBL GR0, 1
汎用レジスタGR0の値とメモリ1番地の値を減算して、汎用レジスタGR0に転送せよ。
使用例3: SUBL GR0, 1, GR1
汎用レジスタGR0の値とメモリ「汎用レジスタGR1の値 + 1」番地の値を減算して、汎用レジスタGR0に転送せよ。
使用例4: SUBL GR0, GR1
汎用レジスタGR0の値と汎用レジスタGR1の値を減算して、汎用レジスタGR0に転送せよ。
算術減算・論理減算に関しても、加算命令と同じように、OF(オーバーフローフラグ)の値の違いによって区別できます。
例2:0 - 5 の計算
- SUBA(算術減算)で計算
・・・マイナスの数も扱える(-32768~32767の範囲)ため、OFは0のまま変化しない。 - SUBL(論理減算)で計算
・・・0未満の数字を扱えない(0~65535の範囲)ため、OFが1に変化する。
ロードアドレス命令を用いた加算・減算
ロードアドレス命令は、指標修飾を利用することで加算・減算を行うことができます。
ロードアドレス命令の利点としてメモリにデータを設定しないため、加算・減算命令を使用するときと比べ、1語分の節約につながります。
- ロードアドレス命令は算術加算・論理加算命令と比べて1語分の節約になる。
ロードアドレス命令については「ロードアドレス命令」の記事を参考にしてください。
しかし、指標修飾にGR0を使用できないため、GR0に入っている値に加算や減算ができないところが難点といえます。
ロードアドレス命令を用いた加算
まず、ロードアドレス命令で加算する場合を見てみます。
例3: GR1の値に1を加算- LAD GR1, 1, GR1
このように第1オペランドと第3オペランドに同じレジスタを設定します。
ロードアドレス命令を用いた減算
次に、減算する場合を見てみます。
例4: GR1の値から1を減算- LAD GR1, -1, GR1
通常の加算・減算命令と異なる動作をする
LAD命令を用いた加算・減算は、通常の加算命令や減算命令とはフラグレジスタの動作が異なります。ここで、ADDA、ADDL、そしてLAD命令で加算した場合のフラグレジスタの動作を見てみましょう。
例5: GR1の値が(FFFF)16のとき、ADDA、ADDL、LAD命令で1を加算する場合フラグレジスタはどうなる?
① ADDA命令で加算した場合
- ADDA GR1, =1
【フラグレジスタ】
ZF | SF | OF |
1 | 0 | 0 |
ADDA命令を用いた加算の場合、1 + (-1)を行っており、答えが0になるため、ZFが1になります。
② ADDL命令で加算した場合
- ADDL GR1, =1
【フラグレジスタ】
ZF | SF | OF |
1 | 0 | 1 |
ADDL命令を用いた加算の場合、65535((FFFF)16)を超えるためOFが1になります。
また、COMET2は、16ビットなので、65535 + 1を行うと65536にはならず元に戻って答えが0になる(1 + (-1) と結果は同じ)ため、①のADDA命令同様にZFが1になります。
③ LAD命令で加算した場合
- LAD GR1, 1, GR1
【フラグレジスタ】
ZF | SF | OF |
1 | 0 | 0 |
LAD命令を用いた加算の場合フラグレジスタに変化はありません。
さいごに
算術加算・論理加算、ロードアドレス命令を使用した加算と、加算する命令が3種類も存在しますが、それぞれの性質を理解した上で使用するようにしてください。
それでは次回にお会いしましょう。