MCode - 2022.1 日本語

Vitis Model Composer ユーザー ガイド (UG1483)

Document ID
UG1483
Release Date
2022-05-26
Version
2022.1 日本語

ザイリンクス MCode ブロックは、Simulink 内でユーザー提供の MATLAB 関数を {3} 内で実行するためのコンテナーです。ブロックのパラメーターは、M 関数名を指定します。このブロックは、Simulink シミュレーション中に M コードを実行してブロック出力を計算します。ハードウェアが生成されるときに、同じコードが等価のビヘイビアー VHDL/Verilog に変換されます。

ブロックの Simulink® インターフェイスは、MATLAB 関数シグネチャおよびブロックのマスク パラメーターからから導出されます。各パラメーターに関数への入力ポートが 1 つあり、関数が返す値ごとに 1 つの出力ポートがあります。ポート名と順序は、パラメーターと戻り値の名前と順序に対応します。

MCode ブロックは、算術演算関数、有限ステート マシン、制御ロジックのインプリメントに便利な MATLAB 言語の限定されたサブセットをサポートしています。

MCode ブロックでは、次の 3 つの主要なコーディング ガイドラインに従う必要があります。

  • ブロックのすべての入力と出力は、ザイリンクス固定小数点型である必要がありす。
  • ブロックには、少なくとも 1 つの出力ポートが必要です。
  • ブロックのコードは、MATLAB パス上、またはブロックを使用するモデルと同じディレクトリにある必要があります。

下に説明する例は、入力の最大値を返す関数 xlmax で構成されています。2 番目の例は、単純な算術演算方法を示します。3 番目の例は、有限ステート マシンのビルド方法を示します。

MCode ブロックの設定

MCode ブロックの MATLAB Function パラメーターは、ブロックの M コード関数の名前を指定します。この関数は、このパラメーターを設定する時点で、次の 3 つのディレクトリのいずれかに存在している必要があります。可能な 3 つのディレクトリは、次のとおりです。

  • モデル ファイルのあるディレクトリ。
  • モデル ディレクトリの private というサブディレクトリ。
  • MATLAB パスのディレクトリ。

ブロック アイコンには、M 関数の名前が表示されます。これを説明するため、関数 xlmax を含むファイル xlmax.m を考えてみます。


function z = xlmax(x, y) 
  if x > y 
    z = x; 
  else 
  z = y; 
  end 

関数 xlmax に基づく MCode ブロックには、入力ポート x および y と出力ポート z があります。

次の図に、MCode ブロックを関数 xlmax を使用するように設定する方法を示します。

図 1. xlmax 関数

モデルがコンパイルされると、xlmax MCode ブロックは次の図のようになります。

図 2. xlmax MCode ブロック

MATLAB 言語サポート

MCode ブロックでは、次の MATLAB 言語がサポートされています。

  • 代入文
  • 単純および複合 if/else/elseif end 文
  • switch
  • 加算および減算のみを使用する算術演算式
  • 加算
  • 減算
  • 乗算
  • 2 のべき乗での除算
  • 比較演算子:
    < 小なり
    <= 以下
    > 大なり
    >= 以上
    == 等号 (=)
    ~= 不等号
  • 論理演算子:
    & AND
    | OR
    ~ NOT

MCode ブロックでは、次の MATLAB 関数がサポートされています。

  • 型変換。唯一サポートされるデータ型は、ザイリンクス固定小数点型の xfix です。このデータ型への返還には、xfix() 型変換関数が使用されます。変換は整数で暗示的に実行されますが、浮動小数点定数では明示的に実行する必要があります。値はすべてスカラーにする必要があります。配列はサポートされません。
  • xfix プロパティを返す関数:
    xl_nbits() ビット数を返します。
    xl_binpt() 2 進小数点の位置を返します。
    xl_arith() 演算型を返します。
  • ビット単位の論理関数:
    xl_and() ビット単位 AND
    xl_or() ビット単位 OR
    xl_xor() ビット単位 XOR
    xl_not() ビット単位 NOT
  • シフト関数: xl_lsh() および xl_rsh()
  • スライス関数: xl_slice()
  • 連結関数: xl_concat()
  • 再解釈関数: xl_force()
  • 内部状態変数: xl_state()
  • MATLAB 関数
    disp() 変数値を表示します。
    error() メッセージを表示し、関数を中止します。
    isnan() 数値が NaN であるかどうかをテストします。
    NaN() 非数 (NaN) を返します。
    num2str() 数値を文字列に変換します。
    ones(1,N) 1 の 1-by-N ベクターを返します。
    pi() pi を返します。
    zeros(1,N) 0 の 1-by-N ベクターを返します。
Data Types

xfix 型には、符号なし固定小数点 (xlUnsigned)、符号付き固定小数点 (xlSigned)、ブール (xlBoolean) の 3 種類があります。これらのデータ型に対する算術演算は、符号付きおよび符号なし固定小数点値を生成します。比較演算は、ブール値の結果を生成します。比較オペランドは、データ型を混合することが理にかなっていれば、どの xfix 型にすることもできます。ブール変数は、ブール変数とは比較できますが、固定小数点数とは比較できません。ブール変数は、算術演算子とは互換性がありません。論理演算子は、ブール変数にのみ適用可能です。すべての演算は全精度、たとえば、情報が失われないために必要な最小限の精度で実行されます。

リテラル定数
整数、浮動小数点、およびブール型リテラルがサポートされます。整数リテラルは、2 進小数点の位置が 0 である適切な幅の xfix 値に自動的に変換されます。浮動小数点リテラルは、xfix() 変換関数を使用して明示的に xfix 型に変換する必要があります。定義済みの MATLABtrue および false は、自動的にブール型のリテラル値に変換されます。
代入
代入の左辺には、1 つの変数のみを指定できます。変数は、複数回代入できます。
制御フロー

if 文の条件式は、ブール値に評価される必要があります。switch 文には、case 節と otherwise 節を含めることができます。switch のセレクターとその case の型に互換性がある必要があります。そのため、case がブール型であれば、セレクターもブール型にできます。switch 文のすべての case は定数である必要があります。また、case を入力値に依存させることはできません。

制御文の複数の分岐で同じ変数に代入する場合、代入する型に互換性があることが必要です。次に例を示します。


if (u > v)
  x = a;
else 
  x = b; 
end

これは、ab が共にブール型または演算型である場合のみ許容されます。

Constant Expressions

論理式は、その値が入力引数の値に依存していなければ、定数です。たとえば、変数 c が次のように定義されているとします。


a = 1;
b = a + 2;
c = xfix({xlSigned, 10, 2}, b + 3.345);
これは、定数が必要などのコンテキストでも使用できます。
xfix() 変換

xfix() 変換関数は、doublexfix に変換したり、xfix を異なる特性を持つ別の xfix に変換します。変換関数の呼び出しは、次のようになります。


x = xfix(type_spec, value)

ここで、xxfix を受け取る変数です。type_spec は作成する xfix のタイプを指定するセル配列で、value は演算の対象となる値です。 value には、浮動小数点または xfix 型を使用できます。type_spec のセル配列は、通常の MATLAB 方式で波かっこを使用して定義します。次に例を示します。


xfix({xlSigned, 20, 16, xlRound, xlWrap}, 3.1415926)

この例は、xfix の近似値 piを返します。近似値は符号付きで、20 ビット (小数部 16 ビット) を占め、オーバーフローが発生した場合は丸めおよび折り返しによって量子化されます。

type_spec は、1、3、または 5 要素で構成されています。一部の要素は省略できます。要素を省略した場合は、要素のデフォルト設定が使用されます。要素は、データ型 (data type)、幅 (width)、2 進小数点の位置 (binary point position)、量子化モード (quantization mode)、およびオーバーフロー モード (overflow mode) をこの順序で指定します。data type には、xlBooleanxlUnsigned、または xlSigned を指定できます。データ型が xlBoolean の場合、追加の要素は不要なので、指定しないでください。ほかのデータ型では、width および binary point position を指定する必要があります。quantization および overflow mode はオプションですが、いずれかを指定した場合は、もう一方も指定する必要があります。量子化には、xlTruncatexlRound、および xlRoundBanker を指定できます。デフォルトは xlTruncate です。オーバーフローには、xlWrapxlSaturate、および xlThrowOverflow を指定できます。xlThrowOverflow を指定している場合にシミュレーション中にオーバーフローが発生すると、例外が発生します。

type_spec のすべての値は、コンパイル時に供給する必要があります。また、type_spec を関数の入力に依存させることはできません。

次に、xfix() 変換のより複雑な例を示します。


width = 10, binpt = 4; 
z = xfix({xlUnsigned, width, binpt}, x + y);

この x への代入は、量子化に xlTruncate とオーバーフローに xlWrap を使用して、x + y を 10 ビット幅で小数部が 4 ビットの符号なし固定小数点数に変換した結果です。

複数の xfix() 呼び出しに同じ type_spec 値が必要な場合、type_spec を変数に代入し、その変数を xfix() 呼び出しで使用できます。

たとえば、次が可能です。

proto = {xlSigned, 10, 4};
x = xfix(proto, a);
y = xfix(proto, b);

xfix Properties: xl_arith, xl_nbits, and xl_binpt

xfix の各値には、演算型、ビット幅、および 2 進小数点位置の 3 つのプロパティがあります。MCode ブロックには、固定小数点値のこれらのプロパティを取得する 3 つの関数があります。これらの関数の結果は定数であり、Simulink でのモデルのコンパイル時に評価されます。

関数 a = xl_arith(x) は、入力値 x の演算型を返します。戻り値は、xlUnsigned の場合は 1xlSigned の場合は 2xlBoolean の場合は 3 です。

関数 n = xl_nbits(x) は、入力値 x の幅を返します。

関数 b = xl_binpt(x) は、入力値 x の 2 進小数点の位置を返します。

Bit-wise Operators: xl_or, xl_and, xl_xor, and xl_not

MCode ブロックには、ビット単位の論理演算を実行する xl_orxl_andxl_xor、および xl_not の 4 つのビルトイン関数があります。

関数 xl_orxl_andxl_xor は、それぞれビット単位の論理和 (OR)、論理積 (AND)、および排他的論理和 (XOR) 演算を実行します。各関数の形式は次のとおりです。


x = xl_op(a, b, …).

各関数は、少なくとも 2 つの固定小数点値を取り、固定小数点値を返します。すべての入力引数は、2 進小数点の位置で揃えられます。

関数 xl_not は、ビット単位の論理否定 (NOT) 演算を実行します。形式は x = xl_not(a) です。入力引数として 1 つの xfix 値を取り、固定小数点値を返します。

次に、これらの関数呼び出しの例を示します。


X = xl_and(a, b);
Y = xl_or(a, b, c);
Z = xl_xor(a, b, c, d);
N = xl_not(x);
Shift Operators: xl_rsh, and xl_lsh

関数 xl_lsh および xl_rsh は、固定小数点値のビット シーケンスをシフトします。関数の形式は次のとおりです。

x = xl_lsh(a, n) および x = xl_rsh(a, n)。ここで、axfix 値、n はシフトするビット数です。

固定小数点数を n ビット数だけ左または右にシフトします。右シフト (xl_rsh) は、固定小数点値を最下位ビットの方向に移動します。左シフト (xl_lsh) 関数は、固定小数点値を最上位ビットの方向に移動します。どちらのシフト関数も全精度シフトです。ビットは破棄されず、シフトされた 2 進小数点の位置に合わせて、必要に応じて出力の精度が調整されます。

次に例を示します。


% left shift a 5 bits 
a = xfix({xlSigned, 20, 16, xlRound, xlWrap}, 3.1415926)
b = xl_rsh(a, 5); 

出力 b は、21 ビットで 2 進小数点がビット 21 に位置する xlSigned 型です。

Slice Function: xl_slice

関数 xl_slice は、固定小数点値のビットのシーケンスにアクセスします。関数の形式は次のとおりです。


x = xl_slice(a, from_bit, to_bit).

固定小数点数の各ビットには、LSB の 0 から MSB まで順にインデックスが付けられます。たとえば、2 進小数点位置が 0 の 8 ビット幅の値では、LSB のインデックスは 0、MSB のインデックスは 7 になります。このブロックは、from_bit または to_bit 引数が入力値のビット インデックス範囲外である場合にエラーを返します。関数呼び出しの結果は、符号なし固定小数点値で、2 進小数点位置は 0 です。

次に例を示します。


% slice 7 bits from bit 10 to bit 4
b = xl_slice(a, 10, 4); 
% to get MSB 
c = xl_slice(a, xl_nbits(a)-1, xl_nbits(a)-1); 
Concatenate Function: xl_concat

関数 x = xl_concat(hi, mid, ..., low) は、複数の固定小数点値を連結して 1 つの固定小数点値を形成します。最初の入力引数が最上位ビットとなり、最後の入力引数が最下位ビットとなります。出力は、符号なしの固定小数点値で、2 進小数点位置は 0 です。

Reinterpret Function: xl_force

関数 x = xl_force(a, arith, binpt) は、出力を新しい演算型 arith、新しい 2 進小数点位置 binpt の新しい型に変換します。arith 引数は、xlUnsignedxlSigned、または xlBoolean のいずれかに指定します。binpt 引数は、0 からビット幅までの値にする必要があります。そうでない場合はエラーが返されます。

State Variables: xl_state

MCode ブロックは、1 つのシミュレーション ステップから次のステップにその値を保持する内部状態変数を持つことができます。状態変数は、MATLAB キーワード persistent を使用して宣言され、xl_state 関数呼び出しを使用して最初に代入する必要があります。

次のコードは、4 ビット アキュムレータを記述しています。


function q = accum(din, rst)
  init = 0;

  persistent s, s = xl_state(init, {xlSigned, 4, 0});
  q = s;
  if rst
    s = init;
 else
    s = s + din;
 end

状態変数 s は persistent を使用して永続的と宣言され、s への最初の代入値は xl_state 呼び出しの結果です。xl_state 関数には、2 つの引数があります。最初の引数は初期値で、定数値を指定する必要があります。2 番目の引数は状態変数の精度です。xfix 関数呼び出しに記述されているように、型セル配列を使用できます。また、xfix 値にすることも可能です。上記のコードでは、s = xl_state(init, din) である場合、状態変数 s は din を精度として使用します。xl_state 関数は、永続的な変数に代入する必要があります。

xl_state 関数は、次のように動作します。

  1. シミュレーションの最初のサイクルでは、xl_state 関数が状態変数を指定の精度に初期化します。
  2. シミュレーションの次のサイクルでは、xl_state 関数が最後のクロック サイクルから残っている状態値を取得し、指定された精度の対応する変数に値を代入します。

v = xl_state(init, precision) は、状態変数の値を返します。最初の入力引数 init は初期値、2 番目の引数 precision はこの状態変数の精度です。引数 precision には、{type, nbits, binpt} または {type, nbits, binpt, quantization,overflow} 形式のセル配列を指定できます。precision 引数には、xfix 値を指定することも可能です。

v = xl_state(init, precision, maxlen) は、ベクター オブジェクトを返します。ベクターは init で初期化され、最大長は maxlen です。ベクターは init で初期化されます。たとえば、v = xl_state(zeros(1, 8), prec, 8) は 8 個の 0 のベクターを作成、v = xl_state([], prec, 8) は最大長が 8 の空のベクターを作成、v = xl_state(0, prec, 8) は 0 を 1 つ含む最大長が 8 のベクターを作成します。

概念的には、ベクター状態変数は両端キューです。2 つの端があり、先頭はアドレス 0 の要素、末尾は (長さ - 1) の要素です。

ベクターに使用可能なメソッドは、次のとおりです。

val = v(idx); アドレス idx の要素の値を返します。
v(idx) = val; アドレス idx の要素に val を代入します。
f = v.front; 先頭の端の値を返します。ベクターが空の場合にエラーを返します。
v.push_front(val); val を先頭にプッシュし、ベクター長を 1 増加します。ベクターがフルの場合にエラーを返します。
v.pop_front; 先頭から要素を 1 つポップし、ベクター長を 1 削減します。ベクターが空の場合にエラーを返します。
b = v.back; 末尾の端の値を返します。ベクターが空の場合にエラーを返します。
v.push_back(val); val を末尾にプッシュし、ベクター長を 1 増加します。ベクターがフルの場合にエラーを返します。
v.pop_back; 末尾から要素を 1 つポップし、ベクター長を 1 削減します。ベクターが空の場合にエラーを返します。
v.push_front_pop_back(val); val を先頭にプッシュし、末尾から 1 要素ポップします。これはシフト演算です。ベクター長は変わりません。この演算を実行するには、ベクターが空でないことが必要です。
full = v.full; ベクターがフルの場合は true を返し、それ以外の場合は false を返します。
empty = v.empty; ベクターが空の場合は false を返し、それ以外の場合は true を返します。
len = v.length; ベクター内の要素の数を返します。

状態変数をクエリするベクターのメソッドは、クエリ メソッドと呼ばれます。戻り値があります。クエリ メソッドには、v(idx)v.frontv.backv.fullv.emptyv.lengthv.maxlen があります。状態変数を変更するベクターのメソッドは、アップデート メソッドと呼ばれます。アップデート メソッドには戻り値はありません。アップデート メソッドには、v(idx) = valv.push_front(val)v.pop_frontv.push_back(val)v.pop_backv.push_front_pop_back(val) があります。シミュレーションサイクル中、ベクターのすべてのクエリ メソッドは、アップデート メソッドを呼び出す前に呼び出す必要があります。この規則を守らないと、モデルのコンパイル中にエラーが返されます。

MCode ブロックは、状態変数の使用方法に応じて、ベクター状態変数をベクター レジスタ、遅延ライン、アドレス指定可能シフト レジスタ、シングル ポート ROM、またはシングル ポート RAM にマップできます。xl_state 関数は、MATLAB 1 次元配列を 0 インデックスの定数配列に変換するためにも使用できます。MCode ブロックでベクター状態変数を FPGA にマップできない場合、モデル ネットリスト時にエラー メッセージが表示されます。次に、ベクター状態変数の使用例を示します。

Delay Line

次の関数の状態変数は、遅延ラインにマップされます。


function q = delay(d, lat)
  persistent r, r = xl_state(zeros(1, lat), d, lat);
  q = r.back;
  r.push_front_pop_back(d);

Line of Registers

次の関数の状態変数は、レジスタのラインにマップされます。


function s = sum4(d)
  persistent r, r = xl_state(zeros(1, 4), d);
  S = r(0) + r(1) + r(2) + r(3);
  r.push_front_pop_back(d);

Vector of Constants

次の関数の状態変数は、定数のベクターにマップされます。


function s = myadd(a, b, c, d, nbits, binpt)
  p = {xlSigned, nbits, binpt, xlRound, xlSaturate};
  persistent coef, coef = xl_state([3, 7, 3.5, 6.7], p);
  s = a*coef(0) + b*coef(1) + c*coef(2) + c*coef(3);

Addressable Shift Register

次の関数の状態変数は、アドレス指定可能シフト レジスタにマップされます。


function q = addrsr(d, addr, en, depth)
  persistent r, r = xl_state(zeros(1, depth), d);
  q = r(addr);
  if en
 r.push_front_pop_back(d);
  end

シングル ポート ROM

次の関数の状態変数は、シングル ポート ROM にマップされます。


function q = addrsr(contents, addr, arith, nbits, binpt)
  proto = {arith, nbits, binpt};
  persistent mem, mem = xl_state(contents, proto);
  q = mem(addr);
Single Port RAM

次の関数の状態変数は、ファブリックのシングル ポート RAM (分散 RAM) にマップされます。


function dout = ram(addr, we, din, depth, nbits, binpt)
  proto = {xlSigned, nbits, binpt};
  persistent mem, mem = xl_state(zeros(1, depth), proto);
  dout = mem(addr);
  if we
    mem(addr) = din;
  end

次の関数の状態変数は、シングル ポート RAM としてブロック RAM にマップされます。


function dout = ram(addr, we, din, depth, nbits, binpt,ram_enable)
  proto = {xlSigned, nbits, binpt};
  persistent mem, mem = xl_state(zeros(1, depth), proto);
  persistent dout_temp, dout_temp = xl_state(0,proto);
  dout = dout_temp;
  dout_temp = mem(addr);
  if we
    mem(addr) = din;
  end

MATLAB 関数

disp()

論理式の値を表示します。MATLAB コンソールの表示を確認するには、MCode の [Block Parameters] ダイアログ ボックスの Advanced タブで Enable printing with disp をオンにする必要があります。引数には、文字列、xfix 値、または MCode 状態変数を指定できます。引数が xfix 値の場合、型、2 進数値、倍精度値を表示します。たとえば、変数 xxfix({xlSigned, 10, 7}, 2.75) を代入すると、disp(x) は次の行を表示します。


type: Fix_10_7, binary: 010.1100000, double: 2.75

引数がベクター状態変数の場合、disp() は、すべての要素の型、最大長、現在の長さ、およびバイナリ値と倍精度値を出力します。各シミュレーション ステップに対して、Enable printing with disp がオンで disp() 関数が呼び出されたときに、対応するブロックのタイトル行が表示されます。タイトル行には、ブロック名、Simulink シミュレーション時間、FPGA クロック番号が表示されます。

次の MCode 関数に、disp() 関数の使用例を複数示します。


function x = testdisp(a, b)
persistent dly, dly = xl_state(zeros(1, 8), a);
persistent rom, rom = xl_state([3, 2, 1, 0], a);
disp('Hello World!');
disp(['num2str(dly) is ', num2str(dly)]);
disp('disp(dly) is ');
disp(dly);
disp('disp(rom) is ');
disp(rom);
a2 = dly.back;
dly.push_front_pop_back(a);
x = a + b;
disp(['a = ', num2str(a), ', ', ...
'b = ', num2str(b), ', ', ...
'x = ', num2str(x)]);
disp(num2str(true));
disp('disp(10) is');
disp(10);
disp('disp(-10) is');
disp(-10);
disp('disp(a) is ');
disp(a);
disp('disp(a == b)');
disp(a==b);

最初のシミュレーション ステップの結果、次の行が表示されます。


xlmcode_testdisp/MCode (Simulink time: 0.000000, FPGA clock: 0)
Hello World!
num2str(dly) is [0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 
0.000000, 0.000000]
disp(dly) is 
type: Fix_11_7,
maxlen: 8,
length: 8,
0: binary 0000.0000000, double 0.000000,
1: binary 0000.0000000, double 0.000000,
2: binary 0000.0000000, double 0.000000,
3: binary 0000.0000000, double 0.000000,
4: binary 0000.0000000, double 0.000000,
5: binary 0000.0000000, double 0.000000,
6: binary 0000.0000000, double 0.000000,
7: binary 0000.0000000, double 0.000000,
disp(rom) is 
type: Fix_11_7,
maxlen: 4,
length: 4,
0: binary 0011.0000000, double 3.0, 
1: binary 0010.0000000, double 2.0, 
2: binary 0001.0000000, double 1.0, 
3: binary 0000.0000000, double 0.0, 
a = 0.000000, b = 0.000000, x = 0.000000
1
disp(10) is
type: UFix_4_0, binary: 1010, double: 10.0
disp(-10) is
type: Fix_5_0, binary: 10110, double: -10.0
disp(a) is 
type: Fix_11_7, binary: 0000.0000000, double: 0.000000
disp(a == b)
type: Bool, binary: 1, double: 1
error()

メッセージを表示し、関数を中止します。この関数の詳細は、MATLAB ヘルプを参照してください。MCode ブロックでは、メッセージの書式設定はサポートされません。次に例を示します。

if latency <=0
  error('latency must be a positive');
end
isnan()

非数 (NaN) の場合は true を返します。isnan(X) は、X が非数 (NaN) の場合に true を返します。X には、倍精度値またはザイリンクス固定小数点のスカラー値を指定する必要があります。この関数は、ベクターまたは行列ではサポートされません。次に例を示します。


if isnan(incr) & incr == 1
  cnt = cnt + 1;
end
NaN()

NaN() 関数は、非数 (NaN) の IEEE 算術表現を生成します。0.0/0.0 や inf-inf などの数学的に定義されていない演算を実行すると、NaN が得られます。NaN(1,N) は、1-by-N ベクターの NaN 値を生成します。次に、NaN の使用例を示します。

if x < 0
  z = NaN;
else
  z = x + y;
end
num2Str()

数値を文字列に変換します。num2str(X) は、X を文字列に変換します。X には、倍精度のスカラー値、ザイリンクス固定小数点値、またはベクター状態変数を指定できます。デフォルトの桁数は、X の要素の大きさに基づきます。次に num2str の例を示します。


if opcode <=0 | opcode >= 10
  error(['opcode is out of range: ', num2str(opcode)]);
end
ones()

ones() 関数は、指定した数の 1 を生成します。ones(1,N) は、1 の 1-by-N ベクターを生成します。ones(M,N)M は 1 にする必要があります。これは通常、xl_state() 関数呼び出しで使用します。たとえば次の行は、[1, 1, 1, 1] で初期化される 1-by-4 ベクター状態変数を生成します。


persitent m, m = xl_state(ones(1, 4), proto)
zeros()

zeros() 関数は、指定した数の 0 を生成します。zeros(1,N) は、1-by-N ベクターを生成します。zero(M,N)M は 1 にする必要があります。これは通常、xl_state() 関数呼び出しで使用します。たとえば次の行は、[0, 0, 0, 0] で初期化される 1-by-4 ベクター状態変数を生成します。


persitent m, m = xl_state(zeros(1, 4), proto)
FOR Loop

FOR 文は完全に展開されます。次の関数は、n 個のサンプルの合計を生成します。


function q = sum(din, n)
  persistent regs, regs = xl_state(zeros(1, 4), din);
  q = reg(0);
  for i = 1:n-1
    q = q + reg(i);
  end
  regs.push_front_pop_back(din);

次の関数は、ビットの反転を実行します。


function q = bitreverse(d)
  q = xl_slice(d, 0, 0);
  for i = 1:xl_nbits(d)-1
    q = xl_concat(q, xl_slice(d, i, i));
  end
Variable Availability

MATLAB コードはシーケンシャルであり、文は順番に実行されます。MCode ブロックでは、すべての可能な実行パスで、変数を使用する前に値が代入されることが必要です (代入の左辺として使用される場合を除く)。その場合、変数は使用可能です。M コード関数が使用可能になっていない変数にアクセスすると、MCode ブロックでエラーが生成されます。

次の M コードがあるとします。


function [x, y, z] = test1(a, b)
  x = a;
  if a>b
    x = a + b; y = a; 
  end
  switch a
    case 0 
      z = a + b; 
    case 1 
      z = a - b;
  end

この例では、ab、および x は使用可能ですが、yz は使用できません。変数 yif 文に else がないため使用できず、変数 zswitch 文に otherwise がないため使用できません。

MCode のデバッグ

MCode をデバッグするには、次の 2 つの方法があります。1 つはコードに disp() 関数を挿入して表示をイネーブルにする方法で、もう 1 つは MATLAB デバッガーを使用する方法です。disp() 関数の使用方法は、このトピックの disp() セクションを参照してください。

MATLAB デバッガーを使用するには、MCode の [Block Parameters] ダイアログ ボックスの Advanced タブで Enable MATLAB debugging をオンにする必要があります。すると、MATLAB 関数を MATLAB エディターで開き、ブレークポイントを設定して、M 関数をデバッグできるようになります。ただし、スクリプトを変更するたびに、MATLAB コンソールで clear functions コマンドを実行する必要があることに注意してください。

M 関数をデバッグするには、まず MCode の [Block Parameters] ダイアログ ボックスの Advanced タブで Enable MATLAB debugging をオンにし、OK または Apply をクリックします。

図 3. [Enable MATLAB Debugging] チェック ボックス

MATLAB エディターで M ファイルを編集し、必要に応じてブレークポイントを設定します。

図 4. ブレークポイントの設定

Simulink シミュレーション中、設定したブレークポイントに到達すると MATLAB デバッガーは停止します。

図 5. ブレークポイントで停止

デバッグ中、MATLAB コンソールで変数名を入力すると値を確認できます。

図 6. 変数の確認

MCode ブロックの関数を MATLAB デバッガーから実行する場合に考慮する必要のある特殊なケースが 1 つあります。MCode ブロック内の switch/case 式は xfix 型にする必要がありますが、MATLAB コンソールから switch/case 式を実行する場合は、double または char 型にする必要があります。MATLAB コンソールで実行しやすくするため、double() への呼び出しを追加する必要があります。たとえば、次のような場合を考えます。


switch i
  case 0
    x = 1
  case 1
    x = 2
  end

ixfix 型です。コンソールから実行するには、このコードを次のように変更する必要があります。


switch double(i)
  case 0
    x = 1
  case 1
    x = 2
end

double() 関数呼び出しは、M コードがコンソールから実行された場合にのみ使用されます。MCode ブロックでは、double() 呼び出しは無視されます。

Passing Parameters

異なる MCode ブロックで同じ M 関数を使用して、M 関数に異なるパラメーターを渡すことにより、各ブロックの動作を異なるものにすることが可能です。これには、入力引数を値にバインドします。入力引数をバインドするには、ブロックの [Block Parameters] ダイアログ ボックスの Interface タブを選択します。これらの引数を値にバインドすると、これらの M 関数引数は MCode ブロックの入力ポートとして表示されなくなります。

次のような M 関数があるとします。


function dout = xl_sconvert(din, nbits, binpt)
proto = {xlSigned, nbits, binpt};
dout = xfix(proto, din);

次の図に、2 つの異なる xl_sconvert ブロックの din 入力に設定されているバインディングを示します。

図 7. dim のバインディング例 1
図 8. dim のバインディング例 2

次の図に、モデルをコンパイルした後のブロックを示します。

図 9. ブロック図


パラメーターは、倍精度値または論理値のいずれかである必要があります。

Optional Input Ports

パラメーターを渡す機構により、MCode ブロックにオプションの入力ポートを持つようにできます。次のような M 関数があるとします。


function s = xl_m_addsub(a, b, sub)
  if sub
    s = a - b;
  else
    s = a + b;
  end

subfalse に設定すると、この M 関数を使用する MCode ブロックは入力ポート ab を持ち、全精度加算を実行します。空のセル配列 {} に設定されている場合、ブロックは入力ポート ab、および sub を持ち、入力ポート sub の値によって全精度加算または減算を実行します。

次の図に、同じ xl_m_addsub 関数を使用するブロックで、入力ポートが 2 つのものと 3 つのものを示します。

図 10. 同じ xl_m_addsub 関数を使用する 2 つのブロック

Constructing a State Machine

MCode ブロックを使用してステート マシンを構築する方法は 2 つあります。1 つは、MATLAB 関数を使用してステートレス遷移関数を指定し、MCode ブロックと 1 つ以上のステート レジスタ ブロックをペアにする方法です。通常、MCode ブロックは次のステートを表す値でレジスタを駆動し、レジスタは現在のステートを MCode ブロックに供給します。これを機能させるには、MCode ブロックから出力されるステートの精度がスタティック、つまりブロックへの入力からは独立していることが必要です。場合によっては、スタティック精度を強制するために、xfix() 変換を使用することが必要である可能性があります。次のコードは、これを示しています。


function nextstate = fsm1(currentstate, din)
  % some other code
  nextstate = currentstate;
  switch currentstate
    case 0, if din==1, nextstate = 1; end
  end
  % a xfix call should be used at the end
  nextstate = xfix({xlUnsigned, 2, 0}, nextstate);

もう 1 つの方法は、状態変数を使用することです。上記の関数は、次のように書き換えることができます。


function currentstate = fsm1(din)
  persistent state, state=xl_state(0,{xlUnsigned,2,0});
  currentstate = state;
  switch double(state)
    case 0, if din==1; state = 1; end
  end
Reset and Enable Signals for State Variables

MCode ブロックは、変数への条件付き代入に 2 つ以下の分岐が含まれる場合、状態変数のレジスタ リセットおよびイネーブル信号を自動的に推論できます。

たとえば次の M コードは、永続的な状態変数 r1 の条件付き代入にイネーブル信号を推論します。


function myFn = aFn(en, a)
  persistent r1, r1 = xl_state(0, {xlUnsigned, 2, 0});
  myFn = r1;
  if en
    r1 = r1 + a
  else
    r1 = r1
  end

永続状態変数 r1 への条件付き代入には、2 つの分岐があります。条件付き代入の実行には、レジスタが使用されます。レジスタの入力は r1 + a に接続され、レジスタの出力は r1 に接続されます。レジスタのイネーブル信号が推論されます。イネーブル信号は、en がアサートされると、en に接続されます。永続的な状態変数 r1r1 + a が代入され、enfalse に評価されると、レジスタのイネーブル信号がデアサートされ、r1r1 が代入されます。

次の M コードも、条件付き代入を実行するために使用されるレジスタのイネーブル信号を推論します。


function myFn = aFn(en, a)
  persistent r1, r1 = xl_state(0, {xlUnsigned, 2, 0});
  myFn = r1;
  if en
    r1 = r1 + a
  end

永続的な状態変数 r1 の条件付き代入が r1 + a で定数値ではないため、リセットではなくイネーブルが推論されます。

永続的な状態変数 r1 の条件付き代入に 3 つの分岐がある場合は、イネーブル信号は推論されません。次の M コードは、永続的な状態変数 r1 の条件付き代入に 3 つの分岐があり、イネーブル信号が推論されない例を示しています。


function myFn = aFn(en, en2, a, b)
  persistent r1, r1 = xl_state(0, {xlUnsigned, 2, 0});
  if en
    r1 = r1 + a
  elseif en2
    r1 = r1 + b
  else
    r1 = r1
  end

リセット信号は、永続的な状態変数に条件により定数が代入された場合に推測できます。リセットは同期です。次のような M コードがあるとします。この例では、rst が true に評価されたときに、永続的な状態変数 r1 に定数である init を代入し、それ以外の場合は r1 + 1 を代入するリセット信号を推論します。


function myFn = aFn(rst)
  persistent r1, r1 = xl_state(0, {xlUnsigned, 4, 0});
  myFn = r1;
  init = 7;
  if (rst)
    r1 = init
  else
    r1 = r1 + 1
  end

リセットを推論する上記の M コード例は、次のようにも記述できます。


function myFn = aFn(rst)
  persistent r1, r1 = xl_state(0, {xlUnsigned,4,0});
  init = 1;
  myFn = r1;
  r1 = r1 +1
  if (rst)
    r1 = init
  end

上記の 2 つのコード例では、永続的な状態変数 r1 を含むレジスタのリセット信号が rst に割り当てられています。rsttrue に評価された場合、レジスタのリセット入力がアサートされ、永続的な状態変数が定数 init に代入されます。rstfalse に評価された場合は、レジスタのリセット入力がディアサートされ、永続状態変数 r1r1 + 1 が代入されます。永続的な状態変数の条件付き代入に 3 つ以上の分岐がある場合は、永続的な状態変数のレジスタにリセット信号は推論されません。

1 つの永続的な状態変数のレジスタにリセット信号とイネーブル信号を推論できます。次の M コード例は、永続的な状態変数 r1 にリセット信号とイネーブル信号を同時に推論します。


function myFn = aFn(rst,en)
  persistent r1, r1 = xl_state(0, {xlUnsigned, 4, 0});
  myFn = r1;
  init = 0;
  if rst
    r1 = init
  else
    if en
      r1 = r1 + 1
    end
  end

永続的な状態変数 r1 のレジスタのリセット入力は、rst に接続されます。rsttrue に評価された場合に、レジスタのリセット入力がアサートされ、r1init が代入されます。レジスタのイネーブル入力は en に接続され、entrue に評価された場合に、レジスタのイネーブル入力がアサートされ、r1r1 + 1 が代入されます。推測されたリセット信号は、条件文の順序に関係なく、推測されたイネーブル信号より優先されることに注意してください。上記の 2 つ目のコード例では、rsten の両方が true に評価されると、永続的な状態変数 r1init が代入されます。

リセット信号とイネーブル信号の推論は、switch 文による永続的な状態変数の条件付き代入でも、switch 文の分岐が 2 つ以下でれば機能します。

MCode ブロックは、FPGA 用のコードを生成する際に、実行されないコードの除去および定数伝搬コンパイラ最適化を実行します。これにより、永続的な状態変数の条件付き代入において、1 つの分岐が実行されない場合に、リセット信号またはイネーブル信号が推論されることがあります。これが発生するは、実行されないコードが削除され、定数伝搬が実行された後に、条件に 2 つの実行される分岐が含まれている必要があります。

Inferring Registers

レジスタは永続的な変数を使用してハードウェアで推論されますが、正しいコーディング スタイルを使用する必要があります。2 つのコード セグメントを含む次のような関数があるとします。


function [out1, out2] = persistent_test02(in1, in2) 
persistent ff1, ff1 = xl_state(0, {xlUnsigned, 2, 0});
persistent ff2, ff2 = xl_state(0, {xlUnsigned, 2, 0});
%code segment 1
out1 = ff1; %these two statements infer a register for ff1
ff1  = in1;
%code segment 2
ff2  = in2; %these two statements do NOT infer a register for ff2
out2 = ff2;
end

コード セグメント 1 では、永続的な変数 ff1 に out1 が代入されます。ff1 は永続的なので、現在の値は前のサイクルで代入されたと想定されます。次の文では、in1 の値が ff1 に代入され、次のサイクル用に保存できます。これにより、ff1 にレジスタが推測されます。

コード セグメント 2 では、最初に in2 の値が永続的な変数 ff2 に代入され、その後 out2 に代入されます。これら 2 つの文は 1 サイクルで完了するため、レジスタは推論されません。組み合わせロジックに遅延を挿入する必要がある場合は、次のトピックを参照してください。

Pipelining Combinational Logic

MCode ブロックの FPGA ビットストリームには、多くの組み合わせロジック段が含まれるため、大きなクリティカル パス遅延が発生する可能性があります。組み合わせロジックをダウンストリームの論理合成ツールで自動的にパイプライン処理するため、MCode ブロックの入力の前または MCode ブロックの出力の後に遅延ブロックを追加できます。これらの遅延ブロックには、合成可能 HDL で遅延をインプリメントするようコード ジェネレーターに指示するパラメーター Implement using behavioral HDL を設定する必要があります。これにより、レジスタ リタイミングまたは最レジスタのバランス調整がインプリメントされるように、ダウンストリームの論理合成ツールに指示できます。別の方法として、ベクター状態変数を使用して遅延をモデル化することも可能です。

Shift Operations with Multiplication and Division

MCode ブロックは、数値が 2 のべき乗である定数で乗算または除算されることを検出できます。検出された場合、MCode ブロックはシフト演算を実行します。たとえば、4 で乗算することは 2 ビットの左シフトと同じで、8 で割ることは 3 ビットの右シフトと同じです。シフトは 2 進小数点を調整することによりインプリメントされ、必要に応じて xfix コンテナーが拡張されます。たとえば、Fix_8_4 値を 4 で乗算すると Fix_8_2 値になり、Fix_8_4 値を 64 で乗算すると Fix_10_0 値になります。

Using the xl_state Function with Rounding Mode

xl_state 関数呼び出しは、状態変数の xfix コンテナーを作成します。コンテナーの精度は、xl_state 関数呼び出しに渡される 2 番目の引数で指定されます。精度で丸めモードに xlRound を使用する場合、丸めを達成するためにハードウェア リソースが追加されます。初期値の丸めのみが必要な場合は、定数の丸めを実行する xfix 呼び出しには追加のハードウェア リソースは必要ありません。丸められた値は、この後 xl_state 関数に渡すことができます。次に例を示します。


init = xfix({xlSigned,8,5,xlRound,xlWrap}, 3.14159);
persistent s, s = xl_state(init, {xlSigned, 8, 5});

ブロック パラメーター

Simulink® モデルでブロック アイコンをダブルクリックすると、[Block Parameters] ダイアログ ボックスが開きます。

図 11. [Block Parameters] ダイアログ ボックス

このトピックで説明したように、MCode ブロックの MATLAB function パラメーターはブロックの関数名を伝搬し、Interface タブで定数入力とその値のリストを指定します。

このブロックで使用されるその他のパラメーターについては、[Block Parameters] ダイアログ ボックスの共通オプション を参照してください。