FC2カウンター FPGAの部屋 2015年01月23日
FC2ブログ

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

FPGAの部屋

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

Vivado HLS 2014.4 の高位合成テスト17(ラプラシアンフィルタ12、Clock Period = 2.5 ns の場合のインプリメント)

Vivado HLS 2014.4 の高位合成テスト16(ラプラシアンフィルタ11、Clock Period = 4 ns の場合のインプリメント)”の続き。

前回は、Clock Period = 4 ns (250MHz)の場合、つまり、Latency = 7 クロックの条件で、ラプラシアンフィルタのCソースからVivado HLS 2014.4 で高位合成されたVerilog HDLファイルをVivado 2014.4でインプリメントして、250MHzつまり 4 ns の遅延で実際に動作するようにインプリメントできるかを確認して成功した。Vivado 2014.4のプロジェクトの使用するFPGAはZYBOに使用されている xc7z010clg400-1 だ。これは今回も同様にVivado 2014.4のプロジェクトで使用する。

今回は、Clock Period = 2.5 ns で、ラプラシアンフィルタのCソースからVivado HLS 2014.4 で高位合成されたVerilog HDLファイルをVivado 2014.4でインプリメントして、400MHzつまり 2.5 ns の遅延で実際に動作するようにインプリメントできるかを確認する。

まずは、Vivado HLS 2014.4 で、Solution Settings ダイアログの左のペインでSynthesis を選択してClock Period のテキストボックスに 2.5 と入力してから、C Synthesis を行った。結果を下に示す。
Vivado_HLS_Study_80_150122.png

Latency は 16 クロックだった。リソースはFFを 1241 個、LUTを 521 個消費する。

Analysis の Resource タブを見た。
Vivado_HLS_Study_84_150123.png

演算が2クロックで行われている。この演算も独立に演算することができるはずなので、もっと演算リソースを使えば並列に行うことができると思う。つまりレイテンシを短くすることができるはずだ。そして、そのためのディレクティブがあるはずだ。後で調べてみよう。

Vivado HLS 2014.4 の作業が終了したので、ラプラシアンフィルタの Verilog HDL ファイルを Vivado 2014.4 のプロジェクトにコピーした。今回は、laplacian_filter.v だけではなく、laplacian_filter_add_32ns_32ns_32_2.v と laplacian_filter_sub_32ns_32ns_32_2.v が追加されていた。
Vivado_HLS_Study_81_150122.png

Vivado 2014.4 のプロジェクトを示す。
Vivado_HLS_Study_82_150122.png

論理合成を行って、成功した。
タイミング制約を クロック周期 = 2.5 ns に変更した。

create_clock -period 2.500 -name ap_clk -waveform {0.000 1.250} [get_ports ap_clk]


インプリメントを行って、成功した。タイミング制約も満足している。ZYBO が 400MHz で動作するとは思わなかった。

Implemented Design で Report Timing Summary をクリックして Timing Summary を見た。
Vivado_HLS_Study_83_150122.png

ラプラシアンフィルタ内のレジスタ間の遅延が最大 2.231 ns に収まっている。

Implemented Design で Report Utilization を見た。
Vivado_HLS_Study_85_150123.png

laplacian_filter.v のLUT使用数は、461 個だった。Vivado HLS での値は 521 個だったので、60 個減った。
次に、FF使用数は 856 個だった。Vivado HLS での値は 1241 だったので、385 個減っている。

これで、ラプラシアンフィルタがZYBO で 400MHz の動作周波数で動作することがわかった。正直、ここまで動作周波数が行くなんて思ってなかった。驚きだ。
Vivado HLS 2014.4 で PIPELINE ディレクティブを追加してラプラシアンフィルタを高位合成すると、必要とする動作周波数に応じて異なるレイテンシの HDL を出力してくれる。これはとっても便利だ。

レイテンシとスループットを同時に満たす必要がある分野でFPGAをHDLで設計しているとレイテンシをギリギリまで切り詰めて設計するので、どうやっても動作周波数が確保できない時がある。HDLで作っているとパイプラインの段数を増やすことになり、HDLを書きなおす必要が出てくる。
C及びC++からの高位合成でアルゴリズムを書いておけば、動作周波数によって、レイテンシを自動で決定してくれるので、ソースを書き直す必要がなく、とっても便利だと思う。
  1. 2015年01月23日 04:58 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2014.4 の高位合成テスト16(ラプラシアンフィルタ11、Clock Period = 4 ns の場合のインプリメント)

Vivado HLS 2014.4 の高位合成テスト15(ラプラシアンフィルタ10、Clock Period = 4 ns の場合のシミュレーション)”の続き。

前回は、Vivado HLS 2014.4 でラプラシアンフィルタのCソースから高位合成したVerilog HDLをシミュレーションした。
今回は、そのラプラシアンフィルタの Verilog HDLファイルをVivado 2014.4でインプリメントしてみた。
Clock Period = 4 ns の場合、つまり、Latency = 7 クロックの条件でラプラシアンフィルタのCソースからVivado HLS 2014.4 で高位合成されたVerilog HDLファイルをVivado 2014.4でインプリメントして、250MHzつまり 4 ns の遅延で実際に動作するようにインプリメントできるかを確認する。Vivado 2014.4のプロジェクトの使用するFPGAはZYBOに使用されている xc7z010clg400-1 とする。

前回の時に、Vivado 2014.4 のプロジェクトは作ってある。但し、ラプラシアンフィルタの Verilog HDLファイルの laplacian_filter.v は32ビット幅のデータ入力が 9 個もあるので、ZYBO の入出力ピンの総数を上まってしまう。そのために、32ビット1個の入力から、9タップのシフトレジスタを置いて、それぞれのタップからラプラシアンフィルタのデータ入力をすることにした。それに、高位合成したHDLファイルはデータ入力もデータ出力もFF出力ではなく、組み合わせ回路出力になっている。そこですべての入力、出力をFFでラッチすることにした。(一部の制御出力はFF出力があった)これらの機能をまとめて、laplacian_filter_top.v を作製した。なお、動作周波数が250MHzと高速だし、後で400MHzくらいでもやってみたいので、FFでラッチする段数はパラメータで入力できるようにしておいた。

次に論理合成を行って、成功した。下に論理合成後の回路を示す。
Vivado_HLS_Study_77_150122.png

右の箱の2列目の色の違いってい箱が laplacian_filter.v である。その他の黄色の箱はFFなので、ラプラシアンフィルタ本体がFFに囲まれているのが分かる。

次に、XDCファイルを作製した。ap_clk に クロック周期 4 ns の制約を与えた。

create_clock -period 4.000 -name ap_clk -waveform {0.000 2.000} [get_ports ap_clk]


インプリメントを行った。成功した。タイミング制約も満たされている。
Vivado_HLS_Study_78_150122.png

Implemented Design で Report Timing Summary をクリックして Timing Summary を見た。
Vivado_HLS_Study_79_150122.png

ラプラシアンフィルタ内のレジスタ間の遅延が最大 3.807 ns に収まっている。

最後に、laplacian_filter_top.v を貼っておく。

`default_nettype none

module laplcian_filter_top #(
    parameter    integer    INPUT_FF_NUMBER =    1,
    parameter    integer    OUTPUT_FF_NUMBER =    1
)(
    input    wire    ap_clk,
    input    wire    ap_rst,
    input    wire    ap_start,
    output    wire    ap_done,
    output    wire    ap_idle,
    output    wire    ap_ready,
    input    wire    [31:0]    xy,
    output    wire    [31:0]    ap_return
);
    wire    [31:0]  x0y0;
    wire    [31:0]  x1y0;
    wire    [31:0]  x2y0;
    wire    [31:0]  x0y1;
    wire    [31:0]  x1y1;
    wire    [31:0]  x2y1;
    wire    [31:0]  x0y2;
    wire    [31:0]  x1y2;
    wire    [31:0]  x2y2;
    reg     [31:0]  xy_d[8:0];
    wire    ap_done_node;
    wire    ap_idle_node;
    wire    ap_ready_node;
    wire    [31:0]    ap_return_node;
    reg        [31:0]    x0y0_d [INPUT_FF_NUMBER-1:0];
    reg        [31:0]    x1y0_d [INPUT_FF_NUMBER-1:0];
    reg        [31:0]    x2y0_d [INPUT_FF_NUMBER-1:0];
    reg        [31:0]    x0y1_d [INPUT_FF_NUMBER-1:0];
    reg        [31:0]    x1y1_d [INPUT_FF_NUMBER-1:0];
    reg        [31:0]    x2y1_d [INPUT_FF_NUMBER-1:0];
    reg        [31:0]    x0y2_d [INPUT_FF_NUMBER-1:0];
    reg        [31:0]    x1y2_d [INPUT_FF_NUMBER-1:0];
    reg        [31:0]    x2y2_d [INPUT_FF_NUMBER-1:0];
    reg        [31:0]    ap_return_d [OUTPUT_FF_NUMBER-1:0];
    reg        [INPUT_FF_NUMBER-1:0]    ap_start_d;
    reg        [OUTPUT_FF_NUMBER-1:0]    ap_done_d;
    reg        [OUTPUT_FF_NUMBER-1:0]    ap_idle_d;
    reg        [OUTPUT_FF_NUMBER-1:0]    ap_ready_d;

    laplacian_filter lap_filter_inst (
        .ap_clk(ap_clk),
        .ap_rst(ap_rst),
        .ap_start(ap_start_d[0]),
        .ap_done(ap_done_node),
        .ap_idle(ap_idle_node),
        .ap_ready(ap_ready_node),
        .x0y0(x0y0_d[0]),
        .x1y0(x1y0_d[0]),
        .x2y0(x2y0_d[0]),
        .x0y1(x0y1_d[0]),
        .x1y1(x1y1_d[0]),
        .x2y1(x2y1_d[0]),
        .x0y2(x0y2_d[0]),
        .x1y2(x1y2_d[0]),
        .x2y2(x2y2_d[0]),
        .ap_return(ap_return_node)
    );

     always @(posedge ap_clk) begin : AP_XY_DELAY
        integer i;

        for(i=8; i>=0; i=i-1) begin
            if (ap_rst) begin
                xy_d[i] <= 32'd0;
            end else begin
                if (i == 8) begin
                    xy_d[i] <= xy;
                end else begin
                    xy_d[i] <= xy_d[i+1];
                end
            end
        end
    end
    assign x0y0 = xy_d[0];
    assign x1y0 = xy_d[1];
    assign x2y0 = xy_d[2];
    assign x0y1 = xy_d[3];
    assign x1y1 = xy_d[4];
    assign x2y1 = xy_d[5];
    assign x0y2 = xy_d[6];
    assign x1y2 = xy_d[7];
    assign x2y2 = xy_d[8];
   
    always @(posedge ap_clk) begin : AP_START_DELAY
        integer i;

        for(i=INPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                ap_start_d[i] <= 1'b0;
            end else begin
                if (i == (INPUT_FF_NUMBER-1)) begin
                    ap_start_d[i] <= ap_start;
                end else begin
                    ap_start_d[i] <= ap_start_d[i+1];
                end
            end
        end
    end
    
    always @(posedge ap_clk) begin : AP_DONE_DELAY
        integer i;

        for(i=OUTPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                ap_done_d[i] <= 1'b0;
            end else begin
                if (i == (OUTPUT_FF_NUMBER-1)) begin
                    ap_done_d[i] <= ap_done_node;
                end else begin
                    ap_done_d[i] <= ap_done_d[i+1];
                end
            end
        end
    end
    assign ap_done = ap_done_d[0];

    always @(posedge ap_clk) begin : AP_IDLE_DELAY
        integer i;

        for(i=OUTPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                ap_idle_d[i] <= 1'b0;
            end else begin
                if (i == (OUTPUT_FF_NUMBER-1)) begin
                    ap_idle_d[i] <= ap_idle_node;
                end else begin
                    ap_idle_d[i] <= ap_idle_d[i+1];
                end
            end
        end
    end
    assign ap_idle = ap_idle_d[0];

    always @(posedge ap_clk) begin : AP_READY_DELAY
        integer i;

        for(i=OUTPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                ap_ready_d[i] <= 1'b0;
            end else begin
                if (i == (OUTPUT_FF_NUMBER-1)) begin
                    ap_ready_d[i] <= ap_ready_node;
                end else begin
                    ap_ready_d[i] <= ap_ready_d[i+1];
                end
            end
        end
    end
    assign ap_ready = ap_ready_d[0];

    always @(posedge ap_clk) begin : AP_X0Y0_DELAY
        integer i;

        for(i=INPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                x0y0_d[i] <= 32'd0;
            end else begin
                if (i == (INPUT_FF_NUMBER-1)) begin
                    x0y0_d[i] <= x0y0;
                end else begin
                    x0y0_d[i] <= x0y0_d[i+1];
                end
            end
        end
    end
    
    always @(posedge ap_clk) begin : AP_X1Y0_DELAY
        integer i;

        for(i=INPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                x1y0_d[i] <= 32'd0;
            end else begin
                if (i == (INPUT_FF_NUMBER-1)) begin
                    x1y0_d[i] <= x1y0;
                end else begin
                    x1y0_d[i] <= x1y0_d[i+1];
                end
            end
        end
    end
    
    always @(posedge ap_clk) begin : AP_X2Y0_DELAY
        integer i;

        for(i=INPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                x2y0_d[i] <= 32'd0;
            end else begin
                if (i == (INPUT_FF_NUMBER-1)) begin
                    x2y0_d[i] <= x2y0;
                end else begin
                    x2y0_d[i] <= x2y0_d[i+1];
                end
            end
        end
    end
    
    always @(posedge ap_clk) begin : AP_X0Y1_DELAY
        integer i;

        for(i=INPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                x0y1_d[i] <= 32'd0;
            end else begin
                if (i == (INPUT_FF_NUMBER-1)) begin
                    x0y1_d[i] <= x0y1;
                end else begin
                    x0y1_d[i] <= x0y1_d[i+1];
                end
            end
        end
    end
    
    always @(posedge ap_clk) begin : AP_X1Y1_DELAY
        integer i;

        for(i=INPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                x1y1_d[i] <= 32'd0;
            end else begin
                if (i == (INPUT_FF_NUMBER-1)) begin
                    x1y1_d[i] <= x1y1;
                end else begin
                    x1y1_d[i] <= x1y1_d[i+1];
                end
            end
        end
    end
    
    always @(posedge ap_clk) begin : AP_X2Y1_DELAY
        integer i;

        for(i=INPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                x2y1_d[i] <= 32'd0;
            end else begin
                if (i == (INPUT_FF_NUMBER-1)) begin
                    x2y1_d[i] <= x2y1;
                end else begin
                    x2y1_d[i] <= x2y1_d[i+1];
                end
            end
        end
    end
    
    always @(posedge ap_clk) begin : AP_X0Y2_DELAY
        integer i;

        for(i=INPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                x0y2_d[i] <= 32'd0;
            end else begin
                if (i == (INPUT_FF_NUMBER-1)) begin
                    x0y2_d[i] <= x0y2;
                end else begin
                    x0y2_d[i] <= x0y2_d[i+1];
                end
            end
        end
    end
    
    always @(posedge ap_clk) begin : AP_X1Y2_DELAY
        integer i;

        for(i=INPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                x1y2_d[i] <= 32'd0;
            end else begin
                if (i == (INPUT_FF_NUMBER-1)) begin
                    x1y2_d[i] <= x1y2;
                end else begin
                    x1y2_d[i] <= x1y2_d[i+1];
                end
            end
        end
    end
    
    always @(posedge ap_clk) begin : AP_X2Y2_DELAY
        integer i;

        for(i=INPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                x2y2_d[i] <= 32'd0;
            end else begin
                if (i == (INPUT_FF_NUMBER-1)) begin
                    x2y2_d[i] <= x2y2;
                end else begin
                    x2y2_d[i] <= x2y2_d[i+1];
                end
            end
        end
    end
    
    always @(posedge ap_clk) begin : AP_RETURN_DELAY
        integer i;

        for(i=OUTPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                ap_return_d[i] <= 32'd0;
            end else begin
                if (i == (OUTPUT_FF_NUMBER-1)) begin
                    ap_return_d[i] <= ap_return_node;
                end else begin
                    ap_return_d[i] <= ap_return_d[i+1];
                end
            end
        end
    end
    assign ap_return = ap_return_d[0];

endmodule

`default_nettype wire

  1. 2015年01月23日 04:08 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0