Zynq + Synthesijer 入門 わさらぼ 三好 健文 2015.3.16
この資料について この資料はZynqとSynthesijerを組み合わせたシステム設計の とっかかりにしてもらことを目的にしています ターゲットボードは ZedboardおよびZyboです Linuxでの実行を想定しています Windowsではコマンドを多少読み違える必要があります Java8が必要です 例題および流れは 杉本様 作の Zynq + Vivado HLS入門 慶應義塾大学 天野研究室 杉本 成 http://www.slideshare.net/narusugimoto/zynq-vivado-hls にならっています 2
この入門でのゴール DDR3のある領域(src)を別の領域(dst)にコピーする PS AXI-GP (2) ARM (4) PL AXIHP_MEMCPY AXI-HP DDR Ctrl. (1) (3) DDR3 (1) ARM上のソフトウェアである領域にデータを書く (2) PL上のハードウェアの動作をキック (3) ある領域のデータを別の領域にコピー (4) 終わったことをPSに通知 3
作業の手順 Synthesijer関連 リソースの準備 PL上のハードウェアの設計(Javaコードの記述とコンパイル) Vivadoでの合成 ARM上のソフトウェア開発のための準備 ARM上のソフトウェアの記述 ソフトウェアのコンパイルと実行 4
作業の手順 Synthesijer関連 リソースの準備 PL上のハードウェアの設計(Javaコードの記述とコンパイル) Vivadoでの合成 ARM上のソフトウェア開発のための準備 ARM上のソフトウェアの記述 ソフトウェアのコンパイルと実行 5
Synthesijer関連リソースの準備 作業の概要 Synthesijer用のディレクトリ(例 $HOME/synthesijer)を作成 Synthesijer*1のページからjar lib applicationsをダウンロード lib applicationsを展開 jarにsynthesijerという環境変数をセット libの展開ディレクトリにsynthesijer_libをセット applicationsの展開ディレクトリにsyntehsijer_appをセット 作業用ディレクトリ($HOME/synthesijer/work)を作って移動 *1 https://sourceforge.net/projects/synthesijer/files/synthesijer-2.0/ 6
Synthesijer関連リソースの準備 作業の例 % mkdir $HOME/synthesijer % cd $HOME/synthesijer % wget https://sourceforge.net/projects/synthesijer/files/synthesijer-2.0/ synthesijer-20150315.jar % wget https://sourceforge.net/projects/synthesijer/files/synthesijer-2.0/ synthesijer_lib_20150315.zip % wget https://sourceforge.net/projects/synthesijer/files/synthesijer-2.0/ synthesijer-applications_20150315.zip % export SYNTHESIJER=$HOME/synthesijer/synthesijer-20150315.jar % unzip synthesijer_lib_20150315.zip % export SYNTHESIJER_LIB=$HOME/synthesijer/synthesijer_lib_20150315 % unzip synthesijer-applications_20150315.zip % export SYNTHESIJER_APP=$HOME/synthesijer/synthesijer-applications_20150315 % mkdir $HOME/synthesijer/work % cd $HOME/synthesijer/work 7
作業の手順 Synthesijer関連 リソースの準備 PL上のハードウェアの設計(Javaコードの記述とコンパイル) Vivadoでの合成 ARM上のソフトウェア開発のための準備 ARM上のソフトウェアの記述 ソフトウェアのコンパイルと実行 8
PL上のハードウェアの設計 作業の概要 Javaコードを記述 SynthesijerでJavaコードをコンパイル IPパッケージの作成(必要なソースをディレクトリにコピー) $SYNTHESIJER_APP/hdl/vhdl/axi_lite_slave_32.vhd $SYNTHESIJER_LIB/vhdl/dualportram.vhd $SYNTHESIJER_APP/hdl/vhdl/simple_axi_memiface_32.vhd synthesijer_lib_axi_simpleaximemiface32rtltest.vhd AXIHP_MEMCPY.vhd 9
Javaのコードを記述 AXHP_MEMCPY.java を書く import synthesijer.lib.axi.*; import synthesijer.rt.*; class AXIHP_MEMCPY{ private final AXILiteSlave32RTL s0 = new AXILiteSlave32RTL(); private final SimpleAXIMemIface32RTLTest m0 = new SimpleAXIMemIface32RTLTest(); private void run(){ int src_addr = s0.data[1]; int dest_addr = s0.data[2]; for(int i = 0; i < 256; i++){ int d = m0.read_data(src_addr + (i<<2)); m0.write_data(dest_addr + (i<<2), d); } } } @auto public void main(){ s0.data[0] = 0x00000000; while(s0.data[0] == 0x00000000) ; // wait for kick from PS run(); s0.data[0] = 0x00000000; // to notify DONE to PS } 10
SynthesijerでJavaコードをコンパイル AXIHP_MEMCPYをSynthsijerでコンパイル % java -cp $SYNTHESIJER:$SYNTHESIJER_APP/bin:. synthesijer.main \ --ip-exact=axihp_memcpy \ AXIHP_MEMCPY.java \ $SYNTHESIJER_APP/src/synthesijer/lib/axi/AXILiteSlave32RTL.java \ $SYNTHESIJER_APP/src/synthesijer/lib/axi/SimpleAXIMemIface32RTL.java \ $SYNTHESIJER_APP/src/synthesijer/lib/axi/SimpleAXIMemIface32RTLTest.java SchdulerBoard init: AXIHP_MEMCPY SchdulerBoard init: synthesijer.lib.axi.simpleaximemiface32rtltest Compile: AXIHP_MEMCPY コンパイル Info: enters into >>> メッセージ Output VHDL: AXIHP_MEMCPY.vhd Output VHDL: synthesijer_lib_axi_simpleaximemiface32rtltest.vhd % ls AXIHP_MEMCPY.vhd 作成されたHDLコードを確認 AXIHP_MEMCPY.vhd % ls AXIHP_MEMCPY_v1_0/ component.xml src xgui IPパッケージ用のテンプレートディレクトリ 11
IPパッケージの作成 必要なソースコードをIPパッケージ用ディレクトリにコピー % grep src AXIHP_MEMCPY_v1_0/component.xml <spirit:name>src/axi_lite_slave_32.vhd</spirit:name> <spirit:name>src/dualportram.vhd</spirit:name> <spirit:name>src/synthesijer_lib_axi_simpleaximemiface32rtltest.vhd</sp...必要な ファイル <spirit:name>src/simple_axi_memiface_32.vhd</spirit:name> <spirit:name>src/axihp_memcpy.vhd</spirit:name> <spirit:name>src/axi_lite_slave_32.vhd</spirit:name> <spirit:name>src/dualportram.vhd</spirit:name> <spirit:name>src/synthesijer_lib_axi_simpleaximemiface32rtltest.vhd</sp... <spirit:name>src/simple_axi_memiface_32.vhd</spirit:name> <spirit:name>src/axihp_memcpy.vhd</spirit:name> % % cp $SYNTHESIJER_APP/hdl/vhdl/axi_lite_slave_32.vhd AXIHP_MEMCPY_v1_0/src % cp $SYNTHESIJER_LIB/vhdl/dualportram.vhd AXIHP_MEMCPY_v1_0/src % cp synthesijer_lib_axi_simpleaximemiface32rtltest.vhd AXIHP_MEMCPY_v1_0/src % cp $SYNTHESIJER_APP/hdl/vhdl/simple_axi_memiface_32.vhd AXIHP_MEMCPY_v1_0/src % cp AXIHP_MEMCPY.vhd AXIHP_MEMCPY_v1_0/src/ % ls AXIHP_MEMCPY_v1_0/src AXIHP_MEMCPY.vhd 必要な dualportram.vhd synthesijer_lib_axi_simpleaximemiface32rtltest.vhd ファイルが axi_lite_slave_32.vhd コピーできた simple_axi_memiface_32.vhd 12
作業の手順 Synthesijer関連 リソースの準備 PL上のハードウェアの設計(Javaコードの記述とコンパイル) Vivadoでの合成 ARM上のソフトウェア開発のための準備 ARM上のソフトウェアの記述 ソフトウェアのコンパイルと実行 13
Vivadoでの合成 作業の概要 Vivadoのプロジェクト作成 Processing System (PS) の追加とパラメタ設定 AXIHP_MEMCPYモジュールの追加 HDLラッパーの生成と修正 合成 14
プロジェクト作成 PSの追加 設定 基本的には Zynq + Vivado HLS入門 慶應義塾大学 天野研究室 杉本 成 http://www.slideshare.net/narusugimoto/zynq-vivado-hls の p.58(vivado Projectの作成 1/9 ) p.83(vivado PS入出力ポート生成3/3 )を参照 ただし 次のような手順で設定 プロジェクトは$HOME/synthesijer/workの下にproject_1として作成 Zedboardの場合: Zyboの場合: プリセットを最初に読んでUART1以外を削除 ZYBO_zynq_def.xmlをimortしてUART1以外を削除 HP0の幅を32bitに変更(PSの設定5/7 割り込みはなし(PSの設定6/7 相当) 相当はスキップ) 15
AXIHP_MEMCPYモジュールの追加 作業の概要 IPコア参照リポジトリの追加 コアのインスタンシエーション ポートの処理 AXIポートの接続(自動接続に任せる) AXIHP_MEMCPYの雑多なポートの処理 axi_inter_memconのaclk/aresetnの処理 pheripheral_aresetnを外部に引き出す 16
AXIHP_MEMCPYモジュールの追加(1) IPコア参照リポジトリの追加 (2) Add Repository...をクリック (4) AXIHPMEM_CPY_v1_0が 見えたらOK [OK]で終了 (1) 設定ダイアログを開く (3) 作成したAXIHPMEM_CPY_v1_0 を選択 追加できた!! 17
AXIHP_MEMCPYモジュールの追加(2) コアのインスタンシエーション (2) AXIHP_MEMCPYを選ぶ(Search:を使うと楽に選択できる) (3) AXIHP_MEMCPYのインスタンスを 追加できた (1) コアの追加ダイアログをクリック 18
AXIHP_MEMCPYモジュールの追加(3.1) ポートの処理(AXIポートの自動接続) (1) Run Connection Automation を 選択 (2) All automation の チェックボックスを選択して [OK] 19
AXIHP_MEMCPYモジュールの追加(3.2) ポートの処理(AXIポートの処理が完了したところ) 次のスライドではここの処理を行う ズームインすると作業しやすい 次の次のスライドで ここの処理を行う 次の次の次のスライドで ここの処理を行う 20
AXIHP_MEMCPYモジュールの追加(3.3) ポートの処理(AXIHP_MEMCPYのその他のポートの処理) resetと.._forbid_..は GUIではなくラーッパーモジュールで代入したいので 外部ポートとして出力 それぞれ (1) ポートをクリック (2) Ctrl-T または 右クリックして Make External をする (1) clkをm_axi_gpi0_aclkなどの ワイヤと接続*1 マウスでポートを選択 マウスカーソルが鉛筆状になった状態で接続元から接続先まで ドラッグ&ドロップするとよい 21 *1
AXIHP_MEMCPYモジュールの追加(3.4) ポートの処理(axi_inter_memconのACLKとARESETNの処理) ACLKをS00_ACLKに ARESETNをS00_ARESETNに 接続する 22
AXIHP_MEMCPYモジュールの追加(3.5) ポートの処理(peripheral_aresetnを外部に引き出す) 注: この信号は 本当にFPGAの チップ外に引き出したいわけではなく ラッパーモジュールで扱うために 引き出す (1) peripheral_aresetnを選択 (2) 右クリックでメニューを開いて Create Portを選択して生成 (ダイアログはOKでよい) 23
AXIHP_MEMCPYモジュールの追加(3.6) ポートの処理(検証) (1) Validate Designを選択 /AXIHP_MEMCPY_0/class_s0_0000_axiと /AXIHP_MEMCPY_0/class_m0_0002_class_obj_0000_axiの クロックに関する警告がでる...のは現状想定の範囲内なのでOK 24
HDLラッパーの生成と修正 作業の概要 Project SettingでTarget LanguageがVerilogなことを確認 VHDLの方が好きな人はVHDLでも良い この資料ではVerilogで話を進める Sourcesタブのdesign_1.bdからラッパーを生成 resetとforbid信号の取り扱いを修正 ボードデザイン(GUIでの設計)では都合上ポートを作成したがチップ外部に 引き出したいわけではない resetには~pheripheral_aresetnを接続.._forbid_.. には 1'b0を与える この信号1'b1を与えるとAXIアクセスを強制禁止できる 今回は禁止*しない*ので即値で1'b0を指定 25
HDLラッパーの生成と修正(1) HDLラッパーの生成 (1.2) (1.3) (1.1) (1) design_1.bdで右クリックして Create HDL Wrapper...を選択 (3) HDLラッパー (desgin_1_wrapper.v)が生成される (2) Copy generated の方を選択する 26
HDLラッパーの生成と修正(2) HDLラッパーの修正 変更前 変更後 削除 メモ GUIで生成した外部ポートはラッパーモジュールでは 直接FPGA外部へ引き出されるポートになる 今回はデザイン内部で利用したいだけなので FPGAの外には出さない 特にコンマの扱いに注意 27
HDLラッパーの生成と修正(3) HDLラッパーの修正 変更前 変更後 削除 メモ GUIで生成した外部ポートはラッパーモジュールでは 直接FPGA外部へ引き出されるポートになる 今回はデザイン内部で利用したいだけなので FPGAの外には出さない 28
HDLラッパーの生成と修正(4) HDLラッパーの修正 - Javaで書いたモジュールにperipheral_resetの極性を反転したものを与える - forbid信号には1'b0(forbidしない 常にAXIアクセスを有効にするの意)を設定 変更前 変更後 変更箇所 29
合成 Flow NavigatorのGenerate Bitstreamをクリックして合成 途中AXIHP_MEMCPYのclkについて警告がでる 今回のケースではOKで続行 30
作業の手順 Synthesijer関連 リソースの準備 PL上のハードウェアの設計(Javaコードの記述とコンパイル) Vivadoでの合成 ARM上のソフトウェア開発のための準備 ARM上のソフトウェアの記述 ソフトウェアのコンパイルと実行 31
ARM上のソフトウェア開発のための準備 作業の概要 ハードウェアプロジェクトのエクスポートとSDKの起動 BSPの生成 アプリケーションプロジェクトの生成 Cソースファイルの生成 32
エクスポートとSDKの起動(1) ハードウェアプロジェクトのエクスポート Include bitstreamのチェックボックスの チェックを入れて [OK] File Export Export Hardware を選択 33
エクスポートとSDKの起動(2) SDKの起動 そのままで[OK] File Launch SDK を選択 34
BSPの生成 Cソースファイルの作成 Zynq + Vivado HLS入門 慶應義塾大学 天野研究室 杉本 成 http://www.slideshare.net/narusugimoto/zynq-vivado-hls の p.117(sdk Board Support Packageの生成1/4 ) p.127(sdk Fileの生成3/3 )を参照 35
作業の手順 Synthesijer関連 リソースの準備 PL上のハードウェアの設計(Javaコードの記述とコンパイル) Vivadoでの合成 ARM上のソフトウェア開発のための準備 ARM上のソフトウェアの記述 ソフトウェアのコンパイルと実行 36
ARM上のソースコードの記述 ソフトウェアの概要は Zynq + Vivado HLS入門 慶應義塾大学 天野研究室 杉本 成 http://www.slideshare.net/narusugimoto/zynq-vivado-hls の p.128(sdk HLSコア制御アプリケーション雛形) p.136(sdk axihp_memcpyソフトウェア )を参照 レジスタ構成が若干違う 最終的なソースコードは次の通り 37
ARM上のソースコードの記述 #include "xil_printf.h" int main() { Xil_DCacheDisable(); int i, mismatch = 0; volatile unsigned int src_data[256], dst_data[256]; for(i = 0; i < 256; i++) src_data[i] = i; unsigned int *baseaddr = (unsigned int*)0x43c00000; xil_printf("\r\n"); baseaddr[1] = (unsigned int)src_data; Synthesijerで作ったコアへの baseaddr[2] = (unsigned int)dst_data; パラメタ渡しと制御の開始 baseaddr[0] = 0xFFFFFFFF; xil_printf("memcpy start, src=%08x dest=%08x\n\r", src_data, dst_data); while(baseaddr[0]!= 0) ; xil_printf("memcpy done\n\r"); for(i = 0; i < 256; i++){ xil_printf("src_data[%d] = %d, ", i, src_data[i]); xil_printf("dst_data[%d] = %d\n\r", i, dst_data[i]); if(src_data[i]!= dst_data[i]) mismatch = 1; } (mismatch==0)? xil_printf("memcpy success!\n\r") : xil_printf("memcpy fail\n\r"); return 0; } 38
作業の手順 Synthesijer関連 リソースの準備 PL上のハードウェアの設計(Javaコードの記述とコンパイル) Vivadoでの合成 ARM上のソフトウェア開発のための準備 ARM上のソフトウェアの記述 ソフトウェアのコンパイルと実行 39
ソフトウェアのコンパイルと実行 ソフトウェアのコンパイルと実行の概要は Zynq + Vivado HLS入門 慶應義塾大学 天野研究室 杉本 成 http://www.slideshare.net/narusugimoto/zynq-vivado-hls の p.137(sdk ソフトウェアのコンパイル 1/2) p.145(sdk 実行結果 )を参照 bitstreamのパスはデフォルトで選択されるものを使用 cuがなければscreenでもok Zedboardなら: screen /dev/ttyacm0 115200 Zyboなら: screen /dev/ttyusb1 115200 40
結果を確認 41
今回のデザインへのエクスキューズ SimpleAXIMemIface32RTLTestは32bitのアクセスのた びに毎回AXIイベントを発行しています より高速な転送 のためには バースト転送をする必要があるでしょう(次頁 参照) 割り込みについてについては 特に考えられていませ ん うまく扱えるようにしたいものです BDに対する CLK, RESETでのCritical Warningは気持ち が悪いのでなんとかしないといけません 42
Javaのコードを記述 AXHP_MEMCPY2.java を書く(バースト版) import synthesijer.lib.axi.*; import synthesijer.rt.*; public class AXIHP_MEMCPY2{ private final AXILiteSlave32RTL s0 = new AXILiteSlave32RTL(); private final AXIMemIface32RTLTest m0 = new AXIMemIface32RTLTest(); private void run(){ int src_addr = s0.data[1]; int dest_addr = s0.data[2]; m0.fetch(src_addr, 256); m0.flush(dest_addr, 256); } } Javaで1ワードずつコピーする わけではないので高速 @auto public void main(){ s0.data[0] = 0x00000000; while(s0.data[0] == 0x00000000) ; // wait for kick from PS run(); s0.data[0] = 0x00000000; // to notify DONE to PS } 43
補足1: CentOSのJava8のインストール たとえば http://qiita.com/hajimeni/items/67d9e9b0d169bf68d1c9 を参考にするなどしてインストールしてください 44