SDSoC (2016.2) のサンプルで pacektize して minmax を使うものがある。
Xilinx/SDSoC/2016.2/samples/platforms/zc702_axis_io/samples/stream
これに自分の stream を差し込んでみた。xilinx のサンプルは ap_axiu<32,1,1,1> を直接つかっていて hls::stream を使っていない。これだと不便だ。
SDSoC の sample をみると
samples/hls_if/hls_stream/
とちゃんと hls_stream を使ったものがある。なので、これをうまく差し込めれば自由に stream を使えることになる。でうまく組み合わせたのが、冒頭の絵になる。
で、これを差し込んだだけ?でうまくいくかというとさにあらず。hls_stream のサンプルでは
void bytestrm_dwordproc( hls::stream<uint8_t> &strm_out, hls::stream<uint8_t> &strm_in, uint16_t strm_len ) { //HLS: #pragma HLS interface axis port=strm_in #pragma HLS interface ap_fifo port=strm_in //HLS: #pragma HLS interface axis port=strm_out #pragma HLS interface ap_fifo port=strm_out
となっている。これだとうまくいかない。ap_fifo は恐らく Vivado HLS で fifo のインタフェースをつくってしまう。そして、SDSoC では stub で
#ifndef __SDSVHLS__ void bytestrm_dwordproc( unsigned char *strm_out, unsigned char *strm_in, unsigned short strm_len ) { // Prototype used by SDSoC to generate stub for hardware function // HLS function does not cross-compile with arm-xilinx*-gnueabi-g++ } #else
とつくっている。完全にダミールーチン。C++ 側のスタブを作るためだけにある。Vivado HLS の機能をフルに使おうとすると、g++ の用意する(最終的にコンパイラは g++だから。フロントエンドは llvm + clang)言語体系とうまくあわない。なので、このように
#ifdef __SDSVHLS__ Vivado HLS の関数 #else g++ の関数 #endif
と両方書いて、うまくその整合性を合わせるのは使う側の責任だ。で、ここの情報が不足している。簡単に破たんする。破綻すると opt が死んだり、謎のエラーが出たりする。
でもサンプルをよく見ると
//HLS: #pragma HLS interface axis port=strm_in
とコメントアウトされている。ありがとう。優秀なプログラマ。ヒントを残してくれてたんだね。ということで、ap_fifo ではなく axis を指定することにする。これで、完全にハードの世界になる。が、これで終わらない。
void my_p2p(hls::stream <ap_axiu<32,1,1,1> > & strm_in, hls::stream <ap_axiu<32,1,1,1> > & strm_out) { //#pragma HLS pipeline enable_flush #pragma HLS interface axis port=strm_in #pragma HLS interface axis port=strm_out //#pragma HLS interface ap_ctrl_none port=return // これが重要だった。
ソース上にすでにコメントで答えが書いてあるが、 ap_ctrl_none が必要だった。my_p2p の引数がすべてハードになってしまったために、C++ とのインタフェースを失ってしまったらしい。通常あるはずの C++ のインターフェスに追加する形で戻り値のインタフェースを追加する(のでしょう)ので、そのインタフェースがないと return のインターフェースが追加できずに合成時にエラーになる。
ということで、上の ap_ctrl_none を追加することでひとまず解決。
で、次のステップとして引数を増やして、stream が流れて行った後の統計情報などをとりたい。(実際にやろうと思っているのは width と height の取得)そこで、
void my_p2p(uint32_t *temp, hls::stream <ap_axiu<32,1,1,1> > & strm_in, hls::stream <ap_axiu<32,1,1,1> > & strm_out)
に変更したら、こんどは temp のインタフェースの offset が特定できずに opt の起動でエラー。opt と偉そうに書いているが何をしているかは不明。どうやら sds++ でコンパイルすると、インタフェースの情報を *.o の中に埋め込む(objdump でみると通常は見られないヘッダーがついている)。opt はそれをみて、どうやら tcl やら xci をつくる。その tcl と xci をみて vivado が IP コアを生成しているようだ。
上記の記述だと hls::stream が邪魔して temp の offset がわからないようだ。ということで、明示的に追加。この辺は SDSoC のサンプルになかったので完全に試行錯誤。
っていうか、ちゃんとサンプル用意してよ。これ、言語仕様なんだから。試行錯誤する時間が馬鹿らしい。
FPGA の部屋ありがとう。ここの情報と twitter の情報で突破で来た。
void my_p2p(uint32_t *temp, hls::stream <ap_axiu<32,1,1,1> > & strm_in, hls::stream <ap_axiu<32,1,1,1> > & strm_out) { #pragma HLS pipeline enable_flush #pragma HLS interface axis port=strm_in #pragma HLS interface axis port=strm_out #pragma HLS interface ap_ctrl_none port=return #pragma HLS interface s_axilite port=temp offset=0x0
こんな感じ。あとは自分で offset を考えて書けばいいんだね。あーこれでたぶん SDSoC 2016.2 がもっている uint16_t の issue (バグじゃねぇか?)も回避できそうだ。まぁ 2016.3 に移行すれば問題ないんだけど。
こんなに苦労したけど、すべて 2016.2 です。2016.3 でどうなっているかは不明。全部、フィックスしてたりして。あと、最終動作確認もまだ。
sds_alloc と CMA
Linux で sds_alloc をすると、どうも CMA の領域を使うらしい。CMA は .config で 256 に設定してある(Mバイト)。つまり、私のシステムでは 0x30000000 からなのだが、VRAM の領域をとることができない。連続して取れる領域の上限があるみたい。(たぶん Linux 側の問題。.config で変えられるかも、、、、)しかも、仮にとれたとしても、物理アドレスがわからない。
vdma を uio 経由で使おうと思ったら物理アドレスが必要なんだよね。
sds_mmap を使う。これは”物理アドレス”を直接使っちゃう。0x30000000 からマップしたら見事にシステムがこけました。どうやら 0x30000000 の先頭はシステム(Linux のカーネル?) が使っているらしい。CMA としてつかっているのか XILINX の Linux ドライバが使っているのかは不明。使っている領域をマップしようとしたらエラーになってくれればいいのに、、、、
今は強引に 0x38000000 からマップしてます。いずれ sds_alloc とバッティングするでしょう。物理アドレスとの整合性を /dev/fb なみにしてほしい。おそらく ioctl で用意しているとは思うけど、現時点ではユーザに見せていない。
SDSoC のプラットフォームと Vivado の階層
どうも、SDSoC 2016.2 は Vivado の階層に対応してないみたい。階層の stream の口を指定したプラットフォームを用意して SDSoC でコンパイルすると、エラーになる。意味不明のエラーでなんだかわらない。しかたがないので、階層の横に stream の FIFO かなにか”よけいな"IPコアを一個用意する予定。合成時に時間がかかっちゃうな、、、、Vivado の最適化で取り除かれるようにしたい。あーでも OOC つかっていると IP コアごとにコンパイルするから取り除かれないかも。
いろいろ障害はあるけれど
いろいろ障害はあったけど、stream とりわけ hls::stream が使えるようになると便利になる(個人的にはね)。C++ のテンプレートがばしばしつかえるのもよい(個人的にはね)。
こういった情報交換が母国語(日本語)でできるしあわせをかみしめつつ。誰かのお役に立てれば。