ゼロからアウトオブオーダーRISC-V CPUを構築する
Building an Order RISC-V CPU from scratch (prawns.dev)
要約
この記事は、エンジニアリング専攻の学生が、退屈な大学のコースに代わる刺激的なプロジェクトとして、ゼロからアウトオブオーダー(OOO)RISC-V CPU「Specula」を設計・実装した経験を詳述しています。彼は、プロセッサ設計の理論を学び、Bluespec SystemVerilogを使用して、レジスタリネーミング、リオーダバッファ、ブランチ予測などの高度な機能を備えた32ビット単一発行OOO RISC-Vコアを開発しました。最終的には、教育用OSであるxv6-rv32をブートさせ、FPGAへの実装も試みました。
全文翻訳
ゼロからアウトオブオーダーRISC-Vコアを構築する - Specula
公開日: 2026-11-06
Specula を選んだ理由
すべては、工学部の4学期(2025年初頭)に、提供されるコースに本当に飽き飽きしたことから始まりました。どれも私を惹きつけるものがなく、好奇心旺盛な子供なら誰でもやるように、本当にワクワクするものを見つけました。私はプロセッサ設計とFPGAの世界に深く入り込んでいました。インオーダープロセッサの基本的な仕組みをよく理解しており、ハザードをどのように処理するかを把握しつつありました。これらのラビットホールセッションの1つで、ラップトップのCPUが私が数ヶ月間構築してきたものとどのように違うかを見るために、実際のインオーダープロセッサの例を検索したことを覚えています。
私のRyzen 9 CPUが「アウトオブオーダー」プロセッサと呼ばれるものであることを発見しました。ビンゴ、大学の実際のコース教材に集中しない理由がさらに増えました。それは、私の次の挑戦にしたいと思っていたもの、主に2つの理由で、その複雑さと、私のラップトップが私が考えていたよりもはるかに洗練されたものを持っているという事実でした。Speculaのレポジトリの説明を「SpeculaはBluespec SystemVerilogで構築されたデュアルイシューのアウトオブオーダーRV32Iプロセッサです」のように始めたことを覚えています…ええ、若い頃の私は本当に野心的すぎました。
私が現代のプロセッサがどのように機能するかという複雑で入り組んだ理論を理解するのに苦労していた間、その説明はしばらくそのままにしていました。私の学習方法は、何かについて読み、それを再現しようとすることで、何がうまくいかなくなるかを見て、その瞬間が理論的なクラスよりもはるかに多くを教えてくれるというものです。これは私のほとんどのプロジェクトでそうでしたが、Speculaは、それ以前に自分で読んで理解しようとしたものとは異なり、Bluespecで試みた2番目のプロジェクトであったため、本当に異例でした…すべて私がまだBluespecを学んでいる間に。
Specula とは具体的に何か?
このブログにたどり着くまで「アウトオブオーダープロセッサ」という言葉を聞いたことのない私の美しい読者のために、簡単なコースを提供させてください。従来のインオーダープロセッサとは異なり、アウトオブオーダープロセッサは、依存関係がない限り(後述)、命令が完了次第実行できます。それは、この目標を達成するために多くの複雑なハードウェアユニットとアルゴリズムを使用します。Speculaは、32ビット、シングルイシュー(つまり、プロセッサはクロックサイクルあたり最大1つの命令を発行できる)、アウトオブオーダー、および投機的(プロセッサは、それらの命令が実際に必要かどうかを確信する前に命令を実行する)RISC-Vプロセッサとなり、すべてBluespec SystemVerilogで記述されています。この設計は、当初の無謀な野心から大きく進化し、実装されたコアは現在1幅で、レジスタリネーミングを使用して偽の依存関係を排除し、リオーダバッファを使用して完了した命令が最終的に正しいプログラム順序でアーキテクチャ状態を更新することを保証しています。
さて、これは多くのバズワードですが、綿菓子のように分解してみましょう。
[画像: Specula microarchitecture]
Speculaの高レベルマイクロアーキテクチャ。一部の内部キューと制御パスは省略されています。
かなりの間、目標はBluespecでアウトオブオーダープロセッサを実行することでした。実際、約4ヶ月間(2025年9月から2026年2月まで)、Speculaは埃をかぶっていました。この間、私は基本的な現代のプロセッサがどのように機能するかについて、はるかに良い理解を深め、また他のアウトオブオーダーRISC-V設計を調査して、Speculaをどこまで進めることができるかというアイデアを得ました。最も有名なのはおそらくバークレーのSonicBOOMでしたが、驚くべきことに、Bluespecでアウトオブオーダーマシンを作成したプロジェクトを見つけました。この連中は、私がまだ身長135cmだった2017年にこのプロジェクトを開始しました。
2026年3月頃にSpeculaに戻り、まだ通常のアウトオブオーダー実行を達成しようとしていました。途中、xv6に出会い、他のプロジェクトがLinuxをブートしているのを見て、「Speculaで教育用OSを実行してみるのはどうだろう?」と思いました。これは、特権モード、CSR、トラップ処理、およびSv32仮想メモリをプロセッサに追加する必要があることを意味し、さらにUART、PLIC、およびVirtIOブロックデバイスのような必要なシステムコンポーネントを構築する必要がありました。
また、設計が実際のハードウェアにどのように変換されるかを見たかったので、Artix-7 FPGAをターゲットにしたVivado合成フローを通しました。はい、またしても50の他のドメインを私のプロジェクトに巻き込み、複雑にしてしまいました。しかし、それが学び方ではありませんか:D
現代のプロセッサの背後にある魔法
現代のプロセッサは数十億もの命令を実行しますが、すべての命令が完了するのに同じ時間がかかるわけではありません。整数加算は、除算やメモリアクセスと比較して比較的迅速に完了する可能性があります。ここで、ある命令がメモリからのデータを待っているが、その数命令後ろにあるいくつかの命令は完全に独立している命令のシーケンスを実行しているプロセッサを想像してください。従来のインオーダープロセッサは、実行すべき有用な作業がある場合でも、停止する可能性があります。これはアウトオブオーダー実行が対処しようとする問題の1つです。プログラムに現れる順序で厳密に命令を実行するように強制するのではなく、プロセッサはオペランドと実行リソースが利用可能になったときに、独立した命令が進捗できるようにします。
もちろん、これは単に命令を並べ替えるほど単純ではありません。一部の命令は前の命令の結果に真に依存しており、他の命令は同じレジスタまたはメモリ位置にアクセスする可能性があります。そのため、これらの依存関係を追跡し、実際に実行準備ができている命令を見つけ、異なる順序で実行してもプログラムの観測可能な動作が変わらないようにするためのメカニズムが必要です。(そして、その過程で、髪の毛を1、2本失わないように。)ここで、レジスタリネーミング、リザベーションステーション、リオーダバッファなどのアイデアが登場します。これらはアウトオブオーダープロセッサを可能にするメカニズムであり、Speculaを探索する際に遭遇するビルディングブロックでもあります。
[画像: In-order vs out-of-order execution]
インオーダープロセッサとアウトオブオーダープロセッサでの命令実行の比較。インオーダープロセッサは長レイテンシ命令で停止するのに対し、アウトオブオーダープロセッサは独立した命令で進捗できます。
フロントエンド:次のものをフェッチし、予測する
脳内で理論が駆け巡っているところで、Speculaの内部がどのように見えるか見てみましょう。Speculaでの各命令の旅はフロントエンドから始まります。その仕事は、メモリから命令をフェッチし、実行をどこに続けるべきかを判断し、命令をバックエンドのために準備することです。Speculaは仮想メモリとRISC-V圧縮命令拡張をサポートしているため、フェッチはアドレスから次の32ビットを読み取るだけの単純な作業ではありません。命令フェッチはSv32アドレス変換を通過し、圧縮命令はパイプラインのさらに先に進む前に展開されます。これにより、プロセッサの残りの部分は一貫した命令表現で作業できます。
フロントエンドのもう1つのクールな部分は、ブランチ予測と呼ばれるものです。次に何をフェッチするかを決定する前にブランチ命令の実行を待つと、フロントエンドがアイドル状態になるため、Speculaはブランチターゲットバッファ(BTB)とともにgshareブランチ予測器を使用して次の制御フローパスを予測します。予測器は64エントリの2ビットパターン履歴テーブルと6ビットのグローバル履歴レジスタを使用し、BTBは16個の直接マッピングされたエントリを含みます。Speculaはまた、一度に1つの未解決の制御フロー命令に制限しており、ブランチ回復を管理可能に保ちます。予測は最終的にブランチが実行されるときにチェックされ、予測器はライトバック時に更新されます。
[画像: Specula branch prediction]
Speculaのブランチ予測。フロントエンドはgshare予測器とBTBを使用して次のフェッチアドレスを決定し、ブランチの成果は実行中に解決され、予測器の状態はライトバック時に更新され、誤予測はROBヘッドで処理されます。
レジスタリネーミングとディスパッチ
このブログ投稿の第2節で、「依存関係」と呼ばれるものについて話しました。簡単に言うと、依存関係とは、1つの命令が安全に実行される前に、別の命令が完了するか結果を提供するのを待たなければならない関係です。そして、現代のプロセッサは命令をアウトオブオーダーで実行しようとするため、依存関係は私たちが達成しようとしている命令速度を制限する可能性があります。同じアーキテクチャレジスタに書き込む2つの命令を考えてみてください。それらが他に依存関係がない場合でも、プロセッサは1つの命令が別の命令がまだ必要としている値を誤って上書きしないようにする必要があります。ここでレジスタリネーミングが登場します。Speculaには、アーキテクチャレジスタを物理レジスタにマッピングするレジスタエイリアステーブル(RAT)があります。命令がディスパッチされると、そのソースオペランドは現在の物理レジスタにマッピングされ、その宛先はフリーリストから新しく割り当てられた物理レジスタを取得します。これにより、Write After Read(WAR)およびWrite After Write(WAW)ハザードによって引き起こされる偽の依存関係が排除され、真のRead After Write(RAW)依存関係が維持されます。
[画像: Register renaming]
Speculaのレジスタリネーミング。各命令は物理宛先レジスタを受け取り、偽の依存関係を排除し、命令間の真のデータ依存関係を維持します。
リネーミングされた後、命令は適切なバックエンド構造にディスパッチされます。Speculaには、算術およびブランチ命令用の8エントリのリザベーションステーションと、ロード、ストア、アトミック操作用の別の8エントリのメモリキューがあります。命令はまた、32エントリのリオーダバッファ(ROB)にエントリを受け取り、その進捗を追跡し、最終的にプログラム順序でリタイアすることを保証します。物理レジスタファイルは64個のレジスタを保持し、フリーリストはどのレジスタが割り当て可能かを追跡します。
[画像: Specula backend]
Speculaのバックエンド組織。リネーミングされた命令はリザベーションステーションまたはメモリキューにディスパッチされ、リオーダバッファはその進捗を追跡し、プログラム順序でリタイアすることを保証します。
実行、メモリ、リタイア
前のセクションでは、Speculaのバックエンド機構の概要を説明しました。現代のプロセッサがこれほど複雑だとは誰が想像できたでしょうか?そして、それをラップトップの小さな正方形に収めるのは、また別のクレイジーな偉業です。しかし、読者の皆さんがマイクロチップ構築の背後にあるアーキテクチャの魔法を本当に理解できるように、さらに深い詳細に入りたいと思います。ですので、後続のセクションは(ネタバレ注意)さらにクールなので、我慢してください。もしリザベーションステーション、ROBなどの動作をすでに知っているなら、次の章にスキップしても構いません。
命令がディスパッチされると、スポットライトはバックエンドに当たります。算術およびブランチ命令は、ソースオペランドが準備できるまで、Speculaの8エントリのリザベーションステーションで待機します。スケジューラは最もインデックスの小さい準備完了エントリを選択して実行に送り出します。必ずしも最も古い命令を選択するわけではありません。命令が選択されると、オペランドは物理レジスタファイルから読み取られます。Speculaの実行ユニットには、整数およびブランチ操作用のALU、FPGAのDSPリソースを使用した乗算器、および完了に32回の反復を要する反復除算器が含まれます。結果は物理レジスタファイルに書き戻され、依存する命令は実行準備完了になります。
メモリ命令は、メモリキューを介して別のパスをたどります。Speculaは、アドレス生成ステージの後にメモリ発行を使用し、その過程でSv32変換が実行されます。ロードは、古いストアのすべてがアドレスを把握するまで待機する必要があり、投機的なメモリ依存関係予測の必要性を回避します。ストアキューは保留中のストアを処理し、バイトレベルのフォワーディングをサポートしており、必要に応じてロードが古いストアから必要なバイトを取得できるようにします。ストア自体は、実行後にすぐにメモリを更新しません。それらは、対応する命令がコミットされるまで保持されます。これにより、メモリの変更はプロセッサのリタイア順序と一致します。
そして最後のトリックはリオーダバッファ(ROB)です。それは、実行プロセス全体をまとめる接着剤のようなものです。命令はディスパッチされた順序とはまったく異なる順序で完了する可能性がありますが、ROBはそれらがプログラム順序でリタイアすることを保証します。命令がROBのヘッドに到達し、正常に完了すると、アーキテクチャ効果をコミットできます。フロントエンドのセクションで思い出したように、Speculaはブランチ予測をサポートしています。そのため、誤予測が発生した場合、ROBの助けを借りて回復が行われます。誤予測されたブランチは、ROBヘッドに到達したときに処理され、Speculaが若い命令をフラッシュし、リネームチェックポイントを復元し、フェッチを正しいアドレスにリダイレクトできるようにします。
[画像: Specula instruction lifecycle]
Speculaの完全な命令ライフサイクル。
Specula で xv6 を実行する
ここまでたどり着いたなら、おめでとうございます。約1時間で半学期分の知識を習得したことになります。Speculaを完全に視覚化するために、オペレーティングシステムの基礎に関する選択科目を受講する必要があります…それはSpeculaの次のマイルストーンだったからです。アウトオブオーダー実行が機能したのは素晴らしいことでした。しかし、私たちコンピュータアーキテクトは「素晴らしい」で止まることはありません。私たちは地球のマントルに到達するまで穴を掘り続けるのが好きです。さて、標準のxv6オペレーティングシステムは64ビットプロセッサ用であり、残念ながら私はすべて32ビット方式で設計しました。そのため、MITのxv6 OSを32ビットRISC Vに移植したxv6-rv32を選択しました。しかし、OSを実行するには、基本的な整数命令セットの実装以上のものが必要です。第2節で述べたように、Speculaは特権実行をサポートし、ソフトウェアが異なる特権レベルで動作できるようにし、例外、割り込み、およびシステムコールを処理するために必要なメカニズムを提供する必要があります。Speculaにとっては、マシンモードとスーパーバイザーモードのサポート、制御およびステータスレジスタ(CSR)、およびトラップハンドラからの復帰命令を追加する必要がありました。また、必要な圧縮命令で命令セットを拡張する必要もありました。
もう1つの重要なことは仮想メモリでした。xv6は、2レベルのページテーブル構造を使用して仮想アドレスを物理アドレスに変換するRISC-Vの32ビット仮想メモリ方式であるSv32を使用します。Speculaは、ページテーブルウォークを通じて、命令フェッチおよびロード/ストアアクセス用のこの変換を実装します。これにより、すべてのプログラムが物理メモリに直接オペレートする必要なく、プロセッサは仮想アドレスを使用するソフトウェアを実行できるようになりました。ここにはまだ改善の余地があります。Speculaは関連する各アクセスでページテーブルウォークを実行し、現在TLBを実装していません。
そして最後に、オペレーティングシステムが何か問題があることを私に伝えたいとき、Speculaの周りに特定の必要なシステムコンポーネントが必要でした。これには、コンソール入出力用のUART、デバイス割り込みを管理するためのプラットフォームレベル割り込みコントローラ(PLIC)、およびディスクアクセスを提供するVirtIOブロックデバイスが含まれていました。VirtIOデバイスはビヘイビアーDMAモデルとして実装されており、PLICはUARTおよびVirtIOデバイスからの割り込みを処理します。
すべてが整ったので、Bluesimでxv6-rv32をブートし、インタラクティブシェルに到達し、基本的なファイルシステム操作を実行することができました。
[画像: xv6]
Specula上のxv6-rv32がBluesimで実行されています。システムは正常にブートしてインタラクティブシェルに入り、ディレクトリの作成、ファイルのリスト表示、ファイルへの書き込みと読み取りを含む基本的なファイルシステム操作をサポートしています。
Specula を FPGA に搭載する
約束通り、これが私の読者のための最後の講義です。要約すると、xv6をまともなレベルでブートできる、機能的なアウトオブオーダーRISC-Vマシンがあります。しかし、これらはすべてシミュレーションに過ぎず、ブレーキをかけるのに最適な場所ではありません。Speculaが実際のFPGAハードウェアに変換されたときにどのように見えるかを見たかったのです。そのため、Artix-7 XC7A35TをターゲットにしたVivado合成フローを通しました。シミュレーションでうまく機能する設計が、必ずしも効率的なハードウェア実装に変換されるとは限りません。現在、私を悩ませている新しい問題は、LUT数、フリップフロップ数、そして最も重要な、クリティカルタイミングパスです。
[画像: basys3]
これは私が手にしたBasys3 FPGAです。Artix-7ファミリーに属し、初心者向けのボードです。
私の最初の合成結果は「順序通り」ではありませんでした。悪いジョークですが、初期実装は約30,582 LUTを占有し(Basysボードは20,800 LUTしか収容できませんでしたが)、推定最大動作周波数はわずか約11.9 MHzでした(つまり、ピーナッツバターの中を移動するカタツムリの群れと同じくらい遅いです)。明らかに、改善の余地はたくさんありました。そのため、マイクロアーキテクチャのさまざまな部分を含む一連の実験を行い、どの構造が最も多くのリソースを消費し、どの論理パスがクロック周波数を制限しているかを理解しようとしました。これらの実験のいくつかは見事に機能し、いくつかは状況を悪化させ、いくつかは明白に見える最適化が常に正しいわけではないことを教えてくれました。
Specula を適合させる
さて、物語の実際の核心に入ります。コーヒーを補充したことを願っています。なぜなら、次の2つのセクションは私が魔法を行うことに関するものだと思うからです。私の設計が約30,582 LUTを占有し、10 ns(100 MHz)クロック制約に対して-73.8 nsのWNS(Worst Negative Slack)を持っていたことを見ました。最もクリティカルなパスは組み合わせ除算器を通っていました。Bluespecでは、a / bとa % bを記述するのは非常に便利ですが、結果として生じるハードウェアは大きな組み合わせ除算ネットワークであり、非常に深い論理パスを作成しました。
さて、何ができるでしょうか?組み合わせ除算器を反復的なradix-2復元除算器に置き換えました。今や商と剰余を単一の組み合わせ操作で生成しようとするのではなく、除算器は32回の反復で計算を実行し、同じハードウェアを再利用します。これにより、実行レイテンシと実装サイズのトレードオフが発生しました。DIVUとREMUは同じ除算器を共有し、除算が進行中はALUは待機します。これにより、LUT使用量は30,582から28,276に減少し、WNSは-73.8 nsから-46.7 nsに改善されました。
[画像: Combinational vs iterative radix-2 restoring divider]
Speculaの元の組み合わせ除算器と反復radix-2復元除算器の比較。
次のボトルネックは、メモリキューから最も古い準備完了メモリ操作を選択するロジックでした。元の実装では、8つのエントリすべてにわたるシリアルな年齢比較チェーンを使用していました。つまり、各比較は前の結果に依存していました。これをバランスの取れた3レベル比較ツリーに置き換え、論理深度を70から57レベルに削減しました。これにより、LUT数は1,970減少し、WNSは11.8 ns改善されました。さらに、この構造を最適化し、ツリーをすべてのペア比較ネットワークに置き換えました。これにより、1-hot選択マスクを使用して最も古い適格なエントリを特定しました。これは、メモリ選択とメモリ発行の分割とともに導入され、選択結果をメモリパイプラインの残りの部分が進む前に登録できるようにしました。
[画像: Memory selector evolution]
Speculaのメモリキューセレクタの進化。シリアル比較チェーンから最終的な全ペア1-hot選択ネットワークへ。
ストアキューフォワーディングも注意が必要でした。ロードがメモリにアクセスするとき、要求されたバイトの一部またはすべてを含む可能性のある古いストアを考慮する必要があります。私の元の実装では、バイトレーンごとに最も若いマッチングストアを特定するためにシリアル優先度チェーンを使用していました。これをバランスの取れた選択ツリーに再構築し、追加の1,018 LUTと7.2 nsのWNS改善をトレードオフしました。さらにストアの順序付け方法を変更しました。ROBタグを繰り返し比較する代わりに、ストアキュー内の相対位置を使用しました。エントリはプログラム順序で割り当てられ、リタイアされるため、キュー位置は現在アクティブなエントリに必要な順序情報を提供します。
これにより、ストア実行パスでのROBタグ年齢比較と追加の8方向ルックアップが不要になりました。結果として、1,241 LUTが削減され、WNSがさらに6.0 ns改善されました。これにより、設計は20,382 LUTになり、最終的にBasys 3の20,800 LUT容量に収まりました。
[画像: Store Queue forwarding and ordering]
ストアキューフォワーディングとROBタグベースの年齢比較を相対的なストアキュー位置に置き換えることの最適化。
FPGA合成でのタイミング追跡
よし、やったぞ!Speculaを空きスペースに収まるようにしました。そして明らかに、以前の修正だけでは実現しませんでした。その過程で、Speculaの最終合成結果に大きく貢献したいくつかのマイクロアーキテクチャ最適化を実験しました。
リオーダバッファの削減がハイライトの1つでした。私がしたことは、リオーダバッファを64エントリから32に削減しただけです。元の64エントリは、この設計が必要とする容量よりも多かったため、リオーダバッファをターゲットに選びました。その深さを減らすことで、追跡する必要のあるインフライト命令の状態と関連ロジックの量も削減されました。この変更により、LUT使用量は驚異的な5,701、フリップフロップ使用量は3,837削減され、WNSは0.8 ns改善されました。意味のあるタイミングペナルティなしで大幅な面積削減です。
コンピュータアーキテクチャの講義では、設計を最適化する最良の方法の1つはパイプライン化することだと常に聞くでしょう。簡単に言うと、パイプライン化とは、大きなタスクを小さな順次ステップに分割し、各ステップが1つの特定のジョブだけを行う技術です。ステップ1がその部分を終えるとすぐにステップ2に渡し、次の生のピースをすぐに掴みます。各ステージは作業を前方に渡し、すぐに次の作業を開始するため、誰も待機せず、各ステージ(ステップ)は同時に忙しくなります。私も同じことをしました!メモリパイプラインを再構築しました。当初、選択、アドレス生成、メモリ発行はより密接に結合されており、長い組み合わせパスを作成していました。パイプラインを分割して、適格なメモリ操作の選択とその発行が、もはや1つの長い組み合わせシーケンスの一部ではなくなりました。もちろん、これは追加のステージングを導入しましたが、初期分割後にWNSは約-20.9 nsから-7.0 nsに改善されました。アドレス生成の後のさらなる分離により、約594 LUTの削減とともに、さらなる改善が得られました。
[画像: Specula memory pipeline]
Speculaのメモリパイプラインの再構築。操作選択、アドレス生成、メモリ発行を個別のステージに分割しています。
フロントエンドとディスパッチロジックも確認する必要がありました。フェッチと変換の側面では、ページング関連の状態を登録し、ページテーブルルートアドレスの処理方法を再構築するなど、いくつかのターゲット変更を行いました。ディスパッチ内の構造も再確認しました。物理レジスタのフリーリストは、当初、利用可能なレジスタを特定する必要があったため、その選択ロジックをバランスの取れた2レベルの8x8ピッカーに再構築しました。
[画像: Specula frontend and dispatch structures]
Speculaのフロントエンドとディスパッチの最適化。Sv32アドレス変換、フェッチプリデコード、物理レジスタ割り当てをカバーしています。
その他の最適化と実験
| 最適化 | 結果 |
|---|---|
リザベーションステーション notFull ロジック | 採用。 313 LUTのコストでWNSを-1.24 nsから-0.57 nsに改善。 |
| DSP48E1 PREG 統合 | 採用。 乗算器結果レジスタをDSPの内部パイプラインレジスタに吸収。 |
| MMUアドレス連結 | 採用。 アドレス加算器を連結に置き換え、124 LUTを節約。 |
| メモリキューオペランドキャプチャ | 却下。 LUT使用量を934増加。64:1レジスタ読み取りがディスパッチに移動。 |
| ROBエントリのスリム化(133 → 96ビット) | 却下。 フリップフロップを1,162節約したが、LUT使用量を1,036増加。 |
| 物理レジスタファイル(64 → 48エントリ) | 却下。 フリップフロップを521削減したが、LUT使用量を120増加。 |
Speculaで試したすべての最適化をここに書き出すと、おそらく研究論文のドキュメントになるでしょう。しかし、ポイントは、既存のメカニズムが不必要な作業をどのように作成しているかを特定し、その作業を効率的な方法で再構築できるかどうかを問うことだと思います。
これらの最適化の後、最終的にターゲットタイミング制約に非常に近い設計が得られました。最終的なVivado合成では、19,675 LUT、12,466フリップフロップ、3つのDSP48E1ブロックが報告され、BRAMは推論されませんでした。これは、Basys 3の公称LUT容量20,800の94.59%です。10 nsのクロック制約(100 MHz)に対して、設計はWNS -0.115 nsを報告し、タイミング違反のエンドポイントは1つだけでした。
クリティカルパスは、開始地点から大きく移動していました。もはやプロセッサの実行パイプラインではなく、VirtIOデバイスモデルのアドレス計算を通っていました。
[!NOTE] これらは合成後の結果であり、配置および配線された実装ではありません。RAMとディスクイメージはブラックボックス化され、シミュレーション指向のロジックが設計にまだ存在していました。そのため、合成されたLUT数はBasys 3の公称容量を下回っていますが、システム全体がボードに収まり、100 MHzで実行できるとは限りません。
クライマックス
はい、Speculaは本当に私がこれまでに試みた中で最も挑戦的なものの1つでした。自分が何をしているのかまったくわからない瞬間がたくさんありましたが、正直に言って、それはおそらく全体の経験の中で最も価値のある部分でした。Speculaにはまだ探求すべきことはたくさんありますが、すぐに探求できるとは約束できません。
あなたのために、ここまでたどり着いたので、何かがあります。マイクロアーキテクチャ、タイミング、アウトオブオーダー実行の深淵に数時間を費やしたい場合は、ここから始めるのが良いでしょう。
- Tomasulo's algorithm は、リザベーションステーションと動的スケジューリングの背後にある元のアイデアであり、「結果は好きなときに到着できる」という動作の由来です。
- AMDのVivado Design Methodology guide (UG949)は、テキストエディタを開く前に論理レベル、ファンアウト、レジスタ配置をどのように考えるかについての良い読み物です。高Fmaxのために最初から設計したい場合。
- John Paul ShenとMikko LipastiによるModern Processor Designは、実際ののアウトオブオーダーコア内のパイプライン、ストアフォワーディング、および投機について参照する教科書です。
- Out-of-order execution, register renaming and retirement は、アウトオブオーダー実行に関する素晴らしい詳細な解説であり、彼は同様のコンテンツに関する多くの貴重な情報を持っています。
そして、パイプラインのバランスを取り、比較ツリーを再構築し、レジスタポートをいじくり回すのに数週間費やしても、ハードウェアがクロックターゲットに到達しない場合は、究極の最適化戦略があります。
[画像: xkcd 378: Real Programmers]
Real programmers use butterflies.