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