FC2カウンター FPGAの部屋 Vivado HLS 2014.4 の高位合成テスト4(Vivado HLS で高位合成したfoo2 を シミュレーション)
FC2ブログ

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

FPGAの部屋

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

Vivado HLS 2014.4 の高位合成テスト4(Vivado HLS で高位合成したfoo2 を シミュレーション)

Vivado HLS 2014.4 の高位合成テスト3(foo2 を Vivado HLS で高位合成)”の続き。

高位合成された foo.v をシミュレーションしてみた。

もう一度、”Vivado Design Suite ユーザー ガイド 高位合成 UG902 (v2014.1) 2014 年 4 月 2 日”の8ページの入力と出力に配列を使用した foo() を引用する。

void foo(int in[3], char a, char b, char c, int out[3]) {
    int x,y;
    for(int i = 0; i < 3; i++) {
        x = in[i];
        y = a*x + b + c;
        out[i] = y;
    }
}


さて、Vivado 2014.4 でプロジェクトを作製して、テストベンチとBlockRAMのモデルを作製した。
foo.v と foo_mul_32s_8s_32_3.v をプロジェクトに入れて、論理シミュレーションを行った。その結果を下に示す。
Vivado_HLS_Study_31_150111.png

ap_idle が 0 になっている間は、約170 ns で、これがピッタリ 170 ns になっていないのは、ap_idle が組み合わせ回路出力だからだ。テストベンチから入れた ap_start が 1 になるまでは、クロックから 0.1 ns 遅延している。ap_start を ap_idle が組み合わせ回路の中で使っているのが原因のようだ。ともかく、インターバルは17クロックであるということが分かった。(1クロックは 10 ns (100MHz clock)
演算が終了するのは、out_r_we0 の3回目のパルスの後なので、16クロックである。
これらは、高位合成後のレポートと合致する。
Vivado_HLS_Study_24_150108.png

Latencyが 16 クロック、Interval が 17 クロックになっているのがわかる。

また、Analysis の Resouce の図と見比べてみると面白い。
Vivado_HLS_Study_30_150109.png

C0 ステートでは、b + c を行っているが、これは、ap_start が 1 になっている間ということがわかる。つまり演算器の入力にFFは入っていないので、前段の出力は、FFで出力したほうが良い。(前段の出力からの遅延とプラスしてクロック周期に収まれば、何の問題もないが、覚えていないと遅延が増える危険があるので、前段の出力はFFで出したほうが安全だろう)
見ているといろいろと面白いのだが、書ききれないので、このへんで終わりにする。もし見てみたい方は実際にシミュレーションをやってみることをお勧めする。

最後に、テストベンチと シングルポートの BlockRAM モデルを貼っておく。
まずは、テストベンチ foo_tb.v から示す。

`default_nettype none

`timescale 100ps / 1ps

//
// foo_tb.v
// 2015/01/10
//

module foo_tb;
        parameter DELAY = 1;

    wire   ap_clk;    // input
    wire   ap_rst;    // input
    reg       ap_start;    // input
    wire   ap_done;
    wire   ap_idle;
    wire   ap_ready;
    wire  [1:0] in_r_address0;
    wire   in_r_ce0;
    wire  [31:0] in_r_q0;    // input
    reg      [7:0] a;    // input
    reg   [7:0] b;    // input
    reg   [7:0] c;    // input
    wire  [1:0] out_r_address0;
    wire   out_r_ce0;
    wire   out_r_we0;
    wire  [31:0] out_r_d0;

    foo uut (
            .ap_clk(ap_clk),
            .ap_rst(ap_rst),
            .ap_start(ap_start),
            .ap_done(ap_done),
            .ap_idle(ap_idle),
            .ap_ready(ap_ready),
            .in_r_address0(in_r_address0),
            .in_r_ce0(in_r_ce0),
            .in_r_q0(in_r_q0),
            .a(a),
            .b(b),
               .c(c),
            .out_r_address0(out_r_address0),
            .out_r_ce0(out_r_ce0),
            .out_r_we0(out_r_we0),
            .out_r_d0(out_r_d0)
    );

    Single_Prot_BRAM_Model #(
        .C_MEMORY_SIZE(4),    // Word (not byte), 2^n
        .DATA_BUS_WIDTH(32)    // RAM Data Width
    ) spbm_read (
        .clk(ap_clk),
        .rst(ap_rst),
        .addr(in_r_address0),
        .ce(in_r_ce0),
        .we(1'b0),
        .din(0),
        .dout(in_r_q0)
    );

    Single_Prot_BRAM_Model #(
        .C_MEMORY_SIZE(4),    // Word (not byte), 2^n
        .DATA_BUS_WIDTH(32)    // RAM Data Width
    ) spbm_write (
        .clk(ap_clk),
        .rst(ap_rst),
        .addr(out_r_address0),
        .ce(out_r_ce0),
        .we(out_r_we0),
        .din(out_r_d0),
        .dout()
    );

    // clk_gen のインスタンス(ap_clk)
    clk_gen #(
        .CLK_PERIOD(100),    // 10nsec, 100MHz
        .CLK_DUTY_CYCLE(0.5),
        .CLK_OFFSET(0),
        .START_STATE(1'b0)
    ) ACLKi (
        .clk_out(ap_clk)
    );

    // reset_gen のインスタンス
    reset_gen #(
        .RESET_STATE(1'b1),
        .RESET_TIME(1000)    // 100nsec
    ) RESET_ARESETN (
        .reset_out(ap_rst),
        .init_done()
    );

    initial begin
        // Initialize Inputs
        ap_start    = 1'b0;
        a             = 8'd0;
        b             = 8'd0;
        c             = 8'd0;

        // Wait until Reset falling edge
        @(negedge ap_rst);

        #1000; // 100 ns Wait
        @(posedge ap_clk); // 次のクロックへ
        #DELAY;

        ap_start    = 1'b1;
        a             = 8'd2;
        b            = 8'd3;
        c            = 8'd4;

        @(posedge ap_clk); // 次のクロックへ
        #DELAY;

        ap_start    = 1'b0;
    end

endmodule

module clk_gen #(
    parameter         CLK_PERIOD = 100,
    parameter real    CLK_DUTY_CYCLE = 0.5,
    parameter        CLK_OFFSET = 0,
    parameter        START_STATE    = 1'b0 )
(
    output    reg        clk_out
);
    begin
        initial begin
            #CLK_OFFSET;
            forever
            begin
                clk_out = START_STATE;
                #(CLK_PERIOD-(CLK_PERIOD*CLK_DUTY_CYCLE)) clk_out = ~START_STATE;
                #(CLK_PERIOD*CLK_DUTY_CYCLE);
            end
        end
    end
endmodule

module reset_gen #(
    parameter    RESET_STATE = 1'b1,
    parameter    RESET_TIME = 100 )
(
    output    reg        reset_out,
    output    reg        init_done
);
    begin
        initial begin
            reset_out = RESET_STATE;
            init_done = 1'b0;
            #RESET_TIME;
            reset_out = ~RESET_STATE;
            init_done = 1'b1;
        end
    end

endmodule

`default_nettype wire


シングルポートの BlockRAM モデル Single_port_BRAM_Model.v を示す。

//
//  Initializing  Single Port BlockRAM  from  internal  data  file
//  Single_port_BRAM_Model.v
//  2015/01/10
//

`default_nettype none

module Single_Prot_BRAM_Model # (
    parameter integer C_MEMORY_SIZE =        4,    // Word (not byte), 2^n
    parameter integer DATA_BUS_WIDTH =        32    // RAM Data Width
)(
    input wire                                clk,
    input wire                                rst,
    input wire    [log2(C_MEMORY_SIZE)-1 : 0]    addr,
    input wire                                ce,
    input wire                                we,
    input wire    [DATA_BUS_WIDTH-1 : 0]        din,
    output reg    [DATA_BUS_WIDTH-1 : 0]        dout
);

    // Beyond Circuts, Constant Function in Verilog 2001を参照しました
    // http://www.beyond-circuits.com/wordpress/2008/11/constant-functions/
    function integer log2;
        input integer addr;
        begin
            addr = addr - 1;
            for (log2=0; addr>0; log2=log2+1)
                addr = addr >> 1;
        end
    endfunction
    
    reg        [DATA_BUS_WIDTH-1:0]    mem    [0:C_MEMORY_SIZE-1];
    integer    i;

    initial begin
        for (i=0; i<C_MEMORY_SIZE; i=i+1)
            mem[i] = i; 
    end

    always @(posedge clk) begin
        if (rst) begin
            dout <= 0;
        end else begin
            if (we & ce)
                mem[addr] <= din;

            if (ce)
                dout <= mem[addr];
        end
    end
endmodule

`default_nettype wire

  1. 2015年01月11日 05:54 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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