EDAboard.com | EDAboard.eu | EDAboard.de | EDAboard.co.uk | RTV forum PL | NewsGroups PL

How get the bit width of a value at Verilog compile time

Ask a question - edaboard.com

elektroda.net NewsGroups Forum Index - Verilog Language - How get the bit width of a value at Verilog compile time

James Harris
Guest

Tue Sep 28, 2010 7:25 pm   



Warning, newbie question ahead. Give the following which I've put at
the top of a Verilog module

parameter BITS = 32;

I need a counter to count down from BITS to zero (inclusive) so the
counter needs to be something like floor(log2(BITS)) + 1 wide. For
example, if the parameter is 32 the counter needs to be 6 bits wide
and if the parameter is 8 the counter needs to be 4 bits wide. I tried
defining the width of the counter as

reg[log2(BITS) + 1] counter;

but this fails. There seems to be no way to take log2 - or any other
type of log - at compile time. I've ended up with

parameter LOG2BITS = 4;
parameter BITS = 2 ** LOG2BITS;
...
reg[LOG2BITS + 1] counter;

where LOG2BITS is set first then BITS is set based on the value of
LOG2BITS.

Is there a better way of doing this?

James

James Harris
Guest

Tue Sep 28, 2010 7:29 pm   



On 28 Sep, 17:25, James Harris <james.harri...@googlemail.com> wrote:

Quote:
Warning, newbie question ahead. Give the following which I've put at

Oops: "Give" should be "Given".

James

Jonathan Bromley
Guest

Tue Sep 28, 2010 7:51 pm   



On Sep 28, 5:25 pm, James Harris wrote:
Quote:
Warning, newbie question ahead.

Not newbie, but a very common need.

Quote:
counter needs to be something like
floor(log2(BITS)) + 1 wide.

There's a system function $clog2 that should do the job. Check
its behaviour carefully: it really does return the ceiling of
log2, so it isn't quite the same as "bits-to-fit-this-integer",
which you can get by $clog2(N+1). $clog2 is a constant function
if given a constant argument, so it should be OK to use the
result as if it were a parameter (i.e. use it in things
like vector width declarations).

However, support for $clog2 and constant functions is
not universal in current tools, so you may have to resort
to other grimness. If the width is reasonably limited,
you can use a macro definition:

`define BITS_TO_FIT(N) ( \
N < 2 ? 1 : \
N < 4 ? 2 : \
N < 8 ? 3 : \
N < 16 ? 4 : \
N < 32 ? 5 : \
N < 64 ? 6 : \
7 )

parameter SIZE = whatever;
localparam COUNTWIDTH = `BITS_TO_FIT(SIZE);

OK, OK, don't shout at me - I never promised it
was going to be nice...
--
Jonathan Bromley

Jonathan Bromley
Guest

Tue Sep 28, 2010 11:28 pm   



On Tue, 28 Sep 2010 14:48:19 -0700 (PDT), gabor wrote:

Quote:
I don't remember where I swiped this code:
[...]
function [31:0] log2;
input [31:0] value;
[...]
I think it started as a recursive function that completely
hosed XST synthesis, and then was re-written as a loop.

Right, that's the way I've done it in VHDL for years;
but in Verilog it's still exposed to the problem of
whether tools really understand what a "constant
function" is (i.e. the result can be used to set a
parameter or to size a vector).

Since it's so much cleaner than the macro I posted,
it would probably be a good idea to start with this
and then fall back to the macro hack if your synthesis
tool doesn't like the function.
--
Jonathan Bromley

Cary R.
Guest

Tue Sep 28, 2010 11:40 pm   



On 9/28/2010 3:28 PM, Jonathan Bromley wrote:

Quote:
Since it's so much cleaner than the macro I posted,
it would probably be a good idea to start with this
and then fall back to the macro hack if your synthesis
tool doesn't like the function.

Or us $clog2() like you mentioned earlier. FYI Icarus
Verilog does not support constant user functions, but
it does support $clog2() in a constant context. For
maximum portability you probably need to have an ifdef
that switches between $clog2() or the constant user
function. Some of the name brand simulators do not
support $clog2(), but their synthesis does! I think
there is a clog2b function out there that matches what
$clog2() does so you can easily just switch between
the two version using a define.

Cary

gabor
Guest

Wed Sep 29, 2010 12:48 am   



On Sep 28, 12:51 pm, Jonathan Bromley <s...@oxfordbromley.plus.com>
wrote:
Quote:
On Sep 28, 5:25 pm, James Harris wrote:

Warning, newbie question ahead.

Not newbie, but a very common need.

counter needs to be something like
  floor(log2(BITS)) + 1 wide.

There's a system function $clog2 that should do the job.  Check
its behaviour carefully: it really does return the ceiling of
log2, so it isn't quite the same as "bits-to-fit-this-integer",
which you can get by $clog2(N+1).  $clog2 is a constant function
if given a constant argument, so it should be OK to use the
result as if it were a parameter (i.e. use it in things
like vector width declarations).

However, support for $clog2 and constant functions is
not universal in current tools, so you may have to resort
to other grimness.  If the width is reasonably limited,
you can use a macro definition:

  `define BITS_TO_FIT(N) ( \
     N <  2 ? 1 : \
     N <  4 ? 2 : \
     N <  8 ? 3 : \
     N < 16 ? 4 : \
     N < 32 ? 5 : \
     N < 64 ? 6 : \
               7 )

  parameter SIZE = whatever;
  localparam COUNTWIDTH = `BITS_TO_FIT(SIZE);

OK, OK, don't shout at me - I never promised it
was going to be nice...
--
Jonathan Bromley

I don't remember where I swiped this code:

`timescale 1 ns / 1 ps
module test ();


function [31:0] log2;
input [31:0] value;
integer i;
reg [31:0] j;
begin
j = value - 1;
log2 = 0;
for (i = 0; i < 31; i = i + 1)
if (j[i]) log2 = i+1;
end
endfunction

initial
begin
$display("10 = %d", log2(10));
$display("32 = %d", log2(32));
$display("64 = %d", log2(64));
$display("4 = %d", log2(4));
end
endmodule

I think it started as a recursive function that completely
hosed XST synthesis, and then was re-written as a loop.

Regards,
Gabor

Mark Curry
Guest

Wed Sep 29, 2010 1:59 am   



FYI, we use a very similar constant function, and have
used with many synthesis tools without much issue -
XST, Precision, dc, Quartus.

A few had issues with directly calling the log2 function
during a module instanciation - we had to create an intermediate
variable. i.e.:

foo #( .some_param( foo_param ), .log2_some_param( log2( foo_param ) ) foo();

Would fail. Creating a localparam would workaround:

localparam log2_foo_param = log2( foo_param );
foo #( .some_param( foo_param ), .log2_some_param( log2_foo_param ) ) foo();

Probably more than the OP wanted to know....

--Mark



In article <3lq4a65r8r001ho501hpf2qvcm71f87r8f_at_4ax.com>,
Jonathan Bromley <spam_at_oxfordbromley.plus.com> wrote:
Quote:
On Tue, 28 Sep 2010 14:48:19 -0700 (PDT), gabor wrote:

I don't remember where I swiped this code:
[...]
function [31:0] log2;
input [31:0] value;
[...]
I think it started as a recursive function that completely
hosed XST synthesis, and then was re-written as a loop.

Right, that's the way I've done it in VHDL for years;
but in Verilog it's still exposed to the problem of
whether tools really understand what a "constant
function" is (i.e. the result can be used to set a
parameter or to size a vector).

Since it's so much cleaner than the macro I posted,
it would probably be a good idea to start with this
and then fall back to the macro hack if your synthesis
tool doesn't like the function.
--
Jonathan Bromley


James Harris
Guest

Wed Sep 29, 2010 6:46 pm   



On 28 Sep, 17:51, Jonathan Bromley <s...@oxfordbromley.plus.com>
wrote:
Quote:
On Sep 28, 5:25 pm, James Harris wrote:

Warning, newbie question ahead.

Not newbie, but a very common need.

counter needs to be something like
  floor(log2(BITS)) + 1 wide.

There's a system function $clog2 that should do the job.  Check
its behaviour carefully: it really does return the ceiling of
log2, so it isn't quite the same as "bits-to-fit-this-integer",
which you can get by $clog2(N+1).  $clog2 is a constant function
if given a constant argument, so it should be OK to use the
result as if it were a parameter (i.e. use it in things
like vector width declarations).

However, support for $clog2 and constant functions is
not universal in current tools, so you may have to resort
to other grimness.  If the width is reasonably limited,
you can use a macro definition:

  `define BITS_TO_FIT(N) ( \
     N <  2 ? 1 : \
     N <  4 ? 2 : \
     N <  8 ? 3 : \
     N < 16 ? 4 : \
     N < 32 ? 5 : \
     N < 64 ? 6 : \
               7 )

  parameter SIZE = whatever;
  localparam COUNTWIDTH = `BITS_TO_FIT(SIZE);

OK, OK, don't shout at me - I never promised it
was going to be nice...

No, that's great, thanks. $clog2 is supported by Icarus (but not by my
current Xilinx installation - I'll have to do something different
there but then the whole installation seems a bit odd so I'll come
back to it). I also wanted but didn't know about localparam so that's
a help too!

James

elektroda.net NewsGroups Forum Index - Verilog Language - How get the bit width of a value at Verilog compile time

Ask a question - edaboard.com

Arabic versionBulgarian versionCatalan versionCzech versionDanish versionGerman versionGreek versionEnglish versionSpanish versionFinnish versionFrench versionHindi versionCroatian versionIndonesian versionItalian versionHebrew versionJapanese versionKorean versionLithuanian versionLatvian versionDutch versionNorwegian versionPolish versionPortuguese versionRomanian versionRussian versionSlovak versionSlovenian versionSerbian versionSwedish versionTagalog versionUkrainian versionVietnamese versionChinese version
RTV map EDAboard.com map News map EDAboard.eu map EDAboard.de map EDAboard.co.uk map Opony