ザイリンクス MCode ブロックは、Simulink 内でユーザー提供の MATLAB 関数を {3} 内で実行するためのコンテナーです。ブロックのパラメーターは、M 関数名を指定します。このブロックは、M コードを実行して、Simulink シミュレーション中にブロック出力を計算します。ハードウェアが生成されるときに、同じコードが等価のビヘイビアー 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
を使用するように設定する方法を示します。
モデルがコンパイルされると、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 ベクターを返します。
- データ型
-
xfix
型には、符号なし固定小数点 (xlUnsigned
)、符号付き固定小数点 (xlSigned
)、ブール (xlBoolean
) の 3 種類があります。これらのデータ型に対する算術演算は、符号付きおよび符号なし固定小数点値を生成します。比較演算は、ブール値の結果を生成します。比較オペランドは、データ型を混合することが理にかなっていれば、どのxfix
型にすることもできます。ブール変数は、ブール変数とは比較できますが、固定小数点数とは比較できません。ブール変数は、算術演算子とは互換性がありません。論理演算子は、ブール変数にのみ適用可能です。すべての演算は全精度、たとえば、情報が失われないために必要な最小限の精度で実行されます。- リテラル定数
- 整数、浮動小数点、およびブール型リテラルがサポートされます。整数リテラルは、2 進小数点の位置が 0 である適切な幅の
xfix
値に自動的に変換されます。浮動小数点リテラルは、xfix()
変換関数を使用して明示的にxfix
型に変換する必要があります。定義済みの MATLAB 値true
およびfalse
は、自動的にブール型のリテラル値に変換されます。 - 代入
- 代入の左辺には、1 つの変数のみを指定できます。変数は、複数回代入できます。
- 制御フロー
-
if
文の条件式は、ブール値に評価される必要があります。switch 文には、case
節とotherwise
節を含めることができます。switch のセレクターとその case の型に互換性がある必要があります。そのため、case がブール型であれば、セレクターもブール型にできます。switch
文のすべての case は定数である必要があります。また、case
を入力値に依存させることはできません。制御文の複数の分岐で同じ変数に代入する場合、代入する型に互換性があることが必要です。次に例を示します。
if (u > v) x = a; else x = b; end
これは、
a
とb
が共にブール型または演算型である場合のみ許容されます。
- 定数式
-
論理式は、その値が入力引数の値に依存していなければ、定数です。たとえば、変数
c
が次のように定義されているとします。a = 1; b = a + 2; c = xfix({xlSigned, 10, 2}, b + 3.345);
これは、定数が必要などのコンテキストでも使用できます。- xfix() 変換
-
xfix()
変換関数は、double
をxfix
に変換したり、xfix
を異なる特性を持つ別の xfix に変換します。変換関数の呼び出しは、次のようになります。x = xfix(type_spec, value)
ここで、
x
はxfix
を受け取る変数です。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
には、xlBoolean
、xlUnsigned
、またはxlSigned
を指定できます。データ型がxlBoolean
の場合、追加の要素は不要なので、指定しないでください。ほかのデータ型では、width
およびbinary point position
を指定する必要があります。quantization
およびoverflow mode
はオプションですが、いずれかを指定した場合は、もう一方も指定する必要があります。量子化には、xlTruncate
、xlRound
、およびxlRoundBanker
を指定できます。デフォルトはxlTruncate
です。オーバーフローには、xlWrap
、xlSaturate
、および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
の場合は1
、xlSigned
の場合は2
、xlBoolean
の場合は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_or
、xl_and
、xl_xor
、およびxl_not
の 4 つのビルトイン関数があります。関数
xl_or
、xl_and
、xl_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)
。ここで、a
はxfix
値、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
引数は、xlUnsigned
、xlSigned
、または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
関数は、次のように動作します。
- シミュレーションの最初のサイクルでは、
xl_state
関数が状態変数を指定の精度に初期化します。 - シミュレーションの次のサイクルでは、
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.front
、v.back
、v.full
、v.empty
、v.length
、v.maxlen
があります。状態変数を変更するベクターのメソッドは、アップデート メソッドと呼ばれます。アップデート メソッドには戻り値はありません。アップデート メソッドには、v(idx) = val
、v.push_front(val)
、v.pop_front
、v.push_back(val)
、v.pop_back
、v.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 進数値、倍精度値を表示します。たとえば、変数x
にxfix({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
この例では、
a
、b
、およびx
は使用可能ですが、y
とz
は使用できません。変数y
はif
文にelse
がないため使用できず、変数z
はswitch
文に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. MATLAB デバッグを有効にする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
i
はxfix
型です。コンソールから実行するには、このコードを次のように変更する必要があります。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
sub
をfalse
に設定すると、この M 関数を使用する MCode ブロックは入力ポートa
とb
を持ち、全精度加算を実行します。空のセル配列{}
に設定されている場合、ブロックは入力ポートa
、b
、および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
に接続されます。永続的な状態変数r1
にr1 + a
が代入され、en
がfalse
に評価されると、レジスタのイネーブル信号がデアサートされ、r1
にr1
が代入されます。次の 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
に割り当てられています。rst
がtrue
に評価された場合、レジスタのリセット入力がアサートされ、永続的な状態変数が定数init
に代入されます。rst
がfalse
に評価された場合は、レジスタのリセット入力がディアサートされ、永続状態変数r1
にr1 + 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
に接続されます。rst
がtrue
に評価された場合に、レジスタのリセット入力がアサートされ、r1
にinit
が代入されます。レジスタのイネーブル入力はen
に接続され、en
がtrue
に評価された場合に、レジスタのイネーブル入力がアサートされ、r1
にr1 + 1
が代入されます。推測されたリセット信号は、条件文の順序に関係なく、推測されたイネーブル信号より優先されることに注意してください。上記の 2 つ目のコード例では、rst
とen
の両方がtrue
に評価されると、永続的な状態変数r1
にinit
が代入されます。リセット信号とイネーブル信号の推論は、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] ダイアログ ボックスが開きます。
このトピックで説明したように、MCode ブロックの MATLAB
function
パラメーターはブロックの関数名を伝搬し、Interface タブで定数入力とその値のリストを指定します。
このブロックで使用されるその他のパラメーターについては、[Block Parameters] ダイアログ ボックスの共通オプション を参照してください。