パイプライン(前編)

概要と特徴

スーパースカラパイプラインの基本

スーパースカラ方式のパイプラインの工程を大きく分けると、命令フェッチから命令デコード(Decode)、命令発行(Issue)までの前半と、命令を実行する後半に分けられます。前半を命令発行パイプラインと呼び、後半を命令実行パイプラインと呼びます。

命令デコーダ(Decode)から、命令実行パイプラインへ同時に送り込むことのできる命令数をイシュー(Issue)と呼び、命令実行パイプラインの本数をウェイ(Way)と呼びます。Cortex-M7の場合はどちらも2本(デュアルイシュー、デュアルウェイ)です。

Cortex-M7のパイプライン

Cortex-M7のパイプラインは64ビットで処理されます。すなわち32ビット命令が2つ同時に処理されることになります。

図1

【Cortex-M7のパイプライン】

前半の命令の発行まではすべての命令が通るパイプラインです。プリフェッチからデコードして、命令を判別するまでのパイプライン処理です。デコード処理が2段になっていて、最初のデコードはDecodeと呼んでいますが、2つ目のデコードは発行(Issue)と呼ばれています。発行の後、2つの命令が後半へ受け渡されます。

後半の実行パイプラインでは、命令の種類によって複数の実行パイプラインに分かれます。ロード/ストア命令だとロード/ストアーパイプラインを通ります。ALUの演算命令だとALUパイプラインを通ります。ALUのパイプラインが2つ合って、同時に演算できますので、デュアルのスーパースカラパイプライン構造になっています。シフターはここに含まれます。複雑な積和演算はMACパイプラインを通ります。浮動少数点演算は浮動小数点演算パイプラインで演算されます。

Cortex-M7のスーパースカラはインオーダー発行なので、命令は基本的にプログラムの順番に従って実行されます。ほとんど全ての命令はプログラムの順番で完了しますが、浮動小数点演算は順番に依存せず完了します(アウトオブオーダーと呼ばれています)。また、デュアル発行なので、対の命令のほとんどは同時実行できます。

命令発行と制限

図1

マイクロ操作(μ-Op)

スーパースカラを勉強すると「マイクロ操作」という言葉がでてきます。スーパースカラでは「マイクロ操作」で命令を実行しますので、まず「マイクロ操作」を説明します。

そもそも、RISCマイコンでは複雑な命令を取り扱わなかったので、Decodeの内部論理回路はランダム論理またはワイヤード論理で構成されてきました。CISCで採用されているひとつの命令をさらに細かいマイクロ操作で実行するような、マイクロ命令やマイクロプログラムは用いられてきませんでした。

しかし、近年ではRISCマイコンもCISCマイコンのような複雑な命令を扱うようになり、複雑な命令の処理を行う必要が出てきました。ランダム論理やワイヤード論理で複雑な命令の処理を行おうとすると、内部論理構造が複雑になり、回路効率が悪くなるので、スーパースカラ方式を採用しているRISCマイコンではマイクロ操作方式を採用するようになりました。

この方式では、デコードされた命令をさらにいくつかのマイクロ操作に分けます。このマイクロ操作のことをμ-Opと呼びます。

デコード(Decode)

Decodeでデコードされた命令は、ここで命令発行準備のためにチェックされます。そしてデコードされた命令をマイクロ操作(μ-Op)に分解します。そして次段のIssueへ受け渡します。

発行ステージ(Issue)

実行パイプラインに入る前にμ-Opによってデータ依存状態を決定します。すなわち同時発行できるかどうかをチェックします。2つの命令にまったく依存性が無い場合や、どちらのALUでも実行可能な場合は、同時発行されて同時実行されます。

イメージ図を描くと下図(a)の様になります。

図2

(a)Inst.1とInst.2に依存性が無く、同時発行、同時実行が可能な場合

しかし、2つの命令が、同時発行できない関係にあったり、一方のALUでしか実行できない場合は、同時発行同時実行ができないので、一方の命令にインターロックがかかります。すなわちμ-Opが一時的に停止され、下図(b)のように、次のサイクルで実行されることになります。例えばSIMD(Single Instruction Multiple Data)命令はひとつのALUでしか演算できませんので、同時発行はできずに、片方はインターロックされることになります。

図3

(b)Inst.1とInst.2に依存性が有って、同時発行、同時実行ができない場合

デュアル発行の制限

発行制限

いくつかの命令はデュアル発行されません。どの命令がデュアル発行されないかは公開されていませんので、明言はできませんが、スーパースカラパイプラインの構造から次のように考えられます。

例えばアンアラインドロード(32bit境界をまたぐ場合)やアンアラインドストア(64bit境界をまたぐ場合)は、「境界におけるアンアラインドアクセスの取り扱い(第2回参照)」の章で述べたように、内部で、2回以上のアラインドアクセスに変換されて実行されるので、デュアル発行されません。SIMD命令はひとつのALUでしか演算できませんので、デュアル発行されません。

浮動少数点演算パイプラインは、1ウェイしかありませんので、 整数と浮動小数点除算フロート分割、浮動小数点平方根、倍精度浮動小数点命令はデュアル発行されません。ただし、整数パイプラインとは並列実行ができます。(実際の浮動少数点演算パイプラインは並列した2つのパイプラインに分かれていますが、ひとつが加算等の単純演算パイプライン、もうひとつが乗算、除算等の演算パイプラインで、実質は1ウェイになります。詳細は後述の「実行パイプライン(第5回参照)」の章で説明します)。

また、一般的に非汎用命令はデュアル発行されません。例えば、モード遷移の命令やデバッグ時に使う命令は、次に続く命令を異なるモードや条件で実行しなければならないので、デュアル発行されません。Cortex-M7で言うと、特権モードに移行するSVC(Supervisor Call)やデバッグ時に使われるBKPT(Break point)命令、また、PRIMASK等の特殊レジスタを扱うMRSやMSR、DMB(Data Memory Barrier)、DSB(Data Synchronization Barrier)もメモリの状態を変えますので、これらが非汎用命令にあたります。

まとめると、次の命令ではデュアル発行は行われません。

  • ●アンアラインドロード(32bit境界をまたぐ場合)
  • ●アンアラインドストア(64bit境界をまたぐ場合)
  • ●整数と浮動小数点除算フロート分割
  • ●浮動小数点平方根
  • ●全ての倍精度浮動小数点命令
  • ●非汎用命令 – SVC, BKPT, MRS, MSR, DMB, DSB

実行パイプライン(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の持っている情報を更新するための処理です。その情報にはブランチの種類や分岐予測が成功したかどうか等の情報が含まれます。