Verilator + Pybind11 で行う、RTLでのアルゴリズムの開発
概要
何らかの問題を解くアルゴリズムをFPGAで作り上げたい場合、例えば Python などで大雑把にアルゴリズム検討をした後に、精度など考えて固定小数点化などもしつつHLS用のC言語に書き下ろしてFPGA用のロジックにコンパイルする、というようなことをされたことのある方も多いのではないでしょうか?
一方で、FPGAならではの計算機アーキテクチャを考えつつ、それに適した形でアルゴリズムも変形していくようなやり方もFPGAならではの醍醐味であります。
この時、HLSで書ければもちろん構わないのですが、トリッキーな内蔵RAMの使い方でキャッシュのようなものを組んで性能を出すとか、DSP部分をフルに使った高密度な演算エンジンを組むとか、ちょっとしたマイコンのようなものを構成してアーキテクチャを構成したいとか、RTLでアルゴリズムを書いたほうが楽しめる要素もまだまだFPGAには残っています。
もし HLSとRTLの関係がC言語とアセンブラのような関係であれば、拘りたいところだけRTLで書けばよいのですが、残念ながらRTLで書いた特殊演算エンジンをHLSから呼び出すようなことはできません。
したがって、RTLを使ってアルゴリズム+計算機設計を楽しむ際には、どうしてもRTLの記述量が増えてしまいます。
また、アルゴリズム自体の精度評価なども必要で、RTL で記述してしまうと、特に画像処理などでは非常に計算時間がかかってしまって、大量のデータセットを流し込んで最終的な精度を見ながら、有効桁数やパラメータ調整を行っていくのも大変です。
しかしながら、Verilator を用いれば、SystemVerilog を C 言語に変換してくれますので、HLS に近い速度での実行が期待できます。
この話は以前こちらに記事を書いております。
今回は、Verilator で変換したVerilogソースを Pybind11 から呼び出すことで、RTLのままアルゴリズム評価に使ってしまおう、という試みのための実験です。
「こんなこともできるよ」という可能性が提示できればと思います。
狙いどころ
今回の狙いどころは下記です。
- 従来 : Pythonでアルゴ考えて、C言語で精度評価して、終わったらHLSでRTLに変換して終り
- 今回 : Pythonでアルゴ考えて、Verilogで精度評価して、終わったら終り
C言語の代わりに SystemVerilog で書くということがミソですが、SystemVerilog も昔の Verilog に比べるとかなり、ソフト屋さんにフレンドリーな言語になってきていますので、案外生産性良く書けるケースも多いです。
HLSで限界までチューニングしていて、「いっそRTLで書かせてくれ!」と思った経験がある方も案外おられるのではないでしょうか?
結局、「アルゴリズム精度評価とネットリスト生成の2つを1つのソースからやってしまおう」という点ではHLSと同じで、
- HSL : C/C++言語をVerilogなどのRTLに変換するツール
- Verilator : SystemVerilog を C++言語 に変換するツール
なわけですから、結局、言語を変えただけで同じ開発フローをやろうとしているわけです。
今回作ったもの
今回作った評価環境はこちらにありますが、pybind11 を使ったということ以外は、以前作ったC++の動作モデルに、
を追加したのみです。後は pybind11 の使い方ですね。
PyBind11 の準備
やるべきことは
pip install pybind11
だけとなります。
Verilator でビルドの為に cmake を呼び出すときに
-Dpybind11_DIR=`pybind11-config --cmakedir`
というオプションを付けておけば CMakeLists.txt の中で
find_package(pybind11 REQUIRED)
とすることで pybind11_add_module() などが使えるようになります。
やってみる
全体構成
今回は、幾つか過去に作っていた簡単な画像処理の呼び出しをやってみました(HLSで書いたほうがいいものも多いですが、あくまで手法のお試しなのでご容赦を)。
全体構成としては下記のような感じです。レジスタ書き込みのバスがWISHBONEバスなのは完全に筆者の好みによるものですが、必要に応じて AXI4-Lite などにブリッジすることは難しくないのでご容赦ください。
大雑把な処理の流れとしては
- WISHBONEバス経由でレジスタ設定を行う
- Axi4StreamWriter にが画像を流し込む
- シミュレーションを進める
- Axi4StreamReader から結果を読みだす
となっております。
この形に特化した形ではありますが、使いやすいようにテンプレート化したのがこちらです。基本的なアクセス機能をつけたC++のクラスを作ってしまえば簡単に Python から呼べるようにできてしまうのが Pybind11 の凄いところですね。
Filter2d 処理
環境が構築で来ている前提になりますが、試すだけなら以下のような流れです。
git clone https://github.com/ryuz/jelly.git
で取得いただいた後、画像などは各自で準備して、ソースのパスなど修正が必要ですが、基本的には
cd jelly/python/verilator/filter2d
make build
make run
下記のようなスクリプトが実行され
下記のような結果が得られます
Sobel フィルタ処理
同じようにお隣の Sobel では
ACPI法でのデモザイク処理
おまけ(KV260 に RaspPI カメラをつないで撮影したものの)
波形確認やカバレッジもできる
ここでなんと Verilator を使ったビルド時に TRACE や COVERAGE を有効にしておくと、波形確認やカバレッジ確認もできてしまいます。
アルゴリズム評価だけでなく、テストベンチとしての機能もある程度 Python で書けてしまうわけですね。
速度が欲しい時とオプションを使い分けると便利だと思います。
おわりに
今回は .py で試しましたが、もちろん .ipynb なファイルで Jupyter Notebook や VS-Code などからインタラクティブに呼び出して使うこともできます。
Pybind11 のお陰で、極めて簡単にこういう事が出来てしまうのが有難いです。アルゴリズム評価においてはインタラクティブに結果を見ながらパラメータ調整ができることはとても嬉しいです。
また、大量の画像セットを流して、結果の統計を分析することも多いわけですが、Verilator で出力されたコードは結構高速ですので、HLSほどではないにせよ、実用に耐える速度が期待できます。
HLSなどといった便利なものがなかった時代、Python に類するようなインタラクティブで高級な言語でアルゴリズム検討を行った後、C言語などで精度も加味したRTL化用のコードを書いて、さらにそこから等価なRTLを人間が書き下ろして、C言語とRTLの結果が同じになるまで様々な検証をやって、やっと完成するというような手順が世の中にはたくさんありました。
HLSの登場で、1つのソースで、アルゴリズム評価とネットリスト生成の両方ができるようになり、等価性の確認を人力でやらなくてよくなり、生産性は一気に上がりました。
一方で、今回はそれと同じことを Velilator の力を借りて、C言語ではなくSystemVerilogでやれることも確認できたわけです。
選択肢が増えたことで、HLSよりもRTLが適した処理を開発するときの手助けになれば幸いです。
Discussion