FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

Vivado 2015.4 HLSを試す(チュートリアル Lab.3)

Vivado HLSのチュートリアルの続きをやっていこう。Introduction Lab.3だ。

今回は、FPGAのデザインに最適になるように、インタフェースの部分を調整するらしい。

まずは、CUI上で論理合成とシミュレーションまでを一通り終わらせる。これがベースデザインとなり、調整するようだ。

ベースデザインの合成とソリューションのコピー

vivado_hls –f run_hls.tcl

次に、デザインを起動して、GUI上での作業に移る。

vivado_hls –f run_hls.tcl

以下のように、ポートの変更をするようだ。

  • ポートCにはRAMが接続される。
  • ポートXはValid信号が接続される。
  • ポートYはValid信号が接続される。

まずは、現在のソリューションをベースにして、新しいソリューションを作成する。

f:id:msyksphinz:20151127235600p:plain

[Project]→[New Solution]を選択して、ソリューションのコピーを作成する。

f:id:msyksphinz:20151128000103p:plain

入出力ポートの改良

入出力ポートに改造を施す。[Directive]タブを選択し、ポートcを右クリックして[Insert Directive]を選択する。

f:id:msyksphinz:20151128000409p:plain

  • [Directive]を[RESOURCE]に設定
  • [core(optional)]を選択し、[RAM_1P_BRAM]を選択する。

f:id:msyksphinz:20151128000736p:plain

  • [Destination]と[Source File]に設定する。これにより、Cソース側にプリミティブが付加されることになる。

f:id:msyksphinz:20151128001108p:plain

  • 同様に、ポートX、ポートYにvalid信号を設定させる。 -- Optionsの[mode]に、[ap_vld]を設定する。これで、Valid信号が設定されるようになる。 -- [Destination]を[Source File]に設定する。

f:id:msyksphinz:20151128001703p:plain

ディレクティブを追加することにより、ソースファイルに以下のような記述が追加された。

void fir (
  data_t *y,
  coef_t c[N],
  data_t x
  ) {
#pragma HLS INTERFACE ap_vld port=y
#pragma HLS INTERFACE ap_vld port=x
#pragma HLS RESOURCE variable=c core=RAM_1P_BRAM

pragmaにより、コンパイラに指定を追加するようだ。

合成の実行

[Solution]→[Run C Synthesis]→[Active Solution]をクリックする。

これで合成が実行される。合成結果を確認しよう。ベースデザインとのDiffを取るとどうなるだろう。

f:id:msyksphinz:20151128002545p:plain

$ diff -y -W200  solution1/syn/verilog/fir.v solution2/syn/verilog/fir.v
// ==============================================================                                       // ==============================================================
// RTL generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC                       // RTL generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2015.4                                                                                      // Version: 2015.4
// Copyright (C) 2015 Xilinx Inc. All rights reserved.                                                  // Copyright (C) 2015 Xilinx Inc. All rights reserved.
//                                                                                                      //
// ===========================================================                                          // ===========================================================

`timescale 1 ns / 1 ps                                                                                  `timescale 1 ns / 1 ps

(* CORE_GENERATION_INFO="fir,hls_ip_2015_4,{HLS_INPUT_TYPE=c,HLS_INPUT_FLOAT=0,HLS_INPUT_FIXED=0   |    (* CORE_GENERATION_INFO="fir,hls_ip_2015_4,{HLS_INPUT_TYPE=c,HLS_INPUT_FLOAT=0,HLS_INPUT_FIXED=0

module fir (                                                                                            module fir (
        ap_clk,                                                                                                 ap_clk,
        ap_rst,                                                                                                 ap_rst,
        ap_start,                                                                                               ap_start,
        ap_done,                                                                                                ap_done,
        ap_idle,                                                                                                ap_idle,
        ap_ready,                                                                                               ap_ready,
        y,                                                                                                      y,
        y_ap_vld,                                                                                               y_ap_vld,
        c_address0,                                                                                             c_address0,
        c_ce0,                                                                                                  c_ce0,
        c_q0,                                                                                                   c_q0,
        x                                                                                          |            x,
                                                                                                   >            x_ap_vld
);                                                                                                      );

ポートが追加されている。でも、良く見てみると、ポートYは最初からValid信号が追加されていたのか。 これはVivadoが自動的に追加していたと考えたほうが良いだろう。

デザインの解析

Analysisペインから、ステートマシンの様子を観察することができる。

f:id:msyksphinz:20151128003330p:plain

  1. まず、Xポートから信号を読み込む。
  2. data(read)、つまりブロックRAMからのデータリードには、2サイクルかかることが分かる。
  3. 乗算には3サイクルかかっている。
  4. 全体では、1ループにC1からC7までの7サイクルが消費されている。

実際のデザインでは?

3サイクル消費されている乗算とか、HDLではどのように記述されているのだろう?生成されたHDLを探すと、その答えがある。

module fir_mul_32s_32s_32_3_Mul3S_0(clk, ce, a, b, p);
input clk;
input ce;
input[32 - 1 : 0] a; // synthesis attribute keep a "true"
input[32 - 1 : 0] b; // synthesis attribute keep b "true"
output[32 - 1 : 0] p;

reg signed [32 - 1 : 0] a_reg0;
reg signed [32 - 1 : 0] b_reg0;
wire signed [32 - 1 : 0] tmp_product;
reg signed [32 - 1 : 0] buff0;

assign p = buff0;
assign tmp_product = a_reg0 * b_reg0;
always @ (posedge clk) begin
    if (ce) begin
        a_reg0 <= a;
        b_reg0 <= b;
        buff0 <= tmp_product;
    end
end
endmodule

入力データをオペランドにセットするのに1サイクル、計算に1サイクルで、あれ、2サイクルしか消費されてなくない? で、その結果が、

fir_mul_32s_32s_32_3 #(
    .ID( 1 ),
    .NUM_STAGE( 3 ),
    .din0_WIDTH( 32 ),
    .din1_WIDTH( 32 ),
    .dout_WIDTH( 32 ))
fir_mul_32s_32s_32_3_U0(
    .clk( ap_clk ),
    .reset( ap_rst ),
    .din0( c_load_reg_223 ),
    .din1( data1_reg_126 ),
    .ce( grp_fu_174_ce ),
    .dout( grp_fu_174_p2 )
);
...
always @ (posedge ap_clk) begin
    if ((ap_const_logic_1 == ap_sig_cseq_ST_st7_fsm_6)) begin
        tmp_6_reg_228 <= grp_fu_174_p2;
    end
end

一回レジスタに入っているということなのかなあ、良く分からん。

デザインのスループットを上げるための最適化

以下のことを行って、デザインの性能を上げる。

新しいソリューションを作成して、以下の最適化を行う。

ループアンローリング

ソースコードを開いた状態で、[Directive]ペインの、[Shift_Accum_Loop]を右クリックし、[Insert Directive]を選択する。 ダイアログが開くので、[UNROLL]ディレクティブを選択する。

f:id:msyksphinz:20151128004602p:plain

シフトレジスタの実装

ソースコードを開いた状態で、[Directive]ペインの、[shift_reg]を右クリックし、[Insert Directive]を選択する。 [ARRAY_PARTITION]ディレクティブを選択する。

f:id:msyksphinz:20151128004747p:plain

合成結果の比較

これまでに作成した、

  • ベースデザイン
  • ポート属性変更デザイン
  • スループット最適化デザイン

の比較をすることができるらしい。

f:id:msyksphinz:20151128005853p:plain

レイテンシや、リソースの比較などを行うことができる。

f:id:msyksphinz:20151128010034p:plain