次の図に、ここに示すコード例の制御ロジックの抽出と I/O ポートのインプリメンテーションを示します。
void foo(int in[3], char a, char b, char c, int out[3]) {
int x,y;
for(int i = 0; i < 3; i++) {
x = in[i];
y = a*x + b + c;
out[i] = y;
}
}
このコード例では前の例と同じ演算が実行されますが、演算が for ループ内で実行され、関数引数のうちの 2 つが配列である点が異なります。結果のデザインでは、コードがスケジューリングされたときに for ループ内のロジックが 3 回実行されます。高位合成では C コードから制御ロジックが自動的に抽出され、RTL デザインでこれらの演算を順序付ける有限ステート マシン (FSM) が作成されます。最終的な RTL デザインでは、最上位関数の引数がポートになります。char
型のスカラー変数は標準の 8 ビット データ バス ポートにマップされます。in
および out
などの配列引数には、データ コレクション全体が含まれます。
高位合成では、配列はデフォルトでブロック RAM に合成されますが、FIFO、分散 RAM、個別のレジスタなどに合成することも可能です。最上位関数で配列を引数として使用すると、ブロック RAM が最上位関数外にあると想定され、データ ポート、アドレス ポート、必要なチップ イネーブルまたはライト イネーブル信号など、デザイン外のブロック RAM にアクセスするためのポートが自動的に作成されます。
FSM では、データをいつレジスタに格納するかと、I/O 制御信号のステートが制御されます。FSM は C0
ステートで開始し、次のクロックで C1
ステートに遷移し、その後 C2
ステート、C3
ステートに遷移します。そして C1
(および C2
、C3
) を 3 回反復してから、C0
ステートに戻ります。
C0
、{C1, C2,
C3}
、{C1, C2, C3}
、{C1,
C2, C3}
の後、C0
に戻ります。
b
と c
の加算が必要なのは 1 回だけなので、この演算は for ループ外に出され、C0
ステートに挿入されます。この加算結果は、C3
ステートに遷移するたびに再利用されます。
デザインでは in
のデータが読み出され、x
に格納されます。FSM の C1
で最初の要素のアドレスが生成されます。また、C1
ステートでは、C1
、C2
、C3
ステートを何回反復する必要があるのかを知るために、加算器がインクリメントされます。C2
ステートでは、ブロック RAM から in のデータが返され、変数 x
として格納されます。
計算に必要なその他の値が a
ポートから読み出され、最初の y
出力が生成されます。FSM で正しいアドレスと制御信号が生成され、この値がブロック外に格納されます。この後デザインは C1
ステートに戻り、配列/ブロック RAM の in
から次の値が読み出されます。このプロセスは、すべての出力が書き込まれるまで継続されます。そして C0
ステートに戻り、b
と c
の次の値が読み出されて、プロセスが再度実行されます。