パイプライン(後編)

実行パイプライン(FPU)

図1

FPU

単精度(SP:single precision)のために最適化されたパイプラインです。内部は物理的に2つのパイプラインに分かれており、ひとつが加算等の単純演算パイプライン、もうひとつが乗算、除算等の演算パイプラインです。個々のパイプラインはどちらの命令スロットにも割り当てられます。また、浮動少数点の積和演算の場合(融合Mac演算も含む)は、この2つのパイプをつなげて実行します。倍精度演算は単精度パイプラインを利用し、ステージを繰り返して行われます。

また、ALUパイプと浮動小数点パイプは、演算タイミングをずらしてあるので、ALUのパイプラインと並列実行が可能になっています。

FPUは、32の単精度レジスターを含む拡張レジスターファイルをもっています。これらは次のようにみなすことができます。

  • ●16の64ビットダブルワードレジスター、D0-D15
  • ●32の32ビットシングルワードレジスター、S0-S31

このレジスターファイルは4読み出しポート/2書き込みポート(32bit長)として、ダイナミックに異なるパイプラインに割り当てることができます。

Cortex-M7のパイプラインは基本的にインオーダーですが、MACと浮動少数点MACの関係はアウトオブオーダーになっています

実行パイプライン(命令終了)

図2

Retire(終了処理)

Retireステージは命令完了を示します。このステージは特に命令に影響を与えることはありません。Retireステージによって、プログラマーから見える状態を更新します。したがって、Retireステージまでのパイプラインは投機的(確定しない)状態です。すなわち、分岐予測が失敗したりすると、Retireステージでパイプラインは破棄されます。

例外処理が始まった場合や、命令同期化バリア命令(ISB命令(Cortex-A編 第11回参照))等でもパイプラインは破棄されます。

実行パイプライン(プリフェッチユニット)

図3

プリフェッチ

6段パイプラインの中には数えられていませんが、プリフェッチサイクルがあります。この工程は、1サイクルで最大64bitの命令をフェッチします。4x64bitプリフェッチキューがあり、DPUパイプラインから命令プリフェッチを切り離します。プリフェッチユニット(PFU)は、TCMインターフェースを使ってデータを読むことができます。アドレスによって、TCUまたは命令キャッシュコントローラーにリクエストを送ります。

ブランチが発生した場合は、BTAC(下部参照)のルックアップが、プリフェッチに使われます。すなわち、BTACからブランチ情報が戻されます。

割り込みが発生した場合は、PFUによってベクタロードとベクタへの分岐が行われます。

実行パイプライン(Branch Target Address Cache)

分岐先予測と分岐投機

前述しましたが、分岐先予測は条件分岐が成立するかどうかを予測するものです。条件分岐命令が終了しないと分岐先が決定しないため、前もって予測しておくシステムです。条件分岐が成立すると、分岐先の命令を初めからフェッチしに行かないといけませんので、段数の多いパイプラインでは大きな障害になります。そこで、前もって予測しておけば、少しはパイプライン障害のダメージを小さくすることができます。

分岐予測は予測だけで、当たるか外れるかですが、当たっても外れても、命令を実行してしまう機能を分岐投機と呼びます。

分岐予測には動的と静的があります。動的予測はブランチ命令の挙動を見ながら予測する方法で、分岐命令のアドレスをインデックスとするキャッシュのBTAC(Branch Target Address Cache)やBHT(Branch History Table)やBTB(Branch Target Buffer)を用います。静的予測とは、分岐命令の内容にのみ基づいて分岐予測を行う場合や、少し複雑な場合は、コンパイラが分岐命令に付与した情報(ヒントビット等)に基づいて、分岐するかしないかを予測する方式です。

Cortex-M7で分岐先アドレスを予測するには、分岐命令の分岐先のアドレスを格納するキャッシュBTACを使います、BTACを分岐予測機能と並列にアクセスして予測します。

BTAC(Branch Target Address Cache)

BTACとは、分岐命令の分岐先のアドレスを格納するキャッシュです。BTB(Branch Target Buffer)と呼ばれる場合もあります。前述のブランチパイプライン(分岐予測機能)と一緒に使用されます。ブランチターゲットから投機的プリフェッチが行われます。

BTACは、命令アドレスをインデックスとしてアクセスするキャッシュです。条件分岐が成立した場合のアドレスだけを記憶します。コアは、分岐予測と並列してBTACをアクセスし、分岐命令の完了を待たずにBTACから読み出したアドレスを次のアドレスとして命令フェッチを開始します。 BTACのエントリー数(Cortex-M7は64エントリー)にも依存しますが、分岐予測が当たって、かつ、BTACにヒットした場合は、比較的高い確率で正しい分岐先のアドレス発行されます。 命令フェッチの無駄をなくすために、BTACの中ではタグを使った、タグマッチ方式でBTACのヒット/ミスヒットを判断します。

Cortex-M7の分岐予測

64エントリーのBATC(下図がイメージ)を用いて分岐予測します、BTACは1サイクルで実行されます。BTACを指定しない場合は静的分岐予測を行います。

図4

実行パイプライン(ブランチの分割数)

ブランチの種類

ブランチと言っても、ブランチの先のアドレスを決める手段によって、ブランチの種類が分かれます。

  • ・直接ブランチ:オフセット値でブランチ先が決まる
  • ・レジスタブランチ:レジスタの値でブランチ先が決まる
  • ・ロードブランチ:ロードされた値でブランチ先が決まる

直接ブランチ

分岐先がプログラムカウンタの値からのオフセットで決まる分岐命令です。命令が発行(Issue)されるとアドレスが有効になります。

レジスタブランチ

レジスタに格納された値が分岐先となるレジスタ間接分岐です。この場合は、レジスタを読むまでは分岐先が決まらないので、デコードサイクルまたは発行(Issue)サイクルの時点では分岐先の予測は難しい(または、できない)です。

しかし、一般的に、レジスタ間接分岐が使われる場合は、サブールチンからの戻り(C言語だと関数からの戻り)です。サブルーチン(関数)が呼ばれるときにアドレスがR14(LR)に格納されて分岐します。R14(LR)はスタックされますので、サブルーチンから戻る時は、R14(LR)の値で戻れば、容易に戻ることができます。すなわち分岐予測は簡単にできることになります。ただし、すべてのサブルーチンが、この場合に当てはまるわけではありません。

ロードブランチ

ロードパイプラインでロードされた値でブランチ先が決まります。