Zynq + Vivado HLS入門
-
Upload
narusugimoto -
Category
Devices & Hardware
-
view
3.593 -
download
5
Transcript of Zynq + Vivado HLS入門
ZYNQ + Vivado HLS入門
慶應義塾大学 天野研究室
修士1年 杉本 成
内容
• 対象はこれからZYNQを使ってみたい方
• 実習形式で進めていく
• ZYNQのCPU⇔FPGA間のデータ転送方法、共有方法をレクチャー
• VIVADO HLS, VIVADO IP Integratorを利用して手軽に実装
• RTLは1行も書かない
目次
• 基礎説明 ZYNQ構成 AXIとは ZYNQ内のAXI経路 VIVADOの特徴
• 実習内容の説明 目標とするデザイン ツールの説明 ツールフロー
• 実習 VIVADO HLSでmemcpyコアを実装 VIVADO IP integraterでIPコアを接続 SDKでソフトウェアを実装、実行 VIVADO Logic AnalyzerでAXI通信を観察
ZYNQ構成
DDR
ZYNQブロック図 *xilinx ホームページより引用
• PS (Processing System)およびPL (Programmable Logic)から構成される
• PSの構成は以下の通り Application Processing Unit(APU)
CPU, DMAコントローラ, GIC等 Memory Interface
DDRコントローラ等 IO Peripheral(IOP)
GPIO, UARTコントローラ等
• PS内、PS⇔PL間のインターフェースは全てARM AXIで統一されている
PS
PL
ZYNQ アドレスマップ
システムレベルのアドレスマップ *UG585 P103より引用
• 各機能にアクセスする際に使用するアドレス一覧
AXIとは
• ARM® AMBA インターフェースのこと※AXI4はAMBA第4世代インターフェース
• MasterとSlaveが1対1で通信を行う• スイッチを介すことで、複数Masterと複数Slaveを
繋げることもできる.(しかし通信は1対1)• Slaveはレジスタもしくはメモリを持っていて、
Masterはアドレスを指定してデータの読み書きを行う
MS
0x00000000
0x0000ffff
AXI4 バースト転送
MS
0x00000000
0x0000ffff
D0
D1
D2
D3
D4
D5
D6
D7
…
• AXI4は指定したアドレスから連続してデータを(毎サイクル)読み出し/書き込みできる
• 指定したアドレスからインクリメント、指定したアドレスから連続して等の設定ができる
• バースト長は最大256である
AXI4 バースト読み出しの例
AXIの種類
• AXI: 普通のAXI• AXILite: AXIの軽量版、バースト転送ができない• AXIstream: アドレスの概念を消したストリーム用
ZYNQ IOPへのアクセス
S M APU ⇔ IOP間 Master => APU Slave => IOP
IOPのレジスタ設定、入出力データの送受信に使用
ZYNQ AXIGP(Slave)
S
M APU ⇔ AXIGP(Slave)間 Master => CPU Slave => AXIGP
データ幅は32bit
ZYNQ AXIGP(Master)
S
M
APU ⇔ AXIGP(Slave)間 Master => AXIGP Slave => DDR
データ幅は32bit
ZYNQ DMAエンジン
S
M
DMA ⇔ DDR間 Master => DMA Slave => DDR
DMA ⇔ AXIGP(Slave)間 Master => DMA Slave => AXIGPS
ZYNQ AXIHP
S
M
AXIHP ⇔ DDR間 Master => AXIHP Slave => DDR
データ幅は32/64bit
ZYNQ ACP
S
M
AXIACP ⇔ APU間 Master => AXIACP Slave => APU
データ幅は64bit
VIVADO IP Integrator
• ISE => XPS
VIVADO Logic Analyzer
• ISE => Chip Scope
ZYNQ
目標とするデザイン
PS
APU
DDR Controler
AXIHP_MEMCPY(created by VIVADO HLS)
inte
rrupt
M
S
S
M
DDR
AXIGP AXIHP
• AXIHPを使用してMEMCPYを行う”AXIHP MEMCPY”をVIVADO HLSで実装
• 読み出し/書き込みアドレスおよびMEMCPYの制御は、APUからAXIGP経由で行う
• 読み出し/書き込みは共に256バースト転送
• ILAコアでAXIのやりとりを監視する
• MEMCPYの終了はinterruptでAPUに割り込みをかける
ILA
VIVADO HLSを利用したMEMCPY
ツールフロー
AXIHP_MEMCPY関数のC記述
AXIHP_MEMCPY関数のDirective設定
AXIHP_MEMCPYのIP化
PSの設定
PSとAXIHP_MEMCPYの接続
bitstreamの生成
ソフトウェアの実装、実行
VIVADO HLS
VIVADO
SDK
VIVADO + SDK
使用するツール手順
波形のキャプチャ
環境
• Vivado 2014.4を対象としている(2014.2以降なら同様のことが可能)
• Zed Board、ZYBOを想定
• zynq_vivadohlsディレクトリで作業する
VIVADO HLS
AXIHP_MEMCPY関数のC記述
AXIHP_MEMCPY関数のDirective設定
AXIHP_MEMCPYのIP化
Projectの生成
AXIHP_MEMCPYの合成
作業手順
VIVADO HLS "AXIHP MEMCPYコア"
AXIHP_MEMCPY(created by VIVADO HLS)
interruptclk
reset
AXILite AXIMS32bit 64bit
VIVADO HLS “Projectの生成1/7”
• vivado_hlsを起動する• [Create New Project]をクリック
1
VIVADO HLS “Projectの生成2/7”
• 任意のProject nameを入力 (自分は”axihp_memcpy”とした)• “Location”は任意(自分はzynq_vivadohlsディレクトリにした)• [Next]をクリック
1
2
3
VIVADO HLS “Projectの生成3/7”
• Top Functionを”axihp_memcpy”とする(対象とする関数の関数名)• [Next] をクリック
1
2
VIVADO HLS “Projectの生成4/7”
• [Next] を選択(今回シミュレーションは行わないので何も加えない)
1
VIVADO HLS “Projectの生成5/7”
• Part Selectionのタブを開く
1
VIVADO HLS “Projectの生成6/7”
ZedBoardの場合• [Boards]タブを選択• “ZedBoard”を選択する• [OK]をクリックする
1
2
3
Zyboの場合• [Parts]タブを選択• “xc7z010clg400-1を選択する• [OK]をクリックする
VIVADO HLS “Projectの生成7/7”
• [Finish]をクリックする
1
VIVADO HLS 起動完了
• Projectの生成が完了した
VIVADO HLS “Fileの作成1/3”
• [Source]を右クリックする• [New File]をクリックする
12
VIVADO HLS “Fileの作成2/3”• File名を”axihp_memcpy.c”とする• 保存先は”zynq_vivadohls/axihp_memcpy/.apc”とする• [OK]をクリック
12
3
VIVADO HLS “Fileの生成3/3”
• [Source]タブの中に”axihp_memcpy.c”が作成された• このファイルにaxihp_memcpyを記述していく
VIVADO HLS “axihp_memcpyの実装1/4”
void axihp_memcpy();
void axihp_memcpy(){
}
• void型のaxihp_memcpy関数を記述する
VIVADO HLS “axihp_memcpyの実装2/4”
typedef unsigned long long u64;
void axihp_memcpy(u64 *axihp_in, u64 *axihp_out);
void axihp_memcpy(u64 *axihp_in, u64 *axihp_out){
}
• axihp(64bit)用の入力, 出力ポートを関数の引数に記述• “unsigned long long”は長いので”u64”に置き換える
VIVADO HLS “axihp_memcpyの実装3/4”
typedef unsigned long long u64;
void axihp_memcpy(u64 *axihp_in, u64 *axihp_out);
void axihp_memcpy(u64 *axihp_in, u64 *axihp_out){
u64 buf[256];
memcpy(buf, axihp_in, 256 * sizeof(u64));
}
• 入力データを受け取るための配列”buf”を用意する• burst転送はmemcpyを使用して表現する
バースト長256のバースト転送(受信)となる※buf[0] = *axihp_in; とすると通常転送の読み出しとなる
VIVADO HLS “axihp_memcpyの実装4/4”
typedef unsigned long long u64;
void axihp_memcpy(u64 *axihp_in, u64 *axihp_out);
void axihp_memcpy(u64 *axihp_in, u64 *axihp_out){
u64 buf[256];
memcpy(buf, axihp_in, 256 * sizeof(u64));
memcpy(axihp_out, buf, 256 * sizeof(u64));
}
• memcpyでバースト転送の書き込みを記述する
バースト長256のバースト転送(送信)となる※*axihp_out = buf[0]; とすると通常転送の書き込みとなる
VIVADO HLS “axihp_memcpy関数”
typedef unsigned long long u64;
void axihp_memcpy(u64 *axihp_in, u64 *axihp_out);
void axihp_memcpy(u64 *axihp_in, u64 *axihp_out){
u64 buf[256];memcpy(buf, axihp_in, 256 * sizeof(u64));memcpy(axihp_out, buf, 256 * sizeof(u64));
}
• 以上でaxihp_memcpy関数は完成となる• AXIHPの読み出し/書き込みアドレスおよび
axihp_memcpyの制御方法は[Directive]で設定していく
VIVADO HLS “Directive設定1/10”
• [Directive]タブをクリックする
1
VIVADO HLS “Directive設定2/10”
• 引数”axihp_in”をaxiポートのmasterとなるように設定していく• [axihp_in]を右クリックする• [Insert Directive]をクリックする
21
VIVADO HLS “Directive設定3/10”
• [Directive]のプルダウンメニューを”INTERFACE”にする• [mode]のプルダウンメニューを”m_axi”にする• [offset]のプルダウンメニューを”slave”にする• [OK]をクリック
1
2
3
4
この設定を”slave”にすると読み出しアドレスを、slaveポートから指定できるようになる
“axihp_in”はaxiのmasterポートと認識されるようになる
VIVADO HLS “Directive設定4/10”
• 引数“axihp_in”の設定が完了した• 設定した内容は[axihp_in]の下に表示される
VIVADO HLS ”Directive設定5/10”
• 引数”axihp_out”も同様に設定していく• [axihp_out]を右クリックする• [Insert Directive]をクリックする
21
VIVADO HLS “Directive設定6/10”
• [Directive]のプルダウンメニューを”INTERFACE”にする• [mode]のプルダウンメニューを”m_axi”にする• [offset]のプルダウンメニューを”slave”にする• [OK]をクリック
1
2
3
4
この設定を”slave”にすると読み出しアドレスを、slaveポートから指定できるようになる
“axihp_out”はaxiのmasterポートと認識されるようになる
VIVADO HLS “Directive設定7/10”
• 引数”axihp_out”の設定が完了した• 次は関数axihp_memcpyの制御方法の設定を行っていく
VIVADO HLS “Directive設定8/10”
• 関数axihp_memcpyの制御方法を設定していく• [axihp_memcpy]を右クリックする• [Insert Directive]をクリックする
21
VIVADO HLS “Directive設定9/10”
• [Directive]のプルダウンメニューを”INTERFACE”にする• [mode]のプルダウンメニューを”s_axilite”にする• [OK]をクリック
1
2
3
この設定により“axihp_memcpy”はaxi slaveポートから制御される.また終了を知らせるinterrupt信号も生成される.
VIVADO HLS “Directive設定10/10”
• 以上でDirectiveの設定が完了した
VIVADO HLS “Synthesis1/3”
• Synthesisを行っていく• [C Synthesis]をクリックする
1
VIVADO HLS “Synthesis2/3”
• Synthesisが完了した
VIVADO HLS “Synthesis3/3”
• 生成されるポート一覧
Slave AXIポート(AXILite)
Master AXIポート(AXI)
VIVADO HLS “IP Packageing1/3”
• axihp_memcpyをIPパッケージ化していく• [Export RTL]をクリックする
1
VIVADO HLS “IP Packaging 2/3”
• “Verilog”または”VHDL”を選択• [OK]をクリックする
1
2
VIVADO HLS “IP Packaging 3/3”
• IPパッケージ化が完了した• 以上でVIVADO HLSによる操作は終了となる
VIVADO
PSの設定
PSとAXIHP_MEMCPYの接続
HardwareのExport
Block Designの生成
Projectの生成
bitstreamの生成
作業手順
VIVADO “Projectの生成 1/9”
• VIVADOを起動する• [Create New Project] をクリック
VIVADO “Projectの生成2/9”
• [Next]をクリック
VIVADO “Projectの生成3/9”
• Project nameを任意のものに変更(自分はzynq_vivadohlsとした)• “Create project subdirectory”のcheckを外す• [Next]をクリック
1
2
3
VIVADO “Projectの生成4/9”
• “RTL Project” を選択する• [Next]をクリック
2
1
VIVADO “Projectの生成5/9”
• “Verilog”または”VHDL”を選択• [Next]をクリック
2
1
VIVADO “Projectの生成6/9”
• [Next]をクリック
1
VIVADO “Projectの生成7/9”
• [Next]をクリック
1
VIVADO “Projectの生成8/9”Zed Boardの場合• [Boards] を選択• “ZedBoard”を選択• [Next]をクリック
Zyboの場合• [Parts] を選択• “xc7z010clg400-1”を選択• [Next]をクリック
1
2
3
VIVADO “Projectの生成9/9”
• 内容を確認して[Finish]をクリック• これでプロジェクトの生成が完了する
1
VIVADO起動完了
VIVADO “Block Designの生成1/3”
• ここからIP IntegratorでBlock Designを生成していく• [Create Block Design] をクリック
1
VIVADO “Block Designの生成2/3”
• 任意のDesign nameに変更して [OK]をクリック• これでBlock Designe の生成が完了する
1
2
VIVADO “Block Designの生成3/3”
• Block Designが生成が完了した• 右側の”Diagram”部分でIPの追加、接続を行いデザインを作成していく
VIVADO “PSの追加1/3”• まずZYNQ PSを追加する• [Add IP] をクリック (Ctrl – i がショートカット)
1
VIVADO “PSの追加2/3”
• Searchに“zynq”と入力して絞り込む• ”ZYNQ7 Processing System”を選択し[ENTER]
1
2
VIVADO “PSの追加3/3”
• Processing Systemが追加された• 次はProcessing Systemの設定を行っていく
VIVADO “PSの設定1/7”
• ZYNQを右クリックし、[Customize Block]を選択(ZYNQをダブルクリックでも可)
1
VIVADO “PSの設定2/7”• [MIO Configuration] タブを選択クリック• [I/O Peripherals]を開く• [UART1] にチェックを入れ, MIO 48, 49が選択されていることを確認
2
1
3
3
VIVADO “PSの設定3/7”• [DDR Configuration] タブをクリック• [DDR Controller Configuration]を開く• ZedBoardの場合、Memory Partを”MT41J128M16 HA-15E”に変更• ZYBOの場合、Memory Partを”MT41J128M16JT-125”に変更
1
23
※ツールのバージョンによっては”MT41K128M16JT-125”
VIVADO “PSの設定4/7”• [Clock Configuration]タブを選択• ZedBoardの場合、Input Frequencyを”33.333333”にする• Zyboの場合、Input Frequencyを”50”にする• [PL Fablic Clocks]タブを開く• FCLK_CLK0の周波数を”100”に設定する
1
2
3
4
VIVADO “PSの設定5/7”
• [PS-PL Configuration]タブをクリック• [HP Slave AXI Interface]タブを開く• “S AXI HP0 interface”にチェックを入れる
1
2
3
VIVADO “PSの設定6/7”• [Interrupts]タブをクリック• [Fabric Interrupts]にチェックを入れて、タブを開く• [PL-PS Interrupt Ports]を開く• IRQ_F2P[15:0]にチェックを入れる• [OK]をクリック
1
2
34
5
VIVADO “PSの設定7/7”
• 以上でPSの設定が完了した
VIVADO “PS入出力ポート作成1/3”
• [Run Block Automation] をクリック
1
VIVADO “PS入出力ポート生成2/3”
• [Apply Board Preset] のチェックを外す• [OK]をクリック
1
2
VIVADO “PS入出力ポート生成3/3”
• PSの外部IOインターフェース(DDR, FIXED_IO)が生成された
VIVADO “HLS IPコアの追加1/7”
• VIVADO HLSで作成したIPコアを追加していく• [IP Settings]をクリックする
1
VIVADO “HLS IPコアの追加2/7”
• [Add Repository]をクリックする
1
VIVADO “HLS IPコアの追加3/7”
• axihp_memcpy(VIVADO HLSのProjectディレクトリ)を選択• [Select]をクリック
1
2
VIVADO “HLS IPコアの追加4/7”
• “Axihp_memcpy”が追加されていることを確認• [OK]をクリック
1
2
VIVADO “HLS IPコアの追加5/7”
• “Axihp_memcpy”のimportが完了したのでIPを追加する• [Add IP]をクリックする
1
VIVADO “HLS IPコアの追加6/7”
• “axihp”と入力して絞り込む• [Axihp_memcpy]を選択し[Enter]を押す
1
2
VIVADO “HLS IPコアの追加7/7”
• “axihp_memcpy”IPコアの追加が完了した• 次は、PSと接続していく
VIVADO “HLS IPコアとPSの接続1/5”
• axihp_memcpy IPコアとPSを接続していく• axihp_memcpyの”interrupt”とPSの”IRQ_F2P”を接続する
1
ドラッグでポート間を接続
VIVADO “HLS IPコアとPSの接続2/5”
• AXIポートを接続していく• [Run Connection Automation]をクリックする
1
VIVADO “HLS IPコアとPSの接続3/5”
• [All Automation]にチェックを入れる• [s_axi_AXILiteS]を選択する• [Clock Connection]を”FCLK_CLK0”に選択する
12
3
VIVADO “HLS IPコアとPSの接続4/5”
• [S_AXI_HP0]を選択する• [Clock Connection]を”FCLK_CLK0”に選択する• [OK]をクリックする
1
2
3
VIVADO “HLS IPコアとPSの接続5/5”
• axihp_memcpy IPコアとPSの接続が完了した• 次はAXIHPポートを監視するILAコアを追加していく
VIVADO 自動配線の結果自動配線を行うとAXIポートが自動的に接続される
自動でリセットシステムが追加される
インターコネクトが自動で挿入される• 複数マスタ、複数スレーブ間のスイッチとなる• 実はPS側のAMBAがAMBA4ではなくAMBA3となっている.
PS側のAMBA3とIP側のAMBA4の緩衝材の働きもする
VIVADO “ILAコアの追加・接続1/6”
• AXIHPポートを監視するためのILAコアを追加していく• [Add IP]をクリックする
1
VIVADO “ILAコアの追加・接続2/6”
• “ila”と入力して絞り込む• [ILA]を選択して[Enter]を押す
1
2
VIVADO “ILAコアの追加・接続3/6”
• ILAコアが追加された• AXIHPポートと接続していく
VIVADO “ILAコアの追加・接続4/6”
• ILAの”clk”とPSの”FCLK_CLK0”を接続する
1
VIVADO “ILAコアの追加・接続5/6”
• ILAの”SLOT_0_AXI”とaxihp_memcpyの”m_axi_gmem64”を接続する
1
VIVADO “ILAコアの追加・接続6/6”
• ILAコアの追加と接続が完了した• 以上でBlock Designでの設計は終了となる
VIVADO “Block Designエラーチェック”
• [Validate Design]をクリックする• エラーが無いことを確認したら、デザインを保存する
1
2
VIVADO “Generate Block Design 1/3”
• Block Designに含まれるIPに必要な制約、デザインのネットリストを生成する
• [Generate Block Design]をクリックする
1
VIVADO “Generate Block Design 2/3”
• [Generate]をクリックする
1
VIVADO “Generate Block Design 3/3”
• 終了したら[OK]をクリックする• Designの生成が完了した
1
VIVADO “HDL wrapperの生成1/3”
• Block DesignのHDL wrapperを生成していく• [Sources]タブを選択する• [design_1]を右クリック• [Create HDL Wrapper]をクリックする
1
23
• [OK]を選択
VIVADO “HDL wrapperの生成2/3”
1
VIVADO “HDL wrapperの生成3/3”
• “design_1_wrapper”ファイルが追加されていることを確認する• HDL wrapperの生成が完了した
1
VIVADO “SDK Export1/2”• Hardwareの情報をSDKにExportする• [File]をクリック• [Export] => [Export Hardware]をクリック
1
2
• [OK] をクリック• Exportが完了したらBitstreamを生成する
VIVADO “SDK Export2/2”
1
VIVADO “Generate Bitstream1/2”
• bitファイルを生成する• [Generate Bitstream]をクリックする
1
VIVADO “Generate Bitstream2/2”
• 完了したら[Cancel]をクリックする• 以上でVIVADOでの実装は終了となる• 次はSDKでソフトウェアを実装していく
1
SDK
Board Suppot Packageの生成
Application Projectの生成
ソフトウェア(polling)の実装
作業手順
アプリケーション実行1
interrupt制御プログラムの追加
アプリケーション実行2
SDK “SDKの起動1/2”• SDKを起動する (linuxの場合 “xsdk” コマンドで起動)• VIVADOは”project_dir/project_name.sdk”にHardware情報を
Exportしている• Workspaceは”zynq_vivadohls/zynq_vivadohls.sdk”を選択する• [OK]をクリック
1
2
SDK “SDKの起動2/2”
• SDKの起動が完了した• design_1_wrapper_hw_platform_0内にExportされた
hardware情報やPSの設定スクリプトがある(バージョンが2014. 2の場合、hardware Platform Specificationを自分で作成する必要あり)
SDK “Board Support Packageの生成1/4”
• [New]をクリック• [Xilinx]タブを開く• [Board Support Package]を選択• [Next]をクリックする
1
23
4
• Project nameに任意の名前を入力(自分は”standalone_bsp_0”を使用)• [Finish]をクリック
SDK “Board Support Packageの生成2/4”
1
2
• [OK]をクリック
SDK “Board Support Packageの生成3/4”
1
SDK “Board Support Packageの生成4/4”
• Board Support Packageが生成された• standalone_bsp_0内にはxilinxが提供するlibraryや
hardwareのアドレスを定義したヘッダーファイル等がある
SDK “Application Projectの生成1/4”• [New]をクリック• [Xilinx]タブを開く• [Application Project]を選択• [Next]をクリック
1
2 3
4
• Project nameを”axihp_memcpy”にする• [Use existing] をチェックをする• [Next]をクリック
SDK “Application Projectの生成2/4”
1
2
3
• [Empty Application] を選択• [Finish]をクリック
SDK “Application Projectの生成3/4”
1
2
SDK “Application Projectの生成4/4”
• Application Projectが生成された
SDK “Fileの生成1/3”
• [axihp_memcpy]タブを開く• [src]を右クリックする• [New] => [File]をクリックする
1
2 3
SDK “Fileの生成2/3”
• File nameを”axihp_memcpy.c”とする• [Finish]をクリックする
2
1
SDK “Fileの生成3/3”
• “axihp_memcpy.c”ファイルが生成された• C言語でソフトウェアを実装していく
SDK “HLS コア 制御アプリケーション雛型”
#include "xil_printf.h"typedef unsigned long long u64;int main(){
int i, mismatch = 0;volatile u64 src_data[256], dst_data[256];for (i = 0; i < 256; i++)
src_data[i] = i; //create source data
//control hls core
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; //compare src_data and dst_data
}(mismatch == 0) ? xil_printf("memcpy success!\n\r"):
xil_printf("memcpy fail\n\r");return 0;
}
• axihp_memcpyコアにsrc_dataの値をdst_dataにコピーさせる• 以降、この雛型に赤文字で書かれたプログラムを追加していく
SDK “キャッシュの無効化”
#include "xil_cache.h"…int main(){
Xil_DCacheDisable(); //Disable Data Cache…return 0;
}
• xil_cache.h内で定義されているXil_DCacheDisable関数を使うとデータキャッシュをオフにすることができる
• DMAを正しく実行するにはflushおよびinvalidateを適切に行う必要がある.簡単のため、今回はキャッシュを無効化する
SDK “axihp_memcpyコアのレジスタ構成1/2”
• standalone_bsp_0/ps_cortexa9_0/include内の“axihp_memcpy_hw.h”を開く
• ファイル内にレジスタのmapが記述されている
SDK “axihp_memcpyコアのレジスタ構成2/2”
0x00 Control signals
0x04Global Interrupt
Enable
0x08IP Interrupt
Enable
0x0cIP Interrupt
Status
0x10Data signal of
axihp_in
0x14 reserved
0x18Data signal of
axihp_out
0x1c reserved
読み出しアドレス
書き込みアドレス
• bit0: ap_start• bit1: ap_done• bit2: ap_idle• bit3: ap_ready• bit7: auto_restart• others: reserved
axihp_memcpyレジスタ(32bit)
SDK “axihp_memcpyアドレスの確認”
• standalone_bsp_0/ps_cortexa9_0/include内の“xparameters.h”に記述されている
• アドレスは0x43c00000で、次のように定義されている“XPAR_AXIHP_MEMCPY_0_S_AXI_AXILITES_BASEADDR”
SDK “読み出し/書き込みアドレスの設定”
…unsigned int *baseaddr = 0x43c00000; //reg0 of hls coreint main(){
…//control hls corebaseaddr[4] = src_data; //set read addrbaseaddr[6] = dst_data; //set write addr…
}
• 0x43c00000番地がaxihp_memcpyのレジスタ0の番地となる
SDK “axihp_memcpyの開始制御”
…int main(){
…//control hls corebaseaddr[4] = src_data; //set read addrbaseaddr[6] = dst_data; //set write addrif ((baseaddr[0] & 0x4) == 0x4) { //if ap_idle is high
xil_printf("memcpy start\n\r");baseaddr[0] |= 0x1; //make ap_start high
}…
}
• ap_idleが1であればap_startを1にして開始する
SDK “axihp_memcpyの終了制御(polling版)”
…int main(){
…//control hls core…if ((baseaddr[0] & 0x4) == 0x4) {//if ap_idle is high
xil_printf("memcpy start\n\r");baseaddr[0] |= 0x1; //make ap_start high
}while ((base_addr[0] & 0x4) == 0); //wait for memcpy(polling)xil_printf("memcpy done!\n\r");…
}
• ap_idleが再び1になるまでwhile文で待機する
SDK “axihp_memcpyソフトウェア”
#include "xil_cache.h"#include "xil_printf.h"typedef unsigned long long u64;unsigned int *baseaddr = 0x43c00000;//reg0 of hls coreint main(){
Xil_DCacheDisable(); //Disable Data Cacheint i, mismatch = 0;volatile u64 src_data[256], dst_data[256];for (i = 0; i < 256; i++)
src_data[i] = i; //create source data
//control hls corebaseaddr[4] = src_data; //set read addrbaseaddr[6] = dst_data; //set write addr
if ((baseaddr[0] & 0x4) == 0x4) { //if ap_idle is highxil_printf("memcpy start\n\r");baseaddr[0] |= 0x1; //make ap_start high
}while ((baseaddr[0] & 0x4) == 0); //wait for memcpy(polling)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; //compare src_data and dst_data
}(mismatch == 0) ? xil_printf("memcpy success!\n\r"):
xil_printf("memcpy fail\n\r");return 0;
}
プログラム全体は以下のようになる
SDK “ソフトウェアのコンパイル1/2”
• [Build ALL]をクリックする• デフォルトでは保存する度に自動でBuildされる
1
SDK “ソフトウェアのコンパイル2/2”
• 実行ファイル(.elf)が生成された
同一
SDK “FPGAのコンフィグレーション1/2”
• ソフトウェア実装が終わったので実行手順に移る• まずFPGAに回路をダウンロードしていく• [Program FPGA]をクリックする
1
SDK “FPGAのコンフィグレーション2/2”
• Bitstreamを”...zynq_vivadohls/zynq_vivadohls.run/impl_1/design_1_wrapper.bit”と選択する
• [Program]をクリックする
1
2
SDK “アプリケーション実行の前に”
• アプリケーションの実行結果はuartで出力される• SDK上で結果を確認することもできるが、不具合が多い(linuxの場合)
したがってscreen, cuコマンドやminicomでシリアルポートに接続する
>ls /dev/ttyACM*ttyACMx>sudo chmod 666 /dev/ttyACMx>cu -s 115200 -l /dev/ttyACMx
cuコマンドの例(ZedBoardの場合)
>ls /dev/ttyACM*ttyACMx>sudo chmod 666 /dev/ttyACMx>screen /dev/ttyACMx 115200
screenコマンドの例(ZedBoardの場合)
SDK “アプリケーションの実行1/3”
• [Debug]タブを開く• [axihp_memcpy.elf]を右クリック• [Run As] => [Run Configuration]をクリック
1
2
3
• [Xilinx C/C++ application (GDB)] を右クリック• [New]をクリックする
12
SDK “アプリケーションの実行2/3”
SDK “アプリケーションの実行3/3”
• [Run]をクリックすると実行される
1
SDK "実行結果"
無事に一致しましたか?(^^)
SDK "二回目以降の実行"
• [Run]の右側の下矢印をクリック• [axihp_memcpy_Debug]をクリックで実行できる
1
2
SDK "Debugモード"
• [Debug]の右側の下矢印をクリック• [axihp_memcpy_Debug]をクリックでDebugモードで実行
1
2
SDK "割り込みプログラム1/4"
#include "xparameters.h"#include "xscugic_hw.h"#include "xil_exception.h"…int main(){
…//control hls coreunsigned int device_id = 0;XScuGic_DeviceInitialize(device_id);Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
XScuGic_DeviceInterruptHandler, device_id);Xil_ExceptionEnable();XScuGic_RegisterHandler(XPAR_PS7_SCUGIC_0_BASEADDR, 61,
axihp_memcpy_handler, NULL);baseaddr[2] |= 0x1;baseaddr[1] = 0x1;XScuGic_EnableIntr(XPAR_PS7_SCUGIC_0_DIST_BASEADDR, 61);…
}
SDK "割り込みプログラム2/4"
#include "xparameters.h"#include "xscugic_hw.h"#include "xil_exception.h"…volatile int memcpy_done = 0;void axihp_memcpy_handler();int main(){
…//while ((baseaddr[0] & 0x4) == 0); //wait for memcpywhile (memcpy_done == 0); //wait for interrupt…
}
void axihp_memcpy_handler(){
baseaddr[2] ^= 0x1;xil_printf("interrupt!\n\r");memcpy_done = 1;baseaddr[3] = 0x1;baseaddr[2] |= 0x1;
}
SDK "割り込みプログラム3/4"...zynq_vivadohls.sdk/standalone_bsp_0/ps7_cortexa9_0/libsrc/scugic_v2_1/src/xscugic_hw.c上記ファイル内にXScuGic_DeviceInterruptHangler関数が記述されてる
注意! キャストされていないので引数にはポインタではなく値をいれる
SDK "割り込みプログラム4/4"
#include "xparameters.h"#include "xscugic_hw.h"#include "xil_exception.h"#include "xil_cache.h"#include "xil_printf.h"typedef unsigned long long u64;unsigned int *baseaddr = 0x43c00000;//reg0 of hls corevolatile int memcpy_done = 0;void axihp_memcpy_handler();int main(){
Xil_DCacheDisable(); //Disable Data Cacheint i, mismatch = 0;volatile u64 src_data[256], dst_data[256];for (i = 0; i < 256; i++)
src_data[i] = i; //create source data
//control hls coreunsigned int device_id = 0;XScuGic_DeviceInitialize(device_id);Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
XScuGic_DeviceInterruptHandler, device_id);Xil_ExceptionEnable();XScuGic_RegisterHandler(XPAR_PS7_SCUGIC_0_BASEADDR, 61,
axihp_memcpy_handler, NULL);baseaddr[2] |= 0x1;baseaddr[1] = 0x1;XScuGic_EnableIntr(XPAR_PS7_SCUGIC_0_DIST_BASEADDR, 61);
baseaddr[4] = src_data; //set read addrbaseaddr[6] = dst_data; //set write addr
if ((baseaddr[0] & 0x4) == 0x4) { //if ap_idle is highxil_printf("memcpy start\n\r");baseaddr[0] |= 0x1; //make ap_start high
}//while ((baseaddr[0] & 0x4) == 0); //wait for memcpy(poling)while (memcpy_done == 0); //wait for interruptxil_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;
//compare src_data and dst_data}(mismatch == 0) ? xil_printf("memcpy success!\n\r"):
xil_printf("memcpy fail\n\r");return 0;
}
void axihp_memcpy_handler(){
baseaddr[2] ^= 0x1;xil_printf("interrupt!\n\r");memcpy_done = 1;baseaddr[3] = 0x1;baseaddr[2] |= 0x1;
}
プログラム全体は以下のようになる
VIVADO Logic Analyzer
Harware Managerの起動
現在の波形をキャプチャ
トリガをかけてキャプチャ
作業手順
VIVADO "Hardware Manager の起動1/6"
• [Open Hardware Manager]タブを開く• [Open Target]をクリック• [Open New Target]をクリック
1
2
3
VIVADO "Hardware Manager の起動2/6"
• [Next]をクリック
1
VIVADO "Hardware Manager の起動3/6"
• [Next]をクリック
1
VIVADO "Hardware Manager の起動4/6"
• [Next]をクリック
1
VIVADO "Hardware Manager の起動5/6"
• [Finish]をクリック
1
VIVADO "Hardware Manager の起動6/6"
• Hardware Managerが起動した
VIVADO "FPGAのコンフィグレーション1/2"
• FPGAのコンフィグレーションがまだの場合、ここでコンフィグレーションを行う
• "xc7z020_1"を右クリック• [Program Device]をクリック
1
2
VIVADO "FPGAのコンフィグレーション2/2"
• [Program]をクリックするとコンフィグレーションが実行される
1
寄り道 "CLKが出力されない1/6"• ZYNQの電源を入れた直後に、ILAを含むデザインを
コンフィグレーションするとワーニングがでる上にILAの操作画面が出てこない
• これはZYNQからCLKがまだ出力されていないことが原因• CLK出力後に[Refresh device]をクリックすると解決される
寄り道 "CLKが出力されない2/6"
• 実はコンフィグレーションが完了した段階ではZYNQからクロックは出力されない
• では、どのタイミングでクロックが出力されるのか?
• ネットで検索すると、"ARM上でアプリケーションを実行する"とクロックが出力されるという情報が多く出てくるが
正しい条件は"ps7_init_config, ps7_post_configを実行する"である
寄り道 "CLKが出力されない3/6"
• 普通ps7_init_config, ps7_post_configはアプリケーション実行前に実行される
寄り道 "CLKが出力されない4/6"
• しかし実行できないときがある
寄り道 "CLKが出力されない5/6"
• AXIポートが何も使用されていないとps7_post_configが実行されない
寄り道 "CLKが出力されない6/6"
XMD% connect arm hwXMD% rst –slcrXMD% cd "project_name".sdk/designe_1_wrapper_hw_platform_0XMD% source ps7_init.tclXMD% ps7_initXMD% ps7_post_configXMD% disconnect 64
• SDKのxmdコンソールでps7_post_configを実行する方法
VIVADO "現在の波形をキャプチャする1/2"
• [Run trigger immediate for this ILA core]をクリックする
1
VIVADO "現在の波形をキャプチャする2/2"
• 現在の波形がキャプチャされた• 次はトリガを設定し、狙ったタイミングでキャプチャする
VIVADO "トリガをかけてキャプチャ1/6"
• バースト受信の開始時にトリガをかける• ARVALIDがHighになったらトリガがかかるように設定していく• Debug Probes内にある"ARVALID"信号を右クリック• [Add Probes to Basic Trigger Setup]をクリック
2
1
VIVADO "トリガをかけてキャプチャ2/6"
• Basic Trigger Setup にARVALID信号が追加される• [Compare Value]タブを開く• [Value]を"1"に設定する
2
1
VIVADO "トリガをかけてキャプチャ3/6"
• キャプチャを開始する• [Run trigger for this ILA core]をクリックする
1
VIVADO "トリガをかけてキャプチャ4/6"
• トリガ待ちの状態になる
VIVADO "トリガをかけてキャプチャ5/6"
• SDKでアプリケーションを実行し、AXI転送を行う
1
2
VIVADO "トリガをかけてキャプチャ6/6"
• VIVADOに戻ってくるとARVALIDがHighになった直後からキャプチャされている
VIVADO "AXI転送時の波形"
Next Step "RTLでAXI State Machine書きたい!!1/5"
• AXIの雛型の作り方• VIVADOのProject Setteingsで"Vendor"を設定する
Next Step "RTLでAXI State Machine書きたい!!2/5"
• [Tools] => [Create and Package IP]をクリック
Next Step "RTLでAXI State Machine書きたい!!3/5"
• [Create a new AXI4 peripheral]を選択
Next Step "RTLでAXI State Machine書きたい!!4/5"
• 必要なAXIポートを備えたIPを作成
Next Step "RTLでAXI State Machine書きたい!!5/5"
"…/zynq_vivadohls/../ip_repo/"ip名"/hdl/"に生成したIPのソースファイルが格納されている
AXIステートマシンが記述されているので、このファイルを改造していくのが良いと思われる
DigilentのZYBOのチュートリアル前半部分が似たような内容になっている
(http://digilentinc.com/Data/Products/ZYBO/ZYBO-Embedded_Linux_Hands-on_Tutorial.pdf)