![]() |
|
|
|||||||
![]() |
VHDL - Computing the width of an unsigned variable from maximum value? |
|
|
Thread Tools | Search this Thread |
|
|
#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 |
|
|
|
|
#2 |
|
Posts: n/a
|
"Torsten Landschoff" <> wrote in message news: ups.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 |
|
|
|
#3 |
|
Posts: n/a
|
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 |
|
|
|
#4 |
|
Posts: n/a
|
"Torsten Landschoff" <> wrote in message news: oups.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 |
|
|
|
#5 |
|
Posts: n/a
|
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; |
|
|
|
#6 |
|
Posts: n/a
|
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 |
|
|
|
#7 |
|
Posts: n/a
|
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 |
|
|
|
#8 |
|
Posts: n/a
|
typo:
> Wiring procedures and entities together processes --------- -- Mike Treseler |
|
|
|
#9 |
|
Posts: n/a
|
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 |
|