FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

BOOM (Berkeley Out-of-Order Machine) のマイクロアーキテクチャドキュメントを読む (7)

RISC-VのアウトオブオーダコアであるBOOM (Berkely Out-of-Order Machine) について勉強を進めている。以下のドキュメントを日本語に訳しながら読んでいくことにした。

docs.boom-core.org


リオーダバッファ(ROB)とディスパッチステージ

リオーダバッファ は、パイプライン内のすべてのインフライト命令の状態を追跡します。 ROBの役割は、プログラマに自分のプログラムがインオーダーで実行されているように見せることです。 命令がデコードされ、リネームされると、その命令はROBと 命令キューディスパッチ され、 busy とマークされます。 命令の実行が終了すると、ROBに通知され、 not busy とマークされます。 ROBの”先頭”がビジー状態でなくなると、その命令は “コミット “され、アーキテクチャの状態が見えるようになります。 例外が発生し、例外命令がROBの先頭にある場合は、パイプラインがフラッシュされ、例外命令の後に発生したアーキテクチャの変更は表示されません。 そして、ROBはPCを適切な例外ハンドラにリダイレクトします。

ROBの構成

The Reorder Buffer

Fig. 16 3命令発行の2ワイドBOOMのリオーダバッファです。ディスパッチされたUops(dis uops)はROBの下側(rob tail)に書き込まれ、 コミットされたUops(com uops)は上側(rob head)からコミットされ、Renameの状態を更新します。 実行を終えたUops(wb uops)は、ビジービットをクリアします。 注:ディスパッチされたUOPは、同じROBの行にまとめて書き込まれ、 メモリ上で連続して配置されるため、1台のPCで行全体を表現することができます。

ROBは、概念的には、すべてのインフライト命令を順に追跡するリングバッファです。 最も古い命令は commit head で指し示され、最新の命令は rob tail で追加されます。

スーパースカラの ディスパッチコミット を容易にするために、ROBは W バンクを持つ円形バッファとして実装されています (ここで W はマシンの dispatchcommit の幅です 1 )。 この構成を Fig. 16 に示します。

ディスパッチ では、最大で W 個の命令が フェッチパケット から ROB の行に書き込まれ、 各命令は行間の異なるバンクに書き込まれます。 1つの フェッチパケット 内の命令はすべてメモリ内で連続している(アラインされている)ため、 これにより1つのPCを フェッチパケット 全体に関連付けることができます (また、 フェッチパケット 内の命令の位置は、自身のPCに低次ビットを提供します)。 これは、分岐コードがROB内にバブルを残すことを意味しますが、 高価なコストが各ROB行で償却されるため、ROBへの命令の追加が非常に安くなります。

ROBの状態

各ROBのエントリには小さなステートが含まれます:

  • エントリが有効か?
  • エントリがBusy状態か?
  • エントリで例外が発生しているか?
  • 分岐マスク(エントリ中のどの分岐命令がまだ投機中であるか?)
  • リネーム状態(論理書き込みアドレスと古い書き込み物理レジスタ)
  • 浮動小数点ステータスアップデート
  • 他の様々なデータ(例えば統計のトラッキングに有益なもの)

PCと分岐予測の情報は、行ごとに保存されます( PC Storage 参照)。 例外状態 は、最も古い既知の例外命令のみを追跡します( Exception State 参照)。

例外の状態

ROBは、最も古い例外命令を追跡します。この命令がROBの先頭に到達すると、例外が発生します。

各ROBエントリには、その命令に例外的な動作が発生したかどうかを示す1ビットのマークが付けられますが、 追加の例外状態(不良仮想アドレスや例外原因など)は、既知の最古の例外命令についてのみ追跡されます。 これは、エントリごとに保存しないことで、かなりのステートを節約できます。

PCの保存

ROBはすべてのインフライト命令のPCを知っていなければなりません。 この情報は以下のような状況で使用されます。

  • どのような命令でも例外が発生する可能性があり、その場合は”例外PC”(epc)を知る必要があります。
  • 分岐命令やジャンプ命令は、対象となる計算のために自分のPCを知る必要があります。
  • ジャンプレジスタ命令は、自分自身のPCと、 プログラム中の次の命令 のPCの両方を知っていなければなりません。

この情報を保存するには非常にコストがかかります。 分岐命令やジャンプ命令は、PCをパイプラインに渡す代わりに、 レジスタリード の段階でROBの”PCファイル”にアクセスし、 分岐ユニット で使用します。 2つの最適化が使われています。

  • 単一のPCのみがROBの行に保存されます。
  • PCファイルは2つのバンクに分かれており、1つのリードポートで連続した2つのエントリーを同時に読み取ることができます(JR命令で使用)。

コミットステージ

コミットヘッド にある命令がビジーでなくなると(そしてそれは例外ではない)、 その命令は コミット されるかもしれません。 スーパースカラのコミットでは、ROBの行全体がnot busy命令について分析されます(そのため、1サイクルでROBの行全体までコミットされる可能性があります)。 ROBは、できるだけ早くリソースを解放するために、行ごとにできるだけ多くの命令を貪欲にコミットします。 しかし、ROBは複数の行をまたいでコミット可能な命令を探すことは(現在は)ありません。

ストアがコミットされて初めて、そのストアをメモリに送ることができます。 スーパースカラでストアをコミットする場合、 Load/Store Unit (LSU) に「いくつのストアをコミットしてよいか」を伝えます。 LSUはコミットされたストアを必要に応じてメモリに排出します。

(レジスタに書き込む)命令がコミットすると、 古くなった物理レジスタ を解放します。 その後、 stale pdst は自由になり、新しい命令に再割り当てされます。

例外とフラッシュ

例外は、 commit head にある命令が除くときに処理されます。 パイプラインはフラッシュされ、ROBは空になります。 リネームマップテーブル をリセットして、真の、非投機的な committed 状態を表す必要があります。 そして、 フロントエンド は適切なPCに指示されます。 アーキテクチャ上の例外であれば、例外となる命令のPC( 例外ベクトル と呼ばれます)がControl/Status Register(CSR)ファイルに送られます。 マイクロアーキテクチャ的な例外(ロード/ストア順序の誤記など)の場合は、失敗した命令がリフェッチされ、 新たに実行を開始することができます。

パラメータ:ロールバックと1サイクルリセット

リネームマップテーブルをリセットする際の動作はパラメータ化可能です。 最初のオプションは、ROBをサイクルごとに1行ずつロールバックしてリネーム状態を解除することです(これはMIPS R10kの動作です)。 各命令に対して、 stale物理的デスティネーション レジスタは、その 論理的デスティネーション 指定のためにマップテーブルに書き戻されます。

より高速なシングルサイクルのリセットが可能です。 これは、リネームテーブルの committed 状態を追跡する別のリネームスナップショットを使用することで実現されます。 この コミットマップテーブル は命令がコミットすると更新されます。2

例外要因

The RV64G ISA provides relatively few exception sources:

  • Load/Store Unit

    page faults

  • Branch Unit

    misaligned fetches

  • Decode Stage

    all other exceptions and interrupts can be handled before the instruction is dispatched to the ROB

なお、メモリ順序の推測エラーもLoad/Storeユニットから発生し、 BOOMパイプラインでは例外として扱われます(実際にはパイプラインの「リトライ」が発生するだけです)。

Point of No Return (PNR)

Point-of-no-returnヘッドは、ROBコミットヘッドの前を走り、 誤判定や例外が発生する可能性のある次の命令をマークします。 これには、未解決の分岐や翻訳されていないメモリ操作などが含まれます。 このように、コミットヘッドの とPNRヘッドの にある命令は、 たとえまだ書き戻されていなくても、 非仕様 であることが保証されます。

現在、PNRはRoCC命令にのみ使用されています。 RoCCコプロセッサは、通常、命令をインオーダーで実行することを期待しており、 投機ミスを許容しません。 そのため、コプロセッサへの命令発行は、その命令がPNRヘッドを通過して、推測可能でなくなってから行うことになります。