FPGA実装について
どうも、12日目を担当する中村です。お待たせしました。
11日目のにしかわくんに引き続き、FPGAについてもっと知ってもらおうと思います(ちなみにASICの実装も同じ感じです)。
概要についてはにしかわくんの記事から知ってもらえたと思うので、今回は実装についてです。
あわせて読めばもうあなたも立派なFPGA屋さんになれるわけですね。
ソフトウェアの実装と同じようにFPGAの実装もプログラミングで実装を行います。
Verilog(ハードウェア言語)だと、意外とC言語と似た書き方をするところも多いので普段C言語を書いている人はつかみやすいかもしれません。ただ、あくまでハードウェア実装なので、実装の考え方なんかはソフトウェア実装と全然違うのでそのへんについて紹介できればなと思います。
目次
1.実装の流れ
2.ハードウェア言語について
3.ハードウェアプログラミング
4.高位合成について
1.実装の流れ
基本的にはソフトウェア実装と同じでコーディングしてコンパイルしてデバッグなのですが、コーディングを行う前に実装する内容について、ブロック図とテキストにまとめます。これが実はかなり重要です。えーそんなんめんどくさい、そんなん書かんくてもわかるやろとか思うかもしれませんが、ハードウェア実装ではブロック図があるとないとでは、デバッグやバージョンアップ含め、その後の開発の効率が段違いになります。なぜかというと、あとで修正や追加が入ったときに、コードだけじゃどこを直せばいいかが全然わからないからです(分からなくもないですが、理解にすごい時間がかかります)。自分で実装したんがからわかるだろ、と思われるかもしれませんが、自分で実装したコードでも、なんでこういう処理にしたんだっけ?みたいなことが多々あります。そうなるとほぼブラックボックスです。他人が実装したものについては言うまでもないです。
ブロック図の書き方ですが、細かければ細かいほどいいと思います(もちろん大まかなブロック図もあるといい)。処理に何CLK(時間みたいなもの)かかってどういうタイミングで出力されるかといった情報が大事です。簡単な例を下にのせときます。
https://gyazo.com/ad2742ffc06d483b16b878a66af866f4
まとめると、実装の流れはブロック図・仕様を書く→コーディング→コンパイル→デバッグ(シミュレーション検証、実機評価)です。
2.ハードウェア言語について
ブロック図を書いたらいよいよコーディングに入ります。ここではハードウェア言語の種類について紹介したいと思います。
ハードウェア言語には以下のものがあります。
VHDL
Verilog-HDL
以上です。2つのみです。ソフトウェア言語と比べてかなり少ないですね。まあ厳密にはSystem VerilogっていうVerilogにちょい機能つけたしたものがあるのですが、今回は省きます。高位合成っていうC言語でハードウェア実装するっていうのもあるのですが、これはまた別なので、あとで紹介します。
いろいろ言いましたが、ハードウェア言語はVHDLとVerilogの2つと思ってもらっていいです。とくに、Verilogで実装するのが主流みたいなとこがあるので、Verilogを覚えておけばまず間違いないでしょう(もちろんVHDLで実装を行っているところもあります。自分も学生の頃はVHDLを書いてました)。
3.ハードウェアプログラミング
簡単にハードウェアプログラミングについて紹介したいと思います。言語はVerilogです。
code:sample.v
module my_module (
input wire clk, //クロック
input wire reset_x, //リセット 基本1でリセット時0
input wire data_in , //入力データ
output wire data_out //出力データ
);
reg r_data; //reg宣言
always @(posedge CLK) begin
if(~reset_x) begin //reset == 0
r_data <= 1'b0; //リセット時 数字はbit数 bはbinary表記 dとすると10進表記,hは16進(例:8'd255 8'hFF
end
else begin
r_data <= data_in; // <= はノンブロッキング代入
end
end
assgin data_out = r_data; //出力に配線
endmodule
if文の感じなんかはC言語と似てます。言ってしまうとあとはほとんど違います。
CLKとはソフトでいうCPUみたいなもの?です。一定の周期で0と1が変動します。このCLKを意識することがハードウェア実装のすべてです。このCLKが0から1に変わるタイミングで処理を行うイメージです。Verilogにはwire,regという宣言があります。この辺がソフトの人はわかりづらいかもしれません。regはFF(フリップフロップ:値を保持するもの)で、FFをつなぐのがwireみたいなイメージ(厳密にはそうじゃないときもある)で、wireを定義するのがassign文です。
https://gyazo.com/314246dfe7b7d9a00824a7c809678af7
演算を行ってその結果をCLKの立ち上がりタイミングでFFにいれる、そのFFの出力をまた次の演算に利用して、演算結果をFFにいれる...といった感じです。また、基本的にreg宣言はノンブロッキング代入です。C言語などは基本ブロッキング代入で、上から順に処理されますが、ノンブロッキング代入ではすべて同時に処理されます。
code:ex.v
always @(posedge CLK) begin
//CLKの立ち上がり時にaをbに、bをcに代入
b <= a;
c <= b;
end
この場合reg b,cへの代入は同時に行われます。CLKの立ち上がり時にa=1,b=2の場合、CLK立ち上がり後はb=1,c=2です。
reg aに対して、bは1clkディレイ(1clk遅れてaの値が入る)、cは2clkディレイということです。
この辺もソフトウェアとは違うところですね。
簡単に実装ポイントについてちょっと書いてみます。
ポイント
1.正しく動かす
2.処理時間をできるだけ短く
3.リソースを節約する
1.正しく動かす
あたりまえですが、期待した通りに動かないと話になりません。正しく動かすことがまず大事です。
ハードウェア実装の場合、正しいタイミングで出力するということに気を付けることが大事です。
例えば、データを演算処理してつぎのモジュールに渡すとき、そのデータが有効かどうかを示す1bitのvalidを同時に渡す、みたいなことがあります。ハードウェアの信号はなにも出力しないなんてことはなく、何かしらのデータが流れています。しかし、そのデータになんの意味がないときもあるわけです(動画でいうとブランキングなど)。このデータとvalidの出力タイミングがずれると、処理したいときにデータが処理されたり、意味ないところで処理しちゃったりしてしまいます。データが処理されている間、その処理にかかるCLK分、validをFFでディレイさせるみたいなことをやります。このタイミングがちゃんとあっているかなどをシミュレーションで検証して確認します。
https://gyazo.com/c474054c92eef5e972522d2574fa9c96
2.処理時間をできるだけ短く
演算をFFにいれると言いましたが、FFを使えば使う分、処理にかかるCLK数が増えることになります。
じゃあ、できるだけFFを減らせばいいやんけと思うかもしれませんが、そんな単純なものでもないです。
FF:AからFF:Bの間で演算を行うとすると、FF:Aの出力から演算が行われて、1CLK後にFF:Bに入ることになります。
この間の演算が多いと1CLKでは間に合わない、といったことが起きます。そうなると正しい処理が保証されなくなり、正しく処理を行うためにCLKの周波数をさげなければならなくなります。結果てきに処理時間としては遅くなります。何か1つ演算を行ったらFFに入れるのが基本です。また、並列処理を意識することが大事です。FPGA内の処理は基本的に並列で動きます。1つ処理をやっている間に、同時に処理できることはできる限りやってしまうことで、ディレイに使うFFも削減でき、処理時間も向上します。
3.リソースを節約する
ハードウェア実装である以上、リソースは常に意識しなければなりません。使うFPGAが小さければ小さいほど、コストも消費電力も優位です。リソースをできるだけ節約して実装することが、ハードウェア設計者のうでのみせどころです。
例えば、乗算器や除算器はできるだけ使用しない、などです。単純に2倍4倍...、1/2,1/4...、を行う場合は必ずビットシフトで行います(1ビット左シフトで2倍、2ビット左シフトで4倍です。右シフトは1/2、1/4...です。詳しくはビット演算で調べてみてください)。リソースの節約にもなるし、FPGAでの除算は特殊で計算時間もかかるので、できるだけ使いたくないです。
このほかにも、無駄なレジスタを削減したり、レジスタの代わりにBlockRAM(FPGA内のRAM)を活用したりするなど考えることはたくさんあります。
4. 高位合成について
高位合成とは、VerilogなどのHDLの知識がなくてもC言語でハードウェア実装しようっていうやつです。SystemCと呼ばれるやつです。この研究はかなり進んでいて、高位合成をつかった研究など学会にもたくさんあがっています。が、問題もあるみたいで、リソースも無限にあってとにかく動けばいいくらいだったらSystemCでほとんど問題なく実装できると思うのですが、最適化をつきつめると、Verilogなどで実装したほうがいいみたいです。ぼく自身そんな詳しくないんですが、高位合成が主流になるときがくると思います。ただ、HDLの知識がないとあるとでは、たとえ高位合成だとしても実装の質が変わって来る(と思う)ので、HDLの知識はあって損はないと思います(たぶん)。
終わりに
ソフトウェアもハードウェアも両方の知識を持つことが大事な気がするので、この機会にちょっと興味をもってもらえたらなと思います。
あと、投稿おくれてすみませんでした。