GCC 用のライブラリのエクスポート

この章では、sds++ コンパイラを使用し、プログラマブル ロジックにインプリメントされるハードウェア関数へのエントリ ポイントを含めてソフトウェア関数のライブラリをビルドする方法について説明します。このライブラリは、Zynq®-7000 SoC および Zynq® UltraScale+™ MPSoC デバイス用の標準 GCC リンカーを使用してアプリケーションへリンクできます。

sds++ では、ライブラリだけでなく、FPGA ビットストリームを含むハードウェア関数とデータ モーション ネットワークの完全なブート イメージも生成されます。このライブラリを使用すると、標準 GCC ツールチェーンを使用してハードウェア関数を呼び出すソフトウェア アプリケーションを開発できます。つまり、同じハードウェア システムをターゲットして sds++ で生成されたブート環境を使用しながら、任意のソフトウェア開発環境で GNU ツールチェーンを使用してソフトウェア アプリケーションを開発できます。

重要: 現在の SDSoC™ リリースでは、ライブラリはスレッドセーフではありませんので、アプリケーション (多くのスレッドおよびプロセスが含まれることあり) 内の 1 つのスレッドから呼び出される必要があります。

共有ライブラリのビルド

ヒント: 共有ライブラリは、Linux OS をターゲットにするアプリケーション プロジェクトの場合にのみ作成できます。

共有ライブラリをビルドするには、sds++ に少なくとも 1 つのアクセラレータが必要です。次の例では、行列乗算および行列加算の 2 つのハードウェア アクセラレータへの 3 つのエントリ ポイントを示します。これらのファイルは samples/libmatrix/build ディレクトリにあります。

  • mmult_accel.cpp: 行列乗算のアクセラレータ コード
  • mmult_accel.h: 行列乗算のヘッダー ファイル
  • madd_accel.cpp: 行列加算のアクセラレータ コード
  • madd_accel.h: 行列加算のヘッダー ファイル
  • matrix.cpp: アクセラレータを呼び出し、データ モーション ネットワークを判断するコード
  • matrix.h: ライブラリのヘッダー ファイル

matrix.cpp ファイルには、アクセラレータ インターフェイスと、ハードウェア関数のプラットフォームとの通信方法 (プラットフォームとアクセラレータ間のデータ モーション ネットワーク) を定義する関数が含まれます。関数 madd は 1 つの行列加算アクセラレータを呼び出し、関数 mmult は 1 つの行列乗算アクセラレータを呼び出します。2 つのハードウェア関数を使用して、行列乗算の出力が行列加算の入力に直接接続された別の関数 mmultadd がインプリメントされます。

/* matrix.cpp */
#include "madd_accel.h"
#include "mmult_accel.h"
    
void madd(float in_A[MSIZE*MSIZE], float in_B[MSIZE*MSIZE], float out_C[MSIZE*MSIZE])                                             
{
  madd_accel(in_A, in_B, out_C);
}
    
void mmult(float in_A[MSIZE*MSIZE], float in_B[MSIZE*MSIZE], float out_C[MSIZE*MSIZE])                                            
{
  mmult_accel(in_A, in_B, out_C);
}
    
void mmultadd(float in_A[MSIZE*MSIZE], float in_B[MSIZE*MSIZE], float in_C[MSIZE*MSIZE], 
float out_D[MSIZE*MSIZE])
{
  float tmp[MSIZE * MSIZE];
    
  mmult_accel(in_A, in_B, tmp);
  madd_accel(tmp, in_C, out_D);
}

matrix.h ファイルは共有ライブラリへの関数インターフェイスを定義し、アプリケーションのソース コードに含められます。

/* matrix.h */
#ifndef MATRIX_H_
#define MATRIX_H_
   
#define MSIZE 16
    
void madd(float in_A[MSIZE*MSIZE], float in_B[MSIZE*MSIZE], float out_C[MSIZE*MSIZE]);
  
void mmult(float in_A[MSIZE*MSIZE], float in_B[MSIZE*MSIZE], float out_C[MSIZE*MSIZE]);
    
void mmultadd(float in_A[MSIZE*MSIZE], float in_B[MSIZE*MSIZE], float in_C[MSIZE*MSIZE], 
float out_D[MSIZE*MSIZE]);
    
#endif /* MATRIX_H_ */

samples/libmatrix/build/shared フォルダーの Makefile には、mmult_accelmadd、および mmult_add 関数をプログラマブル ロジックにインプリメントする必要があることを指定して、プロジェクトをビルドする方法が示されています。

SDSFLAGS = \
    -sds-pf ${PLATFORM} \
    -sds-hw mmult_accel mmult_accel.cpp -sds-end \
    -sds-hw madd_accel madd_accel.cpp -sds-end

オブジェクト ファイルは、GCC 規格の -fpic オプションを使用して、標準共有ライブラリのように位置独立コード (PIC) を含めて生成されます。

sds++ ${SDSFLAGS} -c -fpic –o mmult_accel.o mmult_accel.cpp
    sds++ ${SDSFLAGS} -c -fpic –o madd_accel.o madd_accel.cpp
    sds++ ${SDSFLAGS} -c -fpic –o matrix.o matrix.cpp

GCC 規格の –shared オプションを使用してオブジェクト ファイルをリンクします。

sds++ ${SDSFLAGS} -shared -o libmatrix.so mmult_accel.o madd_accel.o matrix.o

プロジェクトをビルドすると、次のファイルが生成されます。

  • libmatrix.so: GCC を使用してリンクおよびランタイムで使用するための共有ライブラリ
  • sd_card: ボードをブートする SD カード イメージが含まれるディレクトリ

ライブラリの配布

次の構造を使用すると、GCC を使用して標準的な方法でアプリケーションにコンパイルおよびリンクできます。

<path_to_library>/include/matrix.h
<path_to_library>/lib/libmatrix.so
<path_to_library>/sd_card
重要: sd_card フォルダーを SD カードにコピーし、ボードの起動に使用します。このイメージには、ランタイムで使用される libmatrix.so ファイルのコピーが含まれます。

ライブラリを使用したコンパイルおよびリンク

次に、GCC コンパイラでライブラリを使用する例を示します。ライブラリを使用するには、ヘッダー ファイル matrix.h を含め、必要なライブラリ関数を呼び出します。

/* main.cpp (pseudocode) */
#include "matrix.h"
        
int main(int argc, char* argv[])
{
  float *A, *B, *C, *D;
  float *J, *K, *L;
  float *X, *Y, *Z;
  ...
  mmultadd(A, B, C, D);
  ...
  mmult(J, K, L);
  ...
  madd(X, Y, Z);
  ...
}

ライブラリを使用してコンパイルするには、コンパイラを実行する際にヘッダー ファイルを指定する必要があります。ヘッダー ファイルへのパスは、-I オプションを使用して指定します。これらのサンプル ファイルは samples/libmatrix/use ディレクトリにあります。

ヒント: 上記のコードは説明のための擬似コードであり、このディレクトリに含まれる main.cpp ファイルとは異なります。このファイルには、完全にコンパイルおよび実行するため、さらにコードが含まれます。
gcc –I <path_to_library>/include –o main.o main.c

ライブラリをリンクするには、リンカーを実行する際にライブラリを指定する必要があります。ライブラリへのパスは、-L オプションを使用して指定します。また、リンカーにライブラリに対してリンクするよう指示するため -l オプションを使用します。

gcc –I <path_to_library>/lib –o main.elf main.o -lmatrix

GCC コンパイラおよびリンカー オプションの使用に関する詳細は、GCC の資料を参照してください。

ランタイムでのライブラリの使用

ランタイムでは、実行ファイルを読み込む際にローダーにより共有ライブラリが検索されます。ボードを Linux プロンプトにブートした後、ELF ファイルを実行する前に、LD_LIBRARY_PATH 環境変数にライブラリへのパスを追加します。ライブラリを構築したときに作成された sd_card には既にライブラリが含まれているので、sd_card のマウント ポイントへのパスを指定する必要があります。

たとえば、sd_card/mnt にマウントされている場合は、次のコマンドを使用します。

export LD_LIBRARY_PATH=/mnt

共有ライブラリのエクスポート

次に、SDSoC 環境 GUI を使用して SDSoC 環境の共有ライブラリと対応する SD カード ブート イメージをエクスポートする例を示します。

  1. [File] > [New] > [SDx Library Project] をクリックし、[New SDx Library Project] ダイアログ ボックスを表示します。
  2. 新規 SDx ライブラリプロジェクトを作成します。
    1. [Project name] フィールドに「libmatrix」と入力します。
    2. [Location] にディレクトリを指定します。
    3. [Next] をクリックします。
    4. [Accelerated Library Type] ページで [Shared Library] チェック ボックスをオンにします。
    5. [Next] をクリックします。
    6. [Platform]zc102 を選択します。
    7. [Next] をクリックします。
  3. プロジェクトのシステム コンフィギュレーションとソフトウェアの詳細を指定します。
    1. [System Configuration] ダイアログ ボックスはデフォルト値のままにします。
      注記: [Sysroot path] がオフになってることを確認します。
    2. [Next] をクリックします。
  4. [Templates] ページの [Available Templates] から [Matrix Shared Library] を選択し、[Finish] をクリックしてプロジェクトを作成します。
  5. [Project Explorer] ビューで libmatrix を右クリックして [Import Sources] を選択します。
  6. [Import Source] ページで [Browse] をクリックし、samples/libmatrix を選択し、build を選択して、[OK] をクリックします。
  7. [Import Sources] ページで build をオンにして [Finish] をクリックします。

    [Project Explorer] ビューに libmatrix という新しい SDSoC 共有ライブラリ プロジェクトが作成されます。このプロジェクトには mmult_accel および madd_accel の 2 つのハードウェア関数が含まれており、[SDx Project Settings] に表示されます。

  8. ライブラリをビルドします。
    1. [Project Explorer] ビューで libmatrix プロジェクトを選択します。
    2. [Project] > [Build Project] をクリックします。

      ビルドが完了すると、Debug (デバッグ (または現在のコンフィギュレーション) フォルダーにブート SD カード イメージが含まれるようになります。