defineでなくparameterを使う
「defineでなくparameterを使う」
RTL記述中の定数を可変にしておきたいときや、数値でなく名前で表記したいときがある。
例1)RTL記述を汎用にするため、ビット幅を可変にする
例2)シミュレーション時間を短縮するために、長いカウンタ周期を短くする
例3)ステートマシンの状態をしめす定数を、数値でなく名前で表記する
このようなときVerilogでは定数をマクロにする方法とparameterにする方法があるが、マクロは危険なので使わない方がよい。
◇
なぜなら、マクロは、
・ソースファイル内のどこでもdefineでき、defineした以降はずっと有効になる(その後に読み込んだソースファイルに対しても有効になる)。つまりコンパイルする順序に依存する。
・もし複数のソースファイルでたまたま同じ名前のマクロが存在していると、意図しないdefineが使われてしまう危険がある。
・なのでソースファイルの先頭でそのファイル内で使うマクロはすべてdefineすべきだが、抜けていてもコンパイルエラーにならないので気がつかない。
・マクロは単なる文字列置換なので、計算式を間違えやすい。
例) define M N+1 , define K 2*M と書くとK=2*(N+1)でなくK=2*N+1と解釈される
// マクロの定義 `define MSB 15 `define PERIOD 4'd15 module my_module ... ×reg[`MSB:0] a_r; // ビット幅 ... ×if(count_r==`PERIOD) // カウンタ周期 ... endmodule |
◇◇
一方、parameterは、
・モジュール内のみで有効なので安全である。もし宣言せずに使えばコンパイルエラーになって気づく。
・上位モジュールから下位モジュールごとに異なる値を設定することもできる。
・上位から設定されたくなければlocalparamにすればよい。
・テストベンチからFPGA内部に階層パスを指定して設定(defparam)することができる
・parameterは単なる文字列置換ではなく、値として計算される。
例) M=N+1, K=2*Mと書くとK=2*(N+1)と解釈される
// テストベンチから階層パスを指定して値を設定する module tb; defparam top.sub_0.PERIOD=4'd8; top top(...); ... endmodule |
// 上位モジュールから下位モジュールに値を設定する module top(...); sub #(.MSB(15),.PERIOD(4'd10)) sub_0(...); sub #(.MSB(15),.PERIOD(4'd15)) sub_1(...); ... endmodule; |
// 下位モジュール module sub #(parameter MSB=7,PERIOD=4'd8) // デフォルト値 ... ○localparam NUM=100; // 外に見せないものはlocalparamにする ... ○reg[MSB:0] a_r; // ビット幅 ... ○if(count_r==PERIOD) // カウンタ周期 ... endmodule |
(注)parameter値を設定する#記号はディレイを表す#と同じだが意味は無関係