FC2カウンター FPGAの部屋 2017年02月14日

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

FPGAの部屋

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

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