【Vivado HLS】平均計算を高位合成する(任意精度データ型ap_int/ap_fixed)

今までC言語ソース中では全てint型(符号あり32bit整数)で計算してきました。FPGAで実装する場合、基本的にはデータビット数を指定します。また計算時に固定小数点数を使用したい場合も多々あります。Vivado HLSではそれらを実装するため、任意精度データ型というものを使用するとのことで、試してみました。

整数任意精度型:ap_int/ap_uint

整数でビット数を指定するためにはap_int/ap_uintを使用します。ap_intは符号有、ap_uintは符号無です。

ap_[u]int<W>
識別子 意味
W bit数。1~1024まで指定可能。

今回はap_intでビット数を指定してみます。

  • ソースコード
  • #define N 4
    #define DATA_BIT 9
    
    #include "ap_int.h"		// 任意精度型ライブラリ
    #include "hls_stream.h"
    
    typedef ap_int<DATA_BIT> ap_int_data_bit;	// 新しくデータ型名をつける
    
    void average(hls::stream<ap_int_data_bit>& data, ap_int<DATA_BIT+N>* ave);
    #include "average.h"
    
    void average(hls::stream<ap_int_data_bit>& data, ap_int<DATA_BIT+N>* ave)
    {
    	ap_int<DATA_BIT+N> temp = 0;
    
    	average_label0:for (int i = 0; i < N; i++) {
    		temp += data.read();
    	}
    
    	*ave = temp / N;
    }
    #include <stdio.h>
    #include <stdlib.h>
    #include "average.h"
    
    int main()
    {
    	ap_int<DATA_BIT> testData;
    	hls::stream<ap_int_data_bit> testStream;
    	ap_int<DATA_BIT+N> testAve = 0;
    	ap_int<DATA_BIT+N> cmpAve = 0;
    
    	srand(10);
    
    	for (int j = 0; j < 4; j++) {
    		testAve = 0;
    		cmpAve = 0;
    
    		for (int i = 0; i < N; i++) {
    			testData = rand() % 256 - 128;
    			testStream.write(testData);
    			cmpAve += testData;
    		}
    
    		cmpAve /= N;
    
    		average(testStream, &testAve);
    
    		if (testAve != cmpAve) {
    			printf("Test Error!\n");
    			printf("cmpAve=%d testAve=%d\n", (int)cmpAve, (int)testAve);
    		}
    		else {
    			printf("Test OK!\n");
    		}
    	}
    
    	return 0;
    }

    ヘッダファイルaverage.hにて、整数任意精度型をtypedef宣言で名前を付けて、各箇所にて使用しています。初めはHLSストリームテンプレートクラスへの指定時点で直接ap_intを使おうとしましたが、Cシミュレーションの時点でエラーとなってしまったため今のような形としています。(Build Onlyにしてもダメだったので、gccというか、C++の文法上の問題なのでしょうか?)

    #define N 4
    #define DATA_BIT 9
    
    #include "ap_int.h"		// 任意精度型ライブラリ
    #include "hls_stream.h"
    
    typedef ap_int<DATA_BIT> ap_int_data_bit;	// 新しくデータ型名をつける
    
    // これだとコンパイルエラー
    //void average(hls::stream<ap_int<DATA_BIT>>& data, ap_int<DATA_BIT+N>* ave);
    // こっちだとOK
    void average(hls::stream<ap_int_data_bit>& data, ap_int<DATA_BIT+N>* ave);
  • ディレクティブ指定
  • こちらは前回と変わらずap_fifoとPIPELINE+rewindです。
    Vivado HLS 高位合成 ap_int 任意精度

  • シミュレーション波形
  • data_V_V_doutが入力信号として9bit、ave_V_dinが出力信号として13bitとなっており、ビット数が指定できていることが分かります。
    Vivado HLS 高位合成 ap_int

    任意精度固定小数点データ型:ap_fixed/ap_ufixed

    データを固定小数点数として扱いたい場合、ap_fixed/ap_ufixedを使用します。ap_fixedは符号有、ap_ufixedは符号無です。小数ビット数は「全体bit数-整数bit数」で計算できます。

    ap_[u]fixed<W,I,Q,O,N>
    識別子 意味
    W データ全体のbit数
    I 整数bit数
    Q 量子化モード
    O オーバーフローモード
    N オーバーフローモードで折り返しを選択時の飽和bit数

    今回はap_fixedを使用してみます。量子化モード、オーバーフローモードは指定していません。

  • ソースコード
  • #define N 4
    #define DATA_BIT 17  // 全データビット数
    #define INT_BIT 9    // 整数ビット数
    
    #include "ap_fixed.h"    // 任意精度型ライブラリ
    #include "hls_stream.h"
    // ap_fixedをtypedef
    typedef ap_fixed<DATA_BIT, INT_BIT> type_ap_fixed;
    // 固定小数点数で平均計算
    void average(hls::stream<type_ap_fixed>& data, ap_fixed<DATA_BIT+N, INT_BIT+N>* ave);
    #include "average.h"
    
    void average(hls::stream<type_ap_fixed>& data, ap_fixed<DATA_BIT+N, INT_BIT+N>* ave)
    {
    	ap_fixed<DATA_BIT+N, INT_BIT+N> temp = 0.0;
    
    	average_label0:for (int i = 0; i < N; i++) {
    		temp += data.read();
    	}
    
    	*ave = temp / N;
    }
    #include <stdio.h>
    #include <stdlib.h>
    #include "average.h"
    
    int main()
    {
    	// 固定小数点数使用
    	ap_fixed<DATA_BIT, INT_BIT> testData;
    	hls::stream<type_ap_fixed> testStream;
    	ap_fixed<DATA_BIT+N, INT_BIT+N> testAve = 0;
    	ap_fixed<DATA_BIT+N, INT_BIT+N> cmpAve = 0;
    
    	srand(10);
    
    	for (int j = 0; j < 4; j++) {
    		testAve = 0;
    		cmpAve = 0;
    
    		for (int i = 0; i < N; i++) {
    			// テストデータを小数にする
    			testData = (double)(rand() % 256 - 128) / 3.0;
    			testStream.write(testData);
    			cmpAve += testData;
    		}
    
    		cmpAve /= N;
    
    		average(testStream, &testAve);
    
    		if (testAve != cmpAve) {
    			printf("Test Error!\n");
    			printf("cmpAve=%f testAve=%f\n", (double)cmpAve, (double)testAve);
    		}
    		else {
    			printf("Test OK!\n");
    		}
    	}
    
    	return 0;
    }
  • ディレクティブ指定
  • ap_intと変更ありません。

  • シミュレーション波形
  • 小数で計算出来ています。手計算でも合っていたので、問題ないと思います。

    Vivado HLS 高位合成 ap_fixed 固定小数点数

    ちなみにデフォルトの波形表示では小数で表示されません。表示を変更するには、小数で表示したい信号を右クリックして、Radix→Real Settings...を選択します。表示されたダイアログでFixed Pointを選択、信号に合わせて固定小数点数の設定が可能です。

    Vivado HLS 高位合成 シミュレーション 固定小数点数

    Vivado HLS 高位合成 シミュレーション 固定小数点数

    シェアする

    • このエントリーをはてなブックマークに追加

    フォローする