Computing the width of an unsigned variable from maximum val

T

Torsten Landschoff

Guest
Hello World!

I am new to VHDL and after getting my first FPGA configured to blink
an LED, I have a number of questions that I did not find any answers
for. While VHDL seems to be very high level in some aspects, I still
haven't found some features that I would expect are easy to implement.

generic prescaler entity
---------------------
For controlling the on and off time of my led, I used a prescaler to
scale down the 50 MHz clock of the FPGA to microseconds. The output of
the prescaler is connected to a timer which finally toggles the led.

The prescaler has the following component declaration:

component prescaler is
generic (
divider : unsigned );
port (
clock_in : in std_logic;
clock_out : out std_logic );
end prescaler;

To get a fixed time base, I instantiate the component like this:

tick_provider : component prescaler
generic map (
divider => CONV_UNSIGNED(CLOCKHZ / 1_000_000, 6) )
port map (
clock_in => clock, clock_out => tick_us );

Now I'd like to get rid of the "6" for the length of the unsigned
parameter but I did not find any way to infer the length required for
the binary representation of some value. Is there any way to do
something like that:

constant tick_divider : positive := CLOCKHZ / 1_000_000;
...
divider => CONV_UNSIGNED(divider, divider'width)

??

Any insight appreciated.

Greetings, Torsten
 
"Torsten Landschoff" <t.landschoff@gmx.de> wrote in message
news:1171966751.861888.310840@q2g2000cwa.googlegroups.com...
Hello World!

I am new to VHDL and after getting my first FPGA configured to blink
an LED, I have a number of questions that I did not find any answers
for. While VHDL seems to be very high level in some aspects, I still
haven't found some features that I would expect are easy to implement.

generic prescaler entity
---------------------
For controlling the on and off time of my led, I used a prescaler to
scale down the 50 MHz clock of the FPGA to microseconds. The output of
the prescaler is connected to a timer which finally toggles the led.

The prescaler has the following component declaration:

component prescaler is
generic (
divider : unsigned );
port (
clock_in : in std_logic;
clock_out : out std_logic );
end prescaler;

To get a fixed time base, I instantiate the component like this:

tick_provider : component prescaler
generic map (
divider => CONV_UNSIGNED(CLOCKHZ / 1_000_000, 6) )
port map (
clock_in => clock, clock_out => tick_us );

Now I'd like to get rid of the "6" for the length of the unsigned
parameter but I did not find any way to infer the length required for
the binary representation of some value. Is there any way to do
something like that:

constant tick_divider : positive := CLOCKHZ / 1_000_000;
...
divider => CONV_UNSIGNED(divider, divider'width)

??

Any insight appreciated.

Greetings, Torsten

I'd first suggest a different more flexible approach....

1. Change 'divider' from an unsigned to 'natural'.
2. Where you instantiate the component get rid of the call to function
'CONV_UNSIGNED' in the generic map.
3. Inside your component where you actually use divider, change all usages
of 'divider' to work with type 'natural' (it might even work with no
changes).

To answer your specific question though, divider'length gives you what you
called the 'width' of a vector (i.e. the number of bits).

Lastly, since you're using 'CNV_UNSIGNED' this implies that you're using the
std_logic_arith library. This is not a standard, use numeric_std instead
and save yourself some problems down the road.

Kevin Jennings
 
On Feb 20, 11:29 am, "KJ" <kkjenni...@sbcglobal.net> wrote:
I'd first suggest a different more flexible approach....

1. Change 'divider' from an unsigned to 'natural'.
I thought that would not synthesize. Guess I'll give it a try. Thanks
for the suggestion!

2. Where you instantiate the component get rid of the call to function
'CONV_UNSIGNED' in the generic map.
Sure, that's what I had originally anyway.

3. Inside your component where you actually use divider, change all usages
of 'divider' to work with type 'natural' (it might even work with no
changes).
Most likely, minus the counter declaration which currently is

variable counter : unsigned(divider'range);

To answer your specific question though, divider'length gives you what you
called the 'width' of a vector (i.e. the number of bits).
Yes, and divider'range gives me the range, but I can call that only
after having given the width to CONV_UNSIGNED.

Lastly, since you're using 'CNV_UNSIGNED' this implies that you're using the
std_logic_arith library. This is not a standard, use numeric_std instead
and save yourself some problems down the road.
Grmbl, why do they call it std_logic_arith then? ;-)

Thanks for your quick response, Torsten
 
"Torsten Landschoff" <t.landschoff@gmx.de> wrote in message
news:1171968135.278558.212580@m58g2000cwm.googlegroups.com...
On Feb 20, 11:29 am, "KJ" <kkjenni...@sbcglobal.net> wrote:
I'd first suggest a different more flexible approach....

1. Change 'divider' from an unsigned to 'natural'.

I thought that would not synthesize. Guess I'll give it a try. Thanks
for the suggestion!
It will synthesize.

3. Inside your component where you actually use divider, change all
usages
of 'divider' to work with type 'natural' (it might even work with no
changes).

Most likely, minus the counter declaration which currently is

variable counter : unsigned(divider'range);
'counter' could also be type natural...
variable counter : natural range 0 to divider;

Grmbl, why do they call it std_logic_arith then? ;-)

Back in the late 80s there was no math packages, so Synopsys came up with
std_logic_arith and even put it in the ieee library even though it is not
(and never has been) an IEEE package. A couple years later, IEEE came out
with numeric_std which added math support and cleaned up some of the trash
that Synopsys allowed....15 years later it is still not uncommon to see
usage of std_logic_arith where numeric_std should be....it's not at all
uncommon but should still be pointed out when seen.

Kevin Jennings
 
I think I kind of missed your real question when reading your posts. If you
know the maximum value of something and simply need to know how many bits
you'll need to represent it, then you need to take the log (base 2) of that
number...and then generally tack on an extra bit

So if you have an integer 'abc' and want to represent it as an unsigned
signal 'xyz' then you would declare 'xyz' as...

signal xyz: unsigned(log2(abc) + 1 downto 0);

The '+1' is so that if you happen to take the log2() of something that does
not happen to be an integer power of 2 you'll still get enough bits of
precision.

You can also embed the log2 function in your entity. Let's say that signal
'xyz' was an output of your entity. You can do something like this

entity Foo is generic(abc: natural)
port(abc: out unsigned(log2(abc)+1 downto 0));
end Foo;

The magic log2 function is posted below as well as where I got it from.

Kevin Jennings
---------------------------------------------------------------------------------------- -- A synthesizable function that returns the integer part of the base 2logarithm for a -- positive number (posted by Tuukka Toivonen) to VHDL FAQ forum -- http://www.vhdl.org/comp.lang.vhdl/FAQ1.html ---------------------------------------------------------------------------------------- function log2 (x : positive) return natural is begin if x <= 1 then return 0; else return log2 (x / 2) + 1; end if; end function log2;
 
Arggg....typo

port(abc: out unsigned(log2(abc)+1 downto 0));
should have been

port(xyz: out unsigned(log2(abc)+1 downto 0));

Kevin Jennings
 
Torsten Landschoff wrote:

While VHDL seems to be very high level in some aspects, I still
haven't found some features that I would expect are easy to implement.
VHDL can be used as a "high level"
language inside of a process.
Wiring procedures and entities together
is mostly non-procedural.


generic prescaler entity
---------------------
For controlling the on and off time of my led, I used a prescaler to
scale down the 50 MHz clock of the FPGA to microseconds. The output of
the prescaler is connected to a timer which finally toggles the led.

The prescaler has the following component declaration:
I would use clock enables, rather than
dividing clocks and eliminate the component:

procedure update_regs is
-- a counts every clock, b counts when a rolls, c counts when b rolls
begin
a:a_v := a_v + 1; -- fast count
b:if a_v(a_v'left) = '1' then -- a carry?
a_v(a_v'left) := '0'; -- clear carry
b_v := b_v + 1;
c:if b_v(b_v'left) = '1' then -- b carry?
b_v(b_v'left) := '0'; -- clear carry
c_v := c_v + 1; -- slow count, unsigned rolls over, no carry
end if c;
end if b;
end procedure update_regs;

See "clock enable counters" below for details.
http://home.comcast.net/~mike_treseler/

Now I'd like to get rid of the "6" for the length of the unsigned
parameter but I did not find any way to infer the length required for
the binary representation of some value.

Any insight appreciated.
You can write a function, as KJ outlined,
but to calculate an integer value, I prefer to
use ieee.math_real.all;
and keep the calculations in the code
something like this:

constant cal_ratio_r : real := 400*1.0e-6; -- 400ppm
constant magic_number_r : real := 2 ** 25 * 2500.0 / 12500.0;
constant cal_range_r : real := magic_number_r * cal_ratio_r;
constant cal_range_nat_c : natural := natural(cal_range_r);

This works fine for Leo/Quartus.
If it doesn't for ISE, you can put it
in the testbench instead and take the
value from simulation.

-- Mike Treseler
 
Hi again,

On 20 Feb., 12:22, "KJ" <kkjenni...@sbcglobal.net> wrote:
I think I kind of missed your real question when reading your posts. If you
know the maximum value of something and simply need to know how many bits
you'll need to represent it, then you need to take the log (base 2) of that
number...and then generally tack on an extra bit
Right, exactly what I thought.

The magic log2 function is posted below as well as where I got it from.
Great, thanks. That's what I was looking for.

Greetings, Torsten
 

Welcome to EDABoard.com

Sponsor

Back
Top