ユーザー管理のカーネルでは、ホスト アプリケーションに XRT ネイティブ API を使用する必要があり、xrt::ip
クラスの IP オブジェクトとして指定されます。次に、ホスト アプリケーションの構造を設定して、.xclbin ファイルからユーザー管理のカーネルにアクセスする方法の概要を示します。
- XRT ネイティブ API を含めるには、次のヘッダー ファイルを追加します。
#include "experimental/xrt_ip.h" #include "xrt/xrt_bo.h"
-
experimental/xrt_ip.h: IP を
xrt::ip
のオブジェクトとして定義します。 - xrt/xrt_bo.h: XRT ネイティブ API でバッファー オブジェクトを作成できるようにします。
-
experimental/xrt_ip.h: IP を
- デバイス ID の指定と XCLBIN のロード の説明に従って、アプリケーション環境を設定します。
- IP オブジェクト (
xrt::ip
) は、xrt::device
オブジェクト、.xclbin のuuid
、およびユーザー管理のカーネルのname
から構成されます。xrt::ip
はxrt::kernel
標準とは異なり、XRT では IP を管理しないが、レジスタへのアクセスを提供することを示します。//User Managed Kernel = IP auto ip = xrt::ip(device, uuid, "Vadd_A_B");
- IP 引数のバッファーを作成します。
auto <buf_name> = xrt::bo(<device>,<DATA_SIZE>,<flag>,<bank_id>);
バッファー オブジェクト コンストラクターが使用するフィールドは次のとおりです。
-
<device>
: アクセラレータ カードのxrt::device
オブジェクト。 -
<DATA_SIZE>
: データの幅と量によって定義されるバッファーのサイズ。 -
<flag>
: バッファー オブジェクトを作成するためのフラグ。 -
<bank_id>
: IP アクセス用にバッファーを割り当てるデバイス上のメモリ バンクを定義します。指定したメモリ バンクは、.xclbin ファイル内の対応する IP ポートの接続と一致する必要があります。一致しないと、アプリケーションの実行時にbad_alloc
になります。カーネル ポートのメモリへのマップ で説明されるように、--connectivity.sp
コマンドを使用すると、カーネル引数の割り当てを指定できます。
次に例を示します。
auto buf_in_a = xrt::bo(device,DATA_SIZE,xrt::bo::flags::normal,0); auto buf_in_b = xrt::bo(device,DATA_SIZE,xrt::bo::flags::normal,0);
ヒント: IP 接続を検証して特定のメモリバンクを判別することもできるほか、Vitis で生成された .xclbin.info ファイルからこの情報を取得することもできます。たとえば、.xclbin からのユーザー管理のカーネルの次の情報を使用すると、ホスト コード内のバッファー オブジェクトの構築がガイドされます。
Instance: Vadd_A_B_1 Base Address: 0x1c00000 Argument: scalar00 Register Offset: 0x10 Port: s_axi_control Memory: <not applicable> Argument: A Register Offset: 0x18 Port: m00_axi Memory: bank0 (MEM_DDR4) Argument: B Register Offset: 0x24 Port: m01_axi Memory: bank0 (MEM_DDR4)
-
- ホストとデバイス間でデータを転送します。
auto a_data = buf_in_a.map<int*>(); auto b_data = buf_in_b.map<int*>(); // Sync Buffers buf_in_a.sync(XCL_BO_SYNC_BO_TO_DEVICE); buf_in_b.sync(XCL_BO_SYNC_BO_TO_DEVICE);
xrt::bo::map()
は、ホスト側のバッファー バッキング ポインターをユーザー ポインターにマップできるようにします。ただし、マップされたポインターから読み出す前、またはマップされたポインターに書き込んだ後は、DMA 動作の方向フラグを含めてxrt::bo::sync()
を使用する必要があります。 -
バッファーを準備した後 (バッファーの作成、同期は上記を参照) は、必要なすべての情報をダイレクト レジスタ書き込みを使用して IP に渡すことができるようになります。たとえば、次のコードは、
そのあと、データをレジスタに書き込み、ホスト アプリケーションからカーネルに移動しています。xrt::ip::write_register()
コマンドを介してバッファーのベース アドレスを渡す情報を示しています。ip.write_register(REG_OFFSET_A,a_addr); ip.write_register(REG_OFFSET_A+4,a_addr>>32); ip.write_register(REG_OFFSET_B,b_addr); ip.write_register(REG_OFFSET_B+4,b_addr>>32);
- IP 実行を開始します。IP はユーザー管理であるため、任意の数のレジスタ書き込み/読み出しを使用すると、IP の開始/ステータス チェック/再開をして、IP の実行をトリガーできます。次の例では、
s_axilite
インターフェイスを使用して制御レジスタの制御信号にアクセスします。uint32_t axi_ctrl = 0; std::cout << "INFO:IP Start" << std::endl; axi_ctrl = IP_START; ip.write_register(CSR_OFFSET, axi_ctrl); // Wait until the IP is DONE axi_ctrl =0; while((axi_ctrl & IP_IDLE) != IP_IDLE) { axi_ctrl = ip.read_register(CSR_OFFSET); }
- IP の実行が終了したら、バッファー転送方向を指示する適切なフラグを指定し、
xrt::bo::sync
コマンドでデータをホストに転送できます。buf_in_b.sync(XCL_BO_SYNC_BO_FROM_DEVICE);
- オプションで、アプリケーションをプロファイルします。
XRT ではカーネルの開始または停止を管理しないため、
user_managed
カーネルの動作は XRT で管理されるカーネルのように直接プロファイルできません。ただし、ホスト アプリケーションのカスタム プロファイリング で説明したuser_range
オブジェクトとuser_event
オブジェクトを使用すると、ホスト アプリケーションの要素をプロファイルできます。たとえば、次のコードはホスト アプリケーションからレジスタを書き込むのにかかる時間を取得します。// Write Registers range.start("Phase 4a", "Write A Register"); ip.write_register(REG_OFFSET_A,a_addr); ip.write_register(REG_OFFSET_A+4,a_addr>>32); range.end(); range.start("Phase 4b", "Write B Register"); ip.write_register(REG_OFFSET_B,b_addr); ip.write_register(REG_OFFSET_B+4,b_addr>>32); range.end()
次の図に示すように、アプリケーションとカーネルの動作のいくつかの側面は Vitis アナライザーで観察できます。