flaw in to_signed() for big numbers?

K

Kevin Neilson

Guest
Signed types (using numeric_std) can have widths bigger than 32, but the
to_signed() function only takes integers as an argument, so it seems to
be very difficult to assign values to large signed constants. For
example, in my code I have:

constant round_const: signed(c'range) := to_signed(2**x-1,c'length);

This doesn't work if x==32, because 2**32-1 is outside the range of an
integer (which must be <=(2**31-1)). I can't use a real as an argument,
and I can't convert a real to a signed without converting it to an
integer first, and then I have the same problem.

A workaround, for this case, seems to be:

constant round_const: signed(c'range):= (x-1 downto 0=>'1',others=>'0');

But that is weak.
-Kevin
 
Kevin Neilson wrote:
Signed types (using numeric_std) can have widths bigger than 32, but the
to_signed() function only takes integers as an argument, so it seems to
be very difficult to assign values to large signed constants.
32 bit ints are annoying but vector
hex constants work for any value.
my_vec_v := x"123456789abc" ;

I use python to do the conversions

int(0x123456789abc)
20015998343868L
hex(20015998343868)
'0x123456789abcL'


-- Mike Treseler
 
On Wed, 02 Jul 2008 15:31:54 -0600, Kevin Neilson wrote:

Signed types (using numeric_std) can have widths bigger than 32, but the
to_signed() function only takes integers as an argument, so it seems to
be very difficult to assign values to large signed constants. For
example, in my code I have:

constant round_const: signed(c'range) := to_signed(2**x-1,c'length);

This doesn't work if x==32, because 2**32-1 is outside the range of an
integer (which must be <=(2**31-1)). I can't use a real as an argument,
and I can't convert a real to a signed without converting it to an
integer first, and then I have the same problem.

A workaround, for this case, seems to be:

constant round_const: signed(c'range):= (x-1 downto 0=>'1',others=>'0');

But that is weak.
Agreed. In particular, the lack of full-width 32-bit
unsigned integers in VHDL is fairly painful in practice.

Not perfect, but you could consider some functions....

function max_signed(n_bits:positive) return signed is
variable c : signed(n_bits-1 downto 0) :=
(others => '1');
begin
c(c'left) := '0';
return c;
end;

Betcha you already thought of that, though :)
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.bromley@MYCOMPANY.com
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
On Thu, 3 Jul 2008 04:55:52 -0700 (PDT), Rob wrote:

Is the problem with precision a problem with the VHDL standard or is
it just the simulator?
VHDL standard requires integers to support a range of at least
max = 2**31 - 1, min = -(2**31 - 1). Note that this does NOT
include the most negative possible 2s complement number, -(2**31).
I think this was done to maximise portability across platforms;
in the days when VHDL was first designed, there were still
computers around that used sign-and-magnitude arithmetic.

Presumably a simulator could allow an
unconstrained integer to be of arbitrary size
I believe it could. But if you were to exploit that, you
could end up creating code that would not work correctly
in a different but nevertheless standards-compliant simulator.
If a standard specifies a minimum level of something, it's
usually wise to restrict your own code to stay within that
minimum level.

but what says that it should be done like that?
IEEE Std.1076. What higher authority could there be? :)
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.bromley@MYCOMPANY.com
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
On Jul 3, 12:04 am, Mike Treseler <mtrese...@gmail.com> wrote:
Kevin Neilson wrote:
Signed types (using numeric_std) can have widths bigger than 32, but the
to_signed() function only takes integers as an argument, so it seems to
be very difficult to assign values to large signed constants.

32 bit ints are annoying but vector
hex constants work for any value.
my_vec_v := x"123456789abc" ;

I use python to do the conversions

int(0x123456789abc)
20015998343868L
hex(20015998343868)
'0x123456789abcL'


-- Mike Treseler
A few other random thoughts... you could extend Mike's idea to express
a decimal number directly using a string, writing a conversion
function yourself. Then you don't need to leave the VHDL world at all.

function str_to_signed ( s : string; width : integer) return signed;
....
constant x := str_to_signed("1000000000", 64);

But you still need to manually evaluate "2**x - 1" which means you
still lose the ability to make your input argument dependent on a
generic. Perhaps just writing an integer exponentiation of signed
would help? Easy and fast when you have the binary representation of
the exponent, using the "signed" multiply.

function "**" ( x : signed; y : integer) return signed; -- compute x
** y
....
constant round_const: signed(c'range) := (to_signed(2,c'range))**x-1;

For your example (2^n) you might be able to use just a simple shift to
begin with. But your point is well taken - bignums in the LRM would be
nice :)

- Kenn
 
Going slightly off at a tangent here,
Is the problem with precision a problem with the VHDL standard or is
it just the simulator? Presumably a simulator could allow an
unconstrained integer to be of arbitrary size (like in Python).
I know that XST will implement an unconstrained integer as a 32bit
vector, but what says that it should be done like that?


On Jul 3, 12:17 pm, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com>
wrote:
On Wed, 02 Jul 2008 15:31:54 -0600, Kevin Neilson wrote:
Signed types (using numeric_std) can have widths bigger than 32, but the
to_signed() function only takes integers as an argument, so it seems to
be very difficult to assign values to large signed constants. For
example, in my code I have:

constant round_const: signed(c'range) := to_signed(2**x-1,c'length);

This doesn't work if x==32, because 2**32-1 is outside the range of an
integer (which must be <=(2**31-1)). I can't use a real as an argument,
and I can't convert a real to a signed without converting it to an
integer first, and then I have the same problem.

A workaround, for this case, seems to be:

constant round_const: signed(c'range):= (x-1 downto 0=>'1',others=>'0');

But that is weak.

Agreed. In particular, the lack of full-width 32-bit
unsigned integers in VHDL is fairly painful in practice.

Not perfect, but you could consider some functions....

function max_signed(n_bits:positive) return signed is
variable c : signed(n_bits-1 downto 0) :=
(others => '1');
begin
c(c'left) := '0';
return c;
end;

Betcha you already thought of that, though :)
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.brom...@MYCOMPANY.comhttp://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
On Jul 3, 1:51 pm, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com>
wrote:
On Thu, 3 Jul 2008 04:55:52 -0700 (PDT), Rob wrote:
Is the problem with precision a problem with the VHDL standard or is
it just the simulator?

VHDL standard requires integers to support a range of at least
max = 2**31 - 1, min = -(2**31 - 1). Note that this does NOT
include the most negative possible 2s complement number, -(2**31).
I think this was done to maximise portability across platforms;
in the days when VHDL was first designed, there were still
computers around that used sign-and-magnitude arithmetic.

Presumably a simulator could allow an
unconstrained integer to be of arbitrary size

I believe it could. But if you were to exploit that, you
could end up creating code that would not work correctly
in a different but nevertheless standards-compliant simulator.
If a standard specifies a minimum level of something, it's
usually wise to restrict your own code to stay within that
minimum level.

but what says that it should be done like that?

IEEE Std.1076. What higher authority could there be? :)
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.brom...@MYCOMPANY.comhttp://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
I know it's not very constructive to moan about these things, but
people have been having problems with this 32bit issue for years
(among other things). I do wish the evolution of the VHDL standard
wasn't so painfully slow.
 
kennheinrich@sympatico.ca wrote:
A few other random thoughts... you could extend Mike's idea to express
a decimal number directly using a string, writing a conversion
function yourself. Then you don't need to leave the VHDL world at all.

function str_to_signed ( s : string; width : integer) return signed;
...
constant x := str_to_signed("1000000000", 64);

- Kenn
I suppose I could make my own real_to_signed function and pass large
integers to it as reals. If the real is >= 2^31, I could split the real
into two parts, convert them to signeds and concatenate them. Not sure
if this would work. I'd probably also still be constrained by the
54-bit mantissa of a double, but that's a lot better than 32, a number
which is regularly exceeded when using the 48-bit Xilinx DSP48 accumulator.
-Kevin
 
Jonathan Bromley wrote:
On Thu, 3 Jul 2008 04:55:52 -0700 (PDT), Rob wrote:

Is the problem with precision a problem with the VHDL standard or is
it just the simulator?

VHDL standard requires integers to support a range of at least
max = 2**31 - 1, min = -(2**31 - 1). Note that this does NOT
include the most negative possible 2s complement number, -(2**31).
This has bitten me before too, causing an error that took a long time to
track until I found this fact in a textbook.

To be fair, I've encountered similar problems in Verilog, particularly,
as I recall, in using the $itor (integer to real) function for integers
larger than 2^32.
-Kevin
 
On Jul 3, 1:56 pm, Kevin Neilson <kevin_neil...@removethiscomcast.net>
wrote:
kennheinr...@sympatico.ca wrote:

A few other random thoughts... you could extend Mike's idea to express
a decimal number directly using a string, writing a conversion
function yourself. Then you don't need to leave the VHDL world at all.

function str_to_signed ( s : string; width : integer) return signed;
...
constant x := str_to_signed("1000000000", 64);

- Kenn

I suppose I could make my own real_to_signed function and pass large
integers to it as reals. If the real is >= 2^31, I could split the real
into two parts, convert them to signeds and concatenate them. Not sure
if this would work. I'd probably also still be constrained by the
54-bit mantissa of a double, but that's a lot better than 32, a number
which is regularly exceeded when using the 48-bit Xilinx DSP48 accumulator.
-Kevin
As ugly as sin, but it seems to work in simulation. I don't think
there are any fundamental width limitations. Modelsim is nice enough
to show you a decimal int greater than 32 bits (for validation) when
you choose 'decimal' radix in the waveform viewer.

- Kenn

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

package string_signed is
function str_to_signed (
s : string;
width : natural)
return signed ;
end string_signed;

package body string_signed is
function str_to_signed (
s : string;
width : natural)
return signed is
type t is array ('0' to '9') of integer;
constant smap : t := ( '0' => 0, '1' => 1, '2' => 2, '3' => 3,
'4' => 4, '5' => 5, '6' => 6, '7' => 7,
'8' => 8, '9' => 9);

variable v : signed(width-1 downto 0) := to_signed(0, width);
variable z : signed(2*width-1 downto 0) := to_signed(0, 2*width);
begin -- str_to_signed
assert s'length > 0 report "bad string" severity failure;
v := to_signed(smap(s(s'right)), width);
if s'length = 1 then
return v;
else
z := 10 * str_to_signed(s(s'left to s'right-1), width) + v;
assert z(z'left)='0'
and (z(z'left downto width+1) = z(z'left - 1 downto width))
report "ovfl";
return z(width-1 downto 0);
end if;
end str_to_signed;

end string_signed;

library IEEE;
use IEEE.numeric_std.all;
use work.string_signed.all;
entity e is
end e;

architecture a of e is

signal foo : signed(63 downto 0);
begin -- a

foo <= str_to_signed("123456789012345", 64);

end a;
 

Welcome to EDABoard.com

Sponsor

Back
Top