Overflow on INTEGER value.

L

Luis Cupido

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.
 
A

Andy

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
 
A

Andy

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
 
A

Anton Gunman

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 !
 
N

Nicolas Matringe

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
 
R

Rob Gaddi

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?
 
L

Luis Cupido

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:
ADDR_WIDTH: INTEGER:=10;
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 :-(

Your comments are very valuable and I will read them with all attention.
Many thanks.

Luis C.
 
A

Anton Gunman

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.
 
L

Luis Cupido

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.
 
A

Andy

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
 
R

Rob Gaddi

When using "others", the compiler has to be able to figure out from context what 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 argument should 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

Although Quartus 12.0, at least, doesn't have numeric_std_unsigned support yet. Can't speak to other synthesis tools.
 
R

rickman

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:
ADDR_WIDTH: INTEGER:=10;
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 ?

The compiler wants you to tell it how many zeros to pad with, it's not a
mind reader even though it seems obvious to you. Better to do it this way.

data_ii <= ((data_ii'high downto data_in'high+1) =>' 0' ) & data_in;

I'm a bit rusty on VHDL not having done much in a year or two. There
may be an easier way to do this. I seem to recall there is a specific
function in the numeric_std library for resizing... maybe it is called
resize(). In that case it would be something like this...

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

Check the docs, I just don't recall and I don't have access to any docs
at the moment, I am writing this offline.

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.

Yeah, well that is not the best way to do it. ieee.std_logic_anything
is the evil twin of numeric_std or maybe more like the Bizzaro world
version and should be avoided at all costs. One of the many problems is
that it does not allow you to mix signed and unsigned representations
since the two libraries are mutually exclusive. Stick with numeric_std.

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 :-(

Your comments are very valuable and I will read them with all attention.
Many thanks.

I fell out of love with std_logic_vector a long time ago in favor of
unsigned and signed. Integer takes a little getting used to since
modulo arithmetic is not automatic. I hate having my simulation stop
because an integer got out of bounds, but it is only my own fault for
coding it that way.

Rick
 
R

rickman

Although Quartus 12.0, at least, doesn't have numeric_std_unsigned support yet. Can't speak to other synthesis tools.

What is "numeric_std_unsigned"? Do you mean, "numeric_std"? That, I
can assure you, is supported by all synthesis tools updated in the last
5 if not the last 10 years!

Rick
 
L

Luis Cupido

Now I have all three versions working.
with integers
with std_logic_unsigned
and with numeric_std

(kind of made of it a learning experience).


No issues with integers only the 2^32 overflow.
No issues with std_logic_unsigned
Only a last doubt subsisted with numeric_std.


Converting an input that is a std_logic_vector into unsigned.
I found that simple cast works. either from unsigned to std_vectors
and vice versa.

(addr_in is std_logic_vector, addr_ii is unsigned )

addr_ii <= unsigned(addr_in); -- ok


however there are convert functions but they are giving me issues.

addr_ii <= to_unsigned(addr_in); -- Error (10476): VHDL error at
accram_01.vhd(90): type of identifier "addr_in" does not agree with its
usage as "natural" type

I see the std_logic_vector as argument as below...

function TO_UNSIGNED ( ARG: STD_LOGIC_VECTOR) return UNSIGNED;
-- Result subtype: UNSIGNED, same range as input ARG
-- Result: Converts STD_LOGIC_VECTOR to UNSIGNED.


the same for the opposite conversion
cast do work fine.

(data_out is std_logic_vector, data_od is unsigned )

data_out <= std_logic_vector(data_od); -- ok


data_out <= to_stdlogicvector(data_od); -- Error (10405): VHDL error at
accram_01.vhd(92): can't determine type of object at or near identifier
"to_stdlogicvector" -- found 0 possible types

I see also the unsigned as argument as below...

function TO_STDLOGICVECTOR ( ARG: UNSIGNED) return STD_LOGIC_VECTOR;
-- Result subtype: STD_LOGIC_VECTOR, same range as input ARG
-- Result: Converts UNSIGNED to STD_LOGIC_VECTOR.


however the function to_integer( ) works very fine. :)


I'm happy to use casts, all works well,
but what the heck am I doing wrong when using the
to_unsigned and to_stdlogicvector functions ?



Luis C.
 
R

rickman

Now I have all three versions working.
with integers
with std_logic_unsigned
and with numeric_std

(kind of made of it a learning experience).


No issues with integers only the 2^32 overflow.
No issues with std_logic_unsigned
Only a last doubt subsisted with numeric_std.


Converting an input that is a std_logic_vector into unsigned.
I found that simple cast works. either from unsigned to std_vectors
and vice versa.

(addr_in is std_logic_vector, addr_ii is unsigned )

addr_ii <= unsigned(addr_in); -- ok


however there are convert functions but they are giving me issues.

addr_ii <= to_unsigned(addr_in); -- Error (10476): VHDL error at
accram_01.vhd(90): type of identifier "addr_in" does not agree with its
usage as "natural" type

I see the std_logic_vector as argument as below...

function TO_UNSIGNED ( ARG: STD_LOGIC_VECTOR) return UNSIGNED;
-- Result subtype: UNSIGNED, same range as input ARG
-- Result: Converts STD_LOGIC_VECTOR to UNSIGNED.


the same for the opposite conversion
cast do work fine.

(data_out is std_logic_vector, data_od is unsigned )

data_out <= std_logic_vector(data_od); -- ok


data_out <= to_stdlogicvector(data_od); -- Error (10405): VHDL error at
accram_01.vhd(92): can't determine type of object at or near identifier
"to_stdlogicvector" -- found 0 possible types

I see also the unsigned as argument as below...

function TO_STDLOGICVECTOR ( ARG: UNSIGNED) return STD_LOGIC_VECTOR;
-- Result subtype: STD_LOGIC_VECTOR, same range as input ARG
-- Result: Converts UNSIGNED to STD_LOGIC_VECTOR.


however the function to_integer( ) works very fine. :)


I'm happy to use casts, all works well,
but what the heck am I doing wrong when using the
to_unsigned and to_stdlogicvector functions ?



Luis C.

Where do you find these conversion functions to_unsigned and
to_stdlogicvector? I don't think they are part of numeric_std. Maybe
you have too many libraries loaded and aren't keeping them all straight?

Rick
 
L

Luis Cupido

Where do you find these conversion functions to_unsigned and
to_stdlogicvector? I don't think they are part of numeric_std. Maybe you
have too many libraries loaded and aren't keeping them all straight?

Rick

I just have:

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;

the to_unsigned() yes is part of numeric_std,
the to_stdlogicvector() I saw on the web but after
your post I was looking inside the libs that came with Quartus and
You're right that one is not there.

on the numeric_std that came with quartusII it is now very clear that
to_signed() and to_unsigned() functions are for converting integers
only. period !

The origin of all confusion was found here on the web
lines 626 and following where all those stuff for std_logic_vectors also
exists.
Apparently existed in 1994 and were taken out in 1995... :-(

http://www.ece.msstate.edu/~reese/EE8993/ieee_standards/numeric_std.vhd

sometimes the web is a bad place to look for info :-(

lc
 
L

Luis Cupido

It has 4 functions less on version 2.4.
Is this version 2.4 the right/last version to use ?

thanks for your help and patience.

lc

---------------------------------------------------------------------------------------------
-- Version: 2.4
-- Date : 12 April 1995
....snip
--===================
-- Conversion Functions
--===================
-- Id: D.1
function TO_INTEGER (ARG: UNSIGNED) return NATURAL;
-- Result subtype: NATURAL. Value cannot be negative since parameter
is an
-- UNSIGNED vector.
-- Result: Converts the UNSIGNED vector to an INTEGER.

-- Id: D.2
function TO_INTEGER (ARG: SIGNED) return INTEGER;
-- Result subtype: INTEGER
-- Result: Converts a SIGNED vector to an INTEGER.

-- Id: D.3
function TO_UNSIGNED (ARG, SIZE: NATURAL) return UNSIGNED;
-- Result subtype: UNSIGNED(SIZE-1 downto 0)
-- Result: Converts a non-negative INTEGER to an UNSIGNED vector with
-- the specified SIZE.

-- Id: D.4
function TO_SIGNED (ARG: INTEGER; SIZE: NATURAL) return SIGNED;
-- Result subtype: SIGNED(SIZE-1 downto 0)
-- Result: Converts an INTEGER to a SIGNED vector of the specified SIZE.



---------------------------------------------------------------------------------------------
-- : Rev. 1.7 (Nov. 23 1994)
....snip
--===================
-- Conversion Functions
--====================
-- Id: D.1
function TO_INTEGER ( ARG: UNSIGNED) return NATURAL;
-- Result subtype: NATURAL. Value cannot be negative since
parameter is an
-- UNSIGNED vector.
-- Result: Converts the UNSIGNED vector to an INTEGER.

-- Id: D.2
function TO_INTEGER ( ARG: SIGNED) return INTEGER;
-- Result subtype: INTEGER
-- Result: Converts a SIGNED vector to an INTEGER.

-- Id: D.3
function TO_UNSIGNED ( ARG,SIZE: NATURAL) return UNSIGNED;
-- Result subtype: UNSIGNED (SIZE-1 downto 0)
-- Result: Converts a non-negative INTEGER to an UNSIGNED vector with
-- the specified SIZE.

-- Id: D.4
function TO_SIGNED ( ARG: INTEGER; SIZE: NATURAL) return SIGNED;
-- Result subtype: SIGNED (SIZE-1 downto 0)
-- Result: Converts an INTEGER to a SIGNED vector of the specified
SIZE.

-- Id: D.5
function TO_UNSIGNED ( ARG: STD_LOGIC_VECTOR) return UNSIGNED;
-- Result subtype: UNSIGNED, same range as input ARG
-- Result: Converts STD_LOGIC_VECTOR to UNSIGNED.

-- Id: D.6
function TO_SIGNED ( ARG: STD_LOGIC_VECTOR) return SIGNED;
-- Result subtype: SIGNED, same range as input ARG
-- Result: Converts STD_LOGIC_VECTOR to SIGNED.

-- Id: D.7
function TO_STDLOGICVECTOR ( ARG: UNSIGNED) return STD_LOGIC_VECTOR;
-- Result subtype: STD_LOGIC_VECTOR, same range as input ARG
-- Result: Converts UNSIGNED to STD_LOGIC_VECTOR.

-- Id: D.8
function TO_STDLOGICVECTOR ( ARG: SIGNED) return STD_LOGIC_VECTOR;
-- Result subtype: STD_LOGIC_VECTOR, same range as input ARG
-- Result: Converts SIGNED to STD_LOGIC_VECTOR.
 
R

Rob Gaddi

[snip]

What is "numeric_std_unsigned"? Do you mean, "numeric_std"? That, I
can assure you, is supported by all synthesis tools updated in the last
5 if not the last 10 years!

Rick

NSU is a VHDL-2008 package. It's basically meant as a replacement for
std_arith_unsigned, or some of it's equally non-standard brethren. It
allows for direct treatment of std_logic_vector as unsigned without
conversion, and supports TO_INTEGER(slv) and
TO_STANDARD_LOGIC_VECTOR(integer). I go back and forth as to whether
it's the handiest thing ever, or an abomination against strong typing.
 
N

Nicolas Matringe

Le 11/10/2012 18:15, Rob Gaddi a écrit :
NSU is a VHDL-2008 package. It's basically meant as a replacement for
std_arith_unsigned, or some of it's equally non-standard brethren. It
allows for direct treatment of std_logic_vector as unsigned without
conversion, and supports TO_INTEGER(slv) and
TO_STANDARD_LOGIC_VECTOR(integer). I go back and forth as to whether
it's the handiest thing ever, or an abomination against strong typing.
It is an abomination and those who created it should burn in VHD-hell ;o)

Nicolas
 
A

Andy

Converting between "closely related types" does not need an explicit conversion function. Instead, the destination type name is used as an implicit conversion function name: unsigned(my_slv) or std_logic_vector(my_unsigned). "Closely related types" include arrays of the same element type, but there may be other examples. The two numeric_std functions were probably removed because they were not (ever) needed, and discouraged using the language's built-in capabilities.

Andy
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top