Get IEEE-754 single precision representation of a real number in VHDL - vhdl

I want to convert a real number to his bit representation, with the fields of sign, exponent and mantissa in a VHDL TB for testing purposses (as a STD_LOGIC_VECTOR of 32 bits). Is there anyway to convert a real number to this representation directly in VHDL?
I know that in C is possible use a struct to achieve it, but I don't know if it's possible in VHDL.
Thank you.
Edit:
I've found this solution:
https://www.edaplayground.com/x/gQiN
But the synthesizer throw this error:
[XSIM 43-4187] File "/proj/xbuilds/2021.2_INT_0504_1926/installs/all_platforms/Vivado/2021.2/data/vhdl/src/ieee_2008/float_pkg.vhdl" Line 45 : The "Vhdl 2008 Package Instantiation Declaration" is not supported yet for simulation.
Then, I think the best solution is build a VHDL function that convert a real number to their IEEE-754 bit representation.

Chapter 5.2.5.2 of the standard VHDL-2008 says:
The only predefined floating-point type is the type REAL. The range of REAL is host-dependent, but it is guaranteed to be the largest allowed by the chosen representation.
However, functions of the package IEEE.float_pkg are described in chapter G.5.4.3 and include this functions:
To_slv Inputs: arg (float). Converts a floating-point number to a std_logic_vector of the same length.
To_std_logic_vector Alias for to_slv.
To_stdlogicvector Alias for to_slv.
To_sulv Inputs: arg (float). Converts a floating-point number to a std_ulogic_vector of the same length.
To_std_ulogic_vector Alias for to_sulv.
To_stdulogicvector Alias for to_sulv.

At the end, I created this VHDL function that convert a real number to his IEEE-754 integer representation:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;
use ieee.math_real.all;
package Help is
type t_vector is array (natural range <>) of integer;
type data_t is array (natural range <>, natural range <>) of real;
function float_2_slv
(
num : real := 0.0
)
return std_logic_vector;
end package Help;
package body Help is
----------------------------------------------------------------------------------------------------
function float_2_slv
(
num : real := 0.0
)
return std_logic_vector is
constant bits_exponent : integer := 8;
constant bits_mantissa : integer := 23;
variable abs_num : real;
variable sign : std_logic;
variable exponent : real;
variable exponent_norm : std_logic_vector(bits_exponent-1 downto 0);
variable mantissa : real;
variable mantissa_norm : std_logic_vector(bits_mantissa - 1 downto 0);
variable quotient : real;
variable slv : std_logic_vector(31 downto 0);
begin
sign := '0';
abs_num := abs(num);
if num < 0.0 then
sign := '1';
end if;
exponent := floor(log2(abs_num));
quotient := 2.0 ** exponent;
mantissa := abs_num / quotient;
exponent_norm := std_logic_vector(to_unsigned(natural(127.0+exponent), bits_exponent));
mantissa_norm := std_logic_vector(to_signed(natural(round(mantissa*(2.0**(bits_mantissa)))), bits_mantissa));
slv := sign & exponent_norm & mantissa_norm;
return slv;
end;
end package body Help;
If it's required the conversion from a float to an IEEE-754 integer in Vitis, then, could be do it as in C:
uint32_t get_IEEE754(float d)
{
uint32_t bits;
memcpy(&bits, &d, sizeof(d));
return bits;
}

Related

VHDL shift_right number

I want to divide a number by 512 meaning that I need to shift it by 9. For example in my code I want to take the number 26 in binary form to multiply by 100 and then divide it by 512. But instead of dividing by 512 all I need to do is to shift right 9 times the number 26*100. But when I do the shift_right command I get the following error:
Error (10511): VHDL Qualified Expression error at Multiplier_VHDL .vhd(34): SHIFT_RIGHT type specified in Qualified Expression must match std_logic_vector type that is implied for expression by context
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity Multiplier_VHDL is
GENERIC (
display_resolution : INTEGER := 23; -- counter to get to the lowest frequency
display_counter: INTEGER := 8); -- counter to get to 97KHz frequency
port (
Nibble1 : in std_logic_vector(display_counter downto 0) := "000011010"; -- 26 in binary form
Nibble2 : in std_logic_vector(display_counter downto 0);
Result: out std_logic_vector(17 downto 0));
end entity Multiplier_VHDL;
architecture Behavioral of Multiplier_VHDL is
signal number : unsigned(display_counter downto 0) := "001100100"; -- 100 in binary form
begin
Result <= std_logic_vector(unsigned(Nibble1) * unsigned(number));
Result <= (shift_right(unsigned(number), display_counter + 1));
end architecture Behavioral;
shift_right returns either unsigned or signed, depending on what you give it. So you're trying to write an unsigned to a std_logic_vector (Result is of type std_logic_vector).
Also, number is already of type unsigned so there's no need to cast it to unsigned again.
But I give you +1 point for using numeric_std rather than std_logic_arith.

cross total of a std_logic_vector

My purpose of this code is a cross total of a std_logic_vector.
I have the following code:
generic(
lowPass_len : integer := 4;
...
signal inputbuffer : std_logic_vector(lowPass_len-1 downto 0);
signal sum: integer range 0 to lowPass_len;
signal lowpass_alarm_tog : std_logic;
...
inputbuffer <= inputbuffer(lowPass_len-1 downto 1) & alarm_tog_d2_meta;
for i in (lowPass_len-1) downto 1 loop
sum <= to_integer(unsigned(inputbuffer(i-1)) + unsigned(inputbuffer(i)));
end loop;
because inputbuffer is a std_logic_vector, I wanted to cast it to unsigned to make the addition. then convert it to integer, as sum has this kind of type.
ghdl gives me the following mistake for two times in this line
conversion not allowed between not closely related types
The expression inputbuffer(i-1) just returns a single bit of type std_logic. This cannot be directly casted to unsigned because the latter is an array of std_logic.
You have to extend the single bit to a vector of the required length first. The length depends on the highest number which could be encountered in the addition.

VHDL: issues with adding and subtracting

What issues could I run into with this code? I was thinking that there could be an issue if the result from the addition is bigger than what 15 bits can represent (32767), or if I get a negative number in the subtraction.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
use ieee.numeric_std.all;
entity test is
port( input: in std_logic_vector(14 downto 0);
sel : out boolean;
output: out std_logic_vector(14 downto 0));
end test;
architecture test of test is
constant first : integer := 1050;
constant second : integer := 33611;
begin
output <= input - first;
output <= input + second;
sel <= input < first;
end test;
The primary issue you have is that the design intent is not communicated so it is impossible to distinguish correct from incorrect results - in that sense, whatever it does must be right!
I differ from David's opinion in one respect : where he says "std_logic_vector is an unsigned representation" I suggest that std_logic_vector is neither signed nor unsigned; it is just a bag of bits. If it happens to follow unsigned rules, that's an accident of the set of libraries you have included.
Instead, I would delete the non-standard libraries:
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
and use exclusively the standard libraries:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
Then - if the input and output ports are meant to represent unsigned numbers, the best thing to do is say so...
port( input : in unsigned(14 downto 0);
sel : out boolean;
output : out unsigned(14 downto 0));
(If you are not allowed to change the port types, you can use unsigned signals internally, and type convert between them and the ports.)
Now as regards the expressions, they may overflow (and in the case of "second" obviously will!).
In simulation, these overflows OUGHT to be reported as arithmetic errors. (Note : at least one simulator runs with overflow checks off as the default setting! Just dumb...)
As the designer, you decide what the correct semantics for overflows are:
They represent bugs. Simulate with overflow checks enabled, detect and fix the bugs.
They are permitted, and e.g. negative numbers represent large positive numbers. Express this in the code, e.g. as output <= (input - first) mod 2**output'length; Now anyone reading the code understands that overflow is allowed, and simply wraps.
Overflow should saturate to the positive or negative limit. Signal this by writing output <= saturate(input - first); I'll leave writing the Saturate function as an exercise...
The adding operators "+" and "-" are performed bit wise - std_logic_vector is an array type with a base element type of std_ulogic which represents 'bits' as a multi level value system that includes meta values. Their result is bounded by the longer of the two operands. (They don't overflow).
See the source for package std_logic_unsigned:
function "+"(L: STD_LOGIC_VECTOR; R: STD_LOGIC_VECTOR) return STD_LOGIC_VECTOR is
-- pragma label_applies_to plus
constant length: INTEGER := maximum(L'length, R'length);
variable result : STD_LOGIC_VECTOR (length-1 downto 0);
begin
result := UNSIGNED(L) + UNSIGNED(R);-- pragma label plus
return std_logic_vector(result);
end;
Which uses the unsigned add from std_logic_arith:
function "+"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED is
-- pragma label_applies_to plus
-- synopsys subpgm_id 236
constant length: INTEGER := max(L'length, R'length);
begin
return unsigned_plus(CONV_UNSIGNED(L, length),
CONV_UNSIGNED(R, length)); -- pragma label plus
end;
An this uses unsigned_plus also found in std_logic_arith:
function unsigned_plus(A, B: UNSIGNED) return UNSIGNED is
variable carry: STD_ULOGIC;
variable BV, sum: UNSIGNED (A'left downto 0);
-- pragma map_to_operator ADD_UNS_OP
-- pragma type_function LEFT_UNSIGNED_ARG
-- pragma return_port_name Z
begin
if (A(A'left) = 'X' or B(B'left) = 'X') then
sum := (others => 'X');
return(sum);
end if;
carry := '0';
BV := B;
for i in 0 to A'left loop
sum(i) := A(i) xor BV(i) xor carry;
carry := (A(i) and BV(i)) or
(A(i) and carry) or
(carry and BV(i));
end loop;
return sum;
end;
std_logic_vector is an unsigned representation, there is no concept of negative numbers, it's a bag of bits. If you want to signify signed operations you should be using package numeric_std, and either type convert or use operands for your relational and adding operators that are type signed.
That being said you'll get the same answers using std_logic_vector with Synopsys's std_logic_unsigned package or unsigned with the IEEE numeric_std package.
(And your last two use clauses aren't needed by the code you show).
And the reason you don't need a use clause making packages numeric_std or std_logic_arith visible is because you aren't using signed or unsigned types and package std_logic_unsigned has it's own use clause for std_logic_arith and otherwise has declarations for everything you're using in your design specification ("+", "-" and "<").

VHDL assigning literals

I'm trying to use unsigned integers in VHDL with well defined bit widths. It seems VHDL does not like me trying to assign literal values to these types defined as:
variable LCD_DATA: unsigned(19 downto 0) := 0;
But in my IDE (Quartus), I get a complaint "UNSIGNED type does not match integer literal." I also get complaints for adding numbers to types defined like this. Whats the preferred change I need to make?
See other answers, and note that for non-zero literals, you probably want to do something like:
variable LCD_DATA: unsigned(19 downto 0) := to_unsigned(n, 20);
Substitute a literal for n. This works for n=0 too, of course, but it's not as tidy as (others => '0').
--Either
variable LCD_DATA: unsigned(19 downto 0) := (others => '0');
--Or you can also write it like
variable LCD_DATA: unsigned(19 downto 0) := "00000000000000000000";
And for the 2nd part of your question while adding number of this type.
library ieee;
use ieee.std_logic_1164.all;
use IEEE.NUMERIC_STD.ALL;
Check whether you have used above libraries in the code or not.
unsigned is related to std_ulogic, where the value for an element would be '0'.
variable LCD_DATA: unsigned (19 downto 0) := (others => '0');
which provides an aggregate for the default assignment with all elements set to '0'.
You can't assign a single element of integer type to an array of std_ulogic elements.
You can add signed or unsigned to a natural (unsigned) or integer (signed) using "+" functions defined in package numeric_std:
-- Id: A.5
function "+" (L: UNSIGNED; R: NATURAL) return UNSIGNED;
-- Result subtype: UNSIGNED(L'LENGTH-1 downto 0).
-- Result: Adds an UNSIGNED vector, L, with a non-negative INTEGER, R.
-- Id: A.6
function "+" (L: NATURAL; R: UNSIGNED) return UNSIGNED;
-- Result subtype: UNSIGNED(R'LENGTH-1 downto 0).
-- Result: Adds a non-negative INTEGER, L, with an UNSIGNED vector, R.
-- Id: A.7
function "+" (L: INTEGER; R: SIGNED) return SIGNED;
-- Result subtype: SIGNED(R'LENGTH-1 downto 0).
-- Result: Adds an INTEGER, L(may be positive or negative), to a SIGNED
-- vector, R.
-- Id: A.8
function "+" (L: SIGNED; R: INTEGER) return SIGNED;
-- Result subtype: SIGNED(L'LENGTH-1 downto 0).
-- Result: Adds a SIGNED vector, L, to an INTEGER, R.

How to typecast integer to unsigned in VHDL

I am trying to divide two integers as following:
variable m0Low : integer := 0;
variable m1Low : integer := 0;
m1Low := divide(m1Low,m0Low);
With the function :
function divide (a : UNSIGNED; b : UNSIGNED) return UNSIGNED is
variable a1 : unsigned(a'length-1 downto 0):=a;
variable b1 : unsigned(b'length-1 downto 0):=b;
variable p1 : unsigned(b'length downto 0):= (others => '0');
variable i : integer:=0;
begin
for i in 0 to b'length-1 loop
p1(b'length-1 downto 1) := p1(b'length-2 downto 0);
p1(0) := a1(a'length-1);
a1(a'length-1 downto 1) := a1(a'length-2 downto 0);
p1 := p1-b1;
if(p1(b'length-1) ='1') then
a1(0) :='0';
p1 := p1+b1;
else
a1(0) :='1';
end if;
end loop;
return a1;
end divide;
However, I get the following error:
Divide can not have such operands in this context.
I am trying to cast the variables to unsigned m1Low := divide(unsigned(m1Low),unsigned(m0Low));
But I get the following error:
The expression can not be converted to type unsigned.
Any idea what I can do?
Thanks
Haris
To convert integer to unsigned or signed data type over,
use IEEE.NUMERIC_STD.all;
you must use,
to_unsigned(I,U’length);
to_signed(I,S’length)
where I is the integer value and U'length is the unsigned vector length ( the number of bit ).
I didn't verify your code and how it's actually working but my correction on your code is just,
m1Low := to_integer(divide(to_unsigned(m1Low, N),to_unsigned(m0Low, N)));
you should specify N where its the length of your vector depend on your design. I used to_integer() because your function is returning unsigned value to integer variable.
Hope this simple notes help you.
If you want to pass integers as unsigned vectors, you need to convert them, not typecast them.
First you want the numeric_std library:
use ieee.numeric_std.all;
Then you can use to_unsigned to convert the integers to unsigned vectors. For that function you need to know the length of the unsigned vector you are converting to so use the 'length attribute:
destination_vector := to_unsigned(source_integer, destination_vector'length);
You can convert back from unsigned to integer (which doesn't need to be told the length of the input, as information about function inputs is directly available to the function) like this:
destination_integer := to_integer(source_vector);

Resources