Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   VHDL (http://www.velocityreviews.com/forums/f18-vhdl.html)
-   -   Overflow on INTEGER value. (http://www.velocityreviews.com/forums/t953178-overflow-on-integer-value.html)

 Luis Cupido 10-09-2012 12:59 AM

Overflow on INTEGER value.

Hello.

I got a perfectly working code of a component (an accumulating RAM)
with some generic defenition of bus sizes.

As it has the content add operations and some address offsetting all
goes with
straightforward code using integers for both memory (an array of integers)
and pointers. Integer ranges are simply from 0 to 2**BUS_SIZES -1
being the output data bus wider than input data bus (as one would expect).

So far so good, all works.

But if I have a 16bit data bus and want to accumulate 2**18 times
range is 0 to 2**(16+18)-1 which is a 34bit wide data_out bus
and I have a value overflow on the range calculation.

Question:

Is there any clever way to get this simple range calculation working
past the
integer range problem ? (I know that explicit I can have whatever I need
but a I need a calculated value from generic clause and calculating ranges
overflows at 2**32 bit).

I can' t even have a 32bit bus defined range 0 to 2**32-1...

Should I forget integers, and rewrite it all to use unsigned instead ?
Any hints ?

Thanks.

Luis C.

 Andy 10-09-2012 02:17 PM

Re: Overflow on INTEGER value.

If you need a data size larger than 32 bit signed, or 31 bit unsigned, you need to use numeric_std.signed/unsigned. The VHDL standard defines the minimum range (+/- (2**31 - 1), which is not actually 32 bit two's complement (which includes -(2**31)). There are no implementations of which I am aware that extend the range of integers to 64 bit. There are some implemntations that do extend the integer range to that of a true 32 bit two's complement.

Andy

 Andy 10-09-2012 02:26 PM

Re: Overflow on INTEGER value.

I should also noted that you should not "forget integers". Where applicable, they have several advantages over array-based representations:

They are immediately useable as an index to an array.
They are easier to use when detecting carry/borrow.
They DON'T automatically roll over.
They simulate MUCH faster.
They allow non-power-of-two subranges.
They automatically detect out-of-range conditions upon assignment.
They automatically promote results of an expression to integer, regardless of the operand subranges.

Andy

 Anton Gunman 10-09-2012 02:39 PM

Re: Overflow on INTEGER value.

Hello,

I would say that, in your case, it would be best to use the "unsigned" notation for the data.
You could keep the address pointers in integer notation.

Calculating the required number of bits for the accumulator can be straight forward.

constant MY_ACC_WIDTH : integer := INPUT_WIDTH + NUM_OF_ACCS_LOG2;
signal my_unsigned : unsigned(MY_ACC_WIDTH-1 downto 0);
signal my_acc : unsigned(MY_ACC_WIDTH-1 downto 0); -- Single accumulator

-- Accumulator RAM
type type_acc_ram is array(integer range 0 to RAM_SIZE-1) of unsigned(MY_ACC_WIDTH-1 downto 0);
signal my_acc_ram : type_acc_ram := (others => (others => '0'));

In case your input is an integer, you just have to cast it into an equivalent unsigned vector.
Note: In order not to truncate any information and to simplify subsequent operations, you may use the full accumulator width for all your operations.
The synthesis tool (in most cases) should be smart enough to eliminate any bits tied to 'zero' or to 'one'.

If you are using the numeric_std library, you can use the following casts/conversions.

-- integer to unsigned
my_unsigned <= to_unsigned(my_int, my_unsigned'length);

-- unsigned to integer
my_int <= to_integer(my_unsigned);

-- resize (if unsigned: pads with zeros, if signed: performs sign extension)
my_new_unsigned <= resize(my_old_unsigned, my_new_unsigned'length);

Note: If your number of accumulations is a power of 2, (e.g. 2**18) you just have to use NUM_OF_ACCS_LOG2 = 18;
If it's not the case you might need to calculate NUM_OF_ACCS_LOG2; it can be done as such.

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all; -- Only required if you need to calculated the log2
-- ...
constant NUM_OF_ACCS_LOG2 : integer := integer(ceil(log2(real(NUM_OF_ACCS))));

The "real" data types are not used for synthesis, but just for calculating ranges.
Note: You might be able to calculate the log2 in a different way by defining a looping function (instead of using the "real" type).

I hope this helps,
Cheers !

 Nicolas Matringe 10-09-2012 08:14 PM

Re: Overflow on INTEGER value.

Le 09/10/2012 16:17, Andy a écrit :
> The VHDL standard defines the minimum range (+/- (2**31 - 1)

[...]
> There are no implementations of which I am aware that extend the range of integers to 64 bit.

Wouldn't it be time we VHDL users push towards 64-bits integers support?

Nicolas

Re: Overflow on INTEGER value.

On Tue, 09 Oct 2012 22:14:49 +0200
Nicolas Matringe <nicolas.matringe@fre.fre> wrote:

> Le 09/10/2012 16:17, Andy a Ã©crit :
> > The VHDL standard defines the minimum range (+/- (2**31 - 1)

> [...]
> > There are no implementations of which I am aware that extend the range of integers to 64 bit.

>
> Wouldn't it be time we VHDL users push towards 64-bits integers support?
>
> Nicolas

Yeah, I could get behind that. Can anyone think of a legitimate use
case that relies on limitation of integer to 31+sign?

--
Rob Gaddi, Highland Technology -- www.highlandtechnology.com
Email address domain is currently out of order. See above to fix.

 Luis Cupido 10-09-2012 10:55 PM

Re: Overflow on INTEGER value.

Thanks all for the valuable tips.
I could recognize Anton's suggestions in my attempts to
change it to unsigned. Good, tks.

I can't really make the code work with unsigned as I start to
have some issues on things that before were quite trivial.

Generic I have:
INT_WIDTH: INTEGER:=16; -- number of bits for integration counting, set
the maximum number of acc cycles.
DATA_WIDTH: INTEGER:=17;

then I have a

CONSTANT ACC_WIDTH: INTEGER:= DATA_WIDTH +INT_WIDTH

all internals use the ACC_WIDTH and also
output is of ACC_WIDTH

before with integer types I just calculated RANGES from the above
values. which is fairly simple just a power of two. Then internal stuff is
integers and straight forward code.

Now with unsigned I start to have a miriad of other issues that I can't
solve.

like for example:

my input is std_logic_vector, that previously I converted to integer

data_ii <= conv_integer(unsigned(data_in));

now that types are ok I only need to make sizes match by padding zeros.

data_ii <= (others =>' 0' ) & data_in;

" Error (10427): VHDL aggregate error at accram_01.vhd(91): OTHERS
choice used in aggregate for unconstrained record or array type is not
supported"

Why cant the compiler count how many bits are required to fill the thing
up to the L size.
I can't possibly put it explicit as it come from a generic clause. What
am I missing ?

Same as for literals that I can' t use numbers as before etc. and don't
know how to make numeric stuff match the size of the std_logic_vectors
when the sizes are not
fixed but from a generic clause. Should I use convert functions everywhere ?

btw, I'm using
USE ieee.std_logic_unsigned.ALL;
to make it easier on the additions and etc.

Goes without saying that 99.9% of my coding uses std_logic
and integers, and I have been very very happy for many years now :-(

Many thanks.

Luis C.

 Anton Gunman 10-10-2012 01:08 AM

Re: Overflow on INTEGER value.

I personally use the "numeric_std" library and am not too familiar with the conversion functions in the other libraries.
The only main difference when using numeric_std is that "std_logic_vector" types are treated as a signal bus with no arithmetic meaning, hence you cannot add/sub/mult any std_logic_vector(s) directly (this does not apply to the other libraries).
You have to explicitly cast them into either "unsigned" or "signed" type prior to performing any mathematical calculations.
Typically, your top level I/O ports would be of "std_logic_vector", but your internal signals would be of type "unsigned"/"signed".

In case you are willing to use the "numeric_std" library, your code to pad with zeros would look as such:
-- Signal declaration
signal data_ii : unsigned(ACC_WIDTH downto 0);
--...

data_ii <= resize(unsigned(data_in), data_ii'length);
-- OR
-- data_ii <= resize(unsigned(data_in), ACC_WIDTH);

On the other hand, if you still want to stick with your current library, you may always perform the same thing with some bit manipulations as such:

data_ii(data_ii'length-1 downto DATA_WIDTH) <= (others => '0');
data_ii(DATA_WIDTH-1 downto 0) <= data_in;

Or you might use the "conv_unsigned" (instead of "resize").

I would suggest you switch to "numeric_std" and then post some code in case you are still facing issues.

 Luis Cupido 10-10-2012 02:06 PM

Re: Overflow on INTEGER value.

On 10/10/2012 2:08 AM, Anton Gunman wrote:
> I personally use the "numeric_std" library and am not too familiar with the conversion functions in the other libraries.
> The only main difference when using numeric_std is that "std_logic_vector" types are treated as a signal bus with
> no arithmetic meaning, hence you cannot add/sub/mult any

std_logic_vector(s) directly (this does not apply to the other libraries).
> You have to explicitly cast them into either "unsigned" or "signed" type prior to performing any mathematical calculations.
> Typically, your top level I/O ports would be of "std_logic_vector", but your internal signals would be of type "unsigned"/"signed".
>
> In case you are willing to use the "numeric_std" library, your code to pad with zeros would look as such:
> -- Signal declaration
> signal data_ii : unsigned(ACC_WIDTH downto 0);
> --...
>
> data_ii<= resize(unsigned(data_in), data_ii'length);
> -- OR
> -- data_ii<= resize(unsigned(data_in), ACC_WIDTH);
>
> On the other hand, if you still want to stick with your current library, you may always perform the same thing with some bit manipulations as such:
>
> data_ii(data_ii'length-1 downto DATA_WIDTH)<= (others => '0');
> data_ii(DATA_WIDTH-1 downto 0)<= data_in;
>
> Or you might use the "conv_unsigned" (instead of "resize").
>
> I would suggest you switch to "numeric_std" and then post some code in case you are still facing issues.

After a bit of struggle with small details that I was not aware of,
I got it working both with std_logic_unsigned or with numeric_std libs

Funny enough that QuartusII generates better/faster logic when I
do not use integers for the data path and arithmetic.

ok... All progressing now.
Many thanks.

Luis C.

 Andy 10-10-2012 04:53 PM

Re: Overflow on INTEGER value.

When using "others", the compiler has to be able to figure out from contextwhat size is needed. In your case, (others=>'0') is used as an argument to an & operator, which takes an unconstrained vector. Therefore, the & operator does not give the compiler any clues about how wide its left argumentshould be. The compiler also does not "know" that the & is just a concatenator; it is just an operator.

Numeric_std defines a resize() function that can be used intelligently on signed or unsigned types to adjust their size.

Please do not use std_logic_arith, std_logic_unsigned, or std_logic_signed.These are NOT standard IEEE-approved packages, and should have never been in the IEEE library in the first place. The sooner everyone quits using these packages, the better. The IEEE standard package to use instead is numeric_std. VHDL 2008 also includes a numeric_std_unsigned package, which defines arithmetic operators and functions that use std_logic_vector (like std_logic_unsigned, but an official standard.)

Andy

All times are GMT. The time now is 08:02 PM.