web-dev-qa-db-ja.com

ジャンプターゲットアドレスとブランチターゲットアドレスの計算方法

アセンブリ言語が初めてです。 [〜#〜] mips [〜#〜]アーキテクチャについて読んでいたのですが、Jump Target AddressおよびBranch Target Addressそれぞれの計算方法それら。

30
Fahad Uddin

1。支店住所の計算

MIPSの分岐命令には、次の命令を決定するための16ビットオフセットしかない。次の命令を決定するために、この16ビット値にレジスタを追加する必要がありますが、このレジスタは実際にはアーキテクチャによって暗示されています。 PCはフェッチサイクル中に更新され(PC + 4)、次の命令のアドレスを保持するため、PCレジスタです。

(以下の図では、PCは分岐命令自体ではなく、分岐遅延スロットのアドレスです。しかし、本文では、PC + 4と言います。)

また、分岐距離を()分岐命令の後の命令からの-2^15 to +2^15 - 1命令に制限します。ただし、ほとんどのブランチはローカルであるため、これは実際の問題ではありません。

だからステップバイステップ:

  • 16ビットオフセット値を符号拡張して、その値を保持します。
  • 結果の値に4を掛けます。この背後にある理由は、あるアドレスを分岐し、PCが既にワード境界に整列している場合、即値もワード境界に整列する必要があるためです。ただし、下位2ビットを強制的に00にして無駄にするため、すぐにWordをアラインすることは意味がありません。
  • これで32ビットのアドレスができました。この値をPC + 4に追加すると、それがブランチアドレスになります。

Branch address calculation


2。ジャンプアドレスの計算

ジャンプ命令の場合、Mipにはジャンプ位置を決定するための26ビットしかありません。また、ジャンプはMIPSのPCに関連しています。分岐と同様に、即時ジャンプ値はワード境界で整列させる必要があります。したがって、26ビットのアドレスに4を掛ける必要があります。

ステップバイステップ:

  • 26ビット値に4を掛けます。
  • PC + 4値を基準にしてジャンプしているため、ジャンプアドレスの左側にPC + 4値の最初の4ビットを連結します。
  • 結果のアドレスはジャンプ値です。

つまり、PC + 4の下位28ビットを、フェッチされた命令の下位26ビットを2ビット左にシフトして置き換えます。

enter image description here

ジャンプは、必ずしもブランチ自体ではなく、ブランチ遅延スロットに相対的な領域です。上の図では、ジャンプ計算の前に、PCがすでに分岐遅延スロットに進んでいます。 (クラシック-RISC 5ステージパイプラインでは、ジャンプがデコードされるのと同じサイクルでBDがフェッチされたため、PC + 4の次の命令アドレスは、ジャンプとブランチで既に使用可能であり、ジャンプ自身のアドレスとの相対計算はその住所を保存するために余分な作業が必要です。)

出典: Bilkent University CS 224コーススライド

65

通常、アセンブラー(またはリンカー)が計算を正しく行うので、それらの計算について心配する必要はありません。あなたには小さな機能があるとしましょう:


func:
  slti $t0, $a0, 2
  beq $t0, $zero, cont
  ori $v0, $zero, 1
  jr $ra
cont:
  ...
  jal func
  ... 

上記のコードを命令のバイナリストリームに変換するときに、アセンブラー(またはオブジェクトファイルに最初にアセンブルした場合はリンカー)は、関数がメモリ内のどこにあるかを決定します(ここでは、位置独立コードを無視しましょう)。メモリ内の場所は通常、ABIで指定されるか、シミュレータを使用している場合に与えられます( [〜#〜] spim [〜#〜] でコードをロードします- 0x400000 -リンクにはプロセスの適切な説明も含まれていることに注意してください)。

SPIMケースについて説明しており、関数が最初にメモリ内にあると仮定すると、slti命令は0x400000に、beq0x400004に、というように続きます。 。これでもうすぐです! beq命令の場合、分岐先アドレスcont0x400010)のアドレスです。 MIPS命令リファレンス 次の命令に関連する16ビット符号付き即値としてエンコードされていることがわかります(すべての命令は4バイト境界のアドレスに常駐する必要があるため、4で除算されます)。

あれは:

Current address of instruction + 4 = 0x400004 + 4 = 0x400008
Branch target = 0x400010
Difference = 0x400010 - 0x400008 = 0x8
To encode = Difference / 4 = 0x8 / 4 = 0x2 = 0b10

beq $t0, $zero, contのエンコード

0001 00ss ssst tttt iiii iiii iiii iiii
---------------------------------------
0001 0001 0000 0000 0000 0000 0000 0010

ご覧のとおり、-0x1fffc .. 0x20000バイト以内で分岐できます。何らかの理由でさらにジャンプする必要がある場合は、トランポリンを使用できます(指定された制限内に配置された実際のターゲットへの無条件ジャンプ)。

ジャンプターゲットアドレスは、ブランチターゲットアドレスとは異なり、absoluteを使用してエンコードされますアドレス(4で割る)。命令のエンコードではオペコードに6ビットが使用されるため、アドレスには26ビットしか残りません(最後の2ビットが0になると事実上28ビット)、したがって、PCレジスタの4ビットの最上位ビットがアドレスの形成時に使用されます( 256 MBの境界を越えてジャンプする場合を除き、重要ではありません)。

上記の例に戻ると、jal funcのエンコードは次のとおりです。

Destination address = absolute address of func = 0x400000
Divided by 4 = 0x400000 / 4 = 0x100000
Lower 26 bits = 0x100000 & 0x03ffffff = 0x100000 = 0b100000000000000000000

0000 11ii iiii iiii iiii iiii iiii iiii
---------------------------------------
0000 1100 0001 0000 0000 0000 0000 0000

これをすぐに確認し、これを使用してさまざまな指示をいじることができます オンラインMIPSアセンブラー iに遭遇しました(たとえば、sltiなど、すべてのオペコードをサポートしていないことに注意してくださいこれをsltに変更しました):

00400000: <func>    ; <input:0> func:
00400000: 0000002a  ; <input:1> slt $t0, $a0, 2
00400004: 11000002  ; <input:2> beq $t0, $zero, cont
00400008: 34020001  ; <input:3> ori $v0, $zero, 1
0040000c: 03e00008  ; <input:4> jr $ra
00400010: <cont>    ; <input:5> cont:
00400010: 0c100000  ; <input:7> jal func
19
user786653

このような小さな関数の場合、分岐命令の下の命令から、ターゲットまでのホップ数を手動で数えることができます。後方に分岐する場合、そのホップ数は負になります。その番号が16ビットすべてを必要としない場合、ホップ番号の最上位の左側のすべての番号について、それらを1にします。ホップ番号が正の場合、それらをすべて0にします。これにより、ほとんどの場合、余分な演算が大幅に節約されます。

  • クリス
0
kiwicomb123