先日開催された人工知能とハードウェア・ソフトウェア協調設計ワークショップで発表された杉本さんのZynq + Vivado HLSというチュートリアルがとても素晴らしい内容だったので,それにならってZynq + Synthesijerというガイドを書いてみました.RTLは,ほとんど書かなくて大丈夫です.
このガイドでは,Javaで記述したメモリをコピーするモジュールをPLに置き,それをPSから叩く,というシステムの作成を目指します.
スライドでは,コードなどが見づらいので,以下補足です.
Synthesije関連リソースの準備(p.7)
ファイル一式のダウンロードと環境変数の設定をします
% 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
% cd $HOME/synthesijer/work
% mkdir $HOME/synthesijer/work
Javaのコードを記述(p.10)
PL用のハードウェアモジュールのソースコードです.
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
}
}
SynthesijerでJavaコードをコンパイル(p.11)
% 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
IPパッケージの作成(p.12)
必要なソースコードを所定のディレクトリにコピーします
% 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</sprit:name>
<spirit:name>src/simple_axi_memiface_32.vhd</spirit:name>
<spirit:name>src/AXIHP_MEMCPY.vhd</sprit: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</sprit:name>
<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
ARM上のソースコードの記述(p.38)
PS用のソフトウェアのソースコードです.
#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;
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;
}
です.