FC2カウンター FPGAの部屋 Vivado HLS 2016.2 で volatile を使用する場合

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

FPGAの部屋

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

Vivado HLS 2016.2 で volatile を使用する場合

Vivado HLS で AXI4 Master IP を作る際に volatile を使ってあったので、使ってきたがVivado HLS でどのようなときに volatile を使用するのかを調べたことはなかった。今回、hiyuh さんのおかげで、volatile を使う意味が分かった。

Vivado Design Suite ユーザー ガイド 高位合成 UG902 (v2016.1) 2016 年 4 月 6 日”の304ページからの”揮発性デー タの理解”によると、

volatile キーワー ド を使用する と 、 C コンパイラ (および Vivado HLS) でポインター アクセスに関する仮定がされないので、 データが揮発性であ り 変化する可能性があ る と解釈 されます。

ということです。
つまり、ap_start から ap_done の間に関数の入力や出力が変化する場合は、volatile を付けるということのようです。(純粋な C の場合にはそんなことはないのですが、Vivado HLSで合成するとハードウェアになるので、あり得ます。というか、よく使います)
Vivado Design Suite ユーザー ガイド 高位合成 UG902 (v2016.1) 2016 年 4 月 6 日”の305ページの一部を引用します。
Vivado_HLS_volatile_1_160619.png

つまり、AXI4 Master のポートはap_start してから読みまくり、書きまくりになるので、volatile を付けるということのようです。
通常のポートでは、ap_start してからap_done までの間に、連続的に入力ポートから値をRead して、処理して出力ポートから出力という場合には、”Vivado Design Suite ユーザー ガイド 高位合成 UG902 (v2016.1) 2016 年 4 月 6 日”の303ページの真ん中辺りに HLS ストリームライブラリを使ってくださいと書いてあった。

それでは、volatile を使うと、特に入力ポートにINTERFACE 指示子の register オプションを付ければ、単純なFF を付けてくれればよいような気がする。しかし、実際に合成してみた結果はそうなっていないのだが。。。
さて、それでは実際にやってみよう。

Vivado HLS で volatile_test プロジェクトを作成した。
volatile_test.cpp を新規作成した。
Vivado_HLS_volatile_2_160619.png

volatile_test.cpp を示す。

#include <ap_int.h>

void volatile_test(volatile ap_uint<16> multi_in0, volatile ap_uint<16> multi_in1,
        volatile ap_uint<16> *multi_out){
#pragma HLS INTERFACE ap_none register port=multi_out
#pragma HLS INTERFACE ap_none register port=multi_in1
#pragma HLS INTERFACE ap_none register port=multi_in0
    for(int i=0; i<10; i++){
#pragma HLS PIPELINE II=1
        ap_uint<16> temp = (ap_uint<16>)multi_in0 * (ap_uint<16>)multi_in1;
        *multi_out = temp;
    }
}


C コードを合成した結果を示す。
Vivado_HLS_volatile_3_160619.png

合成された volatile_test.v の multi_in0_V を見ると、条件がかなり付いてレジスタに代入されている。
Vivado_HLS_volatile_4_160619.png

これで、本当に1クロックごとに入力ポートからレジスタに代入されているかどうか?をVivado HLS では確認できないので、Vivado 2016.2 でシミュレーションをしてみた。vivado_test プロジェクトを作成して、テストベンチを作りシミュレーションを行う。
Vivado_HLS_volatile_5_160619.png

テストベンチの volatile_test_tb.v を示す。

`default_nettype none
`timescale 100 ps / 1ps

module volatile_test_tb;
    wire   ap_clk;
    wire   ap_rst;
    wire   ap_start;
    wire   ap_done;
    wire   ap_idle;
    wire   ap_ready;
    reg   [15:0] multi_in0_V;
    reg   [15:0] multi_in1_V;
    wire  [15:0] multi_out_V;

    volatile_test volatile_test_i (
        .ap_clk(ap_clk),
        .ap_rst(ap_rst),
        .ap_start(ap_start),
        .ap_done(ap_done),
        .ap_idle(ap_idle),
        .ap_ready(ap_ready),
        .multi_in0_V(multi_in0_V),
        .multi_in1_V(multi_in1_V),
        .multi_out_V(multi_out_V)
    );

    assign ap_start = 1'b1;
    
    always @(posedge ap_clk) begin
        if (ap_rst) begin
            multi_in0_V <= 0;
            multi_in1_V <= 1;
        end else begin
            multi_in0_V <= multi_in0_V + 1; 
            multi_in1_V <= multi_in1_V + 1;
        end
    end

    // ap_clk
    clk_gen #(
        .CLK_PERIOD(100),    // 10.0nsec, 100MHz
        .CLK_DUTY_CYCLE(0.5),
        .CLK_OFFSET(0),
        .START_STATE(1'b0)
    ) sys_clock_i (
        .clk_out(ap_clk)
    );
    
    // ap_rst
    reset_gen #(
        .RESET_STATE(1'b1),
        .RESET_TIME(1000)    // 100nsec
    ) RESET2i (
        .reset_out(ap_rst)
    );
    
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
);
    begin
        initial begin
            reset_out = RESET_STATE;
            #RESET_TIME;
            reset_out = ~RESET_STATE;
        end
    end
endmodule

`default_nettype wire


シミュレーションを行うと、入力ポートは毎クロック、ラッチされているが、出力ポートはap_start から3クロック後のみのようだった。
Vivado_HLS_volatile_6_160619.png

さて、volatile_test.cpp のPIPELINE指示子を削除するとどうだろうか?そうすると、ステートマシンは1状態ではなくなり、複数の状態を取るので、入力ポートがクロックごとにラッチしているか?どうか?がわかる。
volatile_test.cpp を示す。

#include <ap_int.h>

void volatile_test(volatile ap_uint<16> multi_in0, volatile ap_uint<16> multi_in1,
        volatile ap_uint<16> *multi_out){
#pragma HLS INTERFACE ap_none register port=multi_out
#pragma HLS INTERFACE ap_none register port=multi_in1
#pragma HLS INTERFACE ap_none register port=multi_in0
    for(int i=0; i<10; i++){
//#pragma HLS PIPELINE II=1
        ap_uint<16> temp = (ap_uint<16>)multi_in0 * (ap_uint<16>)multi_in1;
        *multi_out = temp;
    }
}


これでC コードの合成を行って、Vivado でシミュレーションを行った。
Vivado_HLS_volatile_7_160619.png

入力ポートは毎クロックごとにラッチされている。PIPELINE指示子を外しても大丈夫のようだ。出力ポートは以前と同様だ。

さて次は、出力ポートのINTERFACE指示子のregister オプションを外してみよう。

#include <ap_int.h>

void volatile_test(volatile ap_uint<16> multi_in0, volatile ap_uint<16> multi_in1,
        volatile ap_uint<16> *multi_out){
#pragma HLS INTERFACE ap_none port=multi_out
#pragma HLS INTERFACE ap_none register port=multi_in1
#pragma HLS INTERFACE ap_none register port=multi_in0
    for(int i=0; i<10; i++){
//#pragma HLS PIPELINE II=1
        ap_uint<16> temp = (ap_uint<16>)multi_in0 * (ap_uint<16>)multi_in1;
        *multi_out = temp;
    }
}


これでC コードの合成を行って、Vivado でシミュレーションを行った。
Vivado_HLS_volatile_8_160619.png

出力ポートのレジスタは無くなったが、出力ポートは依然と同様に、出力ポートはap_start から3クロック後のみだった。ダメじゃん~。。。どうすれば良いのだろうか???
PWMではうまく行っているんだけど、違いは何だろう?あ。。。入出力とも volatile だからか?

(追加)入力もポインタにしてみた。

#include <ap_int.h>

void volatile_test(volatile ap_uint<16> *multi_in0, volatile ap_uint<16> *multi_in1,
        volatile ap_uint<16> *multi_out){
#pragma HLS INTERFACE ap_none port=multi_out
#pragma HLS INTERFACE ap_none register port=multi_in1
#pragma HLS INTERFACE ap_none register port=multi_in0
    for(int i=0; i<10; i++){
//#pragma HLS PIPELINE II=1
        *multi_out = (ap_uint<16>)*multi_in0 * (ap_uint<16>)*multi_in1;
    }
}


これでC コードの合成を行って、Vivado でシミュレーションを行った。
Vivado_HLS_volatile_9_160619.png

良かった。出力ポートに2クロックごとに掛け算の結果が出力されている様に見える(3クロックに1回のようだ)。入力をポインタ(参照渡し)にする必要があるようだ。

次に、出力ポートのレジスタ・オプションを入れてみた。

#include <ap_int.h>

void volatile_test(volatile ap_uint<16> *multi_in0, volatile ap_uint<16> *multi_in1,
        volatile ap_uint<16> *multi_out){
#pragma HLS INTERFACE ap_none register port=multi_out
#pragma HLS INTERFACE ap_none register port=multi_in1
#pragma HLS INTERFACE ap_none register port=multi_in0
    for(int i=0; i<10; i++){
//#pragma HLS PIPELINE II=1
        *multi_out = (ap_uint<16>)*multi_in0 * (ap_uint<16>)*multi_in1;
    }
}


これでC コードの合成を行って、Vivado でシミュレーションを行った。
Vivado_HLS_volatile_10_160619.png

3クロックに1回、出力ポートに結果が出力されている。

最後にPIPELINE指示子を入れてみた。

#include <ap_int.h>

void volatile_test(volatile ap_uint<16> *multi_in0, volatile ap_uint<16> *multi_in1,
        volatile ap_uint<16> *multi_out){
#pragma HLS INTERFACE ap_none register port=multi_out
#pragma HLS INTERFACE ap_none register port=multi_in1
#pragma HLS INTERFACE ap_none register port=multi_in0
    for(int i=0; i<10; i++){
#pragma HLS PIPELINE II=1
        *multi_out = (ap_uint<16>)*multi_in0 * (ap_uint<16>)*multi_in1;
    }
}


レイシテンシはあるが、1クロックごとに出力ポートに結果が出力されている。
Vivado_HLS_volatile_11_160619.png

結局、出力ポートに結果を順次結果を出すためには、入力ポートもポインタ渡しにする必要があるようだ。

おまけに volatile を外すとどうなるか?

#include <ap_int.h>

void volatile_test(ap_uint<16> *multi_in0, ap_uint<16> *multi_in1,
       ap_uint<16> *multi_out){
#pragma HLS INTERFACE ap_none register port=multi_out
#pragma HLS INTERFACE ap_none register port=multi_in1
#pragma HLS INTERFACE ap_none register port=multi_in0
    for(int i=0; i<10; i++){
#pragma HLS PIPELINE II=1
        *multi_out = (ap_uint<16>)*multi_in0 * (ap_uint<16>)*multi_in1;
    }
}


これでC コードの合成を行って、Vivado でシミュレーションを行った。
Vivado_HLS_volatile_12_160619.png

volatile ありと同じ波形だった。結局、今のところは volatile 要らないかも?
  1. 2016年06月19日 06:44 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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