C++ の任意精度整数型 - 2023.2 日本語

Vitis 高位合成ユーザー ガイド (UG1399)

Document ID
UG1399
Release Date
2023-12-18
Version
2023.2 日本語

C++ のネイティブ データ型は、8 ビット境界 (8、16、32、64 ビット) にあります。RTL 信号および演算では、任意のビット長がサポートされます。

Vitis HLS では C++ の任意精度型が提供されており、C コードの変数および演算を任意のビット幅 (6 ビット、17 ビット、234 ビットなど、最大 1024 ビットまで) で指定できます。

ヒント: デフォルトの幅の最大許容幅は 1024 ビットです。このデフォルトは、ap_int.h ヘッダー ファイルを含める前に、マクロ AP_INT_MAX_W に 4096 以下の正の整数値を定義すると上書きできます。

任意精度データ型には、ネイティブ C++ データ型よりも次のような利点があります。

  • ハードウェアの質の改善: たとえば 17 ビットの乗算器が必要な場合、計算で調度 17 ビットが使用されるように指定するために任意精度型を使用できます。

    任意精度型を使用しない場合、このような乗算 (17 ビット) は 32 ビットの整数型を使用してインプリメントする必要があるので、複数の DSP モジュールを使用して乗算がインプリメントされることになります。

  • 正確な C++ シミュレーション/解析: C++ コードの任意精度データ型を使用すると、正確なビット幅を使用して C++ シミュレーションを実行でき、合成前にアルゴリズムの機能 (および精度) を検証できます。

C++ の任意精度型には、C の任意精度型で発生するような問題はありません。

  • C++ 任意精度型は、標準 C++ コンパイラでコンパイルできます。apcc と同等のものは C++ にはありません。
  • C++ 任意精度型には、整数拡張問題はありません。

ファイル拡張子が .c から .cpp に変更されることはよくあるので、これらの問題がない場合はファイルを C++ としてコンパイルできます。

C++ 言語では、ヘッダー ファイル ap_int.h で任意精度の整数型 ap_(u)int<W> が定義されます。たとえば、ap_int<8> は 8 ビットの符号付き整数データ型を表し、ap_uint<234> は 234 ビットの符号なし整数データ型を表します。

ap_int.h ファイルは、$HLS_ROOT/include ディレクトリ ($HLS_ROOTVitis HLS のインストール ディレクトリ) にあります。

次のコード例は、基本演算例 (標準データ型) のコードを繰り返したものです。この例で合成される最上位関数のデータ型は dinA_tdinB_t などです。

#include "cpp_ap_int_arith.h"

void cpp_ap_int_arith(din_A  inA, din_B  inB, din_C  inC, din_D  inD,
 dout_1 *out1, dout_2 *out2, dout_3 *out3, dout_4 *out4
) {

 // Basic arithmetic operations
 *out1 = inA * inB;
 *out2 = inB + inA;
 *out3 = inC / inA;
 *out4 = inD % inA;

}

前の例をアップデートしたこの例では、C++ 任意精度型が使用されています。

  • ソース コードにヘッダー ファイル ap_int.h を追加します。
  • ネイティブ C++ 型を任意精度型 ap_int<N> または ap_uint<N> に変更します。N は 1 ~ 1024 のビット サイズです。前述のとおり、これは必要に応じて 4K ビットに拡張できます。

データ型はヘッダー ファイル cpp_ap_int_arith.h で定義されます。

標準データ型 の基本演算の例と比較すると、入力のデータ型が実際の入力データの最大サイズを表すよう削減されています (8 ビット入力 inA が 6 ビット入力に削減されているなど)。出力はより正確になるよう調整されています。たとえば inAinB の合計である out2 に必要なのは、32 ビットではなく 13 ビットのみです。

次に、C++ 任意精度型を使用した基本演算の例を示します。

#ifndef _CPP_AP_INT_ARITH_H_
#define _CPP_AP_INT_ARITH_H_

#include <stdio.h>
#include "ap_int.h"

#define N 9

// Old data types
//typedef char dinA_t;
//typedef short dinB_t;
//typedef int dinC_t;
//typedef long long dinD_t;
//typedef int dout1_t;
//typedef unsigned int dout2_t;
//typedef int32_t dout3_t;
//typedef int64_t dout4_t;

typedef ap_int<6> dinA_t;
typedef ap_int<12> dinB_t;
typedef ap_int<22> dinC_t;
typedef ap_int<33> dinD_t;

typedef ap_int<18> dout1_t;
typedef ap_uint<13> dout2_t;
typedef ap_int<22> dout3_t;
typedef ap_int<6> dout4_t;

void cpp_ap_int_arith(dinA_t inA,dinB_t inB,dinC_t inC,dinD_t inD,dout1_t 
*out1,dout2_t *out2,dout3_t *out3,dout4_t *out4);

#endif

任意精度の整数が合成されると、標準データ型 と同じ機能を持つデザインになります。cout 演算子を使用して結果をファイルに出力するのではなく、ビルトインの ap_int メソッド .to_int() を使用して、ap_int の結果を標準 fprintf 関数で使用される整数型に変換します。

fprintf(fp, %d*%d=%d; %d+%d=%d; %d/%d=%d; %d mod %d=%d;\n, 
 inA.to_int(), inB.to_int(), out1.to_int(), 
 inB.to_int(), inA.to_int(), out2.to_int(), 
 inC.to_int(), inA.to_int(), out3.to_int(), 
 inD.to_int(), inA.to_int(), out4.to_int());