VHDL-2008 FP32 Support in Vivado
VHDL-2008 introduced native support for floating point types with FLOAT, which is an arbitrary precision floating point type. While you can define generic modules with ports of unconstrained FLOAT type, or any actual size you want, in practice we are interested in single precision and double precision floating point, FLOAT32 and FLOAT64. In particular, FLOAT32 is of interest because in the latest Versal FPGA family there is support for hardened single precision floating point addition and multiplication using the new DSPFP32 primitive.
To use this predefined VHDL-2008 single precision floating point type in our VHDL designs we need to use a float_pkg package. Unlike other VHDL packages commonly used like numeric_std, where you simply declare the package in a use statement, float_pkg does not exist as such, VHDL-2008 comes with an abstract generic version called float_generic_pkg. We have to actually create float_pkg ourselves, deriving it from the generic version. Just create a file called float_pkg.vhd with the following content:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
package fixed_pkg is new IEEE.fixed_generic_pkg
generic map(fixed_round_style=>IEEE.fixed_float_types.fixed_round,
fixed_overflow_style=>IEEE.fixed_float_types.fixed_wrap,
fixed_guard_bits=>2,
no_warning=>true);
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
package float_pkg is new IEEE.float_generic_pkg
generic map(float_exponent_width=>8,
float_fraction_width=>23,
float_round_style=>IEEE.fixed_float_types.round_zero,
float_denormalize=>false,
float_check_error=>true,
float_guard_bits =>2,
no_warning=>true,
fixed_pkg=>IEEE.fixed_pkg);
The key parameters here are float_exponent_width=8 and float_fraction_width=23, which correspond to single precision floating point. You can then use this user defined float_pkg package in your designs like you would numeric_std for example and this gives you access to a FLOAT32 type and many useful functions and operators. We can now define signals, entity ports and generics of this type.
Of course, we are still interested in also having a CFLOAT32 record with real and imaginary fields that are FLOAT32 values and then even unconstrained arrays of these two types, FLOAT32_VECTOR and CFLOAT32_VECTOR, which are quite common in many digital signal processing and linear algebra algorithms. Here is a short example of a user defined package, using the fixed_pkg package we just created, which introduces these types:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
use IEEE.MATH_REAL.all;
use IEEE.MATH_COMPLEX.all;
package cfloat_pkg is
use work.float_pkg.all; -- VHDL-2008 float_pkg with no denormalize, rounding to zero, no warning messages
-- this gives us FLOAT32, operators and conversion functions
constant PI:REAL:=3.1415926535897932;
type REAL_VECTOR is array(INTEGER range <>) of REAL;
type COMPLEX_VECTOR is array(INTEGER range <>) of COMPLEX;
type COMPLEX_MATRIX is array(INTEGER range <>) of COMPLEX_VECTOR;
-- FLOAT is now the standard VHDL-2008 type defined in float_generic_pkg, we do not need a user defined type anymore but this is what FLOAT and FLOAT32 really are
-- type FLOAT is array (INTEGER range <>) of STD_LOGIC; -- arbitrary precision floating point number
-- subtype FLOAT32 is FLOAT(8 downto -23);
type FLOAT32_VECTOR is array(INTEGER range <>) of FLOAT32; -- unconstrained array of FLOAT32
type FLOAT32_MATRIX is array(INTEGER range <>) of FLOAT32_VECTOR; -- unconstrained array of FLOAT32_VECTOR
type CFLOAT32 is record RE,IM:FLOAT32; end record; -- single precision floating point complex number
type CFLOAT32_VECTOR is array(INTEGER range <>) of CFLOAT32; -- unconstrained array of CFLOAT32
type CFLOAT32_MATRIX is array(INTEGER range <>) of CFLOAT32_VECTOR; -- unconstrained array of CFLOAT32_VECTOR
end package cfloat_pkg;
While these VHDL-2008 features had limited support in previous versions of the Xilinx FPGA design tool Vivado, they fully work now in the latest version, which is 2023.2 as I write this post. This means that you can both synthesize and simulate unconstrained arrays of unconstrained records and arrays, generic packages and arbitrary precision fixed and floating point support.
As mentioned above, the latest FPGA family Versal has now hardened single precision floating point adders and multipliers. However, inferring these from behavioral HDL code, that is + and * operators acting on signals of type FLOAT32 is not possible, so in the next post I will describe a design flow to take advantage of these new floating point primitives in your Versal FPGA designs.
Back to the top: The Art of FPGA Design