Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > VHDL > flaw in to_signed() for big numbers?

Reply
Thread Tools

flaw in to_signed() for big numbers?

 
 
Kevin Neilson
Guest
Posts: n/a
 
      07-02-2008
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
 
Reply With Quote
 
 
 
 
Mike Treseler
Guest
Posts: n/a
 
      07-03-2008
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(2001599834386

'0x123456789abcL'
>>>




-- Mike Treseler
 
Reply With Quote
 
 
 
 
kennheinrich@sympatico.ca
Guest
Posts: n/a
 
      07-03-2008
On Jul 3, 12:04 am, Mike Treseler <(E-Mail Removed)> 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(2001599834386

> '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
 
Reply With Quote
 
Rob
Guest
Posts: n/a
 
      07-03-2008
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 <(E-Mail Removed)>
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_bitsositive) 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
> (E-Mail Removed)://www.MYCOMPANY.com
>
> The contents of this message may contain personal views which
> are not the views of Doulos Ltd., unless specifically stated.


 
Reply With Quote
 
Rob
Guest
Posts: n/a
 
      07-03-2008
On Jul 3, 1:51 pm, Jonathan Bromley <(E-Mail Removed)>
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
> (E-Mail Removed)://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.
 
Reply With Quote
 
Kevin Neilson
Guest
Posts: n/a
 
      07-03-2008
http://www.velocityreviews.com/forums/(E-Mail Removed) 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
 
Reply With Quote
 
Kevin Neilson
Guest
Posts: n/a
 
      07-03-2008
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
 
Reply With Quote
 
kennheinrich@sympatico.ca
Guest
Posts: n/a
 
      07-03-2008
On Jul 3, 1:56 pm, Kevin Neilson <(E-Mail Removed)>
wrote:
> (E-Mail Removed) 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;
 
Reply With Quote
 
KJ
Guest
Posts: n/a
 
      07-05-2008

"Kevin Neilson" <(E-Mail Removed)> wrote in message
news:g4gs4b$(E-Mail Removed)...
> 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');
>


1. It's not that hard to write a function to compute a power when the
exponent is not a fraction. Something along the lines of the following is a
start

function pow(b, e: unsigned) return unsigned is
begin
if (to_integer(e) = 0) then
return(1);
elsif (to_integer(e) = 1) then
return(b);
else
return(b * pow(b, e-1);
end if'
end function pow;

1a. Perhaps override "**" to do this if you feel like it.

2. Then, using the synthesizable log2 function, give some more thought to
computing the proper number of bits for the return result and modify the
above mentioned starter function. That way 2**4 (when represented as
unsigned) will come out as 5 bits rather than 12.

2a. Hint for #2, a function to compute the ceil(log2(x)) would likely be a
handy function (perhaps ceil_log2(x)) which returns the smallest unsigned
that is greater than or equal to log2(x) (i.e. returns the conventional
'ceiling' math function).

3. Now you can say
constant round_const: signed(c'range) := pow("0010", "0100") - 1;
constant round_const: signed(c'range) := pow(x"2", x"4") - 1;

Remembering that hard coded constants (like 2 and 4 in this example; 2 and
32 in the OP example) can generally also be represented as generics and that
generics can be signed/unsigned of arbitrary width as well as integers one
is well on their way to working strictly with signed/unsigned directly
instead of doing the math in integers which is the source of the problem
here.

Kevin Jennings


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
GIDS 2009 .Net:: Save Big, Win Big, Learn Big: Act Before Dec 29 2008 Shaguf ASP .Net 0 12-26-2008 09:29 AM
GIDS 2009 .Net:: Save Big, Win Big, Learn Big: Act Before Dec 29 2008 Shaguf ASP .Net Web Controls 0 12-26-2008 06:11 AM
GIDS 2009 Java:: Save Big, Win Big, Learn Big: Act Before Dec 29 2008 Shaguf Python 0 12-24-2008 07:35 AM
GIDS 2009 Java:: Save Big, Win Big, Learn Big: Act Before Dec 29 2008 Shaguf Ruby 0 12-24-2008 05:07 AM
Outlook TNEF flaw could be much worse than WMF flaw Au79 Computer Support 0 01-13-2006 10:48 PM



Advertisments