実行パイプライン

実行パイプライン(ALU)

図4

ALU

この実行パイプラインでは、データ処理命令を実行します。具体的には算術演算、論理演算、飽和演算、ビット操作命令、パッキングなどです。

32ビットのALUが2つ搭載されています。まったく同じALUが2つ搭載されているのではなく、メインとサブの関係になります。SIMD命令等はメインALUで演算され、サブでは演算されません、その為、前述したデュアル発行ができません。

シフタは各ALUに1つづつ、計2つ搭載されていますが、使い方が若干異なります。メインのALUは、シフト演算と単純演算を2つのステージで連続して行ない、サブのALUは、1ステージでシフトか単純演算のどちらかを行います。

Thumb2命令には、シフトとその他の演算などを組み合わせた命令があり、このような場合、シフト演算を行なってから単純演算をする必要があります。その為、2つのシフタは実行タイミングを遅らせてあります。一方、シンプルシフトであれば同時発行、同時実行が可能です。

実行パイプライン(MAC)

図5

MAC

シングルMACパイプラインです。この実行パイプラインでは、主に掛け算と累積算や積和演算を実行します。

シングルMACパイプラインが32bit x 32bit + 64bit → 64bit 演算を2サイクルで実行、そして、結果的に1サイクル1MACのスループットを実現しています。2段構成ですので、最初のサイクルで掛け算を演算して、後段で加算(累積算)します。

図6

Cortex-M7とCortex-M4のISA(Instruction Set Architecture)は同じArmv7-Mです。したがって、積和演算には、パックデータ方式を採用していることになります。パックデータとは32ビットデータを一旦16ビットに分けてから演算して、その結果をパックして32ビットデータに戻します。(上図参照)。これを実現するためには、Macの内部は、4つの16x16符号付乗算器の配列から構成されなければなりません。

実行パイプライン(除算器)

除算器

「ブロック図(第1回参照)」の章で述べましたように、DPU(データプロセスユニット)の中には、割り算ユニットが搭載されています。このユニットは、SDIV(符号付割り算)とUDIV(符号無割り算)をサポートします。

オペランドの内容を判断して早期終了する機能付きです。割る数と割られる数の大きさが近いと実行サイクルも短くなります。最短で2サイクル、最長で12サイクルかかります。

割り算はALUパイプラインのサイクルの中で実行されます。そして、除算器はひとつしか搭載されていませんので除算器の計算が終わるまで(すなわち、除算器が未使用状態になるまで)は、次の除算命令は発行されず、ストールすることになります。割り算は汎用レジスタ間で実行されます。もしRnの値がRmの値で割り切れないならば、結果は0に丸められます。

また、CCR.DIV_0_TRPが1に設定してあれば、0で割った場合は、例外処理が実行されます。

実行パイプライン(ロード/ストア)

図7

ロード/ストアパイプライン

ロード/ストア処理用のパイプラインです。「ブロック図(第1回参照)」の章で述べましたようにロードストアユニット(LSU)が処理します。

デュアル32ビットロードチャネル(結合して64ビットロードチャネル)ですので、実行パイプラインとしては2ウェイになります。32ビットのデュアル発行(Issue)は、TCMとAXIM(64ビットロード幅)およびデュアルの32ビットロード機能とD-キャッシュにロードします。シングル32ビットロードチャネルはAHBインターフェース用です。

ストアチャネルは64ビットが1chですので、これも2ウェイといえます。TCM用に分離されたSTB(ストアーバッファリング)とAHBPとAXIM用のQoS(Quality of Service)です。

実行パイプライン(ブランチ)

図8

分岐先予測

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

分岐予測は分岐命令のアドレスをインデックスとするキャッシュを用います。

ブランチ(分岐)処理

Cortex-M7では分岐予測を効率的に行うためのキャッシュとして、BTAC(Branch Target Address Cache)を搭載しています(BTACについては後ほど詳しく説明いたします)。BTACの機能はキャッシュだけです、実際の分岐予測を行うものではありません。その為、BTACへブランチステータスとブランチ予測情報を伝える処理が並列して行われています。

実際のブランチを行うのではなく、ブランチが発生した際にBTACの持っている情報を更新するための処理です。その情報にはブランチの種類や分岐予測が成功したかどうか等の情報が含まれます。

実行パイプライン(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を指定しない場合は静的分岐予測を行います。

図9

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

ブランチの種類

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

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

直接ブランチ

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

レジスタブランチ

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

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

ロードブランチ

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