Vivado HL WebPACK EditionからVivao HLS(高位合成)を無償で試せるようになりました。Vivado HLSを使うと、CやC++で記述したコードからVerilogやVHDLのコードが生成できます。Vivado 2015.4で実際にHLSを試したときのメモです。
機能を一通り理解するのに必要な時間
チュートリアル(ug871-vivado-high-level-synthesis-tutorial.pdf)を実際に試せば、丸1日でほとんどの機能を理解できます。チュートリアルは、非常にわかりやすいです。また、取り上げられている題材もかなり実践的です。
機能について
次のような簡単な関数でVivado HLSの高位合成を確認してみました。関数float_topは、単純な単精度浮動小数点の乗算関数です。
void float_top(float a, float b,float *c) { *c = a * b; }
テストベンチ
Cで作ったテストベンチを、まったく修正なしで高位合成後のRTLの検証に使えます。例えば、合成後のインターフェスがAXIであっても、それを意識しないでCのテストベンチをそのまま利用できます。また、この例の場合、高位合成で生成されたRTLにはfloatではなく、32ビットのバイナリ・データを渡す必要がありますが、そのようなキャストも自動的に行ってくれます。
#define #define ERROR_THRESH 0.1 typedef union _ftoi { float f; unsigned int u; } ftoi; int main(void) { float fres,fia,fib,fref; int ec = 0; int delta = 0; for (unsigned int i = 0x00800000; i < 0x7f800000; i++) { fi.u = i; fia = fib = fi.f; float_top(fia, fib, &fres); fref = fia*fib; if (fabs(fres - fref) > ERROR_THRESH) ec++; if ((i % 1000)==0) { cout << "IN a: i = " << fia; cout << " IN b: " << fib; cout << " OUT: " << fres; cout << " REF: " << fref; cout << " EC: " << ec << endl; } } return 0; }
インターフェース
クロックやリセット、Valid信号やステータス信号などは、自動的に付加されます。また、ユーザーが明示的に指定することもできます。インターフェースには、AXIを指定することもできます。これらの設定は、Directiveで行います。Directiveは、ソースコード中にpragmaとして挿入するか、または別ファイルに格納できます。
#include "float_top.h" void float_top(float a, float b,float *c) { #pragma HLS INTERFACE s_axilite port=c #pragma HLS INTERFACE s_axilite port=b #pragma HLS INTERFACE s_axilite port=a #pragma HLS PIPELINE *c = a * b; }
波形表示
C/RTL協調シミュレーションの結果は、波形で確認できます。
Solution
Cのコードはそのままで、インターフェースやパイプライン化の設定などを、Solutionというセットで複数試せます。また、Solution同士の結果比較を簡単に行える機能があります。
Vivadoで使う方法
作ったモジュールは、VivadoのIP Catalogに取り込めます。IP Catalogに登録したIPは、IP IntegratorのBlock Designで使えるようになります。
AXIアクセスの方法
インターフェースとしてAXIを指定すると、「どのようにしてプロセッサからアクセスするのか」という点が気になります。これについては、合成対象の関数の入出力とその制御信号がレジスタにマッピングされます。プロセッサからアクセスする場合には、これらのレジスタを制御することになります。レジスタのマッピングは、RTLをIP Catalogとしてエキスポートすると、solution->drivers->float_top_v1_0->srcにレジスタ定義ファイルxfloat_top.hとして生成されます(この例の場合)。また、レジスタの具体的な設定や制御方法は、C/RTL協調シミュレーションの波形結果から確認できます。
// AXILiteS // 0x00 : reserved // 0x04 : reserved // 0x08 : reserved // 0x0c : reserved // 0x10 : Data signal of a // bit 31~0 - a[31:0] (Read/Write) // 0x14 : reserved // 0x18 : Data signal of b // bit 31~0 - b[31:0] (Read/Write) // 0x1c : reserved // 0x20 : Data signal of c // bit 31~0 - c[31:0] (Read) // 0x24 : Control signal of c // bit 0 - c_ap_vld (Read/COR) // others - reserved // (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake) #define XFLOAT_TOP_AXILITES_ADDR_A_DATA 0x10 #define XFLOAT_TOP_AXILITES_BITS_A_DATA 32 #define XFLOAT_TOP_AXILITES_ADDR_B_DATA 0x18 #define XFLOAT_TOP_AXILITES_BITS_B_DATA 32 #define XFLOAT_TOP_AXILITES_ADDR_C_DATA 0x20 #define XFLOAT_TOP_AXILITES_BITS_C_DATA 32 #define XFLOAT_TOP_AXILITES_ADDR_C_CTRL 0x24
まとめ
予想以上に素晴らしいです。math.hやcmath.hの関数が簡単に合成できるところが衝撃的です(しかもWebPACK Editionで)。floatといったCネイティブの精度だけでなく、C++のtemplateなどを使って任意の精度の演算器を生成できるようです。とにかく使いやすいです。
- 演算精度と回路規模のトレードオフ
- パイプライン化と回路規模、パフォーマンスのトレードオフ
などを簡単に検討できそうです。