2022年3月16日水曜日

PYNQとVitis HLSで作るFMA演算IP(2):高位合成と回路合成



 前回高位合成用のC++コードを作成しました。今回はそのコードを使って高位合成を行い、その流れで回路まで作成します。




1.高位合成

 今回はVitis HLSを用いてPYNQ-Z2向けに合成を行います。その際の設定は以下の通り。
  • ターゲット周波数:200MHz
  • Uncertainty:12.5%
  • ターゲットデバイス:pynq-z2(xc7z020clg400-1)
  • 言語:C++0x
 今回は2つのソースファイル(FMA.cpp, FMA.hpp)、1つのテストベンチ(FMA_TB.cpp)を登録します。このうちFMA.cppとFMA_TB.cppのCFLAGSに-std=c++0xオプションを付与します。
 合成結果はこんな感じになりました。

高位合成の結果

 Iteration Latencyは16となりましたが、Intervalが1になっていることからいい感じにパイプライン化できたようです。使用率は
  • DSP : 4%(10/220)
  • LUT:3%(1992/53200)
  • FF:1%(1718/106400)
  • BRAM:0%(0/140)
となっています。余裕ありありですね。合成されたデータフローはこんな感じでした。

データフローの一部。2か所ほど"長い棒"がみえるが、
それぞれfmulとfaddの計算ステップとなっていた。

 一応仕様通りに2並列で計算できているようです。また大半のステップがfmulとfaddで占められていることもわかりました。
 この後CoSimを走らせて結果を確認後、IPを出力します(そのまま出力してもいいのだが、Configuration...のボタンからVendor、Library、Description、Display Nameあたりをいじってからいったん出力->Solution Settings内のConfiguration Settingsのconfig_exportにあるipnameをいじってから出力すると、VivadoでIPを読み込んだ際にオリジナルの名前が付き、ベンダー名で検索がかけられる)。

2.回路合成


 高位合成で作成したIPを使って回路を作成します。ZYNQのIPを最初に置いて、Run Connection Automationを走らせるとDDRとFIXED_IOと外部端子がつながるはずです。
 その後、AXI_HPポートの0から3を有効化します。データ幅はすべて64bitにしましょう。

AXI_HPポートの設定。データ幅はすべて64bitとした。

 AXI_HPポートの設定後、IPへ供給するクロックの設定をします。今回は単一のクロックソースかつ周波数が200MHz程度なので、ZYNQのIPから供給します。Clock Configuration->PL Fabric Clocksの順にたどり、FCLK_CLK0を200MHzに設定します。

クロック設定。今回はHLSに合わせて200MHz。

 ZYNQ IPの設定が終わったら、AXI Direct Memory AccessとAXI Interconnectを4つずつ出します。
 AXI Interconnectの方はMasterとSlaveの数をそれぞれ1に設定します。
DMAの方は入力側(W, X, B)と出力側(Y)で少し異なります。入力側のDMA IPについて、Enable Scatter Gather Engineを無効化し、Width of Buffer Legth Registerを26bits、Address Widthを64Bitsにしておきます。データ入力のIPなので、Read Channelのみ有効にしておきます。Memory Map Data WidthとStream Data Widthは64にしておきます。

読み込み側のDMA IPの設定

 出力側のDMA IPについては、入力側で行ったEnable Scatter Gather Enginenの無効化、Width of Buffer Legth Register->26bits、Address Width->64Bitsの操作を同じく行います。その後、Read Channelを無効化し、Write Channelの有効かを行います。Memory Map Data WidthとStream Data WidthはAUTOのままでOKです。

書き込み側のDMA IPの設定

 最後に各IPを接続します。DMAのIPをCPU側から制御するため、個々のIPに割り当てられている名前が必要になります。サンプルコードをそのまま使いたい場合、
  • S_AXI_HP0 -> axi_dma_0(+interconnect) -> w_axi_0
  • S_AXI_HP1 -> axi_dma_1(+interconnect) -> x_axi_1
  • S_AXI_HP2 -> axi_dma_2(+interconnect) -> b_axi_2
  • y_axi_3 -> axi_dma_3(+interconnect) -> S_AXI_HP3
と接続しましょう。

IPの配線図。
Wが0、Xが1、Bが2、Yが3と覚えると分かりやすい。

 この接続を終えると、Run Connection Automationの表示が出るので、すべてにチェックを入れて実行すれば最終的な回路の完成です。この後、アドレスエディタでDMAと自作IPに対してアドレスを割り当てておきましょう。

 Generate Output Productsを実行し、Create HDL WrapperをLet Vivado manage...の方に入れておきます。Generate Bitsteramをクリックすれば回路の合成が始まります(2回に1回ぐらいで失敗するが、Output Productsをリセットしたのち、Generateしなおして再びBitstreamの生成を行えばいけるはず)。
 Bitstreamの生成が終わったら、.bitのファイルと.hwhのファイルを書きだします。画面左上のFile->Export->Export Hardwareを選択し、Platform typeをFixed、Outputを Include bitstreamに設定します。その後、XSAのファイル名を聞かれるので、適当な名前にします(サンプルコードの通りにしたい場合は、design_1_wrapperをdesign_1に変更)。出力先はどこでもよいです。
 .bitと.hwhはこのXSAファイルに入っているので、7zip等を使い取り出します。最終的にこの.bitと.hwhのファイルを.ipynbから読みだしてプログラムを実行することになります。

3.次回

.bitファイルと.hwhファイルが生成できたので、次回はPYNQ側のコードと速度計測を行っていきます。



©2022 shts All Right Reserved.


0 件のコメント:

コメントを投稿