If I use:
i:= to_integer( signed( slv(upper downto lower)));
I'll get sign extension if upper==lower (which I don't want).
To avoid sign extension, I've tried:
i:= to_integer( signed( '0' & slv(upper downto lower)));
That works great until upper=31, and lower=0---leading to a to_signed
truncation warning (since in this case we're creating a 33-bit vector
and reducing it to a 32-bit integer).
I could just check if upper==lower, and break the conversion into two
cases, but I'm wondering if there's a cleaner, more elegant way of
handling this conversion without warnings.
What's wrong with using unsigned instead of signed?
i:= to_integer( unsigned( slv(upper downto lower)));
- Kenn
--
---------------------------------
> I'm trying to elegantly convert a std_logic_vector(upper downto lower)
> to an integer without sign extension using ieee.numeric_std with upper
> and lower taking on values from 31 to 0 and with upper >= lower. I
> cannot seem to find a syntax that doesn't generate truncation
> warnings, or relies on doing some comparison.
>
> If I use:
>
> i:= to_integer( signed( slv(upper downto lower)));
>
> I'll get sign extension if upper==lower (which I don't want).
>
> To avoid sign extension, I've tried:
>
> i:= to_integer( signed( '0' & slv(upper downto lower)));
I think you might be trying too hard :)
How about:
i:= to_integer( unsigned( slv(upper downto lower)));
The *unsigned* type is there for doing, erm, unsigned arithmetic and
conversions :)
That should work for upper==lower as well:
entity testint is
end entity testint;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
architecture a1 of testint is
signal slv : std_logic_vector(1 downto 0) := "10";
signal one,zero : integer;
begin -- architecture a1
check: process is
begin -- process check
one <= to_integer(unsigned(slv(1 downto 1)));
zero <= to_integer(unsigned(slv(0 downto 0)));
wait for 0 ps;
assert one = 1 report "1==1 failure" severity error;
assert zero = 0 report "0==0 failure" severity error;
wait;
end process check;
end architecture a1;
Or did I misunderstand the problem?
Cheers,
Martin
--
martin.j...@trw.com
TRW Conekt - Consultancy in Engineering, Knowledge and Technology
http://www.conekt.net/electronics.html
>I'm trying to elegantly convert a std_logic_vector(upper downto lower)
>to an integer without sign extension using ieee.numeric_std with upper
>and lower taking on values from 31 to 0 and with upper >= lower. I
>cannot seem to find a syntax that doesn't generate truncation
>warnings, or relies on doing some comparison.
What's wrong with...
i := to_integer(unsigned(slv));
It will of course give you warnings if the MSB of a 32-bit SLV
is set, because VHDL integer cannot represent anything more
positive than (2**31)-1. That's tedious, but a fact of life.
But it should work fine with any slv with between 1 and 31
bits, and it will also work with 32-bit SLVs provided their
MSB is zero.
If you want to use signed() so that 32-bit slv's with the MSB
set will come out as negative integers (yuck) then yes, you have
a small problem with 1-bit values. How about packing to 32 bits
first, and then doing the conversion?
i := to_integer(
signed(
std_logic_vector'(31 downto upper+1 => '0') & slv
)
);
This *may* give warnings for the null range when upper=31,
although it's legal VHDL (I'm pretty sure).
Finally, why not write a custom function instead of trying to
inline the ghastly mess?
function to_uint(v: std_logic_vector) return integer is
begin
if v'length = 0 then
return 0;
elsif v'length = 1 then
return to_integer(unsigned(v));
else
return to_integer(signed(v));
end if;
end;
The function also provides you with a convenient place
to report application-specific errors and so forth.
But most of all it allows you to hide the kruft.
--
Jonathan Bromley, Verification Engineer
Verilab www.THAT_COMPANY.com
end;
Actually, after a brief re-think, you're sort of hosed in any case.
VHDL only officially defines integers as
type integer is range -2147483648 to 2147483647;
which means you can't represent positive x"FFFFFFFF" = 2^32-1 in
integers to begin with. Implementations *may* support larger but it's
not guaranteed.
- Kenn
--
---------------------------------
Remove NOSPAM from email address.
I'm coming to the conclusion that I'm not going to be able to do a 1-
liner in VHDL without living with warnings. I want my conversions to
be warning free (even if it still works out), so I'm thinking of going
with the following:
lower := c_field_offset;
upper := lower + c_field_size - 1;
if (2**c_field_size-1) > integer'high then
i := to_integer( signed( slv(upper downto lower)));
else
i := to_integer( unsigned( slv(upper downto lower)));
end if;
5-lines instead of 1---but then that's VHDL
Gave
i := to_integer( signed( std_logic_vector'(31 downto upper+1 =>
'0') & slv(upper downto lower) ));
a try. Got:
** Warning: [3] test.vhd(25): (vcom-1246) Range 31 downto 32 is
null.
Thanks for the suggestion, though.
FYI, the (2**c_field_size - 1) doesn't work as 2**c_field_size itself
needs to be within the range of integers! I finally punted and just
made it : if c_field_size > 31 then ...
>Gave
>
> i := to_integer( signed( std_logic_vector'(31 downto upper+1 =>
>'0') & slv(upper downto lower) ));
>
>a try. Got:
>
> ** Warning: [3] test.vhd(25): (vcom-1246) Range 31 downto 32 is
>null.
>Thanks for the suggestion, though.
It wasn't as good a suggestion as "write a function to do it".
If you're really allergic to homemade functions, though, you
could kill the warning from the command line:
vcom -nowarn 1246 .....
(or something very like that; check the help files).
Please note, to echo and expand on what someone else said, that
VHDL is NOT guaranteed to support the full 32-bit range. In
particular, the extreme negative value -(2**31) is NOT
guaranteed to be representable as INTEGER. This means that
precisely one 32-bit value (0x8000_0000) is not safe.
Yes, I know it's a damned nuisance, but that's what the
language standard says.
Why do you have to use the integer type? why cant you just stick with
signed/unsigned? Afaik, you can still do all the same arithmatic on
signed/unsigned, but you have no bit width problems.
That is not true: with signed/unsigned you are forced to
deal with bit widths and resizes explicitly, unlike integer.
Given all the pain that comes out of discussions such as this one,
I'd like to point out that with MyHDL, I think I have solved these issues.
In MyHDL, you can use a (constrained) integer with arbitrary sizes,
and the convertor to VHDL will deal with the low-level issues for you.
See:
http://www.myhdl.org/doku.php/why#you_think_vhdl_requires_too_many_conversion_functions
Background:
http://www.jandecaluwe.com/hdldesign/counting.html
Jan
--
Jan Decaluwe - Resources bvba - http://www.jandecaluwe.com
Python as a HDL: http://www.myhdl.org
VHDL development, the modern way: http://www.sigasi.com
Analog design automation: http://www.mephisto-da.com
World-class digital design: http://www.easics.com
>Yes, I know it's a damned nuisance, but that's what the
>language standard says.
Is there somewhere a standard or near-standard package
for things like u_int64 or s_int128?
Writing a testbed for a 64 bit CPU is a royal pain, and
even if these long ints were composed from the usual 31.9 bit ints,
this should simulate much faster than SLVs, where each and
every single bit has to be kissed individually.
regards, Gerhard
>Is there somewhere a standard or near-standard package
>for things like u_int64 or s_int128?
Nothing that I know of. It would be a nice exercise.
Presumably you could represent the big-integer as an
array of (say) 16-bit integers. Then you would need
all the operator overloads, and conversion functions
to/from regular integers (with warnings on overflow),
to/from numeric_std types, and to/from string because
otherwise there would be no easy way to represent
wide literal values.
It is not blindingly obvious that a hand-crafted
package like that would be faster than the simulators'
highly optimized internal implementations of numeric_std.
Certainly it would be no good for synthesis. But I
can see it being useful for testbench, as you suggest.
Do you think it would be sufficient to have signed
and unsigned versions of 16xN bits (1<=N<=lots)?
Obviously one would need to represent a bigint in
units of words, enforcing a granularity on the
available widths; representing it in bits would be
hopelessly inefficient, and using a record with
a bit-width as one of its members would also bring
significant memory and runtime penalty (I suspect).
I don't have time to play with this idea in detail
just now, but it sounds like a pleasant project for
an idle weekend some time.
>Do you think it would be sufficient to have signed
>and unsigned versions of 16xN bits (1<=N<=lots)?
>Obviously one would need to represent a bigint in
>units of words, enforcing a granularity on the
>available widths; representing it in bits would be
>hopelessly inefficient, and using a record with
>a bit-width as one of its members would also bring
>significant memory and runtime penalty (I suspect).
16 bit chunks might still be dangerous for mul & div
because of that 0x8000_0000 value that even resists abs()
and that doesn't really exist in VHDL.
Also, I see no cheap way to extract and insert bit fields
from/to integers. ObHeresy: sometimes unions or
variant records are handy ;-)
Maybe some BCD-style arithmetic on 4 or 8 bit chunks
would be a good compromise. The basic operations could be
table driven but would not hurt the cache tooooo badly.
String I/O was easy and would avoid a lot of extra-long
mul/div/mod, most welcome in test bed codes.
Here it's time to test my own bed now.
Have a nice weekend,
Gerhard