コードのアーキテクチャ
Target Language Compiler (TLC) によるコード生成の特定の部分について調べる前に、Target Language Compiler でどのようにコードが生成されるかを簡単なモデルで検討します。次の図から、ブロックではコードを Mdl
ルーチンに配置することがわかります。ここでは MdlOutputs
を示しています。
static void simple_output(int_T tid) { /* Sin Block: '<Root>/Sine Wave' */ simple_B.SineWave_d = simple_P.SineWave_Amp * sin(simple_P.SineWave_Freq * simple_M->Timing.t[0] + simple_P.SineWave_Phase) + simple_P.SineWave_Bias; /* Gain: '<Root>/Gain' */ simple_B.Gain_d = simple_B.SineWave_d * simple_P.Gain_Gain; /* Outport: '<Root>/Out1' */ simple_Y.Out1 = simple_B.Gain_d; }
ブロックには、入力、出力、パラメーター、状態のほか、一般的なプロパティがあります。たとえば、一般に、ブロックの入出力は、ブロック I/O 構造体 (
のタイプの識別子で生成、model
_B
はモデル名) に書き込まれます。また、接続が切断された場合に積分器 (model
) の状態端子に接続したり、あるいは接地を取る場合に接地 (model
_XrtGround
) に接続すると、ブロックの入力は、外部入力構造体 (
) や状態構造体から開始することもできます。また、ブロックの出力は、外部出力構造体 (model
_U
) に接続することもできます。次の図に、ブロックのデータの一般的なマッピングを示します。model
_Y
これで、ブロック オブジェクトがどのようなものか、大まかに理解できたと思います。次に、Target Language Compiler 固有のコード生成プロセスの特定の部分について見ていきます。
コード生成プロセス
コード生成に適したモデルの部分表現 (
) にモデルがコンパイルされた後、コード ジェネレーターで Target Language Compiler が呼び出されます。Target Language Compiler では、コードの生成用に、関数のライブラリを使用して 2 つのクラスのターゲット ファイルを変換します。model
.rtw
システム ターゲット ファイル
ブロック ターゲット ファイル
システム ターゲット ファイルは、特定のターゲット環境に合わせて生成コードの全体的な構造を指定するために使用されます。ブロック ターゲット ファイルは、ユーザー定義の S-Function ブロックを含む Simulink® ブロックの機能を実装するために使用されます。
C MEX、Fortran、および MATLAB® 言語 S-Function のブロック ターゲット ファイルを作成して、ブロックの機能を生成コード本体に完全にインライン化できます。C MEX S-Function は、非インライン化、ラッパーインライン化、または完全インライン化のいずれかにできます。Fortran S-Function は、ラッパーインライン化または完全インライン化のいずれかでなければなりません。
TLC での S-Function インライン化ステータスの判定方法
Target Language Compiler は、
ファイルで S-Function ブロックのエントリが見つかるたびに、S-Function の呼び出しを生成するかインライン化するかを決定しなければなりません。model
.rtw
Fortran および MATLAB 言語 S-Function については、SimStructs
を使用できないためインライン化する必要があります。このインライン化の形式は、完全なブロック ターゲット ファイルか、代わりの C MEX S-Function ソース ファイルを参照する 1 行のブロック ターゲット ファイルのいずれかになります。
C MEX S-Function については、S-Function コードに明示的な関数 mdlRTW()
があるか、現在のブロックに対する現在のターゲット言語用のターゲット ファイルが TLC ファイル検索パスにあれば、Target Language Compiler でインライン化するように選択されます。C MEX S-Function に明示的な関数 mdlRTW()
がある場合、対応するターゲット ファイルがないとエラー状態になります。
S-Function のターゲット ファイルは、ルート名が S-Function と同じで、拡張子が .tlc
でなければなりません。たとえば、sfix_bitop
という C MEX S-Function のターゲット ファイルのファイル名は sfix_bitop.tlc
になります。
インラインと非インラインの S-Function のコード
この例では、sfix_bitop
という名前の C MEX S-Function に焦点を当てます。コード生成オプションは、調整可能な信号として設定されていない信号線に対して信号メモリの再利用を許可するように設定されています。
Bitwise Operator ブロックの生成コードでは、メモリを節約するために、Sum ブロックの出力用に設定された一時変数が再利用されます。その結果、次に示すように 1 行の非常に効率的なコードになります。
/* Bitwise Logic Block: <Root>/Bitwise Logical Operator */ /* [input] OR 'F00F' */ rtb_temp2 |= 0xF00F;
このインライン ブロックには、初期化やセットアップのコードは必要ありません。
このブロックをインライン化しなかった場合、S-Function そのものと各種オプションに対するソース コードが生成コード ベースに追加され、ブロックの SimStruct
データ用に生成コードでメモリが割り当てられ、S-Function コードを初期化、実行、終了するための S-Function のメソッドの呼び出しが生成されることになります。S-Function の関数 mdlOutputs
を実行するために、次のようなコードが生成されます。
/* Level2 S-Function Block: <Root>/Bitwise Logical Operator (sfix_bitop) */ { SimStruct *rts = ssGetSFunction(rtS, 0); sfcnOutputs(rts, tid); }
シミュレーション時と同じように、関数 mdlOutputs
全体が呼び出されて実行されます。それだけではありません。インラインでない S-Function には、登録、初期化、終了のコードもあります。初期化と終了の呼び出しは上記のフラグメントと同様です。さらに、S-Function の登録コードは、1 つの入力端子と 1 つの出力端子だけの場合でも、C コードが 72 行になりファイル
の一部として生成されます。model
_reg.h
/*Level2 S-Function Block: <Root>/Bitwise Logical Operator (sfix_bitop) */ { extern void untitled_sf(SimStruct *rts); SimStruct *rts = ssGetSFunction(rtS, 0); /* timing info */ static time_T sfcnPeriod[1]; static time_T sfcnOffset[1]; static int_T sfcnTsMap[1]; { int_T i; for(i = 0; i < 1; i++) { sfcnPeriod[i] = sfcnOffset[i] = 0.0; } } ssSetSampleTimePtr(rts, &sfcnPeriod[0]); ssSetOffsetTimePtr(rts, &sfcnOffset[0]); ssSetSampleTimeTaskIDPtr(rts, sfcnTsMap); ssSetMdlInfoPtr(rts, ssGetMdlInfoPtr(rtS)); /* inputs */ { static struct _ssPortInputs inputPortInfo[1]; _ssSetNumInputPorts(rts, 1); ssSetPortInfoForInputs(rts, &inputPortInfo[0]); /* port 0 */ { static real_T const *sfcnUPtrs[1]; sfcnUPtrs[0] = &rtU.In1; ssSetInputPortSignalPtrs(rts, 0, (InputPtrsType)&sfcnUPtrs[0]); _ssSetInputPortNumDimensions(rts, 0, 1); ssSetInputPortWidth(rts, 0, 1); } } . . .
これが S-Function のサイズとメソッドの宣言、割り当て、初期化が終わるまで続きます。生成される登録コードの量は、基本的に入力端子および出力端子の数とサイズに比例します。
インラインでない S-Function は一般に生成コードのサイズに大きく影響しますが、インライン化された S-Function では手書きの生成コードに近いサイズとパフォーマンスが得られます。