Vivado HLSで作ったAXI4-Lite IPのAPI

FPGA

Vivado HLSで高位合成を行うと、RTLと共にSDK用のAPIが生成されます。APIの利用方法をベアメタルで確認しました。

確認用のC関数

float_topという名前の関数です。aとbに単精度の浮動小数点形式の値を設定すると、cに乗算結果が格納されます。InterfaceはAXI4-Liteです(別ファイルのDirectiveで指定しています)。

void float_top(float a, float b, float *c)
{
  *c =  a * b;
}

float_topを高位合成し、そのIPコアを組込んだシステムの詳細はこちらです。

SDKの準備

通常の手順でVivadoのSDKを起動します。具体的な手順は次のとおりです。
まず、Vivado上で次の処理を実行します。

  • File->Export->Export Hardwareを実行
  • File->Launch SDKを実行

SDK起動後、SDK上で次の処理を実行します。

  • File->New->Board Support Packageを実行
  • File->New->Application Projectを実行

この時点で、SDKのProject Explorerは次のような構成になります。この例では、testという名前でApplication Projectを作成しています。

Projectの内容

Projectの内容

IPコアのAPI

APIに必要な処理

関数float_topは、aとbが入力で、cが出力(演算結果)です。このため、Vivado HLSが生成したAPIには次の処理を行う関数が存在するはずです。

  • aに値を設定する関数
  • bに値を設定する関数
  • cの値を読み出す関数

また、ハードウェアを制御するために、次の処理を行うAPIが存在するはずです。

  • 演算を開始する関数
  • 演算の完了を認識する関数

実際のAPI

IPコアのAPIは、次のディレクトリに格納されています(この例の場合)。

  • design_1_wrapper_hw_platform_0->drivers->float_top_v1_0->data->src

ディレクトリには、次のファイルが格納されています。

xfloat_top_hw.h
xfloat_top_linux.c
xfloat_top_sinit.c
xfloat_top.c
xfloat_top.h

float_topを制御するAPIを定義したファイルがxfloat_top.hです。また、そのソースコードがxfloat_top.cです。定義されているAPIの意味は、ug902-vivado-high-level-synthesis.pdfに記載されていました。主なAPIの意味は次のとおりです。生成されるAPIは、Directiveの記述などで多少変わるようです。

API 内容
XFloat_top_Config* XFloat_top_LookupConfig(u16 DeviceId);  コンフィギュレーション情報の取得
int XFloat_top_CfgInitialize(XFloat_top *InstancePtr, XFloat_top_Config *ConfigPtr);  MMUが使われているシステムで、デバイスを初期化
void XFloat_top_Start(XFloat_top *InstancePtr); 処理を開始
u32 XFloat_top_IsDone(XFloat_top *InstancePtr); 処理が終了
u32 XFloat_top_IsIdle(XFloat_top *InstancePtr); IDLE状態
u32 XFloat_top_IsReady(XFloat_top *InstancePtr); 次のデータを受付可能
void XFloat_top_Set_a(XFloat_top *InstancePtr, u32 Data); aに値を設定
u32 XFloat_top_Get_a(XFloat_top *InstancePtr); aの値を取得
void XFloat_top_Set_b(XFloat_top *InstancePtr, u32 Data); bに値を設定
u32 XFloat_top_Get_b(XFloat_top *InstancePtr); bの値を取得
u32 XFloat_top_Get_c(XFloat_top *InstancePtr); c(演算結果)の値を取得
u32 XFloat_top_Get_c_vld(XFloat_top *InstancePtr); cが有効であることを示す情報

テストプログラム

このテストプログラムでは、10回のループで適当なfloatの値a,bを生成し、その乗算結果cを求めています。乗算結果は、IPコアとプログラムの両方で計算し、違いがあるかをチェックしています。floatの値は、32ビットのバイナリに変換してからfloat_topに渡しています。同様に、float_topの演算結果は32ビットのバイナリからfloatに変換する必要があります。

#include <stdio.h>
#include "platform.h"
#include "xfloat_top.h"

// from xparameters.h
#define XF_DEVICE_ID  	XPAR_FLOAT_TOP_0_DEVICE_ID

XFloat_top XFT;// Vivado HLSで作成したIPコアに対応したインスタンス
// float - unsigned 変換
typedef union _fu_u {
  unsigned int u;
  float f;
} fu_u;
// 期待値モデル
float ref_float_top(float a, float b)
{
  return a * b;
}

int main()
{
  int i,Status;
  XFloat_top_Config *ConfigPtr;
  fu_u ref_a, ref_b;
  fu_u in_a, in_b, out_c;
  init_platform();

  // 初期化
  ConfigPtr = XFloat_top_LookupConfig(XF_DEVICE_ID);
  Status =  XFloat_top_CfgInitialize(&XFT, ConfigPtr);
  if (Status != XST_SUCCESS) {
    return XST_FAILURE;
  }
  Status = XFloat_top_IsIdle(&XFT);

  for (i=0;i<10;i++) {
    printf("TEST LOOP %d:\n",i);
    ref_a.f = (float)i;            // 適当
    ref_b.f = (float)(i*100 + i);  // 適当
    while(!XFloat_top_IsReady(&XFT)) ;  // Readyを確認
    XFloat_top_Set_a(&XFT, ref_a.u);  // aに値を設定
    XFloat_top_Set_b(&XFT, ref_b.u);  // bに値を設定
    in_a.u = XFloat_top_Get_a(&XFT);
    in_b.u = XFloat_top_Get_b(&XFT);
    printf("  Get value a = %f(%x), b = %f(%x)\n",
                in_a.f,in_a.u,in_b.f,in_b.u);
    XFloat_top_Start(&XFT);         // 処理を開始
    while (!XFloat_top_IsDone(&XFT)) ;  // Done待ち
    out_c.u = XFloat_top_Get_c(&XFT); // cの値を取得
    printf("  Get value c = %f(%x)\n",out_c.f,out_c.u);
    if ( ref_float_top(ref_a.f, ref_b.f) != out_c.f )  // 期待値比較
      printf("  ERROR! ref = %f, val = %f\n",
                  ref_float_top(ref_a.f, ref_b.f),out_c.f);
  }
  printf("float_top test done.\n");
  cleanup_platform();
  return 0;
}

IDの扱いやXFloat_top_LookupConfig, XFloat_top_CfgInitializeの設定方法は、SDKのサンプルに付属するGPIOなどと同様です。

実行結果

IPコアの処理結果と期待値が完全に一致しました。

TEST LOOP 0:
  Get value a = 0.000000(0), b = 0.000000(0)
  Get value c = 0.000000(0)
TEST LOOP 1:
  Get value a = 1.000000(3f800000), b = 101.000000(42ca0000)
  Get value c = 101.000000(42ca0000)
TEST LOOP 2:
  Get value a = 2.000000(40000000), b = 202.000000(434a0000)
  Get value c = 404.000000(43ca0000)
TEST LOOP 3:
  Get value a = 3.000000(40400000), b = 303.000000(43978000)
  Get value c = 909.000000(44634000)
TEST LOOP 4:
  Get value a = 4.000000(40800000), b = 404.000000(43ca0000)
  Get value c = 1616.000000(44ca0000)
TEST LOOP 5:
  Get value a = 5.000000(40a00000), b = 505.000000(43fc8000)
  Get value c = 2525.000000(451dd000)
TEST LOOP 6:
  Get value a = 6.000000(40c00000), b = 606.000000(44178000)
  Get value c = 3636.000000(45634000)
TEST LOOP 7:
  Get value a = 7.000000(40e00000), b = 707.000000(4430c000)
  Get value c = 4949.000000(459aa800)
TEST LOOP 8:
  Get value a = 8.000000(41000000), b = 808.000000(444a0000)
  Get value c = 6464.000000(45ca0000)
TEST LOOP 9:
  Get value a = 9.000000(41100000), b = 909.000000(44634000)
  Get value c = 8181.000000(45ffa800)
float_top test done.

まとめ

AXI4-Liteインターフェースの場合、次の手順でIPコアにアクセスできました。

  1. 初期設定(XDut_LookupConfig,XDut_CfgInitialize)
  2. ステータスを確認(XDut_IsReady)
  3. 引数に値を設定(XDut_Set_ARG)
  4. 処理を開始(XDut_Start)
  5. 処理終了待ち(XDut_IsDone)
  6. 処理結果を取得(XDut_Get_ARG)
タイトルとURLをコピーしました