FC2カウンター FPGAの部屋

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

FPGAの部屋

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

PYNQボードのFASTX コーナー検出にラプラシアンフィルタIPとアンシャープ・マスクキング・フィルタIPを追加1(Vivado HLS)

PYNQボードには、”PYNQボードでカメラ画像をリアルタイムにFASTX コーナー検出1”、”PYNQボードでカメラ画像をリアルタイムにFASTX コーナー検出2”で、PYNQボードに付けたカメラの画像にFASTX コーナー検出をリアルタイムで行うことができた。
でも、そろそろPYNQ祭りに向けて、もう少しPYNQボードに芸をさせたい。そこで、いつものラプラシアンフィルタIPと最近、assert() の例としてやってみたアンシャープ・マスクキング・フィルタを追加することにした。

まずは、アンシャープ・マスクキング・フィルタIP をPYNQボード用に生成する。

PYNQ のZynq 7020 (xc7z020clg400-1)用のVivado HLS 2016.4 のプロジェクトpynq_unsharp_mask_fixedp を生成した。

unsharp_mask_fixedp のファイルをコピー&ペーストして、Explorer のSource とTest Bench にAdd File した。
assert() 付きの任意精度固定小数点型の実装だ。

アンシャープ・マスクキング・フィルタIP を 800 x 600 解像度に変更した。
pynq_de_other_filters_1_170220.png

Top Function を指定して、一旦、合成した。合成結果を示す。
pynq_de_other_filters_2_170220.png

やはり、Timing のEstimated は、10.08 ns でわずかながらTarget を越している。
Latency は 480036 クロックだった。そうピクセル数が 480000 ピクセルのことを思えば、大体 1 クロックで 1 ピクセルを処理できている。

Timing のEstimated を改善するために、Solution Settings のSynthesis Settings のClock Period を 10 ns から 9 ns に変更した。
これでもう一度、C コードの合成を行った。でもやはり、Timing のEstimated は、10.08 ns で変化が無かった。

Solution Settings のSynthesis Settings のClock Period を 8 ns に設定したところ、Timing のEstimated が 8.25 ns に収まった。
合成結果を示す。
pynq_de_other_filters_3_170220.png

Latency は 480037 クロックで、Timing のEstimated が 10 ns の時よりも 1 クロック増えた。
パーセンテージには表れないほどだが、FF と LUT もリソース使用量が増えている。
これで、10 ns のクロックで動作するだろう。

Export RTL を行った。その際にVivado RTL Synthesis にチェックを入れて、論理合成テストを行った。
pynq_de_other_filters_4_170220.png

論理合成テストも問題ないようだ。

C:\Users\Masaaki\Documents\VIvado_HLS\PYNQ\pynq_unsharp_mask_fixedp\solution1\impl\ip に xilinx_com_hls_unsharp_mask_axis_1_0.zip ができた。
pynq_de_other_filters_5_170220.png
  1. 2017年02月20日 05:14 |
  2. PYNQ
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2016.4 でUNROLL指示子を試してみた

Vivado HLS 2016.4 でUNROLL指示子を試してみた。

UNROLL指示子については、Vivado HLS のユーザーズガイド、”高位合成 UG902 (v2016.4) 2016 年 11 月 30 日”の 133 ページの”最適なループ展開によるパイ プ ラ イ ンの改善”を参考にした。

まずは、134 ページの”図 1‐60: ループの展開”がUNROLL指示子の説明の図となっている。その図を引用する。引用した図にわかりやすいように軸を付け加えさせて頂いた。
unroll_test_1_170218.png

ラプラシアンフィルタの実装による UNROLL 指示子の効果について調べてみよう。まずは、すべての要素を足し算するだけの簡単な 3 x 3 のフィルタを AXI4-Stream で実装した。その unroll_test.cpp を示す。

// unroll_test.cpp
// 2017/02/17 by marsee
//

#include <hls_stream.h>

#define HORIZONTAL_PIXEL_WIDTH 5
#define VERTICAL_PIXEL_WIDTH 5

int unroll_test(hls::stream<int>& ins, hls::stream<int>& outs){
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE axis register both port=outs
#pragma HLS INTERFACE axis register both port=ins
    int pix;
    int usm;

    int line_buf[2][HORIZONTAL_PIXEL_WIDTH];
#pragma HLS array_partition variable=line_buf block factor=2 dim=1
#pragma HLS resource variable=line_buf core=RAM_2P

    int pix_mat[3][3];
#pragma HLS array_partition variable=pix_mat complete

    Loop_y : for (int y=0; y<VERTICAL_PIXEL_WIDTH; y++){
        Loop_x : for (int x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
//#pragma HLS PIPELINE II=1
            ins >> pix;

            Loop_i : for (int i=0; i<3; i++){
//#pragma HLS UNROLL factor=3
                Loop_j : for (int j=0; j<2; j++){
//#pragma HLS UNROLL factor=2
                    pix_mat[i][j] = pix_mat[i][j+1];
                }
            }
            pix_mat[0][2] = line_buf[0][x];
            pix_mat[1][2] = line_buf[1][x];

            pix_mat[2][2] = pix;

            line_buf[0][x] = line_buf[1][x];    // 行の入れ替え
            line_buf[1][x] = pix;
        }
        usm = pix_mat[0][0] + pix_mat[0][1] + pix_mat[0][2]
            + pix_mat[1][0] + pix_mat[1][1] + pix_mat[1][2]
            + pix_mat[2][0] + pix_mat[2][1] + pix_mat[2][2];

        outs << usm;
    }
    return(0);
}


Vivado HLS 2016.4 の unroll_test プロジェクトを示す。
unroll_test_2_170218.png

合成結果を示す(図A)。
unroll_test_3_170218.png

Latency が 416 クロックかかっている。内訳はLoop に示されている。Loop_y, Loop_x, Loop_i, Loop_j が表示されていて、UNROLL されいていないのがわかる。

次に、Loop_j の「#pragma HLS UNROLL factor=2」を生かした。
どうも、Vivado HLS 2016.4 では、factor を書かないとまずいようだ。ディレクティブ・エディタで修正できない。不正だと言われてしまう。
unroll_test_6_170218.png

合成結果を示す(図B)。
unroll_test_7_170218.png

UNROLL指示子を全く入れていない時(図A)に比べてLatency が 416 クロックのところ、191 クロックに縮小した。Loop を見ると Loop_j が展開されて無くなっている。

次に、Loop_i の「#pragma HLS UNROLL factor=3」を生かした。
unroll_test_8_170218.png

合成結果を示す(図C)。
unroll_test_9_170218.png

Loop_j も無くなって、Latency が図B の 191 クロックから 66 クロックに縮小した。Loop を見ると、Loop_j も無くなっている。

Loop_x にPIPELINE 指示子の「#pragma HLS PIPELINE II=1」を入れた。
unroll_test_10_170218.png

合成結果を示す(図D)。
unroll_test_11_170218.png

Latency が 29 クロックに縮小した。Loop を見ても Loop_y_Loop_x になっている。

最後に、Loop_j と Loop_i の UNROLL 指示子をコメントアウトした。
unroll_test_12_170218.png

合成結果を示す(図E)
unroll_test_13_170218.png

図D と同じになった。

つまり、この状況では、PIPELINE 指示子を入れれば下の for ループが展開されるようだ。つまり、PIPELINE 指示子の下にはUNROLL指示子は要らないということになる。
  1. 2017年02月18日 15:20 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2016.4 における assert() 文の効果5(AXI4-Stream版での比較)

Vivado HLS 2016.4 における assert() 文の効果4(自分定義した固定小数点)”の続き。

前回は、アンシャープマスキング・フィルタ単体では、任意精度固定小数点型の方が自分で定義した固定小数点型に比べてリソース使用量が少なくなったという結果だったが、AXI4-Stream インターフェースを被せた状態ではどうなるか?をやってみた。

まずは、変数の変域を指定するために、pow() を使用して、定義値からの生成を行うようにコードを変更した。
それを利用してassert() を書いた。
まずは、任意精度固定小数点型を試してみた。ピンクの枠で示した assert() を追加した。
assert_35_170216.png

C コードの合成結果を示す。
assert_36_170216.png

Analysis 結果を示す。
assert_37_170216.png

37ステートだった。

Analysis 結果で、unsharp_masking() の使用リソースとステート見てみよう。
右上のModule Hierarchy で unsharp_masking をクリックした。
assert_38_170216.png

unsharp_masking() の使用リソースは、FF が 1313 個、LUT が 1331 個だそうだ。ステートは 31 ステートだった。

次に、assert() 文をコメントアウトしてみた。
合成結果を示す。
assert_39_170216.png

LUT が 2244 個から、2262 個に増えていた。FF も 1995 個から 2021 個に増えていた。Latency は同じだった。

Analysis 結果を示す。
assert_40_170216.png

ステートは 38 ステートで変更はない。

Analysis 結果で、unsharp_masking() の使用リソースとステートを見た。
assert_41_170216.png

31ステートで変化はない。FF が 1331 個、LUT が 1357 個だった。assert() が入っているときは、FF が 1313 個、LUT が 1331 個なので、明らかに assert() が無いほうが増えている。

次に、自分で定義した固定小数点型をやってやってみよう。このようにassert() が入っている。
assert_42_170216.png

合成結果を示す。
assert_43_170216.png

FF が 1986 個 、LUT が 1895 個だった。任意精度固定小数点型では、FF が 2244 個、LUT が 1995 なので、明らかに自分で定義した固定小数点型の方がリソース使用量が少ない。単体でテストしたのとは逆の結果になった。
Latency も 3104 クロックに対して、任意精度固定小数点型では 3108 クロックとなっている。

Analysis 結果を示す。
assert_44_170216.png

ステートも 33 ステートだった。こちらも任意精度固定小数点型では、37 ステートだったので、自分で定義した固定小数点型のほうがステートが少ない。

Analysis 結果で、unsharp_masking() の使用リソースとステートを見た。
assert_45_170216.png

FF は 1083 個、LUT は 1245 個だった。任意精度固定小数点型ではFF が 1313 個、LUT が 1331 個だった。

次に、自分で定義した固定小数点型で、assert() をすべてコメントアウトした。
assert_46_170217.png

合成結果を示す。
assert_47_170217.png

FF 、LUT 共に、assert() を入れてあるときと変化が無かった。assert() は効いていない。

AXI4-Stream インターフェースを被せた状態でアンシャープマスキング・フィルタの任意精度固定小数点型と自分で定義した固定小数点型はどっちが使用量が少ないか比べてみたが、自分で定義した固定小数点型の方が少ないという結果になった。これは、アンシャープマスキング・フィルタ単体とは逆の結果だ。

前回は、自分で定義した固定小数点型の方がリソース使用量が少ないという結果になって、自分で定義した固定小数点型を使おうという話になったが、assert() でリソース使用量を減らすことができるし、演算の間違いも少なくなるので、積極的に任意精度固定小数点型を使っていこうと思う。
  1. 2017年02月17日 04:28 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2016.4 における assert() 文の効果4(自分で定義した固定小数点)

Vivado HLS 2016.4 における assert() 文の効果3”の続き。

これまでは、任意精度固定小数点型で assert() 文で変数の変域を指定するリソース使用量の低減効果を見てきたが、今回は、任意精度固定小数点型を使用しない自分で定義した固定小数点演算との比較をしてみた。

最初にC ソースコードを示す。これは、int 型を使用して、PRECISION の 6 ビット左シフトを行って小数桁を確保している。最後には 6 ビット右シフトして整数に戻す。

// unsharp_mask_axis.cpp
// 2015/09/24 by marsee
// assertテスト用

#include <stdio.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>

#include "unsharp_mask_axis.h"

// アンシャープマスキング・フィルタ
// x0y0 x1y0 x2y0 -k   -j  -k
// x0y1 x1y1 x2y1 -k  9+8k -k x 1/9
// x0y2 x1y2 x2y2 -k   -k  -k
//
// k : 鮮鋭化の強さ(固定小数点) , k != 0
// num_adec_k : Kの小数点の位置
// 2015/09/27 : 演算の小数部は num_adec_k*2 ビットとする。
//

#define PRECISION    6    // 小数点以下の桁数、精度(1以上)

int unsharp_masking(int pix_mat[3][3], int k, int num_adec_k)
{
    int y;
    int xy[3][3];
    int result=0;
    int z;

    int x1y1 = (9<<(PRECISION+num_adec_k))/k + (8<<PRECISION);

    for (int i=0; i<=16; i += 8){
        for (int j=0; j<3; j++){
            for (int k=0; k<3; k++){
                xy[j][k] = (pix_mat[j][k] >> i) & 0xff; // RGBのいずれかを抽出
            }
        }

        y = -(xy[0][0]<<PRECISION) -(xy[0][1]<<PRECISION) -(xy[0][2]<<PRECISION)
            -(xy[1][0]<<PRECISION) +x1y1*xy[1][1]         -(xy[1][2]<<PRECISION)
            -(xy[2][0]<<PRECISION) -(xy[2][1]<<PRECISION) -(xy[2][2]<<PRECISION);

        y = ((k * y)/9) >> num_adec_k; // k は num_adc_k だけ左シフトされているので戻す

        z = y + (1<<(PRECISION-1)); // 四捨五入 +0.5
        z = z >> PRECISION; // 小数点以下切り捨て

        if (z<0// 飽和演算
            z = 0;
        else if (z>255)
            z = 255;

        result += z<<i; // i=0 : blue, i=8 : green, i=16 : red
    }

    return(result);
}


プロジェクトを示す。
assert_26_170215.png

C コードの合成結果を示す。
assert_27_170215.png

任意精度固定小数点型で実装したときの assert() 無しに比べて、int 型を使用してシフトで小数を表した時のほうがリソース使用量が多い。それにLatency も長い。

Analysis 結果を示す。
assert_28_170215.png

こちらも、58 ステートで任意精度固定小数点型の38 ステートよりも多い。

次に assert.h をインクルードして、適当な assert() を入れてみた。
assert_29_170215.png

C コードlの合成を行った。
assert_30_170215.png

ものすごくリソース使用量が減った。やはり、assert() が効いているようだ。

Analysis 結果を示す。
assert_31_170215.png

4 ステートになってしまった。

最後に、まともに変域を考えて指定した。
assert_32_170215.png

C コードlの合成を行った。
assert_33_170215.png

元の合成結果と比べて、1353 個が 1291 個に減った。

Analysis 結果を示す。
assert_34_170215.png

58ステートになった。元と変化が無かった。

結果として、自分で定義した固定小数点演算をするよりも任意精度固定小数点型を使ったほうが、リソース使用量が少なかった。更に assert() を使うとリソース使用量が削減できるので、固定小数点を使うときは任意精度固定小数点型を使ったほうが良いと思う。
  1. 2017年02月15日 07:05 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2016.4 における assert() 文の効果3

Vivado HLS 2016.4 における assert() 文の効果2”の続き。

前回も assert() 文を使用して、演算に使用する変数の変域を指定することにより、任意精度固定小数点型の飽和演算は必要ないとVivado HLS に認識してもらい、しかもビット長も制限されることでリソース使用量の低減を図ってきた。しかし、ループカウンタのカウント数の制限によってリソース使用量が低減はされたが、任意精度固定小数点型の通常の演算では assert() 文が効いていなかった。

次に、assert() 文の変域の書き方は C や C++ の if() 文の中の様に C や C++ の結合規則によって記述するということを hiyuh さんに教えてもらった。それで書き直しても、任意精度固定小数点型の通常の演算では assert() 文が効いていなかった。

もう一度、hiyuh さんに、assert() 文を入れる規則を教えてもらった。それを引用する。

assertの挿入箇所が適切ではありません.assertに与えられた条件式はその挿入箇所で評価されますので,被演算対象に対しては値が確定した演算前,代入対象については値が確定した代入後,可及的速やかに適用する必要があります.


ということで、下のソースコードで確かめてみたが、やはりリソース使用量には変化が無かった。

// ap_fixed_test.c
// 2017/02/12 by marsee

#include <assert.h>
#include <ap_fixed.h>

typedef ap_fixed<16,8, AP_RND, AP_SAT> ap_xfix_def;
//typedef ap_ufixed<16,8, AP_RND, AP_SAT> ap_xfix_def;

int ap_fixed_test(ap_xfix_def in0, ap_xfix_def in1, int limit,
        ap_xfix_def *out){

    ap_xfix_def temp;

    assert(in0 > (ap_xfix_def)(-1.0) && in0 < (ap_xfix_def)1.0);
    temp = in0;
    assert(temp > (ap_xfix_def)(-10.0) && temp < (ap_xfix_def)10.0);

    //assert(limit <= 10);
    for (int i=0; i<limit; i++){
#pragma HLS LOOP_TRIPCOUNT min=1 max=10 avg=2
        assert(temp > (ap_xfix_def)(-10.0) && temp < (ap_xfix_def)10.0);
        temp = temp * (ap_xfix_def)2.0;
        assert(temp > (ap_xfix_def)(-10.0) && temp < (ap_xfix_def)10.0);
    }

    assert(temp > (ap_xfix_def)(-10.0) && temp < (ap_xfix_def)10.0);
    assert(in1 > (ap_xfix_def)(-2.0) && in1 < (ap_xfix_def)2.0);
    *out = temp * in1;

    return(0);
}



次に、アンシャープ・マスキング・フィルタでもう一度、検証してみよう。ソースコードを示す。

// unsharp_mask_axis.cpp
// 2015/09/24 by marsee
// ap_fixedバージョン 2015/10/04
//

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <ap_int.h>
#include <ap_fixed.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>
#include <iostream>

#include "unsharp_mask_axis.h"

using namespace std;

// アンシャープマスキング・フィルタ
// x0y0 x1y0 x2y0 -k   -j  -k
// x0y1 x1y1 x2y1 -k  9+8k -k x 1/9
// x0y2 x1y2 x2y2 -k   -k  -k
//
// k : 鮮鋭化の強さ(固定小数点) , k != 0
// num_adec_k : Kの小数点の位置
//

int unsharp_masking(int pix_mat[3][3], k_fixed_td k_fixed)
{
    ap_ufixed<88, AP_RND, AP_SAT> xy[3][3];
    int result=0;
    ap_ufixed<88, AP_RND, AP_SAT> z;
    x1y1_fixed_td x1y1;
    y_fixed_td y;
    /*ap_ufixed<8, 8> xy[3][3];    int result=0;    ap_ufixed<8, 8, AP_RND, AP_SAT> z;    x1y1_fixed_td x1y1;    y_fixed_td y;*/

    x1y1 = (x1y1_fixed_td)9/(x1y1_fixed_td)k_fixed + (x1y1_fixed_td)8// ビット長は 9+8 が2^5=32 より小さく、k_fixedで割るので、NUM_ADC_Kが増える可能性がある

    for (int i=0; i<=16; i += 8){
        for (int j=0; j<3; j++){
            for (int k=0; k<3; k++){
                xy[j][k] = (pix_mat[j][k] >> i) & 0xff; // RGBのいずれかを抽出
            }
        }

        y = -xy[0][0]    -xy[0][1]        -xy[0][2]
            -xy[1][0]    +x1y1*xy[1][1]    -xy[1][2]
            -xy[2][0]    -xy[2][1]        -xy[2][2];
        assert(y > (y_fixed_td)(-10) && y < (y_fixed_td)(10));

        y = (k_fixed * y)/(y_fixed_td)9;
        assert(y > (y_fixed_td)(-10) && y < (y_fixed_td)(10));

        y = y+(y_fixed_td)0.5// 四捨五入
        assert(y > (y_fixed_td)(-10) && y < (y_fixed_td)(10));
        if (y < 0)
            z = 0;
        else if (y > 255)
            z = 255;
        else
            z = y;

        result += z.to_int()<<i; // i=0 : blue, i=8 : green, i=16 : red
    }
    return(result);
}


ヘッダファイルを示す。

// unsharp_mask_axis.h
// 2015/09/26 by marsee

#ifndef __UNSHARP_MASK_AXIS_H_
#define __UNSHARP_MASK_AXIS_H_

//#define HORIZONTAL_PIXEL_WIDTH    1280
//#define VERTICAL_PIXEL_WIDTH    720

#define HORIZONTAL_PIXEL_WIDTH    64
#define VERTICAL_PIXEL_WIDTH    48

#define ALL_PIXEL_VALUE    (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)

#define PRECISION    6    // 小数点以下の桁数、精度(0 以上の数を指定する)
#define K_BITLEN    4    // k のビット長
#define NUM_ADC_K    2    // k の小数点の位置

typedef ap_ufixed<K_BITLEN, K_BITLEN-NUM_ADC_K> k_fixed_td;
typedef ap_fixed<6+PRECISION+NUM_ADC_K, (6+PRECISION+NUM_ADC_K)-PRECISION> x1y1_fixed_td;
typedef ap_fixed<6+PRECISION+NUM_ADC_K+8+3, (6+PRECISION+NUM_ADC_K+8+3)-PRECISION> y_fixed_td;

#define K 2.5 // 鮮鋭化の強さ

#endif


最初に assert() をコメントアウトして合成を行った。(なお、assert() 文の変域は正しくない。結果を見るためにわざと厳しい値にしてある)
assert_17_170214.png

合成後の結果を示す。
assert_18_170214.png

Analysis 結果を示す。
assert_19_170214.png

37 ステートだった。

次に assert() のコメントを外して合成を行った。
assert_20_170214.png

合成後の結果を示す。
assert_21_170214.png

Latency が 146 クロックから 131 クロックに 15 クロック減った。DSP48E, FF, LUT もすべて減っている。

Analysis 結果を示す。
assert_22_170214.png

32ステートだった。assert() 文を入れないときは、37ステートだったので、5ステート減っている。

これで、assert() 文で変数の変域を指定することにより、リソース使用量を減らせることが分かった。

最後に実際に使用予定の変数の変域を入れてみよう。
assert_23_170214.png

合成後の結果を示す。
assert_24_170214.png

やはり、assert() 文が無いのに比べてリソース使用量が減っている。

Analysis 結果を示す。
assert_25_170214.png

36ステートで、assert() 文が無いのに比べて 1 ステート減少した。
  1. 2017年02月14日 05:14 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2016.4 における assert() 文の効果2

Vivado HLS 2016.4 における assert() 文の効果”の続き。

前回は、assert() はfor ループのカウント用変数の変域を与えられるが、通常の変数の変域を指定できるわけでは無いという結論になったが、hiyuh さんに再度教えてもらって、もう一度やってみた。

前回の引数の変域の指定方法が間違っていた。hiyuh さんに教えてもらった C /C++ の結合則に従うということだった。それに、値をキャストするのを忘れていた。更に ap_ufixed もやってみようということでソースコードを書き換えた。
新しい ap_fixed_test.cpp を示す。
assert_7_170213.png

ap_fixed_test.cpp のソースコードを示す。

// ap_fixed_test.c
// 2017/02/12 by marsee

#include <assert.h>
#include <ap_fixed.h>

typedef ap_fixed<16,8, AP_RND, AP_SAT> ap_xfix_def;
//typedef ap_ufixed<16,8, AP_RND, AP_SAT> ap_xfix_def;

int ap_fixed_test(ap_xfix_def in0, ap_xfix_def in1, int limit,
        ap_xfix_def *out){

    ap_xfix_def temp;

    //assert(in0 > (ap_xfix_def)(-1.0) && in0 < (ap_xfix_def)1.0);
    //assert(in1 > (ap_xfix_def)(-2.0) && in1 < (ap_xfix_def)2.0);
    //assert(*out > (ap_xfix_def)(-50.0) && *out < (ap_xfix_def)50.0);
    //assert(in0 < (ap_xfix_def)1.0);
    //assert(in1 < (ap_xfix_def)2.0);
    //assert(*out < (ap_xfix_def)50.0);

    temp = in0;
    //assert(limit <= 10);
    for (int i=0; i<limit; i++)
#pragma HLS LOOP_TRIPCOUNT min=1 max=10 avg=2
        temp = temp * (ap_xfix_def)2.0;

    *out = temp * in1;

    return(0);
}


最初にもう一度、このソースコードのまま合成を行った。
assert_8_170213.png

次に、最初の 3 行の assert() 文を活かしてみよう。これは、符号あり小数の場合だ。
assert_9_170213.png

これを合成した。
assert_10_170213.png

レポートを見ると、assert() 文を活かして無い時と変わらない。

次に、ap_ufixed にして、符号なし小数の場合をやってみた。assert() 文はすべてコメントアウトしてある。
assert_11_170213.png

これを合成した。
assert_12_170213.png

符号あり少数の場合よりも、レイテンシもリソース使用量も少ない。符号なし小数で良いのであれば、大分お得ということができると思う。

次に、下の 3 つの assert() 文を活かした。
assert_13_170213.png

合成を行った。
assert_14_170213.png

assert() 文を入れたときと、入れないときでは変化が無かった。

最後に変数の temp に asset() 文を試しに入れてみた。
assert_15_170213.png

合成を行った。
assert_16_170213.png

temp 変数に assert() 文で変域を指定すると合成されなくなるようだ。
  1. 2017年02月13日 04:54 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2016.4 における assert() 文の効果

Vivado HLS 2016.4 で変域を指定することができる assert() 文の効果を確かめてみた。

まずは、assert() は、”Vivado Design Suite ユーザー ガイド 高位合成 UG902 (v2016.4) 2016 年 11 月 30 日”の 344 ページの”アサート”に書かれている。最初の1文を引用する。

C の assert マクロは、 範囲情報をアサートするのに使用される場合、 合成でサポートされます。 たとえば、 変数 とループ境界の上限を指定でき ます。


そこで、任意精度固定小数点型を使う際の問題点の変数の変域が飽和演算が必要ない状態で、飽和演算回路を入れないようにできるかを探ってみた。
任意精度型固定小数点型を使用したアンシャープマスキング・フィルタの例については下のリンクを参照のこと。
Vivado HLS によるアンシャープマスクキング・フィルタの作製7(C++ の任意精度固定小数点型)
Vivado HLS によるアンシャープマスクキング・フィルタの作製8(C++ の任意精度固定小数点型2)
Vivado HLS によるアンシャープマスクキング・フィルタの作製9(C++ の任意精度固定小数点型3)

ap_fixed_test というVivado HLS 2016.4 のプロジェクトを生成した。
assert_1_170212.png

ap_fixed_test.cpp を貼っておく。

// ap_fixed_test.c
// 2017/02/12 by marsee

#include <assert.h>
#include <ap_fixed.h>

int ap_fixed_test(ap_fixed<16,8, AP_RND, AP_SAT> in0, ap_fixed<16,8, AP_RND, AP_SAT> in1, int limit,
        ap_fixed<16,8, AP_RND, AP_SAT> *out){

    ap_fixed<16,8, AP_RND, AP_SAT> temp;

    /*assert(-1 <= in0 <= 1);    assert(-2 <= in1 <= 2);    assert(-10 <= temp <= 10);    assert(-100 <= *out <= 100); */

    temp = in0;
    //assert(limit <= 10);
    for (int i=0; i<limit; i++)
#pragma HLS LOOP_TRIPCOUNT min=1 max=10 avg=2
        temp = temp * (ap_fixed<16,8, AP_RND, AP_SAT>)2.0;

    *out = temp * in1;

    return(0);
}


まずはC コードの合成を行った。結果を示す。
assert_2_170212.png

Latency のmin は 4、max は 13 だった。これは、LOOP_TRIPCOUNT に設定した値が元になっている。LOOP_TRIPCOUNTのカウントにその他のレイテンシを加えたものが Latency として示されている。だが、LOOP_TRIPCOUNT は合成には影響しない。
そこで、合成に変数の変域を反映させるのが assert() だ。
まずは、引数と変数の変域を指定する assert() のコメントを外した。
assert_3_170212.png

これで合成してみよう。
assert_4_170212.png

前回と同じだ。この assert() は効かないようだ。

次に、今コメントを外した部分をコメントにして、LOOP_TRIPCOUNT の max と同じ値を assert() で指定した文のコメントを外す。
assert_5_170212.png

合成結果を示す。
assert_6_170212.png

FF は 137 個が 110 個に、LUT が 243 個が 189 個に減った。

この結果から、assert() はfor ループのカウント用変数の変域を与えられるが、通常の変数の変域を指定できるわけでは無い様だ。

Vivado HLS 2016.4 における assert() 文の効果2”に続く。
  1. 2017年02月12日 07:16 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0
»