ユーザー管理のカーネルと引数バッファーの設定 - 2021.1 Japanese

Vitis 統合ソフトウェア プラットフォームの資料: アプリケーション アクセラレーション開発 (UG1393)

Document ID
UG1393
Release Date
2022-03-29
Version
2021.1 Japanese

ユーザー管理のカーネルでは、ホスト アプリケーションに XRT ネイティブ API を使用する必要があり、xrt::ip クラスの IP オブジェクトとして指定されます。次に、ホスト アプリケーションの構造を設定して、.xclbin ファイルからユーザー管理のカーネルにアクセスする方法の概要を示します。

  1. 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 でバッファー オブジェクトを作成できるようにします。
  2. デバイス ID の指定と XCLBIN のロード の説明に従って、アプリケーション環境を設定します。
  3. IP オブジェクト (xrt::ip) は、xrt::device オブジェクト、.xclbinuuid、およびユーザー管理のカーネルの name から構成されます。xrt::ipxrt::kernel 標準とは異なり、XRT では IP を管理しないが、レジスタへのアクセスを提供することを示します。
    //User Managed Kernel = IP
    auto ip = xrt::ip(device, uuid, "Vadd_A_B");
  4. 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)
    
  5. ホストとデバイス間でデータを転送します。
        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() を使用する必要があります。

  6. バッファーを準備した後 (バッファーの作成、同期は上記を参照) は、必要なすべての情報をダイレクト レジスタ書き込みを使用して 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);
    
  7. 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);
        }
     
  8. IP の実行が終了したら、バッファー転送方向を指示する適切なフラグを指定し、xrt::bo::sync コマンドでデータをホストに転送できます。
        buf_in_b.sync(XCL_BO_SYNC_BO_FROM_DEVICE);
    
  9. オプションで、アプリケーションをプロファイルします。

    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 アナライザーで観察できます。