やりたいこと
AXI4-Streamの入出力を持つやつを繋げたものをIPをラップしたIPを作りたい。
コード
#ifndef SAMPLE_HPP
#define SAMPLE_HPP
#include <iostream>
#include <ap_int.h>
#include <random>
#include "hls_stream.h"
#include "ap_axi_sdata.h"
const uint32_t W_USR = 32;
typedef hls::axis< uint32_t, W_USR, 0, 0> my_axis;
void top_func(
hls::stream<my_axis>& in_a,
hls::stream<my_axis>& in_b ,
hls::stream<my_axis>& in_c ,
hls::stream<my_axis>& out_res
);
#endif // SAMPLE_HPP
#include "sample.hpp"
// 内部IP 1
void add_st (
hls::stream<my_axis>& in_a,
hls::stream<my_axis>& in_b,
hls::stream<my_axis>& out_res
){
my_axis a, b, res;
in_a.read(a);
in_b.read(b);
res.data = a.data + b.data;
res.user = a.user;
res.last = a.last;
out_res.write( res );
}
// 内部IP 2
void sub_st (
hls::stream<my_axis>& in_a,
hls::stream<my_axis>& in_b,
hls::stream<my_axis>& out_res
){
my_axis a, b, res;
in_a.read(a);
in_b.read(b);
res.data = a.data - b.data;
res.user = a.user;
res.last = a.last;
out_res.write( res );
}
// wrapするトップモジュール
void top_func(
hls::stream<my_axis>& in_a,
hls::stream<my_axis>& in_b,
hls::stream<my_axis>& in_c,
hls::stream<my_axis>& out_res
){
#pragma HLS INTERFACE axis port=in_a
#pragma HLS INTERFACE axis port=in_b
#pragma HLS INTERFACE axis port=in_c
#pragma HLS INTERFACE axis port=out_res
#pragma HLS DATAFLOW
hls::stream<my_axis> a_plus_b_st;
add_st( in_a , in_b , a_plus_b_st );
sub_st( a_plus_b_st , in_c , out_res );
}
#include "sample.hpp"
int main(){
hls::stream<my_axis> in_a, in_b, in_c, out_exp_res, out_act_res;
std::mt19937 engine(0);
const uint32_t TEST_SIZE = 1024;
const uint32_t RAND_LIM = 10000;
for( uint32_t i = 0 ; i < TEST_SIZE ; ++i ){
my_axis a,b,c,res;
a.data = engine() % RAND_LIM ;
b.data = engine() % RAND_LIM ;
c.data = engine() % RAND_LIM ;
a.user = i;
b.user = i + 1000;
c.user = i + 2000;
a.last = (i == TEST_SIZE - 1) ? 1 : 0;
in_a.write(a);
in_b.write(b);
in_c.write(c);
res.data = a.data + b.data - c.data;
res.last = a.last;
out_exp_res.write( res );
}
for( int i = 0 ; i < TEST_SIZE ; ++i ){
top_func( in_a, in_b, in_c, out_act_res );
}
for( int i = 0 ; i < TEST_SIZE ; ++i ) {
my_axis act_res, exp_res;
out_act_res.read( act_res );
out_exp_res.read( exp_res );
if( act_res.data != exp_res.data ) {
printf("result is not same\n");
return 1;
}
if( act_res.last != exp_res.last ) {
printf("TLAST timing is not same\n");
printf("TEST FAILED\n");
return 1;
}
if( act_res.last == 1 )
printf("TLAST is detected at %d\n" , i );
}
printf("TEST PASSED\n");
return 0;
}
エラー内容
これらを用いてIPを生成しようとするとC Simulation
は通るが、C Synthsis
で以下のエラーが出る。
ERROR: [HLS 214-208] The ap_axis|ap_axiu|qdma_axis|hls::axis data types must only be used for AXI-Stream ports in the interface. 'a_plus_b_st' is not an AXI-Stream and/or is not a port in the interface
ERROR: [HLS 200-1715] Encountered problem during source synthesis
エラー内容で検索すると、それっぽい質問が出た1。
解決方法
外部ポートを持たないhls::stream
にはhls::axis
を用いない。
参考にした記事2によると、Vitis HLS 2020.2より外部ポートを持たないhls::stream<hls::axis<hoge_t, ... >>
は弾かれるようになったらしい。そのため以下のようにhls::axis
を用いない形に変える必要がある。
hls::stream<uint32_t> a_plus_b_st;
今回の場合はtuser, tlast
を用いているため、次のようにすることで解決した。
struct internal_st{
uint32_t data;
ap_uint<W_USR> user;
bool last;
};
hls::stream<internal_st> a_plus_b_st;
最初に出た記事の
Because B is not an external interface, you cannot define it as an axis interface. You can simply declare it as an hls::stream<int32_t> to stream data from block_1 to block_2.
を, 『内部信号にhls::stream
を使うな』に勘違いして永遠にエラーを出していた(馬鹿すぎる)。
marseeさんに感謝。