概要

Zynq®-7000 SoC プロセッサおよび Zynq® UltraScale+™ MPSoC プロセッサは、Arm® ベースのプロセッサのソフトウェア プログラマビリティと FPGA のハードウェア プログラマビリティを統合し、1 つのデバイス上に CPU、DSP、ASSP、および混合信号機能を統合して、解析およびハードウェア アクセラレーションを可能にします。SDSoC™ 環境は、Zynq プラットフォームを使用してヘテロジニアス エンベデッド システムをインプリメントするための Eclipse ベースの統合設計環境 (IDE) です。

SDSoC 環境には、C/C++ プログラムを選択した関数がプログラマブル ロジックにコンパイルされた完全なハードウェア/ソフトウェア システムに変換するシステム コンパイラが含まれ、選択した関数のハードウェア アクセラレーションを可能にします。このガイドでは、ソフトウェア プログラマ向けに、アクセラレーションに使用されるハードウェアについて、パフォーマンスを制限または向上する要素や、最高のシステム パフォーマンスを達成するための設計手法などを説明します。

SDSoC 環境を使用するのにハードウェアの詳細な知識は必要ありませんが、デバイス上で使用可能なハードウェア リソースについてと、ハードウェア関数で並列化を増加することにより高パフォーマンスを達成する方法を理解しておくと、パフォーマンス要件を満たすためにコンパイラ最適化指示子を選択するのに役立ちます。

設計手法は、次のとおりです。

  1. ハードウェアでアクセラレーションする関数を検出します。ソフトウェアのプロファイルをすると、計算負荷の高い領域を検出しやすくなります。
  2. Vivado® HLS コーディング ガイドラインを使用してハードウェア関数コードを最適化して、パフォーマンス ターゲットを達成します。
  3. CPU プロセッサ システム (PS) とハードウェア関数のプログラマブル ロジック (PL) 間のデータ転送を最適化します。この段階では、データ アクセスをバーストしやすく再構築し、データ ムーバーを選択します。

このガイドでは、ハードウェア アクセラレーションを達成する方法を説明した後、ユーザーが SDSoC ベースのアプリケーションで使用できる設計手法を使用した実際の例を示します。

SDSoC を使用したソフトウェア アクセラレーション

ザイリンクス デバイスのプログラマブル ロジック (PL) では、プロセッサ アーキテクチャよりも、アプリケーションの実行をより高い割合で並列処理可能です。アクセラレータのハードウェア関数用に sds++/sdscc (sds++ と表記) システム コンパイラで生成されるカスタム プロセッシング アーキテクチャは、CPU とは実行の枠組みが異なるので、パフォーマンスを大幅に向上できます。既存のエンベデッド プロセッサ アプリケーションを PL でアクセラレーションするよう変更することはできますが、ザイリンクス xfOpenCV ライブラリなどの既存のハードウェア関数のソース コード ライブラリを使用してアプリケーションを記述したり、PL デバイスのアーキテクチャがうまく使用されるようにコードを変更したりすることで、パフォーマンスを大幅に向上して、消費電力を削減できます。

CPU のリソースは固定されており、タスクまたは演算を並列処理する機会は限られます。プロセッサは、そのタイプにかかわらず、プログラムをプロセッサのコンパイラ ツールで生成された命令順に実行します。コンパイラ ツールは、C/C++ で記述されたアルゴリズムをターゲット プロセッサにネイティブのアセンブリ言語の構文に変換します。2 つの値の乗算のような単純な演算ですら、複数のアセンブリ命令となり、複数のクロック サイクルで実行されます。

FPGA は本質的に並列処理デバイス ファブリックであり、プロセッサ上で実行可能な関数をどれでもインプリメントできます。ザイリンクス デバイスにはプログラムおよびコンフィギュレーション可能なリソースが大量に含まれており、カスタム アーキテクチャをインプリメントしてどんなレベルの並列処理でも達成できます。FPGA のプログラム ロジックは、すべての計算が同じ ALU を共有するプロセッサとは異なり、アクセラレーション関数を定義してインプリメント可能な空白のキャンバスのようなものです。FPGA コンパイラは、ALU 全体ではなくニューラル ネットの積和ハードウェアのみをインプリメントするなど、各アプリケーションまたはアルゴリズム用に最適化された独自の回路を作成します。

sds++ システム コンパイラを -c オプションを指定して実行すると、必要な関数定義に対して Vivado 高位合成 (HLS) ツールが起動されてファイルがハードウェア IP にコンパイルされます。HLS ツールを呼び出す前に、sds++ コンパイラで #pragma SDS が HLS ツールで解釈可能なプラグマに変換されます。HLS ツールは、同時処理を増やすように、スケジューリング、パイプライン、データデータフローを含むハードウェア指向の変換と最適化を実行します。

sds++ リンカーは、プログラム データフローを解析し、ハードウェア関数内への呼び出しおよびハードウェア関数間の呼び出しを含め、ハードウェアのデータ モーション ネットワークおよびソフトウェア制御コード (スタブと呼ぶ) をシステムにマップして、データ ムーバーを介したアクセラレータとデータ転送を調整します。次のセクションで説明するように、sds++ リンカーは、データ転送をスケジューリングして共有可能な演算を特定し、待機バリア API 呼び出しをスタブに挿入して、プログラム セマンティックが保持されるようにします。

SDSoC アプリケーションの実行モデル

SDSoC 環境アプリケーションの実行モデルは、プラットフォームのブート後にターゲット CPU で実行される C++ プログラムの通常実行を考えると理解できます。C++ バイナリの実行ファイルがハードウェアとどのようにインターフェイスするかを理解しておくと有益です。

プログラム内で宣言されたハードウェア関数はハードウェア アクセラレータにコンパイルされ、標準 C ランタイムでこれらの関数への呼び出しによりアクセスされます。各ハードウェア関数呼び出しがタスクとしてアクセラレータを起動し、関数への各引数が CPU とアクセラレータ間で転送されて、アクセラレータ タスクの完了後にプログラムでアクセスできるようになります。メモリとアクセラレータ間のデータ転送には、DMA エンジンなどのデータ ムーバーが使用され、zero_copy などのユーザー データ ムーバー プラグマを考慮して、sds++ システム コンパイラにより自動的に挿入されます。

図: SDSoC システムのアーキテクチャ

プログラムが正しく機能するようにするため、システム コンパイラはハードウェア関数への各呼び出しをインターセプトし、シグネチャが同じで派生した名前が付けられたスタブ関数への呼び出しに置き換えます。スタブ関数はすべてのデータ移動とアクセラレータの演算を制御し、ハードウェア関数呼び出しの終了時にソフトウェアとアクセラレータ ハードウェアを同期化します。スタブ内では、すべてのアクセラレータとデータ ムーバーは sds_lib ライブラリに含まれる送信および受信 API により制御されます。

ハードウェア関数呼び出し間のプログラム データフローに、プログラム内で関数呼び出し (デストラクターまたは free() 呼び出し以外) が実行された後にアクセスされない配列引数が関係する場合、およびハードウェア アクセラレータをストリームを使用して接続できる場合、メモリへの往復がインプリメントされるのではなく、1 つのハードウェア アクセラレータから直接ハードウェア ストリーム接続を介して次のハードウェア アクセラレータにデータが転送されます。この最適化により、パフォーマンスが大幅に向上し、ハードウェア リソースを削減できます。

SDSoC プログラム実行モデルの手順は次のとおりです。
  1. プログラムのコンストラクターが main() に入る前に sds_lib ライブラリが初期化されます。
  2. プログラム内で、ハードウェア関数への各呼び出しが、元の関数と関数シグネチャが同じ (名前は異なる) のスタブ関数への関数呼び出しによりインターセプトされます。スタブ関数内では、次の手順が実行されます。
    1. 同期アクセラレータ タスク制御コマンドがハードウェアに送信されます。
    2. ハードウェア関数への各引数に対して、非同期データ転送要求が関連付けられた wait() ハンドルと共に適切なデータ ムーバーに送信されます。void 以外の戻り値は、出力スカラー引数として扱われます。
    3. 各転送要求に対して、バリア wait() が発行されます。アクセラレータ間のデータ転送がダイレクト ハードウェア ストリームとしてインプリメントされる場合、この転送のバリア wait() は、この引数のアクセラレータ関数チェーンの最後のアクセラレータ関数に対するスタブ関数で発生します。
  3. プログラムのデストラクターが main() を終了するときに、sds_lib ライブラリがクリーンアップされます。
ヒント: 手順 2a ~ 2c は、アクセラレータ パイプラインの開始および終了時にプログラムを正しく保ち、それと同時にパイプライン内での同時実行を可能にします。

場合によっては、システム コンパイラで自動的には推論できないアクセラレータ タスクの同時実行の可能性を、プログラマが認識していることもあります。sds++ システム コンパイラでは #pragma SDS async(ID) プラグマがサポートされており、このような場合にハードウェア関数への呼び出しの直前に挿入できます。このプラグマを指定すると、データ転送に対してバリア wait() 呼び出しなしでスタブ関数が生成されます。その結果、すべての転送要求を発行した後、制御がプログラムに戻り、アクセラレータの実行中にプログラムの同時実行が可能になります。この場合、プログラム内の適切な同期ポイントに #pragma SDS wait(ID) を挿入してください。このプラグマは sds_wait(ID) API 呼び出しとなり、ハードウェア アクセラレータ、その暗示的なデータ ムーバー、および CPU が正しく同期化されます。

重要:async(ID) プラグマには、対応する wait(ID) プラグマが必要です。

SDSoC のビルド プロセス

SDSoC のビルド プロセスでは、標準のコンパイルおよびリンク プロセスが使用されます。g++ と同様に、sds++ システム コンパイラはサブプロセスを呼び出してコンパイルおよびリンクを実行します。

次の図に示すように、コンパイル段階では、CPU で実行されるオブジェクト コードのコンパイルだけでなく、Vivado 高位合成 (HLS) ツールを使用したハードウェア関数の IP ブロックへのコンパイルおよびリンク、およびターゲット CPU ツールチェーンを使用した標準オブジェクト ファイル (.o) の作成も実行されます。システムのリンク段階では、すべてのハードウェア関数における呼び出し元/呼び出し先の関係のプログラム解析、各ハードウェア関数呼び出しをインプリメントするアプリケーション特定のハードウェア/ソフトウェア ネットワークの生成が実行されます。sds++ システム コンパイラは、Vivado HLS (関数コンパイラ)、生成されたハードウェア システムをインプリメントする Vivado Design Suite、CPU で実行されるアプリケーション バリアを作成する Arm コンパイラおよび sds++ リンカーなど必要なすべてのツールを呼び出して、SD カード用の完全なブート可能イメージを出力することにより、各ハードウェア関数用のアクセラレータ (スタブ) を呼び出します。

図: SDSoC のビルド プロセス

コンパイル プロセスには、次のタスクが含まれます。

  1. コードが解析され、Arm コアの main アプリケーションがコンパイルされ、各ハードウェア アクセラレータに対して個別にコンパイルが実行されます。
  2. 標準 GNU Arm コンパイル ツールでアプリケーションがコンパイルされ、最終出力としてオブジェクト ファイル (.o) が生成されます。
  3. ハードウェアでアクセラレーションされる関数が HLS ツールで実行され、カスタム ハードウェア作成プロセスが開始し、出力としてオブジェクト ファイル (.o) が生成されます。

コンパイル後のリンク プロセスには、次のタスクが含まれます。

  1. デザイン内のデータ移動が解析され、ハードウェア プラットフォームがアクセラレータを受け入れるよう変更されます。
  2. Vivado Design Suite で合成およびインプリメンテーションが実行されてハードウェア アクセラレータがプログラマブル ロジック (PL) 領域にインプリメントされ、デバイス用のビットストリームが生成されます。
  3. エンベデッド プロセッサ アプリケーションからハードウェア関数を呼び出すため、ソフトウェア イメージがハードウェア アクセス API でアップデートされます。
  4. ボードを ELF (Executable and Linkable Format) ファイルのアプリケーションでブートする統合 SD カード イメージが生成されます。