flaw in to_signed() for big numbers?

Discussion in 'VHDL' started by Kevin Neilson, Jul 2, 2008.

  1. 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, Jul 2, 2008
    #1
    1. Advertising

  2. 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
     
    Mike Treseler, Jul 3, 2008
    #2
    1. Advertising

  3. Kevin Neilson

    Guest

    On Jul 3, 12:04 am, Mike Treseler <> 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
     
    , Jul 3, 2008
    #3
  4. Kevin Neilson

    Rob Guest

    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 <>
    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
    > ://www.MYCOMPANY.com
    >
    > The contents of this message may contain personal views which
    > are not the views of Doulos Ltd., unless specifically stated.
     
    Rob, Jul 3, 2008
    #4
  5. Kevin Neilson

    Rob Guest

    On Jul 3, 1:51 pm, 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).
    > 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
    > ://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.
     
    Rob, Jul 3, 2008
    #5
  6. 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
     
    Kevin Neilson, Jul 3, 2008
    #6
  7. 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
     
    Kevin Neilson, Jul 3, 2008
    #7
  8. Kevin Neilson

    Guest

    On Jul 3, 1:56 pm, Kevin Neilson <>
    wrote:
    > 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;
     
    , Jul 3, 2008
    #8
  9. Kevin Neilson

    KJ Guest

    "Kevin Neilson" <> wrote in message
    news:g4gs4b$...
    > 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
     
    KJ, Jul 5, 2008
    #9
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    32
    Views:
    977
    Alan Isaac
    Jul 2, 2007
  2. Shaguf
    Replies:
    0
    Views:
    378
    Shaguf
    Dec 24, 2008
  3. Shaguf
    Replies:
    0
    Views:
    463
    Shaguf
    Dec 26, 2008
  4. Shaguf
    Replies:
    0
    Views:
    250
    Shaguf
    Dec 26, 2008
  5. Shaguf
    Replies:
    0
    Views:
    227
    Shaguf
    Dec 24, 2008
Loading...

Share This Page