ブランチは条件を考慮します。ただし、条件を許可すると、命令のビット数が増えます。したがって、分岐のアドレスは2 ^ 16ビットのみであり、2 ^ 15-1命令だけ逆方向または2 ^ 15命令だけ前方に分岐できます。
ジャンプは無条件であり、条件を省略して保存したビットはアドレスに使用できます。ジャンプは26ビットアドレスを許可するため、分岐よりもコード内でさらにジャンプできます。条件付きでないことを犠牲にして。
分岐(b
)はPC相対変位を使用し、ジャンプ(j
)は絶対アドレスを使用します。この区別は、位置に依存しないコードにとって重要です。また、ジャンプのみが間接制御転送に使用できます(jr
、レジスタ値を使用)。
すでに述べたように、ブランチはビットが少なく、範囲が短く、相対的です。ジャンプはより多くのビットを持ち、絶対的です。
この例を取ります
b l0
nop
beq $0,$1,l1
nop
j l2
nop
l0: .Word 0,0
l1: .Word 0,0
l2: .Word 0,0
あなたはこれを手に入れます
00000000 <l0-0x1c>:
0: 10000006 b 1c <l0>
4: 00000000 nop
8: 10010006 beq zero,at,24 <l1>
c: 00000000 nop
10: 0800000b j 2c <l2>
14: 00000000 nop
18: 00000000 nop
0000001c <l0>:
...
00000024 <l1>:
...
0000002c <l2>:
...
今、他の答えが言及していないかもしれないのは、無条件のbranchが、少なくともgnuアセンブラーによって、等しい場合は同じレジスターのブランチとしてエンコードされるということです。 mipsには無条件の分岐はありません。等しい場合は分岐があり、等しくない場合は分岐があります。
上記のジャンプでは、ワードアドレスである0xBを使用しています。0xB* 4 = 0x2C宛先のアドレスです。または、instruction_address + 4 +(signed_offset * 4)を使用して、宛先アドレスを取得します。
ジャンプにjの代わりにブランチにエイリアスbを使用すると、位置に依存しないコードが作成されます。ジャンプはエイリアスではありませんが、ジャンプする代わりにブランチを使用する方がよいため、移動する場合は再リンクする必要はありません。あなたが純粋主義者なら、$ 0、$ 0、labelで実際の命令を使用するか、$ 4、$ 4、labelで任意のレジスタを選択できます。レジスタ0が特別で高速であることは、より良い選択です。
MIPSのジャンプと無条件分岐は同じではありません。
分岐命令とジャンプ命令の両方がプログラムカウンタレジスタにデータを書き込むため、次のフェッチサイクルで、プログラムメモリ内の次の命令の代わりに異なる命令がフェッチされます。その意味で、彼らは同じタイプの操作を実行します。
異なる点は、分岐が条件付きであるということで、特定の条件が満たされた場合に実行される次の命令のみを変更します。これは、if
ステートメントの実行コードの違いまたは関数の呼び出しによって説明できます。
if (a == 0) {
a = 1
}
setAtoOne()
if
ステートメントは、a = 1
の場合にのみa == 0
を設定する命令にジャンプします。関数は、関係なくその命令にジャンプします。
この場合、条件が常に真であるブランチについて話しています。それはただの別の書き方です
beq $zero, $zero, (int)offset
$ zeroは常に$ zeroに等しいため、常に指定されたオフセットに分岐します。 if文のようなものです
if (true) { a = 1 }
分岐命令とジャンプ命令には別の違いがあります。ジャンプ命令は、PCに設定される絶対アドレスを指定しますが、分岐命令はプログラムカウンタのアドレスをオフセットします。
PC = 32-bit address # Jump
PC += 16-bits lower
実際には、これは厳密には真実ではありません。絶対アドレスとオフセットを使用してアセンブリを記述しますが、ジャンプとブランチの両方で、オフセットにコンパイルされます。これが、jr
命令へのジャンプを使用することを期待して、メモリ内の任意の場所にジャンプまたはブランチできない理由です。これは、MIPSの基本設計、固定長の1ワード命令のためです。
すべてのMIPS命令の長さは1ワード(4バイト/ 32ビット)です。これらには、命令の実行に必要な他の情報とともに6ビットの命令のID(op-codeと呼ばれる)が含まれています。これは、レジスタのIDまたは「即時」値、基本的に命令でエンコードされた整数です。
MIPSのメモリの各バイトには、0x00000000
-0xFFFFFFFF
の間にアドレスがあります。これらのバイトの1つに到達するには、アドレスを指定する必要があります。運がよければ、レジスタにアドレスを保存して、ただjr
して、すでにレジスタに保存されているアドレスを使用します。しかし、そうではありません。
これは問題になり、命令用に32ビットしかないため、その範囲内のアドレスを指定するためにすべてのビットが必要になります。また、プロセッサが命令を識別するために使用する6ビットを放棄する必要がありました。これで26ビットが残りました。
さらに悪いことに、分岐するときに、条件に対して比較する2つのレジスタを指定するために10ビットを追加する必要があります。解決策は、オフセットを使用することです。
アドレス0x12345678
にいて、メモリj 0x1234567c
の次のアドレスへの無条件ジャンプを実行しているとしましょう。これがアセンブリコードです。これがどのようにマシンコードに変換され、実行されるかを示します。
最初に少しチート。命令は1ワード(4バイト)であることがわかっており、MIPSでは、命令はワード境界内になければならないことが指定されています。これは、すべての命令が4バイト離れたアドレスを持っていることを意味し、これはバイナリ表現で常に00で終わることを意味します。素晴らしい、これらの2つの意味のない部分を削ることができます。最初の6頭も剃りますが、心配する必要はありません。後で取り戻します。
jump 0001 0010 0011 0100 0101 0110 0111 1100
jump 00010010 0011 0100 0101 0110 0111 11000000 1000 1000 1101 0001 0101 1001 1111 #in machine code # jump op = 0000 10
00 1000 1101 0001 0101 1001 1111
0000 0000 1000 1101 0001 0101 1001 1111 # extend >> 6
0000 0010 0011 0100 0101 0110 0111 1100 # << 2
0001 0010 0011 0100 0101 0110 0111 1000
1111 0000 0000 0000 0000 0000 0000 0000
AND
0001 0000 0000 0000 0000 0000 0000 0000
この結果を取得して、OR命令整数で
0001 0000 0000 0000 0000 0000 0000 0000
0000 0010 0011 0100 0101 0110 0111 1100
OR
0001 0010 0011 0100 0101 0110 0111 1100
16進数で0x1234567c
であり、どこに行きたいのか、ここにジャンプします。これが、現在の命令から256MB(2 ^ 28ビット)以上離れてジャンプできない理由です(レジスタjr
の値にジャンプしない限り)
ブランチについても同じ基本的な考え方が当てはまりますが、比較するレジスタが2つあるため(10ビットが必要です)、オフセットに使用できるのは16ビットのみであるため、ブランチでジャンプできない理由があります。
ループを実装し、条件付き割り当てを実行するために、プロシージャ内で分岐を使用することがほとんどなので、一般にこれは問題ありません。
これはすべて、MIPSアーキテクチャの設計の結果です。分岐とジャンプの唯一の違いが条件付きアスペクトであり、「無条件」分岐が無条件ジャンプと同じように動作する命令を持つことは完全に可能でした。