FPGAをはじめてみたい
「FPGAという何やら面白いものがあるらしくて、使うとすごい計算やいろいろなデバイス制御ができるらしい。」
と、興味を持って頂ける方はそれなりにいらっしゃるのではないでしょうか?
早速なんらかのHDLなる言語を勉強し、例えば SystemVerilog を少し勉強すれば下記のようなプログラムを書くことが出来ます。
入力ポート a,b から入ってくるデータをクロックサイクル毎に加算してc に出力するロジックのソースです。
module add ( input logic reset, input logic clk, input logic [31:0] a, input logic [31:0] b, output logic [31:0] c ); always_ff @( posedge clk ) begin if ( reset ) begin c <= 0; end else begin c <= a + b; end end endmodule
すばらしい! これであなた専用の加算エンジンができあがりです。 このエンジンは 300MHz で動かせば 300MOPs の演算能力を持ち、10個並べれば 3GOPs、10000個並べれば 3TOPs です。
と、ここまではプログラミング言語を教科書通り勉強すればたどり着くのですが、
で、「ここにどうやってデータ入れればいいの?」
という、最初にして最大の壁がやってきます。
- 例えば PCIe経由でPCのCPU上で動くプログラムからデータを送り込む
- 例えば USB経由でPCのCPU上で動くプログラムからデータを送り込む
- 例えば LAN経由でPCのCPU上で動くプログラムからデータを送り込む
- 例えば HDMI の入力や出力に繋いで2つの画像を合成する回路として使う
などなど、いくらでも思いつくわけですが、
- PCIeのI/F回路とプロトコルスタックをFPGAにも作らないと繋がらない
- USBのI/F回路とプロトコルスタックをFPGAにも作らないと繋がらない
- Ether のI/F回路と TCP/IP のプロトコルスタックをFPGAにも作らないと繋がらない
- HDMIの入出力回路やタイミング同期する周辺回路を作らないと繋がらない
などなど、周辺回路を何とかしないといけないわけです(実は最後の奴が一番楽じゃないかとすら思う筆者ですが)。
ここでメーカーが用意してくれてるものやOSSなど「今あるサンプルを使って何とかする」という流れになるのは当然なのですが、しばし、やりたい計算とインターフェースの仕様が整合しない(逆もしかりで、インターフェースの性能を活かせる演算器にすべき部分もある)ので、折角書いた演算器の性能が出ずに、CPUで計算した方が速いなんてことになることもしばしばです。
また、性能が出ても「こんなに大変じゃ、やってられない」と工数当たりの利得が得られないケースもありますし、「引き継げない」「メンテできない」と言った理由でビジネスの選択肢から外されるケースもあるでしょう。
極論ですが、現状この壁がFPGAの最大の壁で、息をするようにこの壁が乗り越えられるレベル に達すると、もう何でもできるFPGAマスターになっている気がします。
FPGAを勉強するにはFPGAが出来ないといけない、という、「缶詰の中の缶切り」状態になりかねません。
逆に、既にこの壁を乗り越えてしまった人には、もう壁でなくなっているので、この壁を何とかしようとする動機が薄れる気がします。乗り越えたら乗り越えたで振り返らずに折角できるようになったやりたかったことをやりたいのが人と言うものです。なので初心者の壁がいつまでも高いままそこに居座っている気もしています。
対CPU データ交換は Zynq が一番答えに近い?
この問題は、「何をする為にどんな方法で何とデータ交換するか?」によって解が違うので、一概に一発で解決できるソリューションはあまりない気はします。古くは RS-232C で UART 通信するロジックをせっせと書いたり、EZ-USB のようなものを使ったり、あれこれやっていたのですが、なかなか銀の弾丸にはなり得ませんでした。 Alveo などの解もあるのかもしれませんが、趣味で使うにはなかなか高価です。
そんななかで、対 CPU 通信に関していえば Zynq は(というか Linux の FPGA Manager は)、比較的再利用性の高い CPU と FPGA 間の接続環境な気はします。
例えば PYNQ
例えば私は使ったことないのですが、PYNQ などは、データ転送の性能はともかくとして、非常に多くの環境に同じインターフェースを提供し、多くの Python ユーザーに対して、冒頭の課題に対するひとまずの解決を提供しています(もちろん性能出そうとすると、いろいろ周辺回路の準備も必要なのですが)。
ACRi さんのブログ記事「PYNQ を使って Python で手軽に FPGA を活用 (1)、 (2)、 (3)、 (4)、 (5)」 などもとても興味深い記事でした。
Python 使う方々に向けて、「次にC言語覚えるより Verilog 覚える方が楽しいですよー」と、勧誘するのにとてもよさそうなツールに思えました。
やはり u-dma-buf が至高?
そうは言っても Rust や C/C++ でせっせと低レイヤーを叩いている筆者としては、もう少し直接的にアクセスがしたくなるわけです。
Zynq を使う上では、さしあたっては root 権限で /dev/mem
を叩く方法があるわけですが、それだとメモリマップドI/Oにアクセスできるだけでやはりいろいろと性能を引き出すには難しい部分があります。
そうなってくると ikwzm氏の u-dma-buf などが神ソフトになってくるわけです。
他には同氏の uiomem だったり、Linux の UIO だったり、このあたりが Zynq 等の SoC の載ってる 色んなボード環境で共通的に使える というのが非常にありがたいわけです。
FPGA と CPU の間のデータのやり取りで、ある程度エコシステムと呼べるような、流用性の高いOSSなどのソフトウェア資産の走りとも言えるもので、私の中ではとても有難い物でした。
なお、筆者も調子に乗って Rust の本来あるべきメモリ安全性を棚に上げて unsafe だらけのこんなクレートを作ったりしています(苦笑)。
/dev/mem
を叩く類の操作は、「PL をちょっと試してみる」という、ユニットテストを書くのに近い部分があるので、unsafe 多用でも便利な方が嬉しいケースもあるので、まあお許しください。なお C++版はこちらに記事にしていたりもします。
それでもデバイスドライバを書くのが最善ではある?
それでもやはり、最後は、自分でデバイスドライバを書くのが最善という事にはなってくるのかなと思います。
/dev/mem
を叩くのに始まる汎用ドライバの利用は、どうしてもユーザーアプリが終了した場合の、PL の後始末に責任を持ってくれません。
Linux のプロセスが落ちると、確実にデストラクタを読んでくれる保証がないので、「DMA を起動したままアプリが落ちる」と言うような危険な状態に陥ることを回避できません。
一方で、ちゃんとデバイスドライバを作れば、Linux はプロセス終了時に開いているファイルはすべて閉じてくれますので、安全な後始末を保証する事も可能になります。
なにより、ドライバのオープン中はプロセスが存命中であることを保証できるので、ユーザープロセス側のメモリにPLからアクセスする という事も可能になります。Linux のデバイスドライバ内では ユーザープロセスの論理空間にアクセスするためのページテーブルを作ってもらうようなシステム関数にアクセスできますので、ある意味何でもありですので、「メモリコピーを減らして最高パフォーマンスを出す」にはこの方法が必要になる気がします。
おわりに
またしても何のソリューションも示していない駄文になってしまいましたが、この「FPGA の勉強を始めたときの壁」に対しては私も何らかのアプローチが出来ないものかとは常々思っている次第です。
- PLへの bitstream のロード/アンロード
- UIO とか u-dma-buf とかのロード/アンロード
- メモリマップドI/O への高速な読み書き
- カーネル空間で確保したメモリへの読み書き
- ユーザー空間のメモリへの読み書き
- PL側のDMAや、CPUからのアクセスを受け付けるインターフェイス回路
などなど、このあたりのソフトウェア資産を使いやすく整備していく必要がある気はしています。
Zynq などの登場で、「FPGAボードとCPUの接続形態がボード毎に一点物で終わる」という事態がだいぶ回避されて使いまわしが効くようになってきているので、今後ますます資産が増えていく事を期待する次第です。
余談
なお、今回はあくまで 対CPU の話でして、私のような「カメラやディスプレイの動作タイミングに合わせて、その間で動くAI認識エンジン作って遊ぼう」みたいな、CPU 置いてけぼりの世界でコンピューティングを楽しんでいる人間には実はあまり関係なかった話ではあります。
そういった別ルートから RTL を覚えて、ある程度使えるようになってからCPUとのやり取りを始めた、という経歴なので、ある意味チートコースでこの壁を乗り越えてきた人間だったりもします。
一方で、現在の IoT 全盛期に CPUと繋がってインターネットと繋がって、多彩なIT処理と有機的に繋がっていくことは既に必須事項になっているので、今からFPGA を始める方には、その価値を引き出すための最初のハードルがとても高くなっているのではないかと言う気もしています。
FPGAプログラミングは、極めて低レイヤーで、リアルの世界に対するインタラクションを行う部分で非常に強みを発揮しますので、まさにリアルとバーチャルを繋ぎ合わせて新しいコンピューティングを生み出してくれる可能性のある領域です。 是非是非、新しい方にどんどん参入してもらえるように、いろいろな壁を取り払っていきたいものです。
そして何より、冒頭のような 3GOPs のエンジンを作ったとして、それをちゃんと 3GOPs で働かせるための計算機アーキテクチャとは何ぞや? という本質の部分で思い悩める領域に入ってきていただきたいと思うわけです。
壁は高くとも、乗り越えると本当に楽しい領域です。より多くの方と一緒に FPGA を楽しめればと思います。