Main Content

生成されたコード内の固定小数点マルチワード処理

この例では、生成されたコード内で各種マルチワード処理生成を制御する方法を示します。

この例では、次の内容について説明します。

  • マルチワード処理を使用した大きなデータ型のコードの生成方法

  • 想定外のマルチワード コードの阻止方法

シンプルなマルチワード処理

このモデルでは、生成された C コード内でさまざまな整数演算および固定小数点演算がマルチワードになる仕組みを示します。マルチワードのコードは通常、C 言語の [long] より広いデータ型のパラメーターまたは信号によってトリガーされます。

open_system('fxpdemo_multiword_example1');
set_param('fxpdemo_multiword_example1','SimulationCommand','Update');

モデルのコードを生成します。

evalc('slbuild(''fxpdemo_multiword_example1'');'); % Suppress output

生成コードでは、マルチワード処理は関数を使用して実装されます。これらの関数の名前には "MultiWord" が含まれています。

生成されたマルチワード関数の 1 つである MultiWordAdd() について調べてみます。

fid = fopen('fxpdemo_multiword_example1_grt_rtw/fxpdemo_multiword_example1.c') ; ctext = fread(fid, '*char')'; fclose(fid);
match = regexp(ctext, 'void MultiWordAdd.*?\n\}', 'match'); disp(match{1});
void MultiWordAdd(const uint32_T u1[], const uint32_T u2[], uint32_T y[],
                  int32_T n)
{
  int32_T i;
  uint32_T carry = 0U;
  uint32_T u1i;
  uint32_T yi;
  for (i = 0; i < n; i++) {
    u1i = u1[i];
    yi = (u1i + u2[i]) + carry;
    y[i] = yi;
    carry = carry != 0U ? (uint32_T)(yi <= u1i) : (uint32_T)(yi < u1i);
  }
}

この関数は C でマルチワードの加算を実装します。2 つのオペランドと結果はワード数がすべて同じで、加算は一度に 1 ワードずつ行われます。

close_system('fxpdemo_multiword_example1', 0);

Relational Operator ブロック

次の Relational Operator ブロックの例では、生成コード内にマルチワード関数が含まれることが予想されます。2 つの入力データ型は uint32 および ufix32_En3 です。比較に適しているのは、データ型 ufix35_En3 です。このデータ型は両方のオペランドの実際値をすべて表現できるからです。

データ型 ufix35_En3 は、64 ビットの 2 ワード データ型を使用して実装されることが予想されます。

open_system('fxpdemo_multiword_example2');
set_param('fxpdemo_multiword_example2','SimulationCommand','Update');

このモデルは 32 ビットの C の long 型を使用する CPU 用に構成されています。64 ビットのデータ型はマルチワード型になります。

get_param(bdroot, 'ProdBitPerLong')
ans =

    32

モデルのコードを生成して確認します。

evalc('slbuild(''fxpdemo_multiword_example2'');'); % Suppress output
fid = fopen('fxpdemo_multiword_example2_grt_rtw/fxpdemo_multiword_example2.c') ; ctext = fread(fid, '*char')'; fclose(fid);
match = regexp(ctext, 'void fxpdemo_multiword_example2_step.*?\n\}', 'match'); disp(match{1});
void fxpdemo_multiword_example2_step(void)
{
  /* RelationalOperator: '<Root>/LessThan' incorporates:
   *  Inport: '<Root>/In1'
   *  Inport: '<Root>/In2'
   */
  Y = ((U1 <= 536870911U) && ((U1 << 3) < U2));
}

マルチワード コードは生成されませんでした。このコードはシングルワードであり、uint32 の比較データ型を使用します。その結果、比較中に桁落ちが発生することがあります。

Simulink は比較用の内部データ型の要件をバランスよく調整します。この場合、すべてのデータ型がシングル ワードであるため、正確で煩雑な計算を行う代わりに、サイズが小さく高速なコードを生成する効率的なデータ型を実装します。

close_system('fxpdemo_multiword_example2', 0);

この計算の精度を高めるには、次のいずれかの手順を実行します。

  • シングル ワードの比較型を使用して完全な精度で比較できる入力データ型を選択します。16 ビットの型または 2 つのまったく同じ型などです。

  • 少なくとも 1 つの入力にマルチワード型を指定して、(シミュレーションとコード生成の両方で) Simulink がマルチワード型を使用するようにします。こうすると、このブロックにマルチワード処理を使用するように Simulink に通知されます

  • 64 ビット システム対応モデルを構成します。

MATLAB Function ブロック

次に示す MATLAB Function ブロックの例では、すべてシングルワードの場合の計算を示します。マルチワード コードは想定していません。

open_system('fxpdemo_multiword_example3');
set_param('fxpdemo_multiword_example3','SimulationCommand','Update');

mfb = get_param('fxpdemo_multiword_example3/MATLAB Function','MATLABFunctionConfiguration'); mfb.FunctionScript
ans =

    'function y = fcn(u1, u2)
     %#codegen
     
     y = fi(u1 * u2, 0, 32, 0);'

モデルのコードを生成します。

evalc('slbuild(''fxpdemo_multiword_example3'');'); % Suppress output
fid = fopen('fxpdemo_multiword_example3_grt_rtw/fxpdemo_multiword_example3.c') ; ctext = fread(fid, '*char')'; fclose(fid);
match = regexp(ctext, 'void fxpdemo_multiword_example3_step.*?\n\}', 'match'); disp(match{1});
void fxpdemo_multiword_example3_step(void)
{
  uint64m_T tmp;
  uint64m_T tmp_0;

  /* MATLAB Function: '<Root>/MATLAB Function' incorporates:
   *  Inport: '<Root>/In1'
   *  Inport: '<Root>/In2'
   */
  /* MATLAB Function 'MATLAB Function': '<S1>:1' */
  /* '<S1>:1:4' */
  uMultiWordMul(&U1, 1, &U2, 1, &tmp_0.chunks[0U], 2);
  uMultiWordShrNear(&tmp_0.chunks[0U], 2, 3U, &tmp.chunks[0U], 2);

  /* Outport: '<Root>/Out1' incorporates:
   *  MATLAB Function: '<Root>/MATLAB Function'
   */
  fxpdemo_multiword_example3_Y.Out1 = uMultiWord2uLongSat(&tmp.chunks[0U], 2);
}
close_system('fxpdemo_multiword_example3', 0);

モデルに含まれるすべてのデータ型がシングルワードの場合も、マルチワード関数に対する 3 つの呼び出しと 2 つのマルチワード変数が得られました。

MATLAB Function ブロックの固定小数点演算は fimath プロパティの設定によって制御されます。

fimath
ans = 


        RoundingMethod: Nearest
        OverflowAction: Saturate
           ProductMode: FullPrecision
               SumMode: FullPrecision

この fimath は完全精度の ProductMode を指定します。したがって、精度をできるかぎり維持するように乗算が実行されます。乗算データ型の uint64_En3 はマルチワード型として実装されます。

MATLAB コードのコード生成では fimath を操作してマルチワードを制御できます。以下に例を示します。

  • コード効率化の要件を満たすように fimath プロパティを調整します。この例では、'ProductMode''KeepLSB' に、'OverflowAction''Wrap' に設定します。

  • MATLAB Function ブロック内で、特定の計算に合わせて調整された ローカル fimaths を 定義し、グローバル fimath を利用しません。

load_system('fxpdemo_multiword_example4'); % No need to show this model. Only show the MATLAB code.
mfb = get_param('fxpdemo_multiword_example4/MATLAB Function','MATLABFunctionConfiguration'); mfb.FunctionScript
ans =

    'function y = fcn(u1, u2)
     %#codegen
     F = fimath('ProductMode','KeepLSB',...
         'ProductWordLength',32,...
         'OverflowAction','Wrap');
     u1 = setfimath(u1,F);
     u2 = setfimath(u2,F);
     y = fi(u1 * u2,0,32,0);
     '

この fimath によりこちらのコードが生成されます。

evalc('slbuild(''fxpdemo_multiword_example4'');'); % Suppress output
fid = fopen('fxpdemo_multiword_example4_grt_rtw/fxpdemo_multiword_example4.c') ; ctext = fread(fid, '*char')'; fclose(fid);
match = regexp(ctext, 'void fxpdemo_multiword_example4_step.*?\n\}', 'match'); disp(match{1});
void fxpdemo_multiword_example4_step(void)
{
  uint32_T tmp;

  /* MATLAB Function: '<Root>/MATLAB Function' incorporates:
   *  Inport: '<Root>/In1'
   *  Inport: '<Root>/In2'
   */
  /* MATLAB Function 'MATLAB Function': '<S1>:1' */
  /* '<S1>:1:6' */
  /* '<S1>:1:7' */
  /* '<S1>:1:8' */
  tmp = U1 * U2;
  Y1 = (uint32_T)((tmp & 4U) != 0U) + (tmp >> 3);
}
close_system('fxpdemo_multiword_example4', 0);
clear ctext fid match mfb
clear ans

参考

|