Ryuz's tech blog

FPGAなどの技術ブログ

RISC-Vもどきのバレルプロセッサ作ってみた

はじめに

だいぶ前に、RISC-V もどきの最小セットを作って遊んでいましたが、今回はその延長でもう少し遊んでみました。

動機としては

  • レジスタファイルの構成に LUTRAM や BlockRAM を使うのだから、レジスタ32個だけじゃもったいない
  • 複数スレッド動かすならパイプラインストール気にせずにパイプライン深くして周波数上げちゃえ

という話で、分岐予測の類の工夫は何もないまま、やみくもにパイプラインだけ深くするお馬鹿実装となっています。 例によって割り込みも無ければ、乗算器も除算器もない RV32I のコンパイラが流用できる最小セットになっています。

元々組み込みでコントローラとして使う分には、割り込みや例外は基本的にコンテキストスイッチの為にあるので、レジスタをスレッド数や割り込みハンドラの数だけ持って、ハードウェアスレッドをやるなら不要じゃないかという大胆な割り切りもあります。

それだけシンプル化しても 500MHz ぐらいヒィヒィ言ってるあたりが私の技量の無さではあるのですが、だましだまし動き始めたので少し記録としてブログにしておきます。

Intel の ハイパースレッディングなどで有名なSMT(simultaneous multithreading)は、命令の依存関係でどうしても発生する各種ハザード類に対して、依存性のない複数スレッドを混在させることでパイプラインの空きを埋めるのに有効な手法だと思います。

ちなみに今回はスーパースカラでも何でもないので SMT とは違っていて、何と呼ぶのがいいのか悩んでいたところ X で、「それはバレルプロセッサと呼ぶんだよ」と教えて頂きました。

FPGA では LUT の後ろには FF がいて、これをバイパスするかどうかでパイプライン段数は概ね決まってくるので、段数を増やしてもリソースコストはあまり増加せず、通常は

  • パイプライン段数を増やすことで増えるハザードや分岐予測ミスのペナルティ増加
  • パイプライン段数を増やすことで上昇できるクロック周波数

のバランスのいいところに落ち着けることになると思います(実際段数を倍にすると、周波数は倍にならないけどペナルティーは倍になるので)。 ですが、今回はバレルプロセッサの効果を体感するのが主目的なので、それらは無視してパイプラインをどんどん増やしてみました。

プロジェクトはこちらに入れています。

調子乗って 10段パイプラインになっていたり、途中にスキッドバッファ入れたら 500MHz に届いたとか、いろいろありました(笑)。

シミュレーション

一応、浮動小数点演算などが正しい結果を出し始めたので、Lチカするだけの馬鹿プログラムを書いてみたところ、ループ部分で分岐ミスだらけ(予測してないので当たり前)で、パイプラインがスカスカになってくれましたので、スレッドを増やして実験してみました。

バレルプロセッサのシミュレーション

上記は極端な事例ですが、スレッドを増やしてパイプラインを埋める効果はありそうです。

実機で動かしてみた

スレッド4つでそれぞれで LEDチカチカさせてみました。

ILA を入れるのに 400MHz で動かしたものが下記です。ちゃんとIDが切り替わりながら動いてるのが ILA で観測できました。

ILAの波形

実物もなんかそれっぽく点灯しています。

youtu.be

合成結果は以下の通りです。メモリは 8kバイトです(もっと増やせますが周波数が下がります)。

合成結果

今回はプログラムダウンロードを AXI4-Lite ではなく AXI4 でもできるようにしたなど余計な機能も入っていますが、システム全体でまあまあの規模ではないでしょうか(どうなんだろう)?。

本当にうれしいのか?

私個人としては以前にこちらで書いたように、1つのプロセッサを TSS (Time Sharing System) で使うのは、ポラックの法則的にはマイナスであり、単純に時分割でプロセッサリソースを配分するバレルプロセッサと言うのはリアルタイムコンピューティング的にはスジの悪いアプローチだと考えています。 本質的にはスケジューリングは優先度順に行われるべきと考えています。

一方で

  • シングルスレッドでどうしても発生するハザードでの演算器の稼働率低下を抑えられる
  • タスクスイッチのコストが無い

の2点についてはメリットがあると考えています。なので状況次第ではメリットが出てくると考えています。

今後どうするのか

要するに、優先度を考えずにスケジューリングをするのが問題なので、

  • あくまでユーザーの価値が最高となる順に優先度実行しつつ
  • 無駄が出そうなら次優先度のタスクを流す

という事が出来ればベストなわけです。

とはいえ、ハザードなどは実行時にしかわかりませんし、あまり予測機構にリソースつぎ込むと本末転倒になりかねません。

ローコストで出来る範囲で、これらに近づけていく事が、ポラックの法則へのささやかな抵抗になればと考えている次第です。

おわりに

KV260 で RISC-V が使いたいだけであれば、AMDMicroBlaze V や VexRiscv などが選択肢になると思います。

とは言え、自分で思いついたアイデアをあれこれ検証して中を弄ってみるのには、まずは自分で書いてみるというのは大事な事だと思います。

RISC-V アーキテクチャは、自由に作るとができ、情報やツールも多く、趣味的に弄るにはとてもよい題材だと思います。