Main Content

このページの翻訳は最新ではありません。ここをクリックして、英語の最新版を参照してください。

HDL 用の MATLAB Function ブロック設計パターン

eml_hdl_design_patterns ライブラリ

eml_hdl_design_patterns ライブラリは、HDL コード生成における MATLAB Function ブロックの便利な用途を示す例を広範に収集したものです。

ライブラリを開くには、MATLAB® プロンプトで以下のコマンドを入力します。

eml_hdl_design_patterns

次のように、さまざまなハードウェア要素の例としてライブラリ内の多数のブロックを使用できます。

  • ライブラリからモデルへブロックをコピーして、それを計算単位として使用します。

  • コードをブロックからコピーし、それを既存の MATLAB Function ブロック内のローカル関数として使用します。

カスタム ブロックを作成する場合は、MATLAB Function ブロックから生成される HDL コードをインライン化するか、インスタンス化するかを制御できます。[コンフィギュレーション パラメーター] ダイアログ ボックスの [HDL コード生成][グローバル設定][コーディング スタイル] セクションにある [インラインの MATLAB Function ブロック コード] チェック ボックスを使用します。詳細は、インラインの MATLAB Function ブロック コードを参照してください。

メモ

MATLAB Function ブロックの MATLAB Datapath アーキテクチャでは [インラインの MATLAB Function ブロック コード] 設定は使用しないでください。代わりに [FlattenHierarchy] を使用します。詳細については、MATLAB Datapath アーキテクチャを使用した、MATLAB Function ブロック境界を越えた HDL 最適化を参照してください。

効率的な固定小数点アルゴリズム

MATLAB Function ブロックでは、浮動小数点演算に加え、Fixed-Point Designer™ の関数 fi を使用した固定小数点演算をサポートしています。この関数は、任意の語長と小数部の長さを操作するコーディング アルゴリズムで便利な丸めモードと飽和モードをサポートしています。HDL Coder™ は、fi のすべての丸めモードとオーバーフロー モードをサポートしています。MATLAB Function ブロックから生成された HDL コードは、MATLAB セマンティクスに対してビットトゥルーです。生成されたコードは、VHDL® および Verilog® にネイティブなビット操作演算子およびビット アクセス演算子 (Slice、Extend、Reduce、Concat など) を使用します。

次の説明では、MATLAB Function ブロックから生成された HDL コードが、加算または減算が実行される前に加算オペランドと減算オペランドが結果の型にキャストされる cast-before-sum セマンティクスにどのように準じているかを示します。

eml_hdl_design_patterns ライブラリを開き、Combinatorics/eml_expr ブロックを選択します。eml_expr は、異なる固定小数点データ型をもつ加算、減算、乗算の演算子を含む単純な式を実装しています。生成された HDL コードは、固定小数点オペランドによりこの式の変換を示しています。MATLAB Function ブロックは次のコードを使用します。

% fixpt arithmetic expression
expr = (a*b) - (a+b);
 
% cast the result to (sfix7_En4) output type
y = fi(expr, 1, 7, 4);

ブロックの既定の fimath 仕様によって、MATLAB Function ブロック内の固定小数点オペランドを使用した演算式の動作が決まります。

fimath(...
   'RoundMode', 'ceil',...
   'OverflowMode', 'saturate',...
   'ProductMode', 'FullPrecision', 'ProductWordLength', 32,...
   'SumMode', 'FullPrecision', 'SumWordLength', 32,...
   'CastBeforeSum', true)

オペランドと出力のデータ型は次のとおりです。

  • a: (sfix5_En2)

  • b: (sfix5_En3)

  • y: (sfix7_En4)

HDL コード生成の前に、この式が内部的に複数のステップに分解されます。

expr = (a*b) - (a+b);

ステップは次のとおりです。

  1. tmul = a * b;

  2. tadd = a + b;

  3. tsub = tmul - tadd;

  4. y = tsub;

MATLAB Function ブロックの設計ガイドラインに示す fimath の設定に基づいて、この式は内部的にさらに分解されます。

  • 指定した ProductMode'FullPrecision' に基づいて、tmul の出力型は (sfix10_En5) として計算されます。

  • CastBeforeSum プロパティは 'true' に設定されているため、ステップ 2 は次のように分解されます。

    t1 = (sfix7_En3) a;
    t2 = (sfix7_En3) b;
    tadd = t1 + t2;

    sfix7_En3 は、2 進小数点を配置し、発生する可能性のあるオーバーフローに対処するために余分なビットを考慮した後の結果の和の型です。

  • tmul (sfix10_En5)tadd (sfix7_En3) の中間の型に基づいて、ステップ 3 の減算の結果の型は sfix11_En5 として計算されます。したがって、ステップ 3 は次のように分解されます。

    t3 = (sfix11_En5) tmul;
    t4 = (sfix11_En5) tadd;
    tsub = t3 - t4;
  • 最後に、次の最終的な式ステートメントにつながるより小さい型 (sfix7_En4) に結果がキャストされます。

    tmul = a * b;
    t1 = (sfix7_En3) a;
    t2 = (sfix7_En3) b;	
    tadd = t1 + t2;
    t3 = (sfix11_En5) tmul;
    t4 = (sfix11_En5) tadd;
    tsub = t3 -  t4;
    y = (sfix7_En4) tsub;

次のリストは、eml_expr ブロックから生成された VHDL コードと Verilog コードを示しています。

VHDL コードは次のとおりです。

 BEGIN
    --MATLAB Function 'Subsystem/eml_expr': '<S2>:1'
    -- fixpt arithmetic expression
    --'<S2>:1:4'
    mul_temp <= signed(a) * signed(b);
    sub_cast <= resize(mul_temp, 11);
    add_cast <= resize(signed(a & '0'), 7);
    add_cast_0 <= resize(signed(b), 7);
    add_temp <= add_cast + add_cast_0;
    sub_cast_0 <= resize(add_temp & '0' & '0', 11);
    expr <= sub_cast - sub_cast_0;
    -- cast the result to correct output type
    --'<S2>:1:7'
    
    y <= "0111111" WHEN ((expr(10) = '0') AND (expr(9 DOWNTO 7) /= "000"))
            OR ((expr(10) = '0') AND (expr(7 DOWNTO 1) = "0111111"))
           ELSE
          "1000000" WHEN (expr(10) = '1') AND (expr(9 DOWNTO 7) /= "111")
           ELSE
           std_logic_vector(expr(7 DOWNTO 1) + ("0" & expr(0)));

END fsm_SFHDL;

Verilog コードは次のとおりです。

//MATLAB Function 'Subsystem/eml_expr': '<S2>:1'
    // fixpt arithmetic expression
    //'<S2>:1:4'
    assign mul_temp = a * b;
    assign sub_cast = mul_temp;
    assign add_cast = {a[4], {a, 1'b0}};
    assign add_cast_0 = b;
    assign add_temp = add_cast + add_cast_0;
    assign sub_cast_0 = {{2{add_temp[6]}}, {add_temp, 2'b00}};
    assign expr = sub_cast - sub_cast_0;
    // cast the result to correct output type
    //'<S2>:1:7'
    assign y = (((expr[10] == 0) && (expr[9:7] != 0)) 
                || ((expr[10] == 0) && (expr[7:1] == 63)) ? 7'sb0111111 :
                ((expr[10] == 1) && (expr[9:7] != 7) ? 7'sb1000000 :
                expr[7:1] + $signed({1'b0, expr[0]})));

これらのコード例は、MATLAB Function ブロックから生成された HDL コードが高水準の HDL 演算子を使用した固定小数点演算式のビットトゥルー動作を表していることを示しています。HDL コードは高水準の bitselect および partselect 複製演算子や明示的な符号拡張およびサイズ変更演算子のような HDL コーディング ルールを使用して生成されます。

永続変数を使用したモデルの状態

MATLAB Function ブロックのプログラミング モデルでは、状態を保持する要素は永続変数として表現されます。persistent が宣言された変数は、ソフトウェア内の関数呼び出し全体およびシミュレーション時のサンプル タイム ステップ全体で、その値を保持します。

HDL Coder で HDL コード内のレジスタを推定するには、この永続変数が書き込まれる前に MATLAB コードでこれを "読み取らなければなりません"。コードがこのルールに従っていない場合、警告メッセージが表示されます。

次の例は、入力サンプル u をシミュレーション タイム ステップの 1 回分遅らせる unit delay ブロックを示しています。usfix6 型の固定小数点オペランドです。u_d は入力サンプルを保持する永続変数です。

function y = fcn(u)
 
persistent u_d;
if isempty(u_d)
    u_d = fi(-1, numerictype(u), fimath(u));
end
 
% return delayed input from last sample time hit
y = u_d;
 
% store the current input to be used later
u_d = u;

このコードでは、HDL コードの生成中に u_d にレジスタを推測させるため、u_d は、u_d = u に書き込まれる前に代入ステートメント y = u_d で読み取られます。

HDL Coder で unit delay ブロック用に次の HDL コードが生成されます。

ENTITY Unit_Delay IS
    PORT (
        clk : IN std_logic; 
        clk_enable : IN std_logic; 
        reset : IN std_logic;
        u : IN std_logic_vector(15 DOWNTO 0);
        y : OUT std_logic_vector(15 DOWNTO 0));
END Unit_Delay;


ARCHITECTURE fsm_SFHDL OF Unit_Delay IS


BEGIN
    initialize_Unit_Delay : PROCESS (clk, reset)
    BEGIN
        IF reset = '1' THEN
            y <= std_logic_vector(to_signed(0, 16));
        ELSIF clk'EVENT AND clk = '1' THEN
            IF clk_enable = '1' THEN
                y <= u;
            END IF;
        END IF;
    END PROCESS initialize_Unit_Delay;

永続変数の初期化は、初期化プロセスのグローバル リセット領域に移動されます。

永続変数のベクトルを、整数の遅延、タップ遅延、タップ遅延ベクトル ブロックのモデル化に使用する方法については、eml_hdl_design_patterns ライブラリの Delays サブシステムを参照してください。これらの設計パターンは、モデル内の MATLAB Function ブロックの各実行間で状態を伝達する逐次アルゴリズムを実装する際に役立ちます。

MATLAB Function ブロックを使用した知的財産の作成

MATLAB Function ブロックは、知的財産を生み出し、アルゴリズムの一部の代替の実装を作成するうえで役立ちます。このように MATLAB Function ブロックを使用することで、高水準なアルゴリズムを作成しながら、HDL コード ジェネレーターに詳細な動作を指示できます。

たとえば、eml_hdl_design_patterns ライブラリ内のサブシステム Comparators には、ベクトルの最小値を見つけるためのいくつかの代替アルゴリズムが含まれています。Comparators/eml_linear_min ブロックは、線形モードで連続的にベクトルの最小値を検出します。Comparators/eml_tree_min ブロックは、ツリー構造内の要素を比較します。ツリー実装は、log2(N) 段階の間にパイプライン レジスタを追加することでより高いクロック周波数を実現できます (eml_hdl_design_patterns/Filters の例を参照してください)。

ここで、Comparators ブロック内の単純な比較動作を算術演算 (たとえば、加算、減算、乗算) で置き換え、中間結果を量子化しなければならない場合を検討します。fimath 丸め設定を使用して、中間値が次の段階に送られる前に、中間値の計算を調整できます。この手法は、生成されたハードウェアの調整やアルゴリズムのカスタマイズに使用できます。

調整不可能なパラメーター引数

[シンボル] ペインでパラメーターを選択し、[プロパティ インスペクター] でその [スコープ][パラメーター] に設定してから、[プロパティ インスペクター][詳細設定] セクションで [調整可能] オプションをオフにすることで、MATLAB Function ブロックの調整不可能なパラメーターを宣言できます。

調整不可能なパラメーターはブロック上の信号端子としては表示されません。MATLAB Function ブロックのパラメーター引数は、Simulink® モデルの信号からではなく、親 Simulink マスク サブシステムで定義されたパラメーターまたは MATLAB ベース ワークスペースで定義された変数からの値をとります。

制御ロジックと単純な有限ステート マシンのモデル化

MATLAB Function ブロックは、固定小数点演算と組み合わせた switch/caseif-elseif-else などの構造を制御できるため、制御ロジックをすばやくモデル化できます。

eml_hdl_design_patterns ライブラリ内の FSMs/mealy_fsm_blk ブロックと FSMs/moore_fsm_blk ブロックは、MATLAB Function ブロックにおける Mealy および Moore 有限ステート マシンの実装例を提供しています。

次のリストは Moore ステート マシンの実装を示します。

function Z = moore_fsm(A)
 
persistent moore_state_reg;
if isempty(moore_state_reg)
    moore_state_reg = fi(0, 0, 2, 0);   
end
 
S1 = 0;
S2 = 1;
S3 = 2;
S4 = 3;
  
switch uint8(moore_state_reg)
    
    case S1,        
        Z = true;
        if (~A)
            moore_state_reg(1) = S1;
        else
            moore_state_reg(1) = S2;
        end        
    case S2,        
        Z = false;
        if (~A)
            moore_state_reg(1) = S1;
        else
            moore_state_reg(1) = S2;
        end        
    case S3,        
        Z = false;
        if (~A)
            moore_state_reg(1) = S2;
        else
            moore_state_reg(1) = S3;
        end        
    case S4,        
        Z = true;
        if (~A)
            moore_state_reg(1) = S1;
        else
            moore_state_reg(1) = S3;
        end
    otherwise,
        Z = false;
end

この例では、永続変数 (moore_state_reg) が状態変数をモデル化しています。出力は状態変数のみに依存するため、Moore マシンがモデル化されます。

eml_hdl_design_patterns ライブラリ内の FSMs/mealy_fsm_blk ブロックは、Mealy ステート マシンを実装します。Mealy ステート マシンは、出力が入力と状態変数に依存する点で Moore ステート マシンとは異なっています。

MATLAB Function ブロックは、制御ステートメントと永続変数を使用して、単純なステート マシンとその他の制御ベースのハードウェア アルゴリズム (パターン マッチング機能や同期関連のコントローラーなど) をすばやくモデル化できます。

複雑な時相論理を用いたより複雑な階層ステート マシンをモデル化するには、Stateflow® チャートを使用してステート マシンをモデル化します。

カウンターのモデル化

HDL コード生成用に MATLAB Function ブロックで算術および制御ロジック アルゴリズムを実装するために、HDL 関連の簡単なコーディング要件がいくつかあります。

  • 最上位レベルの MATLAB Function ブロックはタイム ステップごとに 1 回呼び出されなければならない。

  • プログラム ループを完全に展開できなければならない。

  • リセット値と更新ロジックをもつ永続変数を使用してシミュレーションのタイム ステップ間で値を保持しなければならない。

  • ループ内部では量子化されたデータ変数を使用しなければならない。

以下のスクリプトは、事前設定された値と制御入力をもつ同期アップ/ダウン カウンターをモデル化する方法を示しています。この例では、ブロック入力 (presetClear など) を使用した永続状態変数のグローバル リセット制御とローカル リセット制御の両方を示しています。isempty 条件は、同期リセットの制御下で初期化プロセスに入ります。presetClear セクションは、生成された HDL コード内の出力セクションで実装されます。

カウント ループを実装する up case ステートメントと down case ステートメントはどちらも、カウンターの値の加算または減算後に量子化される必要があります。既定の設定では、MATLAB Function ブロックはブロックに指定された固定小数点設定を自動的に伝播します。ただし、このスクリプトでは、中間量と定数の固定小数点設定は明示的に指定されます。

function [Q, QN]  = up_down_ctr(upDown, presetClear, loadData, presetData)
 
% up down result
% 'result' syntheses into sequential element
 
result_nt = numerictype(0,4,0);
result_fm = fimath('OverflowMode', 'saturate', 'RoundMode', 'floor');
 
initVal = fi(0, result_nt, result_fm);
 
persistent count;
if isempty(count)
    count = initVal;
end
 
if presetClear
    count = initVal;
elseif loadData
    count = presetData;
elseif upDown
    inc = count + fi(1, result_nt, result_fm);
    -- quantization of output
    count = fi(inc, result_nt, result_fm);
else
    dec = count - fi(1, result_nt, result_fm);
    -- quantization of output
    count = fi(dec, result_nt, result_fm);
end
 
Q = count;
QN = bitcmp(count);

ハードウェア要素のモデリング

次のコード例は、MATLAB Function ブロック コード内で、関数 bitsliceget と関数 bitconcat を使用してシフト レジスタをモデル化する方法を示しています。この関数は、32 ビット固定小数点オペランド入力をもつシリアル入力および出力シフターを実装します。詳細については、eml_hdl_design_patterns ライブラリの Shift Registers/shift_reg_1by32 ブロックを参照してください。

function sr_out = fcn(shift, sr_in)
%shift register 1 by 32

persistent sr;
if isempty(sr)
    sr = fi(0, 0, 32, 0, 'fimath', fimath(sr_in));
end

% return sr[31]
sr_out = getmsb(sr);

if (shift)
    % sr_new[32:1] = sr[31:1] & sr_in
    sr = bitconcat(bitsliceget(sr, 31, 1), sr_in);
end

次のコード例は、shift_reg_1by32 ブロック用に生成された VHDL プロセス コードを示しています。

shift_reg_1by32 : PROCESS (shift, sr_in, sr)
    BEGIN
      sr_next <= sr;
      -- MATLAB Function Function 'Subsystem/shift_reg_1by32': '<S2>:1'
      --shift register 1 by 32
      --'<S2>:1:1
      -- return sr[31]
      --'<S2>:1:10'
      sr_out <= sr(31);

      IF shift /= '0' THEN 
          --'<S2>:1:12'
          -- sr_new[32:1] = sr[31:1] & sr_in
          --'<S2>:1:14'
          sr_next <= sr(30 DOWNTO 0) & sr_in;
      END IF;

    END PROCESS shift_reg_1by32;

Shift Registers/shift_reg_1by64 ブロックは 64 ビット シフターを示しています。この場合、シフターはオペランドを表現するために 2 つの固定小数点の語を使用して、固定小数点整数の 32 ビットの語長制限を解消します。

MATLAB Function ブロックを使用して簡単に実装できる他の便利なハードウェア要素については、eml_hdl_design_patterns モデルを参照してください。

10 進数からバイナリへの変換

整数型からビット ベクトル出力を生成するか、またはその逆を行う変換を実行できます。この変換を実行する方法を示すモデル例については、モデル hdlcoder_int2bits_bits2int を開きます。

open_system('hdlcoder_int2bits_bits2int')
モデルは、Word Twiddlers ライブラリ配下の eml_hdl_design_patterns ライブラリに実装されている MATLAB Function ブロックを使用します。

参考

関連するトピック