Verilogパラメータのマスター:再利用可能でスケーラブルなモジュールの構築
パラメータは、モジュールを異なる仕様で再利用できるようにするVerilogの構成要素です。例えば、4ビットアダーをパラメータ化してビット数の値を受け取れるようにし、モジュールインスタンス化時に新しいパラメータ値を渡せるようにします。これにより、Nビットアダーが4ビット、8ビット、16ビットアダーになれます。これらは関数呼び出し時に渡される関数の引数のようなものです。
parameter MSB = 7; // MSBは定数値7を持つパラメータ
parameter REAL = 4.5; // REALは実数を保持
parameter FIFO_DEPTH = 256, MAX_WIDTH = 32; // 2つのパラメータを宣言
parameter [7:0] f_const = 2'b3; // 2ビット値が8ビットに変換: 8'b3
パラメータは基本的に定数であり、実行時に値を変更することは違法です。ネット、変数、または他のパラメータで既に使用されている名前を再宣言することは違法です。
パラメータにはモジュールとspecifyの2つの主要なタイプがあり、両方とも範囲指定を受け付けます。しかし、通常は格納する値に必要なだけの幅にするため、範囲指定は必須ではありません。
モジュールパラメータ
モジュールパラメータを使用すると、モジュール内のパラメータ定義を上書きでき、モジュールがコンパイル時に異なるパラメータセットを持つようになります。パラメータはdefparam文またはモジュールインスタンス文で変更できます。パラメータ名には大文字を使用して一目でわかるようにするのが一般的です。
以下のモジュールは、バス幅、データ幅、FIFOの深さを指定するためにパラメータを使用し、モジュールインスタンス化時またはdefparam文で新しい値で上書きできます。
// Verilog 1995スタイルのポート宣言
module design_ip (addr, wdata, write, sel, rdata);
parameter BUS_WIDTH = 32, DATA_WIDTH = 64, FIFO_DEPTH = 512;
input addr;
input wdata;
input write;
input sel;
output rdata;
wire [BUS_WIDTH-1:0] addr;
wire [DATA_WIDTH-1:0] wdata;
reg [DATA_WIDTH-1:0] rdata;
reg [7:0] fifo [FIFO_DEPTH];
// 設計コードはここに記述...
endmodule
新しいANSIスタイルのVerilogポート宣言では、以下のようにパラメータを宣言できます。
module design_ip #(
parameter BUS_WIDTH=32,
parameter DATA_WIDTH=64
) (
input [BUS_WIDTH-1:0] addr,
// 他のポート宣言
);
パラメータの上書き
パラメータはモジュールインスタンス化時に新しい値で上書きできます。最初の部分では、design_ipモジュールをd0という名前でインスタンス化し、新しいパラメータを#( )内で渡しています。2番目の部分では、Verilog構造のdefparamを使用して新しいパラメータ値を設定しています。最初の方法がRTL設計で新しいパラメータを渡す最も一般的な方法です。2番目の方法は、モジュールを再インスタンス化せずに設計パラメータを素早く更新するためにテストベンチシミュレーションでよく使用されます。
module tb;
// モジュールインスタンス化での上書き
design_ip #(BUS_WIDTH = 64, DATA_WIDTH = 128) d0 ([port list]);
// defparamによる上書き
defparam d0.FIFO_DEPTH = 128;
endmodule
例
counterモジュールには、デフォルト値がそれぞれ2と0のパラメータNとDOWNが宣言されています。Nは出力のビット数を制御し、カウンタの幅を効果的に制御します。デフォルトでは2ビットカウンタです。パラメータDOWNはカウンタがインクリメントするかデクリメントするかを制御します。デフォルトではパラメータが0に設定されているため、カウンタはインクリメントします。
2ビット アップカウンタ
module counter #(
parameter N = 2,
parameter DOWN = 0
) (
input clk,
input rstn,
input en,
output reg [N-1:0] out
);
always @ (posedge clk) begin
if (!rstn) begin
out <= 0;
end else begin
if (en)
if (DOWN)
out <= out - 1;
else
out <= out + 1;
else
out <= out;
end
end
endmodule
counterモジュールは、デフォルト値が2なので必須ではないですがN=2でインスタンス化されています。DOWNはモジュールインスタンス化時に渡されていないため、デフォルト値の0を取り、アップカウンタになります。
module design_top (
input clk,
input rstn,
input en,
output [1:0] out
);
counter #(.N(2)) u0 (
.clk(clk),
.rstn(rstn),
.en(en)
);
endmodule
デフォルトパラメータが使用され、N=2で2ビットカウンタ、DOWN=0でアップカウンタが実装されていることがわかります。カウンタからの出力はトップレベルで未接続のままです。
4ビット ダウンカウンタ
この場合、counterモジュールはN=4でインスタンス化され、4ビットカウンタになります。DOWNにモジュールインスタンス化時に1が渡されるため、ダウンカウンタが実装されます。
module design_top (
input clk,
input rstn,
input en,
output [3:0] out
);
counter #(.N(4), .DOWN(1)) u1 (
.clk(clk),
.rstn(rstn),
.en(en)
);
endmodule
specifyパラメータ
これらは主にタイミングと遅延値を提供するために使用され、specparamキーワードで宣言されます。specifyブロック内とメインモジュール本体の両方で使用できます。
// specifyブロックの使用
specify
specparam t_rise = 200, t_fall = 150;
specparam clk_to_q = 70, d_to_q = 100;
endspecify
// メインモジュール内
module my_block ( ... );
specparam dhold = 2.0;
specparam ddly = 1.5;
parameter WIDTH = 32;
endmodule
specifyパラメータとモジュールパラメータの違い
// 表形式で違いをまとめると:
// Specifyパラメータ: specparamで宣言、specifyブロック内またはメインモジュール内で宣言可能
// specparamとparameterを代入可能、SDFで値を上書き可能
// モジュールパラメータ: parameterで宣言、メインモジュール内でのみ宣言可能
// specparamを代入不可、インスタンス宣言パラメータ値やdefparamで上書き可能
| Specifyパラメータ | モジュールパラメータ |
|---|---|
specparamで宣言 |
parameterで宣言 |
specifyブロック内またはメインモジュール内で宣言可能 |
メインモジュール内でのみ宣言可能 |
| specparamとparameterを代入可能 | specparamを代入不可 |
| SDFで値を上書き可能 | インスタンス宣言パラメータ値またはdefparamで上書き可能 |
Verilog
- Verilogマスター:デジタル回路設計のための完全チュートリアル
- Verilog連結マスター:実践ガイド
- Verilogエッセンシャル:簡潔な概要
- Verilog代入文の理解:種類、構文、ベストプラクティス
- Verilogブロッキング代入とノンブロッキング代入:違いを徹底解説
- Verilog関数のマスター:効率的なRTL設計のために
- Verilogタスクの理解:関数との違い、構文、使用法
- Verilog階層参照スコープのマスター:モジュールとブロックでの名前衝突回避
- Verilogクロックジェネレータ:設計と実装ガイド
- Verilog数学関数のマスター:効率的なハードウェア設計のために
- Verilog $timeformatのマスター:精度と表示制御