2019年1月27日日曜日

SystemC で $clog2 を使う

ハードウェア設計では,メモリサイズに対するアドレスバスの bit 幅等で log2 を使いたい場面が出てくる (bit 幅の指定に使うので,コンパイル時定数であることが重要).
いつからか Verilog では $clog2() が使えるようになって便利だが,SystemC でそれに該当するものはなさげ.

仕方がないので,ダメ元で std::log() を使ってみる.
●定義
#define BIT_WIDTH( n ) (( int )( log(( n ) * 2 - 1 ) / log( 2 )))

●使用
#define HOGE 1024
sc_uint<BIT_WIDTH( HOGE )> HOGE_t;

●VivadoHLS のログ
./hoge.h:39:27: error: non-type template argument of type 'int' is not an integral constant expression
typedef sc_uint<(( int )( log(( HOGE ) * 2 - 1 ) / log( 2 )))> HOGE_t;
                ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
シミュレーションでは (g++ の最適化が強力なので) コンパイル時定数になってくれるので ok なんだけど,VivadoHLS の高位合成コンパイラでは怒られた.

んー,と思っていたら,テンプレートメタプログラミングなる手法があること発見!
template<int num> struct BitWidthTmplate { enum { Val = BitWidthTmplate<num / 2>::Val + 1 }; };
template<> struct BitWidthTmplate<0> { enum { Val = 0 }; };
#define BIT_WIDTH( n ) ( BitWidthTmplate<( n ) - 1>::Val )
これだと VivadoHLS でも通ったヽ(´ー`)ノ

constexpr 使ったら std::log() でも行けそうな気がするけど,Vivado の C++ 高位合成コンパイラは C++11 ですら無いので使えない.┐('~`;)┌

0 件のコメント:

コメントを投稿