大きな画面での利用をおすすめします — アニメーションと操作がより快適になります。
入力

CPU パイプライン

CPU パイプラインは命令をフェッチ、デコード、実行、メモリアクセス、書き戻しの 5 段に分け、各段で別の命令を処理する。満杯で停止がなければ毎サイクル一命令を完了できる。改善するのはスループットであり、一命令は依然として 5 段を通る。依存があれば待機も加わる。

洗濯、乾燥、折り畳みが各一時間枠なら、4 組を一組ずつ終えるには 12 枠かかる。最初の組が乾燥へ進んだ時点で次の洗濯を始めれば 6 枠になる。個々の機械は速くならず、空き時間が減る。CPU も 5 段を重ねるが、後の命令が前の未完成の結果を必要とする場合は依存を解決する必要がある。

仕組み

IF は命令語を取得する。ID はデコードしてソースレジスターを読む。EX は ALU を実行する。MEM はデータメモリを読み書きする。WB は宛先レジスターへ書く。本モデルは毎サイクル一命令を発行し、プログラム順に進み、追い越さず、クロック境界で次段へ渡す。

データの問題は、ID の読み取りと WB の書き込みの間から生じる。消費側が ID に来ても、生産側がまだ書き戻していなければ、レジスターには旧値がある。

転送機構がない場合、ハザード検出が消費側を値の準備まで ID に保持する。これがストールだ。命令が EX へ入らず、空きが後段へ進むものをバブルという。依存による追加サイクルであり、充填・排出時の通常の空きとは区別する。

ハザードも他の停止もなければ、n 命令は n+4 サイクル。初期充填の 4 サイクルの後は毎クロック一命令を完了する。5 命令は逐次実行の 25 に対して 9、500 命令は 2500 に対して 504 となる。固定費を長い命令列で分担する。

ステップ実行

既定の機械はストールのみで、フォワーディングがない。レジスターへの書き戻しまで値を使えない。

  • I1 — add $t1, $s1, $s2
  • I2 — sub $t2, $s3, $s4
  • I3 — lw $t3, 0($s0)
  • I4 — or $t4, $t3, $t1
  • I5 — and $t5, $t4, $t2

最初の 3 命令は独立する。I4 は I3 がロードする $t3、I5 は I4 が計算する $t4 を読む。

  1. サイクル 1:I1 をフェッチする。他の 4 段は空で、充填を始める。
  2. サイクル 2:I1 が $s1, $s2 を読み、I2 をフェッチする。
  3. サイクル 3:I1 は EX、I2 は ID、I3 は IF。
  4. サイクル 4:I1 は MEM、I2 は EX、I3 は ID、I4 は IF。
  5. サイクル 5:I1 は WB、I2 は MEM、I3 は EX、I4 は ID、I5 は IF。5 段が埋まるが、I4 の必要な $t3 は未完成だ。I3 はまだメモリへ進んでおらず、書き戻しはサイクル 7 になる。
  6. サイクル 6、7:I4 を ID、I5 を IF に保持する。EX に新命令が入らず、バブルが 2 個できる。サイクル 7 前半に I3 が $t3 を書き、後半に I4 が読むため、同サイクルの読み書きでさらに一周期待つ必要はない。
  7. サイクル 8:正しい $t3 で I4 が EX へ進む。ID に来た I5 は、I4 がサイクル 10 に書く $t4 を待つ。
  8. サイクル 9、10:さらに 2 サイクル保持し、バブルが 2 個増える。
  9. サイクル 11–13:I5 だけが EX、MEM、WB を進み、排出を終える。

5 命令で 13 サイクル。理想の 9 よりバブル 4 個分多いが、非パイプラインの 25 より短い。空の段枠がバブル、命令行の破線付き ID の繰り返しが保持を示す。

データハザード、ストール、フォワーディング

RAW、つまり先行書き込みへの後続読み取り依存はプログラムの誤りではない。I4 が I3 のロード結果を使うのは正当であり、ハードウェアが正しい値を渡す必要がある。

転送なしでは直後の依存に 2 サイクル、一命令間隔が増えれば 1 サイクル、命令位置が三つ離れれば 0 サイクルかかる。最後の場合は生産側の WB と消費側の ID が重なる。

フォワーディング、別名バイパスは、パイプラインレジスターの結果を EX 入力へ直接渡す。書き戻して読み直すまで待たない。ロード値は MEM の終わりに MEM/WB レジスターへ入り、次のサイクルの EX へ送れる。

ハードウェアを切り替えると、同じ 5 命令が 10 サイクルになる。I4 はサイクル 7 の EX で $t4 を作り、バイパスがサイクル 8 の I5 の EX に渡す。この ALU 依存のストールはなくなる。

転送でも残る下限

残る一回は load-use ハザードだ。ALU 結果は EX 終了時にでき、直後の命令の次サイクル EX に間に合う。ロード値は一段後の MEM 終了までできず、直後の消費側は同じサイクルの EX で欲しがる。まだ存在しない値は転送できない。

必要な全バイパスがあり、メモリが一サイクルで応答するこの 5 段機械では、ロード直後の使用は一サイクル停止する。lw / use pairs は 4 命令に 2 組のロード直後使用があり、バブル 2 個で理想の 8 が 10 サイクルになる。

lw / use, rescheduled は同じ二つのロードと二つの加算を、同じ結果のまま並べ替える。ロードを先に置き、各ロードと使用の間へ無関係な命令を挟むと、10 が 8 サイクル、バブル 2 個が 0 になる。機械は同じで順序が違う。コンパイラーの命令スケジューリングはこの隙間を埋める。この順序実行モデルは後方の独立命令を自分で探さない。

各命令が直前の ALU 結果を使う 5 命令の連鎖は、転送ありで 9、なしで 17 サイクル。後者はバブル 8 個、一命令平均 3.4 サイクルとなる。

境界ケース

  • WB と ID の同時刻:レジスターファイルを前半で書き、後半で読む設計なら停止しない。この規約がなければ既定の実行は 13 サイクルから 15 サイクルになり、2 回の停止がそれぞれ 1 サイクル延びる。
  • 充填と排出:まだ何もフェッチされていない、またはもうフェッチするものがないために空いた段はバブルではない。バブルは前後に命令がある空段だ。充填と排出の空きが、下限が n ではなく n+4 になる理由だ。長い命令列では固定費の比率が小さくなる。
  • 十分離れた依存:I4 が読む $t1 は三命令前の I1 が書く。I4 が ID に来たとき I1 は WB に到達しており、追加停止はない。
  • 独立命令列:同じ 5 操作コードでもオペランドが衝突しなければ、転送の有無によらず 9 サイクル。転送は依存の罰則を減らし、理想下限自体は短縮しない。
  • 生産側が二つ:I5 は $t4 と $t2 を読む。遅い方の準備まで待てばよく、待ち時間を足し合わせない。

よくある間違い

  • パイプラインが一命令の処理経路を短縮すると考える。5 段は残り、ストールは遅延を増やす。利点は複数命令のスループットで測る。
  • 一つの依存を一サイクルの損失と数える。転送なしの直後依存はこの機械で 2 サイクル。値が生まれ、使われる時刻から計算する。
  • ロード値を EX/MEM から転送する。そこにあるのは ALU が計算したアドレスで、ロードしたデータではない。
  • 停止がその命令だけに影響すると考える。順序パイプラインでは後ろも止まり、追い越せない。
  • 三つの ID 枠を三回のデコードと読む。一つの命令が ID を三サイクル占めている。破線が待機を示す。

モデルの範囲

教材の MIPS 型 5 段順序パイプラインを扱う。分岐・ジャンプはなく、制御ハザードは分岐予測のレッスンで扱う。メモリは常に一サイクルで、キャッシュミスの停止はない。一サイクル一命令を順序発行し、スーパースカラーやアウトオブオーダー実行は省略する。

実プロセッサーの段数や発行方式は設計によって異なり、14–20 段程度の深い構成もある。深さは依存や予測失敗の代価を増やすことがあり、予測と転送の重要性につながる。このモデルは技術を理解する土台であり、手元のチップの記述ではない。