16
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

$clog2によるビット幅算出のよくある間違い

Last updated at Posted at 2019-10-12

\$clog2()は2を基数としたlogの値を整数に切り上げした値(Ceiling Log2)を返すSystemVerilogのシステムタスクである。
ある値を表現するのに必要なビット数を計算するのによく使われ、そのように解説しているページをよく見かける。その事自体は正しいが、その使用方法の解説の多くが必ずしも正しくはないので、正しい解説をしておこうと思う。
尚、頂いたコメントの情報では、Vivadoの古いバージョンで\$clog2()が切り下げの処理になってしまっており、正しく計算されない場合があるそうです。なので古いVivadoを使っていた人が記事を書いた場合そのような解説になっている可能性があるとの事です。Vivadoを使っていて\$clog2の値がどうもおかしい場合にはバージョンを確認してみて下さい。

例えば0~7までの値を取る信号の場合ビット幅は[2:0]の3bitである。
\$clog2(7)は3 (log2(7) = 2.???)なので[\$clog2(7)-1:0]のビット幅となる。最大値7をパラメータ化して

parameter  MAX_VAL = 7;
parameter  WIDTH   = $clog2(MAX_VAL);  // 3
logic[WIDTH - 1 : 0]  val;

のように書ける。このような解説のページが多い。しかしこれは必ずしも正しくない。これが正しいのはMAX_VALが2のべき乗以外の場合のみである。
2のべき乗の時、例えば8の場合を見てみよう。
0~8の値を表すには0000~1000なので必要ビット幅は[3:0]の4bitとなる。それに対して\$clog2(8)は3となる。なので、

parameter  MAX_VAL = 8;
parameter  WIDTH   = $clog2(MAX_VAL);  // 3
logic[WIDTH - 1 : 0]  val;

は間違っており、思わぬバグとなってしまう。じゃあどうすれば良いかと言うと

parameter  MAX_VAL = 8;
parameter  WIDTH   = $clog2(MAX_VAL+1);  // 4
logic[WIDTH - 1 : 0]  val;

が正しい。

\$clog2(1) = 0 // log2(1) = 0
\$clog2(2) = 1 // log2(2) = 1
\$clog2(3) = 2 // log2(3) = 1.???
\$clog2(4) = 2 // log2(4) = 2
\$clog2(5) = 3 // log2(5) = 2.???
\$clog2(6) = 3 // log2(6) = 2.???
\$clog2(7) = 3 // log2(7) = 2.???
\$clog2(8) = 3 // log2(8) = 3

と3は一つ上の2のべき乗の数4の仲間、5,6,7は8の仲間なのである。4は3ではなくて5,6,7の仲間に入れたい。8は9~15の仲間に入れたい。なので一つずらす為に+1をすればいいのである。

\$clog2(1 + 1) = 1 // log(2) = 1
\$clog2(2 + 1) = 2 // log(3) = 1.???
\$clog2(3 + 1) = 2 // log(4) = 2
\$clog2(4 + 1) = 3 // log(5) = 2.???
\$clog2(5 + 1) = 3 // log(6) = 2.???
\$clog2(6 + 1) = 3 // log(7) = 2.???
\$clog2(7 + 1) = 3 // log(8) = 3
\$clog2(8 + 1) = 4 // log(9) = 3.???

上記の例は信号の最大値 MAX_VALをパラメータにして必要バス幅を求めたが、メモリのワード数や配列の要素数からアドレスに必要なビット幅を求めるはどうするか考えてみよう。ワード数が8のメモリ或いは要素数が8個の配列の場合、アドレスは0~7の8個で

parameter  MEM_DEPTH = 8;
parameter  ADD_WIDTH = $clog2(MEM_DEPTH);  // 3
logic[ADD_WIDTH - 1 : 0]  addr;
logic[31:0]  mem[MEM_DEPTH];

となる。この場合にはMEM_DEPTHが他のどんな値でも正しい。なぜならアドレスが最大値7の0~7という8種類の値を取ると言うのをパラメータ MEM_DEPTHで使用したからである。つまりMEM_DEPTH = MAX_VAL + 1と最初から+1されてるからである。
要するに
\$clog2()を使って必要ビット幅を算出する場合、最大値で考えた場合+1が必要、個数で考えた場合はそのままの値でOK
となる。

「\$clog2()を使えば必要ビット幅が分かるんだ!」と慌てて飛び付くとこのような落とし穴にはまってしまうので十分気を付けてほしい。

16
8
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?