FC2カウンター FPGAの部屋 Vivado HLSのI/Oプロトコル(ブロックレベルとポートレベル)

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

Vivado HLSのI/Oプロトコル(ブロックレベルとポートレベル)

Vivado HLS 2015.4 から、WebPACKでもVivado HLS が使えるようになり、高位合成を使おうという機運が盛り上がっていると思います。Xiliinx社さんのご英断に感謝致します。

今日は、Vivado HLS のI/O プロトコルにに付いて書いてみたいと思います。
ソフトウェアの C、C++ がHDL 、つまりハードウェアになるので、時間の概念が入ってきます。つまり、ソフトウェアは関数コールで関数を呼び出して実行させますが、ハードウェアはそこに回路の実体ができちゃってます。つまり関数をコールする、しないにかかわらず、いつもお仕事をできる、しちゃえる状態にあるわけです。その回路を何らかの条件で始まりを指示する必要あります。つまり、C の関数の引数の信号線だけではなく、追加の信号も必要になるということです。
これらの信号は、Vivado HLS でHDL へ変換する過程で付加されます。ですので、C をVivado HLS で高位合成して、HDL を見ると見慣れない余計な信号があるのが見えると思います。

例えば、次のCソースコードをVivado HLS 2015.4 で高位合成してみましょう。(合成と書こうと思いましたが、Xilinx社のマニュアルで高位合成と書いてあるので、ここでも高位合成とします)

// marsee_example2.c
// 2015/12/06 by marsee
// 掛け算サンプル
//

int marsee_example1(int multi_in0, int multi_in1, int *multi_out){
    *multi_out = multi_in0 * multi_in1;
    return 0;
}


marsee_example2.c を高位合成してみました。
Vivado_HLS_IO_Protcol_1_151206.png

Clock の ap_clk はクロック周期の制約が 10 ns に対して、6.08 ns になったということです。約 164 MHz ですね。
掛け算回路のレイテンシは 5 クロックで、インターバルは 6 クロックという結果が出ました。
右のウインドウを見ると、solution1 フォルダの syn フォルダに verilg フォルダができていて、そこに、marsee_example1.v と marsee_example1_mul_32s_32s_32_6.v ができていました。
Vivado_HLS_IO_Protcol_2_151206.png

marsee_example1.v がトップファイルなので、その宣言部を見てみましょう。下に示します。

// ==============================================================
// RTL generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2015.4
// Copyright (C) 2015 Xilinx Inc. All rights reserved.
// 
// ===========================================================

`timescale 1 ns / 1 ps 

(* CORE_GENERATION_INFO="marsee_example1,hls_ip_2015_4,{HLS_INPUT_TYPE=c,HLS_INPUT_FLOAT=0,HLS_INPUT_FIXED=0,HLS_INPUT_PART=xc7z010clg400-1,HLS_INPUT_CLOCK=10.000000,HLS_INPUT_ARCH=others,HLS_SYN_CLOCK=6.080000,HLS_SYN_LAT=5,HLS_SYN_TPT=none,HLS_SYN_MEM=0,HLS_SYN_DSP=4,HLS_SYN_FF=6,HLS_SYN_LUT=1}" *)

module marsee_example1 (
        ap_clk,
        ap_rst,
        ap_start,
        ap_done,
        ap_idle,
        ap_ready,
        multi_in0,
        multi_in1,
        multi_out,
        multi_out_ap_vld,
        ap_return
);

parameter    ap_const_logic_1 = 1'b1;parameter    ap_const_logic_0 = 1'b0;
parameter    ap_ST_st1_fsm_0 = 6'b1;parameter    ap_ST_st2_fsm_1 = 6'b10;
parameter    ap_ST_st3_fsm_2 = 6'b100;parameter    ap_ST_st4_fsm_3 = 6'b1000;
parameter    ap_ST_st5_fsm_4 = 6'b10000;parameter    ap_ST_st6_fsm_5 = 6'b100000;
parameter    ap_const_lv32_0 = 32'b00000000000000000000000000000000;parameter    ap_const_lv1_1 = 1'b1;
parameter    ap_const_lv32_5 = 32'b101;parameter    ap_true = 1'b1;

input   ap_clk;
input   ap_rst;
input   ap_start;
output   ap_done;
output   ap_idle;
output   ap_ready;
input  [31:0] multi_in0;
input  [31:0] multi_in1;
output  [31:0] multi_out;
output   multi_out_ap_vld;
output  [31:0] ap_return;


Cソースコードでは、example_marsee() の引数はmulti_in0, multi_in1, *multi_out のみでしたが、ap_clk, ap_rst, ap_done, ap_ready, multi_out_ap_vld, ap_return が増えていまます。
ちなみに、Vivado HLS では、値渡しの引数は入力信号、参照渡しの引数は入力信号、出力信号、または入力信号と出力信号の両方に合成されます。
ap_clk, ap_rst, ap_done, ap_ready, ap_return の信号は回路ブロックの、つまりブロック・レベルのインターフェース・プロトコルの信号です。これは冒頭に書いたようにC 関数の引数以外のハードウェアの回路にするのに必要なハンドシェークの信号です。
multi_out_ap_vld だけが、ポート・レベルのインターフェース・プロトコルの信号です。ポート(C 関数の引数はハードウェア(HDL) に合成した場合はポートになります)を考えてみましょう。ポートでは、ソフトウェアと違って、値が用意されて渡されるわけではありません。ポートという実体が常に存在しています。ですから、いつから信号が有効であるのかを示す必要があります。それが、multi_out_ap_vld です。
高位合成結果でレイテンシが 5 クロックという結果でしたが、これは入力を入れてから掛け算出力が出るまでに 5 クロック掛かるという意味でした。multi_in0 と multi_in1 の正しい掛け算の値が multi_out に出力された時に、multi_out_ap_vld は 1 になります。つまり、掛け算の出来上がりを知らせる信号です。
入力の multi_in0 と multi_in1 にはポート・レベルのインターフェース・プロトコル信号が付いていませんが、これは演算の間、値を保持することになります。
インターフェース・プロトコルには名前が付いていて、今回のブロック・レベルのインターフェース・プロトコル信号は ap_ctrl_hs で、multi_in0, multi_in1 は ap_none、multi_out は ap_vld です。

実際の掛け算回路動作を C/RTL コシミュレーションで表示してみましょう。
テストベンチを作製します。marsee_example2_tb.c という名前にしました。下に示します。

// marsee_example_tb.c
// 2015/12/06 by marsee
//

#include <stdio.h>
#include <stdlib.h>

int marsee_example1(int multi_in0, int multi_in1, int *multi_out);

int main(){
    int multi_in0, multi_in1, multi_out;
    int ret_val;

    multi_in0 = 2; multi_in1 = 3;
    ret_val = marsee_example1(multi_in0, multi_in1, &multi_out);
    printf("multi_out = %d\n", multi_out);

    return(ret_val);
}


C/RTL コシミュレーションの結果を下に示します。
Vivado_HLS_IO_Protcol_3_151206.png

下のウインドウに multi_out = 6 が表示されています。
C/RTL コシミュレーションの結果の波形をVivado で見ることができるので、見てみましょう。これです。
Vivado_HLS_IO_Protcol_4_151206.png

ap_start が 1 にアサートされて、掛け算が始まり、同時に ap_idle が 0 になっているのが分かります。同時に multi_in0 には 2 が、multi_in1 には 3 が入力されています。掛け算の値 6 が multi_out に出力されると multi_out_ap_vld, ap_done が 1 になります。ap_return にも、戻り値の 0 がセットされます。

このようにソフトウェアからハードウェアになると、プロトコル信号が必要となる場合があります。いろいろな回路上の都合からデータを受け取れない場合、データを受け取ったけど演算に時間がかかり、すぐに正しい結果を出力できない場合はインターフェース・プロトコル信号を付加して、ハンドシェークする必要があります。

ブロック・レベル、ポート・レベルのインターフェース・プロトコル信号については、高位合成(UG902) V2015.3 日本語版 2015/09/30 の 133 ページを御覧下さい。
  1. 2015年12月06日 04:16 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:2

コメント

高位合成の説明にパイプラインも入れてみてはいかがでしょうか?
関数の高位合成でハンドシェイクが必要になると、プログラムを順番に実行しているようなイメージになりハードウェアで実行しているイメージがわきにくいですが
パイプラインであれば連続した時間の概念が入るのでイメージしやすいかな....

余計にわかりにくいかも知れませんが
  1. 2015/12/08(火) 08:36:30 |
  2. URL |
  3. おる #-
  4. [ 編集 ]

おるさん、こんにちは。

パイプラインの件、了解しました。
Vivado HLS勉強会の資料を公開する準備を進めています。パイプラインの件はそちらで説明しようと思っています。

なお、この記事は、HDL Advent Calendar 2015の6日目の記事です。
http://qiita.com/advent-calendar/2015/hdl
  1. 2015/12/10(木) 05:40:47 |
  2. URL |
  3. marsee #f1oWVgn2
  4. [ 編集 ]

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
http://marsee101.blog19.fc2.com/tb.php/3326-9da8849c
この記事にトラックバックする(FC2ブログユーザー)