FPGA開発日記

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

MicrosemiのFPGA向けRISC-Vソフトコア

Microsemiが自社のFPGA向けに、RISC-Vのソフトコアを発表した(FPGA向けは世界初ということだが)。

www.newelectronics.co.uk

http://www.microsemi.com/images/soc/products/nav/processors/Microsemi_IGLOO2_RISC-V_Block_Diagram_2016_11.jpg

(画像はMicrosemiのウェブサイトより引用。)

Microsemiの発表によれば、自社のFPGA(SmartFusionおよびIGLOO)向けのRISC-VソフトコアIPを開発したとのことで、Eclipseベースのソフトコンソールも提供される。

詳細はこっちだ。

www.microsemi.com

RV32IMということは、32ビットの最小構成タイプ、浮動小数点は付いておらず、パイプラインは5段。おそらく制御コアとして利用することを想定しているのだろう。

上記のMicrosemiのウェブサイトを見る限り、RISC-VのIPの外にはDDRのコントローラがAXI経由で接続されており、PLD部(?)とはAPB経由で接続されるようになっている。 Zynqで言うところのARMコアの立ち位置ということで良いのかな。ということは、動作周波数はどれくらいになるのだろう?

ロジックの量で言うと、

Suitable for use with all Microsemi FPGAs, the RISC-V core requires about 12,000 logic elements.

なので、MicrosemiのFPGAのロジックエレメントの規模が良く分かっていないが、数値的にはあまり大きくない感触ではある。

ってか、Microsemiは自社のFPGA向けに他にどのようなソフトコアIPを提供しているんだ?

www.microsemi.com

それなりに揃っている印象ではある。Cortex-Mとか用意しているのならそれでも十分じゃないかと感じる。Cortex-Mで性能が足りない、という状況を想定しているのかな。

だとしたら、各種ソフトコアIPの性能比較の表を用意するべきだろう。これではRISC-Vを選択するメリットが分からない。

もうちょっとリリースノートを読み進めてみる。

  • SoftConsole v5.0 Release Notes

http://www.microsemi.com/document-portal/doc_download/136463-microsemi-softconsole-v5-0-release-notes

SoftConsole v5.0 supports development and debugging of software targeting RISC-V CPU based SoCs on Microsemi FPGA devices.

ははあ。Linux経由でFPGA上のRISC-V CPUコアをデバッグできるという環境のことか。 OpenOCDなどという記述も出ているので、JTAG経由でデバッグするのかな?

L1データキャッシュの実装設計(LSUとの接続部の検討)

L1データキャッシュは、L1命令キャッシュと違って書き込みにも対応する必要がある。もちろん、LSUもReadとWriteを同様に対応しなければならないのだが、いくつかの問題にぶち当たった。

一般的なLSUの構成

一般的なLSUの構成は、Hisa Ando氏の本にあるように、以下のような構成を取るものが一般的である。

高性能コンピュータ技術の基礎

高性能コンピュータ技術の基礎

f:id:msyksphinz:20161116013833p:plain

LSUは、データの一貫性を保つために、ロードとストアの順番について制限がある。 - (基本的に)ストアは順番に実行する。 - (命令的に)ロードの前にストアを実行する。

このようにしないと、同じアドレスにおいてストア命令がロード命令に追い抜かされてしまう場合が発生し、データがメモリに書き込まれる前にロードをしてしまい、誤ったデータをロードしてしまう可能性がある。

上記のロードキューとストアキューを別々にした場合にも当該の問題が発生する可能性がある。 つまり、ロード側のキューが掃けるのが先の場合、ストア命令よりもロード命令が先に実行される可能性があり、その結果データが正しく読み込まれない場合が発生する。

この場合に備えて、ストア側のキューからロード側のキューへフォワーディングする機構が存在する(メモリディスアンビギュエーション)。

しかし、そもそもこの上記の図は、メモリに対してロードとストアが同時に発行できることが前提だ。では、L1キャッシュがロードとストアを1つのポートから実行しなければならない場合、どのように実装すべきか?

L1キャッシュの口がロードとストアで共通の場合

この場合、そもそも上記のようにロードキューとストアキューを別々に分けるのはナンセンスということになる。 どちらのキューからリクエストを出すのか選別しなければならなないし、それを実現しながらメモリの一貫性を保つ必要がある。

そうすると、一つのメモリキューからリクエストを出すのだが、これがやっかいだ。

下記はそのようなロードストアキューを表現してみた。この場合、インデックスは昇順で進んでいき、Index=2のストア命令を実行中。ただしコミットはIndex=3まで確定。 それより先の命令はまだコミット未確定ということになる。

f:id:msyksphinz:20161116015817p:plain:w400

ストア命令は、メモリ(まずはL1キャッシュ)にリクエストを出すのは、その命令が確定するまで、つまりコミットが発生しないと進めることができない。 一方でロード命令は、メモリにリクエストを出すのはコミットを待つ必要がない。このため、自由にメモリへのリクエストを出しつつ、フラッシュで破棄される場合はリオーダバッファをクリアするだけで良い、という訳だ。

そうすると、パイプラインフラッシュが発生した場合に、どこまで命令キューを元に戻すかという問題がある。

  1. ストア命令が完了して、ストア処理を実行中の場合→ストアロードキューの先頭ポインタを元に戻す必要はない。ストアは命令コミット確定後の操作のため、そのまま実行し続ける
  2. ロード命令が実行されている場合→当該ロード命令は破棄すべき。確定したコミット位置まで戻す必要あり。

そうすると、結局上記のExeIndexをどこまで戻せば良いのか?ということになる。きちんと定式化できたとしても、実装するのはかなり複雑になるのではないか。

一つの解決策

そもそもロード命令とストア命令の実行が確定するタイミングが上記の1.と2.で異なる。 これが問題なのであって、ロード命令であっても、ロードオペランドが確定した時点で(メモリアクセスを実行する前でも)、仮のコミットを発生してしまう。

このコミットが発生すると、ロード命令が確定され、フラッシュ対象から外れる。 このフラッシュ対象から外れたロード命令はかならず実行されるため、実行タイミングとしてはストア命令と同一になり、キューの管理が楽になる。

f:id:msyksphinz:20161116020446p:plain:w400

二つめの解決策

最初からロードとストアのキューを分け、メモリディスアンビギュエーションを実装する。 さらに、L1キャッシュの制御ステートマシンを複製し、メモリのリード用ポートとライト用ポートを分離する。 これによりL1キャッシュはロードとストアを別々のステートマシンで同時に処理できるようになる。

問題は、タグメモリとデータメモリを、デュアルポート化して、ロードとストアを同時に処理できるようにならなければならない。 f:id:msyksphinz:20161116020814p:plain

追記: 二つめの解決策はダメだ。もし同時にミスを検出した場合、やはりどこかで外部のインタフェースのためにリクエストを一本に統一する必要がある。 結局どこで一本に統一するかの違いだけであって、一つめの解決策が実装のし易さについても有 利な気がする。

RISC-Vのトレードマークと商標利用について(1)

RISC-VのMLにて、商標利用およびトレードマークの扱いについて議論が起きている。

正直、商標や、著作権などについては全くの素人のため、あまり詳しい部分は分かっていないのだが、現状のRISC-Vの商標について調べてみた。

ロゴについて

riscv.org

RISC-V商標またはRISC-Vロゴは、以下のガイドラインに従う限り、非営利の研究および学術プロジェクトに自由に使用することができます。

https://riscv.org/wp-content/uploads/2015/11/logo.png

ただし、ちょっとしたバリエーションもあって面白い。色調を合わせるときなどに使用できるようだ。ちなみに、「RISC-V Colors」という項目もあり、読んでみると面白い。

https://riscv.org/wp-content/uploads/2015/11/primary_alternative.png

https://riscv.org/wp-content/uploads/2015/11/limited_use.png

RISC-Vのトレードマーク使用について

メーリングリストの中には、

Which brings us to the use of the RISC-V logo and word mark (trademarks).
Our intent here is to have the trademarks used as a trusted label across implementations.
For non revenue bearing projects (research, academic, open source, etc.), there is no charge for the trademark license although passing the to be defined, community generated compliance suites will be required. For all revenue bearing products and services (including offerings that are built on open source platforms), license to the trademarks will be provided to members of the RISC-V Foundation who are party to our soon to be released membership agreement (compliance suite testing applies here as well).

ううむ、Google翻訳

RISC-Vロゴとワードマーク(商標)の使用につながります。私たちの意図は、商標を実装全体にわたって信頼できるラベルとして使用することです。非営利目的のプロジェクト(研究、学術、オープンソースなど)の場合、定義されたものを通過するにもかかわらず、商標ライセンス料はかかりません。コミュニティが作成したコンプライアンススイートが必要になります。すべての収入製品およびサービス(オープンソースプラットフォーム上に構築された製品を含む)については、商標のライセンスは、間もなくリリースされるメンバーシップ契約の当事者であるRISC-V財団のメンバーに提供されます(コンプライアンススイートテストが適用されます)ここでも同様)。

もちろん、非営利な組織やオープンソースプロジェクトでは、RISC-Vのアーキテクチャとトレードマークを自由に使うことができる。 ただし、商用目的として利用する場合には、実装したアーキテクチャやシミュレータ、コンパイラなどに小してコンプライアンステストスートを通過させる必要がある、ということになりそうだ。

もちろん、オープンソースプロジェクトについても、コンプライアンステストスイートを通過させる必要があるだろう。そうでないと、RISC-Vに対応ということを謳うことは出来なさそうだ。

If a company builds proprietary extensions on top of that open source platform for commercial benefit, that company would be required to obtain a trademark license as part of the RISC-V Foundation membership in order to call their product a RISC-V product.

命令拡張などを商用製品の拡張として企業が行う際には、もちろんRISC-Vの委員会からトレードマークライセンスを取得する必要がある。

まだ自分でも理解し切れていない部分がある。もうちょっとまとめなければ。

L1データキャッシュの実装検討(ステートマシン作成)

前回までの実装で分岐予測の機構までは実装できたが、L1データキャッシュの実装がまだできていない。 L1命令キャッシュの実装は完了しているのだが、L1データキャッシュは、さらに以下の実装が必要だろう。

  • データ書き込み処理
  • データ書き込み時の、キャッシュアップデート処理
  • データ書き込み時にキャッシュが既に埋まっていた場合の、キャッシュの追い出し処理

これらをどのようにして実装するか、ということを考えていき、Verilog-HDLに落とし込んでいきたい。

データキャッシュとCPUコアの接続

データキャッシュは、CPUコアに対して以下のように接続されると考えている。

f:id:msyksphinz:20161114085558p:plain

L1データキャッシュを制御するためのステートマシンが存在し、それに対してタグメモリ、データメモリが接続されている。 タグメモリとデータメモリは、CPUコアからのリクエストが発生すると直ぐに読み込みに入り、ヒットすればそのままデータ処理、ミスすればAXIの外部インタフェースにリクエストを出す、ということになりそうだ。

ここでFastAXIと書いているのは、別にそういう規格がある訳ではなく、オリジナルで設計したバス規格で良い、ということだ。

データキャッシュを制御するためのステートマシンの設計

さて、データキャッシュを制御するためのステートマシンだが、読み込み処理と書き込み処理に分けてステートマシンを考えることができそうだ。

データキャッシュへの読み込みリクエスト

データキャッシュへの読み込みについては、リクエストが出された状態で、デファルトでステートマシンがCompareTagステートにいるとする。 ここで直ぐにタグ比較を行い、ヒットすればそのままステートを変化させずにデータを返す。

しかしミスとなれば、当該ラインの置き換えを行わなければならない。この場合には、

  • タグキャッシュの当該ラインがDirty(Writeリクエストによりアップデート済み)ならば、当該ラインを外部メモリにスピルアウトする。
  • タグキャッシュの当該ラインがDirtyではない、あるいはEmptyである場合には、該当するラインを外部メモリからロードする。

という処理が必要になり、ステートマシンは以下のようになるだろう。

f:id:msyksphinz:20161114090212p:plain

まず、ヒットすればそのままデータを読み出す。ミスで、かつ当該タグラインがDirty状態であれば、データを一度AXIバス経由で外に出し(Wait AW_ACK, Wait W_ACKステート)、本当に欲しいデータを読み込んでくる(Wait AR_ACK, Wait R_Ackステート)、という具合だ。 もし当該タグラインがDirtyでなければ、そのまま本当に欲しいデータを読み込んでくれば良い(Wait AR_ACK, Wait R_Ackステート)。

データキャッシュへの書き込みリクエスト

書き込みリクエストも、同様のステートマシンで処理できると考えている。

f:id:msyksphinz:20161114090440p:plain

分岐予測実装に関する考察と実装(3. 自作RISC-Vプロセッサを使った実験)

前回までで、分岐予測の実装についておおよそ解説した。分岐予測は、

  • 予測を早いステージで実行する。複数命令を同時に実行する場合は、どのウェイを有効にするかよく考えること
  • 予測結果は分岐ユニットで判別する。無条件分岐命令でも、レジスタ相対ジャンプは常に予測成功となる訳ではないので注意すること

ということを注意する必要がある。

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

これらの考察をもとに、自作RISC-Vプロセッサに分岐予測を実装した。この効果を測定してみよう。

といっても、自作RISC-Vプロセッサは数ヶ月前から実装しているもので、分岐予測もここ数週間をかけて実装したものだ。すぐに出来たわけではなく、かなりバグも残っていると思うので、検証は継続して行う必要がある。

自作RISC-Vプロセッサで、Coremarkがとりあえず動作するようになってきた。そのうちgithubに公開しようと思うが、とりあえずは満足できる性能が出せるまではプライベートリポジトリで作業する。

ちなみに主なスペックは

  • 4命令同時実行のスーパスカラ、アウトオブオーダ発行、インドーダ完了
  • 1st Icache, Dcache搭載
  • 整数命令のみ実装。32ビット幅。CSRなどは未実装、割り込みは未実装

と、命令実行幅のみやたらと広く、まだ基本的な部分の実装を全て終わらせることが出来ていない。 CSRとかちゃんと実装しないと、OSも立ち上げられない...

また、分岐予測もまともに実装できていない状態だったため、性能はかなり低いものだった。分岐予測を実装したことにより、どの程度性能が向上したかを見てみよう。

分岐予測の基本スペックは、単純な1段分岐で、これもまだ十分なものとは言えない。また分岐対象の命令は、

  • 比較命令(相対ジャンプ)
  • 即値ジャンプ命令 (JAL)

とした、JALRは命令のレジスタ相対ジャンプのため、予測が難しい。リターンスタックポインタとして利用されている状況が判別できれば、やりようはあるかもしれない。

サイクル数 CMK/MHz
分岐予測未実装 1110419 0.90
比較命令のみ分岐予測 702470 1.42
比較命令+即値命令の分岐予測 676250 1.48

比較命令および即値命令に対して分岐予測を実装したことにより、おおよそ50%の性能向上となった。

CPUの性能に詳しい人ならば直ぐに分かると思うが、この性能ではまったくのダメダメだ。BOOMの測定結果を見てみると、4-wayの実装にてCoremarkのスコアは4.0を軽く越えていたように思う。 最近のアウトオブオーダプロセッサならば、4.0は越えてあたり前なのだ。

IPC測定

一応現在の体力を把握するために、Coremarkを走らせた場合の1000サイクル毎のIPCを測定してグラフにしてみた。

f:id:msyksphinz:20161111022845p:plain

だいたい0.4あたりに中央値がありそうだ。これはヒドい。

弱いところを見付けて、早急に改善しなければ。。。

分岐予測実装に関する考察(2. 分岐予測の結果反映と、結果のリプレース)

前回の続き。分岐予測を実行するところまで書いたが、今度は分岐が当たったかどうかを調査しなければならない。

msyksphinz.hatenablog.com

分岐予測の成功条件、分岐予測の更新条件

分岐予測に成功した、というのは何だろうか?

  • 当該命令が「予測した」命令である (PR_EN_x)信号により判別する。
  • 予測した結果と「異なる」
    • 「分岐する」と予測したが「分岐しない」 or 「分岐しない」と予測したが「分岐する」(2.1.)
    • 「分岐する」と予測して正解したが、「分岐先アドレスが異なる」 (2.2.)

2.1. は、通常の比較および相対ジャンプにて発生する条件だ。つまり、飛び先は常に同一であるため、2.2.の「ジャンプ先アドレスが異なる」ということは発生しない。つまり、「分岐する」か「分岐しない」かのどちらかが成否に関係する。これはMIPSRISC-VではBEQ命令やBNE命令などに相当する。

一方で、分岐予測にて分岐すると予測し正解しても、実際には外れている場合がある。それがレジスタ相対ジャンプで、ジャンプしてもレジスタ値が異っていると、常に同一アドレスにジャンプしないのでミスとなる。 これはMIPSRISC-VなどではJALR命令などに相当する。

これらの条件を考えると、分岐予測は分岐の成立不成立のみを考える単純なものではなく、飛び先のアドレスまで考慮しなければならない。 アドレス比較も入るため高速に実行するのはなかなか難しいため、おそらく一般的なCPUではアドレスを削って判定しているだろうと思われる。 例えばテキスト領域に配置してある命令では分岐予測を実行するが、それ以外の場所では常に分岐予測を実行せず、分岐する場合は常にパイプラインフラッシュするなど。 これにより、比較するアドレス範囲を絞ることができ、回路の動作周波数を改善できる可能性がある。

f:id:msyksphinz:20161110011744p:plain

分岐予測テーブルの更新

最後に分岐予測テーブルを更新するのだが、

  • 分岐元のアドレス (次のフェッチでテーブル参照のインデックスに使われる)
  • 分岐先のアドレス (次のフェッチで分岐予測のジャンプ先として使われる)
  • 分岐したか否か (ステートマシンの更新)

の情報が必要だ。これらに基いて、分岐予測のテーブルがアップデートされる。

という訳で、分岐予測について2回に分けてまとめてみたが、これは私の趣味で作っている自作CPUのためのまとめなので、このまとめに基いてバグを潰さなければ。。。

変な方向にジャンプしてしまい今のところ上手く動作してくれない。。。

分岐予測実装に関する考察(1. 分岐予測する場所と、フェッチラインの考察)

2016/11/09 図に誤りあり。一部差し替えました。

CPUにおける分岐予測といえば、複数命令を同時発行させる現代のCPUにおいて不可欠な技術であり、投機実行の技術を支える重要な高速化技法であるが、だいたいのの解説書の場合、以下のような記述で説明がなされている。

以下の図はComputer Architecture Quantitative Approach, Fifth Editionより抜粋

f:id:msyksphinz:20161109015633p:plain

Computer Architecture, Fifth Edition: A Quantitative Approach (The Morgan Kaufmann Series in Computer Architecture and Design)

Computer Architecture, Fifth Edition: A Quantitative Approach (The Morgan Kaufmann Series in Computer Architecture and Design)

この図では、ステージ名がかろうじて書いてあるが、じゃあ実際にどうやって実装すれば良いんだろう?考えてみると、いろいろ複雑だ。

  • 分岐予測はどのステージで実行する? ** それに伴い、どの段階で命令フェッチを分岐予測に沿って変更すれば良い?
  • 分岐予測が当たったかどうかは、どのステージで判定すれば良い? ** 判定基準は?
  • 複数命令幅を同時にフェッチしてくるようなスーパスケーラのプロセッサでは、どのように実現すれば良い?

これらのことを考えながら、さらにどのような信号を定義するか、またどのような制御を組むかを考えなければならない。

分岐予測はどのステージで実行する?

分岐予測は、

  1. 予測元となるプログラムアドレス
  2. 予測先となるプログラムアドレス

の組で実現される。この予測元となるプログラムアドレスは、IFUつまり命令フェッチユニットから情報が得られる。 このプログラムアドレスは、例えばAXIなどで命令ワード幅以上の命令をフェッチしてくる場合は、複数のアドレスから調査する必要がある。

MIPSで0x1fc0_0000から命令を128ビット幅でフェッチしてきた場合、128ビット幅、つまり命令4つ分(0x1fc0_0000, 0x1fc0_0004, 0x1fc0_0008, 0x1fc0_000c)で分岐予測すべきアドレスが無いか、調査する必要がある。

f:id:msyksphinz:20161109021318p:plain

分岐予測の結果、得られる情報は?

分岐予測テーブルで、当該プログラムアドレスで分岐予測をすべきか調査した結果、ある命令で分岐予測できるということが分かった場合、情報を取得する。

  • PC_PR_EN_x (0<=x<4) : PC=A+x*4で分岐予測の履歴があり、分岐予測できる。
  • PC_PR_TAKEN_x (0<=x<4) : PC=A+x*4で分岐予測可能であり、かつ「分岐する」という予測である

この2つの情報が得られる訳だ。

分岐予測の結果、どのフェッチラインを破棄すべき?

そして、PC_PR_TAKENが1である場合、実際に分岐予測を実行する。ここで分岐元プログラムアドレスがA+0x8, 分岐先プログラムアドレスがB+0x04(Bが128ビットアラインとする)である場合、

  • A+0x00, A+0x04, A+0x08までは実行する
  • A+0x0c は破棄する

また分岐先プログラムアドレスBが128ビットアラインとは限らないため、最初の数ワードはフェッチする必要が無いかもしれない。この場合も、一応128ビット幅でフェッチしておいて、仕様しない場所の命令は無効化しておく必要がある。

つまり今回の場合は、

  • B+0x0は破棄する
  • B+0x04, B+0x08, B+0x0cを実行する

f:id:msyksphinz:20161109022131p:plain

f:id:msyksphinz:20161109084015p:plain