前回高位合成用の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オプションを付与します。
合成結果はこんな感じになりました。
![](https://blogger.googleusercontent.com/img/a/AVvXsEgf96_iVUy-eIEU3MXKBb5lqy6FEpMiGjI24kMoWKKhavDrOis4F-klWnV8B1Owi6OxWcchAT1AJqsIevpXYvKg4LLImNZzNDDZD4x5PIm4kasl6lweEnQfOI1t3I6dq1spHhruSYIqX9xPyAOX6RpXQn2DOtgcTDVkKWACVEWPqyFO9_7pZpRQUZBO=w400-h149) |
高位合成の結果 |
Iteration Latencyは16となりましたが、Intervalが1になっていることからいい感じにパイプライン化できたようです。使用率は
- DSP : 4%(10/220)
- LUT:3%(1992/53200)
- FF:1%(1718/106400)
- BRAM:0%(0/140)
となっています。余裕ありありですね。合成されたデータフローはこんな感じでした。
![](https://blogger.googleusercontent.com/img/a/AVvXsEiiOeVIB_GMtN_DtCtISGb0k8MGgCviG9C5RGLaZ6_uMnZZ_EsSLvuv_jTqxiq47Vlw3PLPEmhmfJPUT555v8qTNvGT-oart9Og53tjPYZIJ3xTPNIJJ8uITfJc3PV0D5t6PtXosJzq6hlm7y6mZz81hHCPwPx_TgeRqYxwQ9MzHK0zgsehdBXczCZc=w400-h236) |
データフローの一部。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にしましょう。
![](https://blogger.googleusercontent.com/img/a/AVvXsEhGNZ_fe932B8xMfpL-4V3g4g4NMF-G_Iy6SNezlAhpbwYHbzgE0BIimU7mKJCy-HPJt3xIQ7Q7WUDHwvYBPKd0DczUeqDO8mfLX-qRU5AEh48OHNBY08i2aPLcAbQfaswzlWSw_wWuAdBjYMgVZtmtZFG7FT46pMJVswW-KXZwBIHVYo2t_k8Iisrt=w400-h259) |
AXI_HPポートの設定。データ幅はすべて64bitとした。 |
AXI_HPポートの設定後、IPへ供給するクロックの設定をします。今回は単一のクロックソースかつ周波数が200MHz程度なので、ZYNQのIPから供給します。Clock Configuration->PL Fabric Clocksの順にたどり、FCLK_CLK0を200MHzに設定します。
![](https://blogger.googleusercontent.com/img/a/AVvXsEgPrQw9QPgx8HUhJo4bg_2qBFVnMObAK3ZyxkJHLV_ovA3r96GWiahAsbI_crRp7-Wwzt3bOC5ep9xWuDY4H_RH4AhOKE8a_xZiTG9On2sPNf0yfgRIbK57_VqMzv9qtapv9moxeiB6bdr6D0mEawy0GO59qOUIIhG8whSIVCv3NglKjQUqk_UDPUcJ=w400-h260) |
クロック設定。今回は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にしておきます。
![](https://blogger.googleusercontent.com/img/a/AVvXsEiOncj29k_dPdC8BkJulf8wUO0B-muTzef43z83a2Ad2LnWTlLu1STLhGaWIh8HFcopTeTJ-NfCVC096jBt0ALR_zTQfLeFVsXyfxOpMlVaD_mbVtx1k2AdvjPeJHymMVQMXgzMsE4YSoT88II7klwPo1-eP2y9RGWIxe8Yo2sV9ySdKrszRbuZstIQ=w400-h250) |
読み込み側の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です。
![](https://blogger.googleusercontent.com/img/a/AVvXsEh6fV_XnMIedToZYj-w_KrGG0uPV7ErdeePbzZ6AVrrH3HTD1Z5Dqkj2gwCKwpZagzP1Yx42xOW4P6T5en3G-E7NbJ6hVhVdEcfb7-H0lVvPmLrhZtj9lRickwtIhesIR3HQCmlqM_cmdLhfZB-xj3FifSaCJ0JivlvuqTw04DkwdICeZOz76f0nVB8=w400-h245) |
書き込み側の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
と接続しましょう。
![](https://blogger.googleusercontent.com/img/a/AVvXsEizL8t27tch4QM1y1bbjUjZdJYPjId5M4C34ngdQJxq7Fup9Fyv3CAQWue6Ovw7H1ci2t54HCfXDDcu_B_MSSERo5aqkKKH6UoMlvguBdBbic2Wa9Ls8ww1vWRrj1ChjaqgVlBxZ76oJ__G-SUx6Tm_2wB7HiqxeqWunEMQqmbrUoOmyPxYs3wyiW7t=w400-h189) |
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.次回
©2022 shts All Right Reserved.