Vivado HLSのメモ

最近Vivado HLSで高位合成を使い始めました。やっぱり、HDLを生で書くよりも圧倒的に早くコーディング・検証できるので、計算処理の記述ではとても助かっています。もしかすると、他の人の参考になるかもしれないので、作業していて気がついた点をまとめておきます。間違った記述があったらコメント欄で指摘してください。

[toc]

Co-simulationでhandshake signals are not bundled to AXI_lite slaveというエラーが出る

HLSでAXI-Liteで引数を渡す設定にしているときに、Co-simulationで

[shell wraplines=”true”]

This design has AXI_lite interface port but function-level handshaking signals are not bundled to AXI_lite slave.

[/shell]

というエラーが出ることがあります。たとえば、

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
INFO: [COSIM 212-333] Generating C post check test bench ...
INFO: [COSIM 212-12] Generating RTL test bench ...
CRITICAL WARNING: [COSIM 212-372] This design has AXI_lite interface port but function-level handshaking signals are not bundled to AXI_lite slave.
CRITICAL WARNING: [COSIM 212-4] *** C/RTL co-simulation finished: FAIL ***
10
while executing
"source /home/spire/hls/hls_sample/solution1/cosim.tcl"
invoked from within
"hls::main /home/spire/hls/hls_sample/solution1/cosim.tcl"
("uplevel" body line 1)
invoked from within
"uplevel 1 hls::main {*}$args"
(procedure "hls_proc" line 5)
invoked from within
"hls_proc $argv"
Finished C/RTL cosimulation.

これは、トップレベル関数の戻り値のdirectiveに

1
#pragma HLS INTERFACE s_axilite port=return

を記述していないことが原因。void関数の場合でも、引数をAXI-Lite Slave指定にするときは、returnポートをAXI-Lite Slave指定にする必要があるようです。

AXI Masterポート指定のディレクティブのdepthの単位はバイト

データの入出力をAXI Masterポートで行うときに、以下のようなdirectiveを指定しますが、この時のdepthはバイト単位。たとえば、uint32_t* buffer[32]のときは、depthは128(バイト)にします。これをワード単位で記述すると、Co-simulationのときにsegmentation faultでシミュレーションに失敗します。

1
2
3
#pragma HLS INTERFACE m_axi port=axi_master offset=slave depth=128

トップレベル関数とC++のメソッド名が重複しているとCo-simulationが失敗する

つまるところ、トップレベル関数名とstatic publicメソッド名を違うものにするとうまくいくようです。 Vivado HLS 2016.2でこのエラーになることは確認しました。新しいバージョンでは修正されているかもしれません。

詳細

以下のようなdouble同士の掛け算を実行するアクセラレータ関数を作りたいとします。 トップレベルは関数として宣言し、その実装ではC++のクラスのstatic publicメソッドを 呼び出して計算を実行するとします。

ヘッダファイルは以下のような感じで、

[cpp title=”multiply.h”] // Implementation class class Accelerator { public: static double multiply(double a, double b); };

// Top-level function double multiply(double a, double b); [/cpp]

C++ソースファイルは以下のようなものです。

[cpp title=”multiply.cpp”] #include “multiply.h”

// Implementation class double Accelerator::multiply(double a, double b) { return a * b; }

// Top-level function double multiply(double a, double b) {

#pragma HLS INTERFACE s_axilite port=return #pragma HLS INTERFACE s_axilite port=a #pragma HLS INTERFACE s_axilite port=b

1
return Accelerator::multiply(a,b); } [/cpp]

それで、以下のようなテストベンチでC++シミュレーションを実行してみます。

[cpp title=”test_multiply.cc”] #include #include "multiply.h"

int main() { double a = 3.1415; double b = 2.71; double c = multiply(a, b);

1
2
3
4
5
6
7
8
9
10
11
double epsilon = 1e-10;
double delta = c - (a * b);

printf(" c  = %.6e\n", c);
printf("a*b = %.6e\n", a * b);

if (delta < epsilon) {
	return 0;
} else {
	return 1;
} } [/cpp]

Projectメニュー→Run C Simulationで実行すると、以下のように成功します(シンプルな計算なので、当たり前ですが)。

[shell title=”multiply_csim.log”] Compiling ../../../src/multiply.cpp in debug mode Generating csim.exe c = 8.513465e+00 a*b = 8.513465e+00 INFO: [SIM 1] CSim done with 0 errors. [/shell]

今度はCo-simulationを実行するために、Solution → Run C Synthesis → Active Solutionで高位合成を実行してから、Solution → Run C/RTL Cosimulationを実行すると、以下のようなエラーになります。

[shell wraplines=”true”] Starting C/RTL cosimulation … /Xilinx/Vivado_HLS/2016.2/bin/vivado_hls /hls/hls_sample/solution1/cosim.tcl INFO: [HLS 200-10] Running ‘/Xilinx/Vivado_HLS/2016.2/bin/unwrapped/lnx64.o/vivado_hls’ INFO: [HLS 200-10] On os “CentOS release 6.7 (Final)” INFO: [HLS 200-10] In directory ‘/hls’ INFO: [HLS 200-10] Opening project ‘/hls/hls_sample’. INFO: [HLS 200-10] Opening solution ‘/hls/hls_sample/solution1’. INFO: [SYN 201-201] Setting up clock ‘default’ with a period of 10ns. INFO: [HLS 200-10] Setting target device to ‘xc7z020clg484-1’ INFO: [COSIM 212-47] Using XSIM for RTL simulation. INFO: [COSIM 212-14] Instrumenting C test bench … Build using “/Xilinx/Vivado_HLS/2016.2/lnx64/tools/gcc/bin/g++” Compiling apatb_multiply.cpp Compiling multiply.cpp_pre.cpp.tb.cpp In file included from apatb_multiply.cpp:18:0: /Xilinx/Vivado_HLS/2016.2/include/ap_stream.h:70:2: warning: #warning AP_STREAM macros are deprecated. Please use hls::stream<> from “hls_stream.h” instead. [-Wcpp] /hls/hls_sample/src/multiply.cpp: In function ‘double AESL_ORIG_DUT_multiply(double, double)’: /hls/hls_sample/src/multiply.cpp:15:8: error: ‘AESL_ORIG_DUT_multiply’ is not a member of ‘Accelerator’ make: ** [obj/multiply.cpp_pre.cpp.tb.o] エラー 1 CRITICAL WARNING: [COSIM 212-317] C++ compile error. CRITICAL WARNING: [COSIM 212-321] EXE file generate failed. CRITICAL WARNING: [COSIM 212-321] EXE file generate failed. CRITICAL WARNING: [COSIM 212-331] Aborting co-simulation: C simulation failed, compilation errors. CRITICAL WARNING: [COSIM 212-4] ** C/RTL co-simulation finished: FAIL ** command ‘ap_source’ returned error code while executing “source /hls/hls_sample/solution1/cosim.tcl” invoked from within “hls::main /hls/hls_sample/solution1/cosim.tcl” (“uplevel” body line 1) invoked from within “uplevel 1 hls::main {}$args” (procedure “hls_proc” line 5) invoked from within “hls_proc $argv” Finished C/RTL cosimulation. [/shell]

しょうがないので、C++クラス内のメソッド名をmultiplyImplに変更して実行すると、

[cpp title=”multiply.h”] // Implementation class class Accelerator { public: static double multiplyImpl(double a, double b); };

// Top-level function double multiply(double a, double b); [/cpp]

以下のようにWarningはでつつも、Co-simulation自体は実行され、結果も妥当なようです。

[shell wraplines=”true”]

run all

Note: ****************** renorm_and_round_logic.vhd : FULL_MANT_RND1_DEL is using fast_input which will be faster, but create more FFs. ****************** Time: 0 ps Iteration: 0 Warning: OPMODE Input Warning : The OPMODE 011XX11 with CARRYINSEL 000 to DSP48E1 instance is invalid. Time: 100010 ps Iteration: 0 Process: /apatb_multiply_top/AESL_inst_multiply/multiply_dmul_64ns_64ns_64_6_max_dsp_U1/multiply_ap_dmul_4_max_dsp_64_u/U0/i_synth/mult/OP/R_AND_R/logic/R_AND_R/dsp48_e1/dsp48e1_add/DSP48E1_ADD/DSP/prcs_opmode_drc File: /wrk/2016.2/continuous/2016_06_02_1577090/data/vhdl/src/unisims/primitive/DSP48E1.vhd Note: simulation done! Time: 965 ns Iteration: 1 Process: /apatb_multiply_top/generate_sim_done_proc File: /hls/hls_sample/solution1/sim/vhdl/multiply.autotb.vhd Failure: NORMAL EXIT (note: failure is to force the simulator to stop) Time: 965 ns Iteration: 1 Process: /apatb_multiply_top/generate_sim_done_proc File: /hls/hls_sample/solution1/sim/vhdl/multiply.autotb.vhd $finish called at time : 965 ns

quit

INFO: [Common 17-206] Exiting xsim at Sat Nov 12 20:19:58 2016… INFO: [COSIM 212-316] Starting C post checking … c = 8.513465e+00 ab = 8.513465e+00 INFO: [COSIM 212-1000] ** C/RTL co-simulation finished: PASS *** Finished C/RTL cosimulation. [/shell]

ちなみにCo-simulationの実行結果をみると、掛け算処理が33クロックで処理されていました。

Latency Interval
RTL Status min avg max min avg max
VHDL Pass 33 33 33 0 0 0
Verilog NA NA NA NA NA NA NA

なお、引数と結果の精度を単精度(float)に変更すると、DSP48の使用量が11個→3個になり、Co-simulationでレポートされるlatencyは18クロックサイクルに減少しました。