The latest approved IEEE 1076 standard (termed VHDL-2008) adds signed (sfixed) and unsigned (ufixed) fixed-point data types and a set of primitives for their manipulation. The VHDL fixed-point and floating-point packages provide synthesizable implementations of arithmetic operators, scaling and operand resizing. Sadly it takes a while for tools to catch up, and the free versions of tools such as "Web Packs" are well behind the latest. This means that these new types are not always available to try out. Thankfully David Bishop and Jim Lewis created a good VHDL-93 compliant version of the library which can be compiled up and I have got ModelSim, Vivado and Quartus Prime to simulate and synthesise fixed point arithmetic using the libraries. However the compilation was not quite as straight forward as you might hope. Here's how I did it in case you need the same.
- Tool Support
- Compilation
- ModelSim Library Compilation
- VHDL
- Fixed Point
- Floating Point
- Float Representation
- Synthesis
- Synthesis with Vivado
- Synthesis with Quartus Prime
- Conclusions
- References
Tool Support
The definitive sources no longer seem to be available from http://www.vhdl.org/fphld/vhdl.html. Different versions of the libraries seem to be packaged with different tools and you can search for the files:
- fixed_float_types_c.vhd
- fixed_pkg_c.vhd
- float_pkg_c.vhd
The instructions given in Fixed point package user’s guide were found to be incomplete, mainly because my version of ModelSim had an earlier revision of the VHDL packages. This caused some discrepancies in how to compile them up.
Tool | Compatibility | Version Used Here | Package Source location | Package Source Version |
---|---|---|---|---|
ModelSim | Yes | INTEL FPGA STARTER EDITION 10.5b, Revision: 2016.10, Date: Oct 5 2016 |
C:\intelFPGA_lite\18.1\modelsim_ase\vhdl_src\floatfixlib | Revision: #1, 2016/05/18 |
Quartus Prime | Yes | Ver 18.1.1 Build 646 04/11/2019 | VHDL-2008 source only. Use the source from ModelSim. | Not Applicable |
Vivado | Yes | Version 2019.1.1 (64-bit) | C:\Xilinx\Vivado\2019.1\ids_lite\ISE\vhdl\src\ieee_proposed | Revision: 1.3, 2011/03/24 |
NB. The file system path names assume default installation locations.
Compilation
So I have two versions of fixed_pkg using different libraries, hence the solution here depends on which of the two versions you choose to compile. Unfortunately the version I went with from ModelSim did not follow the intended instructions. But the version with Vivado with different library usage does match the instructions.
-- --------------------------------------------------------------------
-- "fixed_pkg_c.vhdl" package contains functions for fixed point math.
-- Please see the documentation for the fixed point package.
-- This package should be compiled into "ieee_proposed" and used as follows:
-- use ieee.std_logic_1164.all;
-- use ieee.numeric_std.all;
-- use ieee_proposed.fixed_float_types.all;
-- use ieee_proposed.fixed_pkg.all;
--
-- This verison is designed to work with the VHDL-93 compilers
-- synthesis tools. Please note the "%%%" comments. These are where we
-- diverge from the VHDL-200X LRM.
-- --------------------------------------------------------------------
-- Version : $Revision: #1 $
-- Date : $Date: 2016/05/18 $
-- --------------------------------------------------------------------
use STD.TEXTIO.all;
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
library floatfixlib;
use floatfixlib.fixed_float_types.all;
package fixed_pkg is
...
The libraries in the Vivado version are different and hence library floatfixlib is no longer required.
-- --------------------------------------------------------------------
-- "fixed_pkg_c.vhdl" package contains functions for fixed point math.
-- Please see the documentation for the fixed point package.
-- This package should be compiled into "ieee_proposed" and used as follows:
-- use ieee.std_logic_1164.all;
-- use ieee.numeric_std.all;
-- use ieee_proposed.fixed_float_types.all;
-- use ieee_proposed.fixed_pkg.all;
--
-- This verison is designed to work with the VHDL-93 compilers
-- synthesis tools. Please note the "%%%" comments. These are where we
-- diverge from the VHDL-200X LRM.
-- --------------------------------------------------------------------
-- Version : $Revision: 1.3 $
-- Date : $Date: 2011/03/24 07:44:24 $
-- --------------------------------------------------------------------
use STD.TEXTIO.all;
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
library IEEE_PROPOSED;
use IEEE_PROPOSED.fixed_float_types.all;
package fixed_pkg is
...
Going with the former from ModelSim, I now want to compile and simulate and then synthesis a simple fixed point multiplier in Q8.8 format. However there's a twist with the float_pkg library dependencies.
-- --------------------------------------------------------------------
-- "float_pkg" package contains functions for floating point math.
-- Please see the documentation for the floating point package.
-- This package should be compiled into "ieee_proposed" and used as follows:
-- use ieee.std_logic_1164.all;
-- use ieee.numeric_std.all;
-- use ieee_proposed.fixed_float_types.all;
-- use ieee_proposed.fixed_pkg.all;
-- use ieee_proposed.float_pkg.all;
--
-- This verison is designed to work with the VHDL-93 compilers. Please
-- note the "%%%" comments. These are where we diverge from the
-- VHDL-200X LRM.
--
-- --------------------------------------------------------------------
-- Version : $Revision: #1 $
-- Date : $Date: 2016/05/18 $
-- --------------------------------------------------------------------
use STD.TEXTIO.all;
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
library floatfixlib;
use floatfixlib.fixed_float_types.all;
use floatfixlib.fixed_pkg.all;
package float_pkg is
...
Here fixed_pkg has been compiled into a different library, floatfixlib instead of ieee_proposed, so we need to cater for this difference when compiling.
ModelSim Library Compilation
The Windows batch file to compile the fixed_pkg library is given below. There are two points to note:
- The separation of the two packages into two different libraries. With the ModelSim version you will need to compile one file into library floatfixlib. This has been corrected in the version included with Vivado.
- The float_pkg expects to use fixed_pkg compiled into floatfixlib not ieee_proposed.
- The -93 switch is essential, don't try to compile with -2008
- The inclusion of a vcom command line switch "-nowarn 3". This is to prevent the expected warning messages caused by a "null range".
** Warning: C:\intelFPGA_lite\18.1\modelsim_ase\vhdl_src\floatfixlib\fixed_pkg_c.vhd(1470): (vcom-1246) Range 0 downto 1 is null. ** Warning: C:\intelFPGA_lite\18.1\modelsim_ase\vhdl_src\floatfixlib\fixed_pkg_c.vhd(1471): (vcom-1246) Range 0 downto 1 is null. ** Warning: C:\intelFPGA_lite\18.1\modelsim_ase\vhdl_src\floatfixlib\fixed_pkg_c.vhd(1472): (vcom-1246) Range 0 downto 1 is null. ** Warning: C:\intelFPGA_lite\18.1\modelsim_ase\vhdl_src\floatfixlib\fixed_pkg_c.vhd(6873): (vcom-1246) Range 2 to 1 is null.
constant NAUF : UNRESOLVED_ufixed (0 downto 1) := (others => '0');
constant NASF : UNRESOLVED_sfixed (0 downto 1) := (others => '0');
constant NSLV : STD_ULOGIC_VECTOR (0 downto 1) := (others => '0');
constant NUS : STRING(2 to 1) := (others => ' ');
@echo off
set SIM=%USERPROFILE%\ModelSim
rem Batch file's directory where the source code is
set SRC=C:\intelFPGA_lite\18.1\modelsim_ase\vhdl_src\floatfixlib
set DEST=%SIM%\libraries
echo Compile Source: %SRC%\*
echo Into Destination: %DEST%
echo.
if not exist %DEST% (
md %DEST%
)
rem vlib needs to be execute from the local directory, limited command line switches.
cd /d %DEST%
if exist ieee_proposed (
vdel -lib ieee_proposed -modelsimini ./modelsim.ini -all
)
rem $ verror 1907
rem
rem vcom-vlog Message # 1907:
rem Following -nowarn, an additional argument, representing which category
rem of warning message to suppress, must be specified.
rem 1 = Unbound component (VHDL)
rem 2 = Process without a WAIT statement (VHDL)
rem 3 = Null range (VHDL)
rem 4 = No space in physical (e.g. TIME) literal (VHDL)
rem 5 = Multiple drivers on unresolved signal (VHDL)
rem 6 = VITAL compliance checks ("-nowarn VitalChecks" also accepted) (VHDL)
rem 7 = VITAL optimization messages (VHDL)
rem 8 = Lint warnings (VHDL and Verilog)
rem 9 = Signal value dependency at elaboration (VHDL)
rem 10 = VHDL-1993 constructs in VHDL-1987 code (VHDL)
rem 11 = PSL warnings (VHDL and Verilog)
rem 12 = Non-LRM compliance to match Cadence behavior (Verilog)
rem 13 = Constructs that coverage can't handle (VHDL and Verilog)
rem 14 = Locally static error deferred until run time (VHDL)
rem 15 = SystemVerilog assertions using local variable (Verilog)
rem Turn off the warning about null ranges as this is expected.
vlib ieee_proposed
vmap floatfixlib ./ieee_proposed
vmap ieee_proposed ./ieee_proposed
rem Must use VHDL-1993 not VHDL-2008
vcom -quiet -93 -nowarn 3 -work ieee_proposed %SRC%\fixed_float_types_c.vhd %SRC%\fixed_pkg_c.vhd %SRC%\float_pkg_c.vhd
set ec=%ERRORLEVEL%
rem Do not pause inside MS Visual Studio Code, it has its own prompt on completion.
if not "%TERM_PROGRAM%"=="vscode" pause
exit /b %ec%
By "double mapping" (vmap) the floatfixlib to the ieee_proposed library, the compilation of both packages nwo works. But when using the latter library, the former mapping must now also be made. (See this example modelsim_compile.cmd batch file.)
VHDL
Here are two simple tests of these libraries creating a simple Q8.8 fixed point multiplier using the sfixed type and a floating point multipler using the float type. The simulation screen shots are intended to show the precision on conversion of the required real values to sfixed and float respectively, and the test bench shows two ways to call the to_fixed conversion function.
Fixed Point
library ieee;
use ieee.std_logic_1164.all;
library ieee_proposed;
use ieee_proposed.fixed_pkg.all;
entity sfixed_mult is
port(
clk : in std_logic;
reset : in std_logic;
a : in sfixed( 7 downto -8);
b : in sfixed( 7 downto -8);
o : out sfixed(15 downto -16)
);
end entity;
architecture rtl of sfixed_mult is
begin
process(clk)
begin
if rising_edge(clk) then
if reset = '1' then
o <= (others => '0');
else
o <= a * b;
end if;
end if;
end process;
end architecture;
entity test_sfixed_mult is
end entity;
library ieee;
use ieee.std_logic_1164.all;
library ieee_proposed;
use ieee_proposed.fixed_pkg.all;
library local;
use local.testbench_pkg.all;
architecture test of test_sfixed_mult is
signal clk : std_logic;
signal reset : std_logic;
signal a, b : sfixed( 7 downto -8);
signal o : sfixed(15 downto -16);
begin
clock(clk, 10 ns);
test_sfixed_mult_i : entity work.sfixed_mult
port map (
clk => clk,
reset => reset,
a => a,
b => b,
o => o
);
process
begin
reset <= '1';
a <= to_sfixed(0.0, a);
b <= to_sfixed(0.0, b'high, b'low);
wait_nr_ticks(clk, 2);
reset <= '0';
wait_nr_ticks(clk, 2);
a <= to_sfixed( 5.1, a'high, a'low);
b <= to_sfixed(-2.2, b);
wait_nr_ticks(clk, 10);
stop_clocks;
wait;
end process;
end architecture;

Floating Point
library ieee;
use ieee.std_logic_1164.all;
library ieee_proposed;
use ieee_proposed.float_pkg.all;
entity float_mult is
port(
clk : in std_logic;
reset : in std_logic;
a : in float(7 downto -8);
b : in float(7 downto -8);
o : out float(7 downto -8)
);
end entity;
architecture rtl of float_mult is
begin
process(clk)
begin
if rising_edge(clk) then
if reset = '1' then
o <= (others => '0');
else
o <= a * b;
end if;
end if;
end process;
end architecture;
entity test_float_mult is
end entity;
library ieee;
use ieee.std_logic_1164.all;
library ieee_proposed;
use ieee_proposed.float_pkg.all;
library local;
use local.testbench_pkg.all;
architecture test of test_float_mult is
signal clk : std_logic;
signal reset : std_logic;
signal a, b : float(7 downto -8);
signal o : float(7 downto -8);
begin
clock(clk, 10 ns);
test_sfixed_mult_i : entity work.float_mult
port map (
clk => clk,
reset => reset,
a => a,
b => b,
o => o
);
process
begin
reset <= '1';
a <= to_float(0.0, a);
b <= to_float(0.0, b'high, -b'low);
wait_nr_ticks(clk, 2);
reset <= '0';
wait_nr_ticks(clk, 2);
a <= to_float( 5.1, a'high, -a'low);
b <= to_float(-2.2, b);
wait_nr_ticks(clk, 10);
stop_clocks;
wait;
end process;
end architecture;

# ** Warning: Design size of 23062 statements exceeds ModelSim-Intel FPGA Starter Edition recommended capacity. # Expect performance to be adversely affected.
Float Representation
Setting up number representation with floating point numbers can be done by following these screen shots.





The last screenshot shows you have a reusable representation for quick selection.
Synthesis
Synthesis with Vivado
Vivado produced the desired results out of the box with no additional library manipulations or source code inclusion.


Synthesis with Quartus Prime
Quartus Prime needed more work and the inclusion of the two additional package files.
set_global_assignment -name VHDL_FILE "C:/intelFPGA_lite/18.1/modelsim_ase/vhdl_src/floatfixlib/fixed_pkg_c.vhd" -hdl_version VHDL_1993 -library ieee_proposed set_global_assignment -name VHDL_FILE "C:/intelFPGA_lite/18.1/modelsim_ase/vhdl_src/floatfixlib/fixed_float_types_c.vhd" -hdl_version VHDL_1993 -library floatfixlib
Be sure to note the subtle difference in library mappings between the two types of arithmetic.
set_global_assignment -name VHDL_FILE "C:/intelFPGA_lite/18.1/modelsim_ase/vhdl_src/floatfixlib/float_pkg_c.vhd" -hdl_version VHDL_1993 -library ieee_proposed set_global_assignment -name VHDL_FILE "C:/intelFPGA_lite/18.1/modelsim_ase/vhdl_src/floatfixlib/fixed_pkg_c.vhd" -hdl_version VHDL_1993 -library floatfixlib set_global_assignment -name VHDL_FILE "C:/intelFPGA_lite/18.1/modelsim_ase/vhdl_src/floatfixlib/fixed_float_types_c.vhd" -hdl_version VHDL_1993 -library floatfixlib
Quartus Prime then synthesised the desired design.


Conclusions
It is entirely possible to write RTL code to infer fixed point arithmetic without the latest versions of the tools using the VHDL-2008 libraries, but it takes some manipulation and the provided instruction may not work. There are plenty of people struggling on various forums when I performed an Internet search, hence I've written up a working solution. I also note how synthesisable the floating point libraries are in both tools, but you won't be using the DSP primitives.