Computing the width of an unsigned variable from maximum value?

Discussion in 'VHDL' started by Torsten Landschoff, Feb 20, 2007.

  1. 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, Feb 20, 2007
    #1
    1. Advertising

  2. Torsten Landschoff

    KJ Guest

    "Torsten Landschoff" <> wrote in message
    news:...
    > 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
     
    KJ, Feb 20, 2007
    #2
    1. Advertising

  3. On Feb 20, 11:29 am, "KJ" <> 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, Feb 20, 2007
    #3
  4. Torsten Landschoff

    KJ Guest

    "Torsten Landschoff" <> wrote in message
    news:...
    > On Feb 20, 11:29 am, "KJ" <> 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
     
    KJ, Feb 20, 2007
    #4
  5. Torsten Landschoff

    KJ Guest

    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;
     
    KJ, Feb 20, 2007
    #5
  6. Torsten Landschoff

    KJ Guest

    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
     
    KJ, Feb 20, 2007
    #6
  7. 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
     
    Mike Treseler, Feb 20, 2007
    #7
  8. typo:

    > Wiring procedures and entities together

    processes
    ---------

    -- Mike Treseler
     
    Mike Treseler, Feb 20, 2007
    #8
  9. Hi again,

    On 20 Feb., 12:22, "KJ" <> 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
     
    Torsten Landschoff, Feb 22, 2007
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. AndrewF
    Replies:
    1
    Views:
    811
    Bruce Barker
    Oct 10, 2005
  2. Replies:
    3
    Views:
    437
    James Kanze
    Nov 19, 2008
  3. optical supercomputing

    Optical Computing: special issue - Natural Computing, Springer

    optical supercomputing, Dec 19, 2008, in forum: C Programming
    Replies:
    0
    Views:
    437
    optical supercomputing
    Dec 19, 2008
  4. optical supercomputing

    Optical Computing: special issue - Natural Computing, Springer

    optical supercomputing, Jan 16, 2009, in forum: C Programming
    Replies:
    0
    Views:
    457
    optical supercomputing
    Jan 16, 2009
  5. pozz
    Replies:
    12
    Views:
    765
    Tim Rentsch
    Mar 20, 2011
Loading...

Share This Page