Verilogで表現したい数値に応じてwireやregのビット幅を考えて手動で入力するのが面倒なので、自動で必要なビット数を割り出してくれるマクロに$clog2というものがあります。
ただし、Verilog 2001以前は$clog2がサポートされていないので、自作の関数を使うことでこの問題が解決できます。
「IEEE Standard Verilog Hardware Description Language」を見ると、160ページ目前後に「Use of constant function」という章で定数関数というものがありることが分かります。
定数関数の仕様
定数関数の仕様についてざっくりとみると、以下のような感じぽいです。
- 定数関数はグローバルではなくローカルな関数とする
- elaborate時に値が確定する
- 内部システムタスクは基本無視される
いろいろ定義や制約が書いていますが、回路には実装されずに、実装までの間に値が確定する関数だということを使用者側としては一番はっきりさせておきたいところです。
値に対してビット数を自動計算するclogb2関数記述
clogb2の実装例:
function integer clogb2 (
input integer value
);
begin
value = value-1;
for (clogb2=0; value>0; clogb2=clogb2+1) begin
value = value>>1;
end
end
endfunction
clogb2の使用例:
module hoge ();
localparam P_BASE = 20;
localparam P_BIT = clogb2(P_BASE);
function integer clogb2 (
input integer value
);
begin
value = value-1;
for (clogb2=0; value>0; clogb2=clogb2+1) begin
value = value>>1;
end
end
endfunction
endmodule
このようにすることで、20という最大値を表現するのに必要なビット数6を人間の頭で計算せずにパラメータP_BITに自動で設定することができます。
自動で置き換わってくれるので、仕様を変更した際にビット数のだけ変え忘れるといった事態も防ぐことができます。
定数関数が合成されないか確認してみる
この関数を使って小規模な回路を実装してみました。
Vivadoのimplementation Schematicの出力のブロック図を見ても、それらしいものは見当たらないので、定数関数が実際に回路に実装されることはないでしょう。ブロック図を見るとすでにビット数が確定していることが分かります。

そもそもレジスタサイズが定まらないと、回路に実装できないのですから当たりまえですよね、、
参考:
・https://inst.eecs.berkeley.edu/~cs150/fa06/Labs/verilog-ieee.pdf
・http://cafeandverify.blogspot.com/2010/04/constant-function_13.html
・https://docs.xilinx.com/r/2022.1-日本語/ug901-vivado-synthesis/定数関数および定数式の使用