今回は値を比較する命令を見てみたいと思います。値を比較というと、C言語では「if文」が頭を過ぎるでしょう。人間にとって数と数を比較することは簡単なことですが、機械的に比較を実現するにはどういう計算が必要なのでしょうか。
それでは、実際にどのように値と値を比較しているのか見てみたいと思います。
比較命令
比較命令は、2つの異なる数値を比較し、大きい、小さい、そして同じかどうかを判定する命令です。
また、比較命令は「算術比較」と「論理比較」の2種類の命令が用意されていて、算術と論理で数値の扱いに違いがあります。
算術比較
名称 | オペコード | 第1オペランド | 第2オペランド | 第3オペランド
|
ComPare Arithmetic | CPA | レジスタ | アドレス or レジスタ | ---
|
レジスタ | アドレス | レジスタ
|
使用例1: CPA GR0, A
汎用レジスタ
GR0のデータとメモリ
A番地のデータを算術比較せよ。
使用例2: CPA GR0, 1
汎用レジスタ
GR0のデータとメモリ
1番地のデータを算術比較せよ。
使用例3: CPA GR0, 1, GR1
汎用レジスタ
GR0のデータとメモリ
汎用レジスタGR1のデータ+1番地のデータを算術比較せよ。
使用例4: CPA GR0, GR1
汎用レジスタ
GR0のデータと汎用レジスタ
GR1のデータを算術比較せよ。
論理比較
名称 | オペコード | 第1オペランド | 第2オペランド | 第3オペランド
|
ComPare Logical | CPL | レジスタ | アドレス or レジスタ名 | ---
|
レジスタ | アドレス | レジスタ
|
使用例1: CPL GR0, A
汎用レジスタ
GR0のデータとメモリ
A番地のデータを論理比較せよ。
使用例2: CPL GR0, 1
汎用レジスタ
GR0のデータとメモリ
1番地のデータを論理比較せよ。
使用例3: CPL GR0, 1, GR1
汎用レジスタ
GR0のデータとメモリ
汎用レジスタGR1のデータ+1番地のデータを論理比較せよ。
使用例4: CPL GR0, GR1
汎用レジスタ
GR0のデータと汎用レジスタ
GR1のデータを論理比較せよ。
比較方法
比較は、比較する2値を引き算し、計算結果の符号の種類を見ることで実現しています。
例えば、AとBという値を比較する場合、まず、A - Bを実行します。その結果、AがBより小さければ答えはマイナス値になり、Bが大きければ答えはプラス値になり、そしてAとBが同じなら答えがゼロになります。
- A > B ・・・A - B の結果、答えの符号はプラス
- A < B ・・・A - B の結果、答えの符号はマイナス
- A = B ・・・A - B の結果、答えがゼロ(ゼロは符号なし)
ここで、
「A ≧ B」はどうするのか?という疑問が湧いてきますが、以下のように考えます。
「A > B または A = B」
このように考えることで解決できます。
比較時のオペランドの対応関係
オペランドの対応関係は、第2オペランドに対して第1オペランドがどのくらいの大きさであるか、と捉えます。
例えば、
CPA GR0, GR1 のオペランドはどのような対応関係で比較しているのかというと...
GR1(後) に対して GR0(前) が、どのくらいの大きさの値かを見ています。
CPA GR0, GR1 ・・・GR1に対してGR0が、大きいのか小さいのか、または同じなのかを比較
算術比較・論理比較の違い
算術比較と論理比較の違いは、マイナスの数を考慮するか、しないかというところにあります。
算術比較・論理比較は、以下のような違いがあります。
例1: GR0の値が-1 、GR1の値が0のときの比較
① 算術比較の場合
GR0 < GR1 --> SF =
1 になります
算術比較の場合、SFが1に変化します。
② 論理比較の場合
GR0 > GR1 --> SF =
0 のままです
算術比較の場合、SFが1に変化しません。
それでは、なぜ、このように結果が異なるのか見てみましょう。
なぜ算術比較・論理比較の結果フラグに違いがあるのか
算術比較・論理比較においてフラグに違いがある理由は、算術と論理では16進数の扱いに違いがあることが関係しているためです。
ここで、10進数「-1」は16進数「FFFF」ですが、この16進数「FFFF」は10進数「65535」でもあります。
- -1 = (FFFF)16
- 65535 = (FFFF)16
CPAは、(FFFF)
16を
-1として
CPLは、(FFFF)
16を
65535として扱います。
つまり、CPAとCPLでは以下のような違いがあります。
例2: GR0の値が(FFFF)16 、GR1の値が0のときの比較
① 算術比較の場合
大小関係が
GR0 < GR1(
-1 < 0) ・・・
SF = 1
(FFFF)
16は、10進数で-1であるため、SFが1に変化します。
② 論理比較の場合
大小関係が
GR0 > GR1(
65535 > 0) ・・・
SF = 0
(FFFF)
16は、10進数で65535であるため、SFが0のまま変化しません。
以上のように、似たような比較命令でも真逆の結果になってしまうのですね。
その前に、なぜ、-1と65535が同じになってしまうのか?それについては「
16進数のマイナスの数」の記事も参考にしてみてください。
比較の仕組み
コンピュータにおいて比較とは、比較する値と値の減算をハードウェア上で行うことによって実現しています。
すなわち、
「第1オペランド - 第2オペランド」 を行いフラグレジスタがどう変化したのかを見て判断しています。
【比較の方法】
第1オペランド ― 第2オペランド
ここで、
「CPA GR0, GR1」 のニーモニックを例に比較してみましょう。
まず、COMET2は、比較のために減算(
GR0 - GR1 )を行います。
その結果...以下①~③のようになります。
① GR0 < GR1になった場合
GR0 < GR1ということは、GR0がGR1より小さいということであり、減算の結果はマイナスのため
SF = 1 になります。
【フラグレジスタ】
② GR0 = GR1になった場合
GR0 = GR1ということは、GR0とGR1が同じということであり、減算の結果はゼロのため
ZF = 1 になります。
【フラグレジスタ】
③ GR0 > GR1になった場合
GR0 > GR1ということは、GR0がGR1より大きいということであり、減算の結果はプラスのため
SF = 0、ZF = 0 になります。
【フラグレジスタ】
このように、大小の比較は、
減算によって変化するフラグレジスタの状態を参照することで実現しています。尚、比較命令を使う場合は、OF(オーバーフローフラグ)は気にしなくても問題ありません。
分岐命令
分岐命令は、通常、フラグレジスタを変化させる命令の後に使用する命令です。
分岐命令は、フラグレジスタの内容を参照し、ラベルで指定されら行に移動する機能を持っていて、フラグレジスタを変化させる命令の後に記述します。
実は、CASL2にはフラグレジスタを変化させる命令と変化させない命令の2種類が存在します。通常、分岐命令は、フラグレジスタを変化させる命令の後の行に記述して使用します。
どの命令がフラグレジスタを変化させ、どの命令がフラグレジスタを変化させないのか、については「
CASL2でフラグレジスタを変化させる命令の種類」の記事を参考にしてみてください。
分岐命令の使用に慣れない内は、比較命令とセットで考えることで、解りやすいでしょう。
正分岐
名称 | オペコード | 第1オペランド | 第2オペランド
|
Jump on PLus | JPL | ラベル | ---
|
アドレス | レジスタ
|
使用例1: JPL LOOP
フラグレジスタの
ZF = 0 かつ
SF = 0 のとき、
ラベルLOOPの行に移動せよ。
使用例2: JPL 1, GR1
フラグレジスタの
ZF = 0 かつ
SF = 0 のとき、メモリ
汎用レジスタGR1のデータ+1番地の行に移動せよ。
通常、使用例1のような使い方をします。
SF = 0 かつ ZF = 0。つまり、0以外でプラスのとき指定した行(アドレス)に分岐、という意味です。
※ 数値がプラスのときに分岐するため、値が0の時には分岐しません。しかし、ゼロという数字も符号が有りません。そこで、ゼロとマイナス数を区別するために ZF = 0 (比較結果がゼロでないとき)という条件も含んで判定されます。
負分岐
名称 | オペコード | 第1オペランド | 第2オペランド
|
Jump on MInus | JMI | ラベル | ---
|
アドレス | レジスタ
|
使用例1: JMI LOOP
フラグレジスタの
SF = 1のとき、
ラベルLOOPの行に移動せよ。
使用例2: JMI 1, GR1
フラグレジスタの
SF = 1のとき、メモリ
汎用レジスタGR1のデータ+1番地の行に移動せよ。
通常、使用例1のような使い方をします。
SF = 1。つまり、符号が付いたとき(マイナスのとき)に、指定した行(アドレス)に分、という意味です。
零分岐
名称 | オペコード | 第1オペランド | 第2オペランド
|
Jump on ZEro | JZE | ラベル | ---
|
アドレス | レジスタ
|
使用例1: JZE LOOP
フラグレジスタの
ZF = 1のとき、
ラベルLOOPの行に移動せよ。
使用例2: JZE 1, GR1
フラグレジスタの
ZF = 1のとき、メモリ
汎用レジスタGR1のデータ+1番地の行に移動せよ。
通常、使用例1のような使い方をします。
ZF = 1。つまり、0のときに、指定した行(アドレス)に分岐、という意味です。
非零分岐
名称 | オペコード | 第1オペランド | 第2オペランド
|
Jump on Non Zero | JNZ | ラベル | ---
|
アドレス | レジスタ
|
使用例1: JNZ LOOP
フラグレジスタの
ZF = 0のとき、
ラベルLOOPの行に移動せよ。
使用例2: JNZ 1, GR1
フラグレジスタの
ZF = 0のとき、メモリ
汎用レジスタGR1のデータ+1番地の行に移動せよ。
通常、使用例1のような使い方をします。
ZF = 0。つまり、0でないのときに、指定した行(アドレス)に分岐、という意味です。
オーバーフロー分岐
名称 | オペコード | 第1オペランド | 第2オペランド
|
Jump on OVerflow | JOV | ラベル | ---
|
アドレス | レジスタ
|
使用例1: JOV LOOP
フラグレジスタの
OF = 1のとき、
ラベルLOOPの行に移動せよ。
使用例2: JOV 1, GR1
フラグレジスタの
OF = 1のとき、メモリ
汎用レジスタGR1のデータ+1番地の行に移動せよ。
通常、使用例1のような使い方をします。
OF = 1。つまり、数値がオーバーフローしたとき、指定した行(アドレス)に分岐、という意味です。
無条件分岐
名称 | オペコード | 第1オペランド | 第2オペランド
|
unconditional JUMP | JUMP | ラベル | ---
|
アドレス | レジスタ
|
使用例1: JUMP LOOP
ラベルLOOPの行(アドレス)に移動せよ。
使用例2: JUMP 1, GR1
メモリ
汎用レジスタGR1のデータ+1番地の行に移動せよ。
通常、使用例1のような使い方をします。
フラグレジスタは関係なしに、指定した行(アドレス)に分岐、という意味ですね。
分岐命令は、CPA・CPL命令とセットで使用したり、フラグレジスタを変化させる命令の直前に記述されていることが多いです。
最後に
今回は、比較命令・分岐命令ということで紹介いたしました。
分岐命令の動作に慣れていない内は解り難いと感じますが、実際に手を動かしている内に理解できるようになってきますから、頑張ってシミュレータでプログラムを組んでみてください。
続きはまた次回にご期待を!