#やりたいこと
Zed boardを買ってZynqいじりしていたのですが,自分でHDLゴリゴリ書いて作った独自回路をPLに書き込んでPSから利用する方法がよく分からなかったので,まとめてみました.
AXI4インタフェースを持った独自IPを作成し,Zynqのコアとつなぎます.
ここでは単純な加算器をAXI4-Liteインタフェースを利用した独自IPとして作成し,CPUから利用してみます.
使用したVivadoのバージョンは2014.2です.
#プロジェクトの作成
まずは普通にプロジェクトを作ります.
ここではadder_testという名前にしました.
#Block design
左側のFlow navigatorから,IP Integrator -> Create Block Design でBlock Designを開きます.名前はここではsystem
にしました.
Add IPをクリックして,ZYNQ7 Processing System
を選択し,Zynqのコアを追加します.
Zynqコアをダブルクリックしてカスタマイズします.
PresetsからZed boardを選び,OKします.(IPとの通信のためにAXI Masterインタフェース,テストプログラムのためにUARTがあればよいと思いますが,面倒くさいのでプリセットから選びます.)
#独自IP追加
上のメニューから,Tool -> Create and Package IP を選びます.
こんなダイアログが出ます.
nextを押します.
Create a new AXI4 peripheralを選んでNextを押します.
IP名を適当に決めて,Nextを押します.今回はsimple_adderにしました.
S00_AXIをS_AXIにリネームしました.リネームする必要は無いと思いますが,一つしかポートが無いので番号は消しました.
#IP編集
新しいウィンドウが開いて,IPの編集が行えます.
Sourcesペインを見ると,ソースファイルが2つできています.
トップレベルのsimple_adder_v1_0の下にAXI slaveインタフェースのsimple_adder_v1_0_S_AXIがあります.
詳しくは中身を読んでください.
##ソース編集
simple_adder_v1_0_S_AXI.v
を編集して,加算器にします.
このモジュールはslv_reg0
, slv_reg1
, slv_reg2
, slv_reg3
というレジスタを持っていて,Writeするとこれらのレジスタにデータが入り,Readするとこれらのレジスタから値が読み出されるようになっています.
ベースアドレスでアクセスするとslv_reg0
にWrite/Readされ,ベースアドレスにオフセットを足してslv_reg1
, slv_reg2
, slv_reg3
にアクセスします.この辺は詳しくは後述します.
今回は例としてslv_reg0
とslv_reg1
の和をslv_reg2
に入れるようにしてみます.
slv_reg0
, slv_reg1
, slv_reg2
, slv_reg3
をドライブしているalways @( posedge S_AXI_ACLK )
~end
ブロックを探します.
if (slv_reg_wren)
~end
の中でslv_reg0
, slv_reg1
, slv_reg2
, slv_reg3
への書き込みが行われているのがわかります.(これがWrite処理)
ここにelse
を足して,
slv_reg2 <= slv_reg0 + slv_reg1;
を書き加えます.(もっとうまいやり方があるのだろうな)
##パッケージ
左側のFlow NavigatorからProject Manager -> Package IPを選びます.
全項目に緑色チェックマークがついているのでOKです.Review and Packageタブを選んでRe-Package IPを押します.
これでIPの編集は終了です.
#IP追加
もともとのプロジェクトのウィンドウに戻ってきました.
Add IPを押して,先ほど作った独自IP,simple_adder_v1.0を追加します.
Run Block Automation, Run Connection Automationを実行します.
こんな感じで配線されます.(Regenerate Layoutボタンを押すと再配置されて見やすくなります.)
追加したsimple_adderにアドレスが割り振られているのが確認できます.
#Bitstream作成
Sourcesペインでsystem_i - system (system.bd)
を右クリックして,メニューからCreate HDL Wrapper
を選びます.ダイアログではLet Vivado manage wrapper and auto-update
を選んでおくと良いと思います.
これでトップレベルのHDLが生成されます.
またsystem_i - system (system.bd)
を右クリックして,メニューからGenerate Output Products
を選びます.ダイアログでGenerateをクリックします.
そうしたら,Generate Bitstreamを押してビットストリームを作成します.ダイアログでsaveするかとかsynthesisとimplementationするかとか聞かれますがyesで.
#ソフトウェアの作成
SDKへエクスポート
Bitstreamができたら,上部のメニューからFile -> Export -> Export Hardwareを選択します.
ダイアログでInclude bitstreamにチェックが入っていることを確認して,OKを押します.
File -> Launch SDK を選択してSDKを起動します.
これでハードウェアの情報がSDKにも読み込まれます.
SDKの起動直後の画面でsimple_adderのアドレスがあることを確認
##SDKでプロジェクト作成
上部のメニューから File -> New -> Application Projectを選択.
プロジェクト名を適当に決めて,あとはデフォルトのままNext.
##ソース編集
adder_testプロジェクト以下のsrc -> helloworld.c を編集します.
#include <stdio.h>
#include "platform.h"
#include "xparameters.h"
#include "xil_io.h"
#define SIMPLE_ADDER_ADDR_OFFSET1 4
#define SIMPLE_ADDER_ADDR_OFFSET2 8
int main()
{
u32 result;
init_platform();
print("Hello World\n\r");
Xil_Out32(XPAR_SIMPLE_ADDER_0_S_AXI_BASEADDR, 123);
Xil_Out32(XPAR_SIMPLE_ADDER_0_S_AXI_BASEADDR + SIMPLE_ADDER_ADDR_OFFSET1, 456);
result = Xil_In32(XPAR_SIMPLE_ADDER_0_S_AXI_BASEADDR + SIMPLE_ADDER_ADDR_OFFSET2);
xil_printf("123 + 456 = %d\r\n", result);
cleanup_platform();
return 0;
}
#define SIMPLE_ADDER_ADDR_OFFSET1 4
はsimple_adder_v1_0.vに定義されている
parameter integer C_S_AXI_ADDR_WIDTH = 4
にもとづいています.
simple_adder.h
インクルードファイルはadder_test_bspプロジェクト以下のSrc -> include内にあります.
たまにsimple_adder.h
が生成されてsimple_adderとやりとりするのに便利なマクロが定義されたりするんですが,どうやったらこのファイルが生成されてくれるのかわかりません…
誰か教えてください
##デバッグ実行
adder_testを選択した状態で上部のメニューからRun -> Debug Configurationsを選択します.
ダイアログでXilinx C/C++ application (GDB)をダブルクリックします.
Reset Entire Systemを選択し,Program FPGAにチェックが入った状態にします.
STDIO Connectionタブでコンソールの設定を行います.
Tera term等,別のターミナルソフトを使う場合は不要です.
設定が終わったら,Applyして設定を保存し,Debugを押します.パースペクティブを変えますか的なダイアログが出たらOKします.
##確認
デバッグモードなのでステップ実行が始まります.とりあえずここではResumeを押して普通に実行してしまいます.
Hello World
123 + 456 = 579
と表示され,加算回路にAXIを使ってアクセスし利用することができたのがわかります.
#言い訳
以上です.
Zynqを触り始めて1ヶ月くらいの初心者なのでご指摘などなどぜひよろしくお願いします.