SDSoC の概要

SDSoC™ 環境では、標準プログラミング言語を使用してハードウェア アクセラレーションされたエンベデッド プロセッサ アプリケーションを開発および配布できます。Eclipse ベースの統合設計環境 (IDE)、エンベデッド プロセッサ アプリケーション用のコンパイラ、およびザイリンクス デバイスのプログラマブル ロジック リソースにインプリメントするハードウェア関数用のコンパイラを使用するエンベデッド プロセッサ開発フローが含まれます。sdscc/sds++ (sds++ と表記) システム コンパイラは、プログラムを解析してソフトウェア関数とハードウェア関数間のデータフローを判断し、ターゲット オペレーティング システムとしてベアメタル、Linux、および FreeRTOS をサポートするアプリケーション特定のシステム オン チップ (SoC) を生成します。sds++ システム コンパイラは、自動的にデータ転送をインプリメントし、ハードウェア アクセラレータとアプリケーション ソフトウェアを同期し、通信と計算をパイプライン処理するハードウェア IP およびソフトウェア制御コードを生成します。

Zynq®-7000 SoC および Zynq UltraScale+™ MPSoC などのザイリンクスが提供する SoC デバイスを使用すると、アプリケーションの一部をハードウェア アクセラレータにインプリメントし、プロセッサで実行される最適化コードよりも何倍も高速に実行できます。ザイリンクス FPGA および SoC デバイスには、プロセッサ上で実行可能などんな関数でもインプリメントできるカスタム アーキテクチャが含まれ、消費電力を抑えてパフォーマンスを向上できるので、従来の CPU/GPU アクセラレーションよりも多くの利点があります。ザイリンクス デバイスでソフトウェア アクセラレーションを使用する利点を把握するには、ハードウェアでアプリケーションの計算負荷の高い部分をアクセラレーションしてみます。これらの関数をカスタム ハードウェアにインプリメントすると、パフォーマンスと消費電力の理想的なバランスを達成できます。SDSoC 環境には、エンベデッド プロセッサ アプリケーションのパフォーマンスをプロファイリングし、アクセラレーションする部分を決定するためのツールおよびレポートが含まれます。キャッシュ、メモリ、バス使用量の自動ランタイム インストルメンテーションも提供され、ハードウェア上でのリアルタイムのパフォーマンスを確認できます。

ハードウェアでアクセラレーションされたアプリケーションを開発する際、ソフトウェア中心のプログラミング ワークフローを使用できるので、FPGA またはハードウェア設計経験がない開発者でも、FPGA アクセラレーションの利点を活用できます。ハードウェア関数はソフトウェア関数と同様に呼び出すことができ、ハードウェア/ソフトウェアの分割はコンパイラで自動的にインプリメントできます。または、Vivado® HLS コンパイラを使用するハードウェア中心のアプローチを使用するか、最適化された RTL アクセラレータを作成およびパッケージして C 呼び出し可能 IP のライブラリとして配布することにより、エンベデッド プロセッサ アプリケーションで使用可能な定義済みのハードウェア アクセラレータを作成することもできます。

SDSoC 環境には、Zynq ベースの標準の開発ボードである ZCU102、ZCU104、ZCU106、ZC702、および ZC706 用の定義済みプラットフォームが含まれます。ZedBoard、MicroZed、Zybo、Avnet エンベデッド ビジョン キット、ビデオおよびイメージング キット、SDR キットなどのサードパーティ プラットフォームも使用できます。特定の市場要件に合わせたカスタム プラットフォームを作成することもできます。SDSoC プラットフォームには、エンベデッド プロセッサ、ハードウェア関数、およびプラットフォームでサポートされるペリフェラルを定義するハードウェア部分と、ブート イメージ、ドライバー、およびアプリケーション コードを定義するソフトウェア部分が含まれます。標準 SDSoC プラットフォームの 1 つからプロジェクトを開始し、デザイン コンセプトを評価して、プロダクション用のカスタム プラットフォームにインプリメントできます。

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 カード イメージが生成されます。

SDSoC 開発手法

SDSoC 環境では、次の 2 つの主なユース ケースがサポートされます。

ソフトウェア中心設計
標準プログラミング言語を使用して記述されたアクセラレーション アプリケーションの開発方法で、計算負荷の高い関数をプログラマブル ロジックにアクセラレーションしたり、アプリケーションをプロファイリングすることによりアプリケーション ボトルネックを特定してアクセラレーションする箇所を見つけたりすることができます。
ハードウェア中心設計
基本的な関数のライブラリなど、エンベデッド プロセッサ アプリケーションで使用するための定義済みアクセラレーション関数の開発方法です。この設計手法はトップダウン アプローチで進められ、ハードウェア関数を C や C++ などの標準プログラミング言語で記述してから、RTL に合成してプログラマブル ロジックにインプリメンテーションするか、標準 RTL デザイン手法を使用してアクセラレーション関数を作成して最適化します。

これら 2 つのユース ケースは組み合わせて使用されることもよくあります。ソフトウェアおよびハードウェア開発者のチームがハードウェア アクセラレータを定義して、それを使用するエンベデッド プロセッサ アプリケーションを開発します。この組み合わせ手法には、異なる開発者または異なる企業が開発したさまざまなアプリケーション コンポーネントが使用されます。ザイリンクス xfOpenCV ライブラリなどのアクセラレーション アプリケーションで使用可能なライブラリから定義済みハードウェア関数を使用でき、またチーム内ですべてのアクセラレータを開発することもできます。

ソフトウェア中心設計

ソフトウェア中心フローを使用したアクセラレーション アプリケーションの開発およびアクセラレータの開発は、まず C または C++ プログラミング言語を使用するところから開始します。コードは、コードのアーキテクチャに注意を払いながら、標準のソフトウェア プログラムとして記述します。ソフトウェア中心の開発フローは、通常次の手順を使用します。

表 1. ソフトウェア中心設計手法のフロー
タスク 手順
エンベデッド プロセッサ アプリケーションをプロファイル。
  • パフォーマンスのベースラインを作成し、ボトルネックおよびアクセラレーションする関数を特定します。
  • アクセラレーションの潜在性を査定し、バジェットと要件を計画。
必要なアクセラレータ コードを記述。
  • 必要な関数を変換して、最適化なしでハードウェア関数コードを定義します。
機能の検証 (必要に応じて繰り返し)。
  • システム エミュレーションを実行して、次を含むアプリケーションおよびアクセラレータのプロファイリング データを生成します。
    • FPGA リソース使用量の見積もり。
    • 全体的なアプリケーション パフォーマンス。
    • アプリケーション呼び出しとアクセラレータの開始/停止時間を示す視覚的なタイムライン。
  • ツール ガイダンスで示された推奨事項を実行します。
パフォーマンスの最適化 (必要に応じて繰り返し)。
  • プロファイル サマリとアプリケーション タイムラインを解析します。
  • システム全体のデータの動きを最適化します。
    • アプリケーションから DDR、DDR からアクセラレータ、およびハードウェア関数インターフェイスからローカル バッファー (バースト)
    • 効率的な転送サイズを使用して DDR バンド幅を最大限に使用
    • 転送のオーバーラップ
    • プリフェッチ
  • パフォーマンスを向上するためアクセラレータ コードを最適化します。
    • タスク レベルの並列処理 (データフロー)
    • 命令レベルの並列処理 (パイプラインおよびループ展開)
    • データ サイズとインターフェイス バンド幅を一致 (任意ビット幅)

ハードウェア中心設計

ハードウェア中心フローでは、まずアクセラレータの開発と最適化に集中し、アドバンス FPGA 設計手法を使用して C 呼び出し可能な IP のライブラリを作成します。これは、Vivado HLS で使用可能な C または C++ でハードウェア関数の定義をするか、RTL 言語を使用するか、Vivado Design Suite で既存の IP デザインまたはブロック デザインから開始します。ハードウェア関数は RTL コードで定義し、ターゲット デバイスのプログラマブル ロジックに合成およびインプリメントします。アクセラレータ アプリケーションで C 呼び出し可能な IP を使用するには、ソフトウェア関数シグネチャが必要です。ない場合は、複数のアプリケーションに使用できるように、関数のコンパイル済みライブラリが作成されます。ハードウェア中心設計手法フローでは、通常次の手順を使用します。

表 2. ハードウェア中心の設計手法
タスク 手順
SDSoC プラットフォーム仕様と Zynq-7000 SoC デバイス仕様およびプログラミング モデルを検討。
  • ハードウェア プラットフォーム、ソフトウェア プラットフォーム、データ ムーバー、AXI インターフェイス、DDR。
サイクル バジェットとパフォーマンス要件を決定。  
アクセラレータ アーキテクチャおよびインターフェイスを定義します。  
アクセラレータを開発。
  • C または C++関数に Vivado HLS を使用します。
  • Vivado Design Suite で従来の RTL 設計方法を使用します。
機能およびパフォーマンスの検証 (必要に応じて繰り返し)。
  • Vivado HLS でハードウェア/ソフトウェア協調シミュレーションを実行します。
  • Vivado シミュレータでロジック シミュレーションを実行します。
リソース使用量を削減して周波数が増加するように結果の質を最適化 (必要に応じて繰り返し)。
  • HLS の場合は、デザイン ルール チェック (DRC) で問題が検出されないことを確認します。
  • 『UltraFast 設計手法ガイド (Vivado Design Suite 用)』 (UG949) の設計手法を使用して Vivado インプリメンテーション フローを実行します。
  • アウト オブ コンテキスト合成および見積もりのベスト プラクティスを使用します。
C 呼び出し可能な IP を SDSoC 環境にインポート。
  • HLS フローの場合は、C または C++ コードを SDSoC プロジェクトにインポートします。
  • RTL フローの場合は、C 呼び出し可能 IP ウィザードを使用します。
  • 詳細は、C 呼び出し可能なライブラリを参照してください。
サンプル アプリケーション コードを開発してハードウェア関数をテスト。
  • C 呼び出し可能な IP と同じインターフェイスのダミー関数を使用してサンプル アプリケーションをテストします。詳細は、C 呼び出し可能なライブラリを参照してください。
ハードウェア関数がアプリケーションと問題なく動作するかを検証 (必要に応じて繰り返し)。
  • デバッグにシステム エミュレーションを使用します。
  • 複雑な内部デバッグ問題にはハードウェア デバッグ手法を使用します。
パフォーマンス用にホスト コードを最適化 (必要に応じて繰り返し)。
  • [Profile Summary] レポート、[Activity Timeline]、ホスト アプリケーションのイベント タイマーを使用してパフォーマンスを測定します。
  • DRC で問題が検出されないことを確認します。
  • 必要なパフォーマンスと同じアクティビティ タイムラインを達成するようにします。
  • 手法: トランザクションのオーバーラップ、アウト オブ オーダー (OOO) 合成、サブデバイス。
ソフトウェア アプリケーション レイヤー (API、share lib、プラグインなど) を完成させる。  

SDSoC を使用したアクセラレーションのベスト プラクティス

次に、SDSoC 環境でアプリケーション コードおよびハードウェア関数を開発する際のベスト プラクティスを示します。

  • 全般的なガイドライン:
    • データを PL 領域にコピーするのではなく、ストリーミングすることで、リソース使用量を削減して並列処理を向上させます。たとえば画像処理アプリケーションでは、画像フレームを 1 つの長いデータ転送にコピーするのではなく、フレームを構成するピクセルの行をストリーミングします。
    • データを何回も転送するのではなく、PL 領域にローカルのデータを再利用することにより、DMA を制限します。
    • 次のような特徴のある関数をアクセラレーションするようにします。
      • データ転送時間に対する計算時間の比が高い。
      • 通信ストリームが予測可能。
      • アクセラレータ外に制御ロジックが不要な自己完結型の制御構造。
    • 複数のアクセラレータ、またはアクセラレータの複数インスタンスを同時に実行することにより、タスク レベルの並列処理を増加できる可能性を探します。
  • ソフトウェア中心設計フローの場合:
    • 配列サイズを把握し、sds_alloc()/sds_free() を使用して物理的に隣接したメモリを割り当て/割り当て解除するなど優れたメモリ管理手法を使用することにより、デバイス フットプリントを削減して、ベースライン パフォーマンスを向上します。
    • システム エミュレーションを使用してコードを頻繁に検証することにより、論理的に正しいかどうかを確認します。
    • ハードウェア関数を個別の C/C++ ファイルに記述し、インクリメンタルな変更に対してデザイン全体をコンパイルし直さなくてすむようにします。
  • ハードウェア中心設計フローの場合:
    • IP またはアクセラレータの AXI4 インターフェイス オフセット、およびどの関数定義パラメーターにどのデータ型が必要かを把握しておきます。インターフェイスは、バイト アライメントする必要があります。
    • 元の Vivado IP プロジェクトを維持して変更がすばやくインプリメントされるようにします。
    • スタティック ライブラリ (.a) ファイルと該当するヘッダー ファイルを一緒に保持しておきます。