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

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

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


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

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

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に

#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でシミュレーションに失敗します。


#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メソッドを
呼び出して計算を実行するとします。

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

// Implementation class
class Accelerator {
public:
	static double multiply(double a, double b);
};

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

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

#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

	return Accelerator::multiply(a,b);
}

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

#include <stdio.h>
#include "multiply.h"

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

	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;
	}
}

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

   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.

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

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.

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

// Implementation class
class Accelerator {
public:
	static double multiplyImpl(double a, double b);
};

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

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

## 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
a*b = 8.513465e+00
INFO: [COSIM 212-1000] *** C/RTL co-simulation finished: PASS ***
Finished C/RTL cosimulation.

ちなみに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クロックサイクルに減少しました。