├── .gitignore ├── denormalizer ├── denormalizer_configuration │ ├── denormalizer_with_1_stage_pipe_pkg.vhd │ ├── denormalizer_with_2_stage_pipe_pkg.vhd │ ├── denormalizer_with_3_stage_pipe_pkg.vhd │ └── denormalizer_with_4_stage_pipe_pkg.vhd └── denormalizer_pkg.vhd ├── normalizer ├── normalizer_configuration │ ├── normalizer_with_1_stage_pipe_pkg.vhd │ ├── normalizer_with_2_stage_pipe_pkg.vhd │ ├── normalizer_with_3_stage_pipe_pkg.vhd │ └── normalizer_with_4_stage_pipe_pkg.vhd └── normalizer_pkg.vhd ├── float_type_definitions ├── float_word_length_24_bit_pkg.vhd ├── float_word_length_16_bit_pkg.vhd ├── float_word_length_18_bit_pkg.vhd ├── float_word_length_20_bit_pkg.vhd └── float_type_definitions_pkg.vhd ├── LICENSE ├── ghdl_compile_vhdl_float.bat ├── vhdl2008 ├── altera │ ├── sim_native_fp32.vhd │ └── multiply_add_arch_agilex.vhd ├── multiply_add_arch_hfloat.vhd ├── float_adder_generic_pkg.vhd ├── fast_hfloat_pkg.vhd ├── multiply_add_entity.vhd ├── float_multiplier_generic_pkg.vhd ├── normalizer_generic_pkg.vhd ├── denormalizer_generic_pkg.vhd └── float_to_real_conversions_pkg.vhd ├── testbenches ├── tb_float_comparisons.vhd ├── adder_simulation │ ├── tb_subtract.vhd │ ├── tb_pipelined_add.vhd │ └── tb_float_adder.vhd ├── simulate_float_filter │ └── tb_float_filter.vhd ├── float_to_real_simulation │ ├── tb_fp_2_real_functions.vhd │ ├── tb_float_conversions.vhd │ └── fp2real_functions_tb.vhd ├── vhdl2008 │ ├── normalizer_tb.vhd │ ├── type_conversions_tb.vhd │ ├── mult_add_entity_agilex_tb.vhd │ └── mult_add_entity_tb.vhd ├── float_to_integer_simulation │ ├── tb_float_to_integer_converter.vhd │ └── integer_to_float_simulation_tb.vhd ├── denormalized_numbers │ ├── saturated_add_tb.vhd │ └── tb_denormal_conversions.vhd ├── denormalizer_simulation │ └── tb_denormalizer.vhd ├── simulate_normalizer │ └── tb_normalizer.vhd ├── float_multiplier_simulation │ └── tb_float_multiplier.vhd ├── float_alu_simulation │ ├── tb_alu_lc_filter_pkg.vhd │ └── tb_float_alu.vhd └── float_fused_multiply_add │ └── fused_multiply_add_tb.vhd ├── README.md ├── float_to_real_conversions ├── float_to_real_conversions_pkg.vhd └── float_to_real_functions_pkg.vhd ├── float_adder └── float_adder_pkg.vhd ├── float_first_order_filter └── float_first_order_filter_pkg.vhd ├── float_to_integer_converter └── float_to_integer_converter_pkg.vhd ├── float_multiplier └── float_multiplier_pkg.vhd ├── vunit_run_vhdl_float.py └── float_arithmetic_operations └── float_arithmetic_operations_pkg.vhd /.gitignore: -------------------------------------------------------------------------------- 1 | *.swn 2 | *.swo 3 | *.*~ 4 | *.swp 5 | vunit_out/ 6 | *.cf 7 | *.o 8 | *.fst 9 | *.fst.* 10 | *.json 11 | *.toml 12 | -------------------------------------------------------------------------------- /denormalizer/denormalizer_configuration/denormalizer_with_1_stage_pipe_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | package denormalizer_pipeline_pkg is 6 | 7 | constant pipeline_configuration : natural := 1; 8 | 9 | end package denormalizer_pipeline_pkg; 10 | -------------------------------------------------------------------------------- /denormalizer/denormalizer_configuration/denormalizer_with_2_stage_pipe_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | package denormalizer_pipeline_pkg is 6 | 7 | constant pipeline_configuration : natural := 2; 8 | 9 | end package denormalizer_pipeline_pkg; 10 | -------------------------------------------------------------------------------- /denormalizer/denormalizer_configuration/denormalizer_with_3_stage_pipe_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | package denormalizer_pipeline_pkg is 6 | 7 | constant pipeline_configuration : natural := 3; 8 | 9 | end package denormalizer_pipeline_pkg; 10 | -------------------------------------------------------------------------------- /denormalizer/denormalizer_configuration/denormalizer_with_4_stage_pipe_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | package denormalizer_pipeline_pkg is 6 | 7 | constant pipeline_configuration : natural := 4; 8 | 9 | end package denormalizer_pipeline_pkg; 10 | -------------------------------------------------------------------------------- /normalizer/normalizer_configuration/normalizer_with_1_stage_pipe_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | package normalizer_pipeline_pkg is 6 | 7 | constant normalizer_pipeline_configuration : natural := 1; 8 | 9 | end package normalizer_pipeline_pkg; 10 | -------------------------------------------------------------------------------- /normalizer/normalizer_configuration/normalizer_with_2_stage_pipe_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | package normalizer_pipeline_pkg is 6 | 7 | constant normalizer_pipeline_configuration : natural := 2; 8 | 9 | end package normalizer_pipeline_pkg; 10 | -------------------------------------------------------------------------------- /normalizer/normalizer_configuration/normalizer_with_3_stage_pipe_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | package normalizer_pipeline_pkg is 6 | 7 | constant normalizer_pipeline_configuration : natural := 3; 8 | 9 | end package normalizer_pipeline_pkg; 10 | -------------------------------------------------------------------------------- /normalizer/normalizer_configuration/normalizer_with_4_stage_pipe_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | package normalizer_pipeline_pkg is 6 | 7 | constant normalizer_pipeline_configuration : natural := 4; 8 | 9 | end package normalizer_pipeline_pkg; 10 | -------------------------------------------------------------------------------- /float_type_definitions/float_word_length_24_bit_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | 6 | -- 24 bits 7 | package float_word_length_pkg is 8 | 9 | constant mantissa_bits : integer := 24; 10 | constant exponent_bits : integer := 8; 11 | 12 | end package float_word_length_pkg; 13 | 14 | -------------------------------------------------------------------------------- /float_type_definitions/float_word_length_16_bit_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | -- configure word lengths to 8 bit exponent with 16 bit mantissa 6 | 7 | package float_word_length_pkg is 8 | 9 | constant mantissa_bits : integer := 16; 10 | constant exponent_bits : integer := 8; 11 | 12 | end package float_word_length_pkg; 13 | 14 | -------------------------------------------------------------------------------- /float_type_definitions/float_word_length_18_bit_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | -- configure word lengths to 8 bit exponent with 18 bit mantissa 6 | 7 | package float_word_length_pkg is 8 | 9 | constant mantissa_bits : integer := 18; 10 | constant exponent_bits : integer := 8; 11 | 12 | end package float_word_length_pkg; 13 | 14 | -------------------------------------------------------------------------------- /float_type_definitions/float_word_length_20_bit_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | -- configure word lengths to 8 bit exponent with 20 bit mantissa 6 | 7 | package float_word_length_pkg is 8 | 9 | constant mantissa_bits : integer := 20; 10 | constant exponent_bits : integer := 8; 11 | 12 | end package float_word_length_pkg; 13 | 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Jari Honkanen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ghdl_compile_vhdl_float.bat: -------------------------------------------------------------------------------- 1 | echo off 2 | if "%1"=="" ( 3 | set source=./ 4 | ) else ( 5 | set source=%1 6 | ) 7 | 8 | ghdl -a --ieee=synopsys --std=08 %source%/float_type_definitions/float_word_length_16_bit_pkg.vhd 9 | ghdl -a --ieee=synopsys --std=08 %source%/float_type_definitions/float_type_definitions_pkg.vhd 10 | ghdl -a --ieee=synopsys --std=08 %source%/float_arithmetic_operations/float_arithmetic_operations_pkg.vhd 11 | 12 | ghdl -a --ieee=synopsys --std=08 %source%/normalizer/normalizer_configuration/normalizer_with_4_stage_pipe_pkg.vhd 13 | ghdl -a --ieee=synopsys --std=08 %source%/normalizer/normalizer_pkg.vhd 14 | 15 | ghdl -a --ieee=synopsys --std=08 %source%/denormalizer/denormalizer_configuration/denormalizer_with_4_stage_pipe_pkg.vhd 16 | ghdl -a --ieee=synopsys --std=08 %source%/denormalizer/denormalizer_pkg.vhd 17 | 18 | ghdl -a --ieee=synopsys --std=08 %source%/float_to_real_conversions/float_to_real_functions_pkg.vhd 19 | ghdl -a --ieee=synopsys --std=08 %source%/float_to_real_conversions/float_to_real_conversions_pkg.vhd 20 | ghdl -a --ieee=synopsys --std=08 %source%/float_adder/float_adder_pkg.vhd 21 | ghdl -a --ieee=synopsys --std=08 %source%/float_multiplier/float_multiplier_pkg.vhd 22 | ghdl -a --ieee=synopsys --std=08 %source%/float_to_integer_converter/float_to_integer_converter_pkg.vhd 23 | 24 | ghdl -a --ieee=synopsys --std=08 %source%/float_alu/float_alu_pkg.vhd 25 | 26 | ghdl -a --ieee=synopsys --std=08 %source%/float_first_order_filter/float_first_order_filter_pkg.vhd 27 | -------------------------------------------------------------------------------- /vhdl2008/altera/sim_native_fp32.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY ieee ; 2 | USE ieee.NUMERIC_STD.all ; 3 | USE ieee.std_logic_1164.all ; 4 | 5 | --- simulation 6 | --- ,use ip instantiation in synth code instead 7 | 8 | entity native_fp32 is 9 | port ( 10 | fp32_mult_a : in std_logic_vector(31 downto 0) := (others => 'X') -- fp32_mult_a 11 | ;fp32_mult_b : in std_logic_vector(31 downto 0) := (others => 'X') -- fp32_mult_b 12 | ;fp32_adder_a : in std_logic_vector(31 downto 0) := (others => 'X') -- fp32_adder_a 13 | ;clk : in std_logic := 'X' -- clk 14 | ;ena : in std_logic_vector(2 downto 0) := (others => 'X') -- ena 15 | ;fp32_result : out std_logic_vector(31 downto 0) -- fp32_result 16 | ); 17 | end entity native_fp32; 18 | 19 | architecture sim of native_fp32 is 20 | 21 | use ieee.float_pkg.all; 22 | 23 | signal mpy_result : float32 := (others => '0'); 24 | signal mpy_result_buf : float32 := (others => '0'); 25 | signal add_pipeline : float32 := (others => '0'); 26 | 27 | begin 28 | 29 | pipelined_multiply_add : process(clk) 30 | begin 31 | if rising_edge(clk) then 32 | mpy_result <= to_float(fp32_mult_a) * to_float(fp32_mult_b); 33 | add_pipeline <= to_float(fp32_adder_a); 34 | mpy_result_buf <= mpy_result + add_pipeline; 35 | fp32_result <= to_slv(mpy_result_buf); 36 | end if; 37 | end process; 38 | 39 | end sim; 40 | -------------------------------------------------------------------------------- /testbenches/tb_float_comparisons.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY ieee ; 2 | USE ieee.NUMERIC_STD.all ; 3 | USE ieee.std_logic_1164.all ; 4 | use ieee.math_real.all; 5 | 6 | library vunit_lib; 7 | context vunit_lib.vunit_context; 8 | 9 | use work.float_type_definitions_pkg.all; 10 | use work.float_arithmetic_operations_pkg.all; 11 | use work.float_to_real_conversions_pkg.all; 12 | 13 | entity float_comparisons_tb is 14 | generic (runner_cfg : string); 15 | end; 16 | 17 | architecture vunit_simulation of float_comparisons_tb is 18 | 19 | constant clock_period : time := 1 ns; 20 | constant simtime_in_clocks : integer := 50; 21 | 22 | signal simulator_clock : std_logic := '0'; 23 | signal simulation_counter : natural := 0; 24 | ----------------------------------- 25 | -- simulation specific signals ---- 26 | 27 | begin 28 | 29 | ------------------------------------------------------------------------ 30 | simtime : process 31 | begin 32 | test_runner_setup(runner, runner_cfg); 33 | wait for simtime_in_clocks*clock_period; 34 | test_runner_cleanup(runner); -- Simulation ends here 35 | wait; 36 | end process simtime; 37 | 38 | simulator_clock <= not simulator_clock after clock_period/2.0; 39 | ------------------------------------------------------------------------ 40 | 41 | stimulus : process(simulator_clock) 42 | 43 | begin 44 | if rising_edge(simulator_clock) then 45 | simulation_counter <= simulation_counter + 1; 46 | check(not(to_float(0.0) > to_float(1.0))); 47 | check((to_float(-1.0) > to_float(-2.0))); 48 | check((to_float(1.0) > to_float(-2.0))); 49 | check((to_float(3.0) > to_float(-2.0))); 50 | check(not (to_float(-3.0) > to_float(2.0))); 51 | check(not (to_float(-2.0) > to_float(2.0))); 52 | 53 | 54 | end if; -- rising_edge 55 | end process stimulus; 56 | ------------------------------------------------------------------------ 57 | end vunit_simulation; 58 | -------------------------------------------------------------------------------- /vhdl2008/multiply_add_arch_hfloat.vhd: -------------------------------------------------------------------------------- 1 | architecture hfloat of multiply_add is 2 | 3 | use work.normalizer_generic_pkg.all; 4 | use work.denormalizer_generic_pkg.all; 5 | use work.float_adder_pkg.all; 6 | use work.float_multiplier_pkg.all; 7 | 8 | constant g_exponent_length : natural := g_floatref.exponent'length; 9 | constant g_mantissa_length : natural := g_floatref.mantissa'length; 10 | 11 | constant hfloat_zero : hfloat_record := ( 12 | sign => '0' 13 | , exponent => (g_exponent_length-1 downto 0 => (g_exponent_length-1 downto 0 => '0')) 14 | , mantissa => (g_mantissa_length-1 downto 0 => (g_mantissa_length-1 downto 0 => '0'))); 15 | 16 | constant init_normalizer : normalizer_record := normalizer_typeref(2, floatref => hfloat_zero); 17 | signal normalizer : init_normalizer'subtype := init_normalizer; 18 | 19 | constant init_adder : float_adder_record := adder_typeref(2, hfloat_zero); 20 | signal adder : init_adder'subtype := init_adder; 21 | 22 | constant init_multiplier : float_multiplier_record := multiplier_typeref(hfloat_zero); 23 | signal multiplier : init_multiplier'subtype := init_multiplier; 24 | 25 | constant init_float_array : float_array(2 downto 0) := (2 downto 0 => hfloat_zero); 26 | signal add_array : init_float_array'subtype := init_float_array; 27 | 28 | begin 29 | 30 | 31 | mpya_out.is_ready <= '1' when normalizer_is_ready(normalizer) else '0'; 32 | mpya_out.result <= to_std_logic(get_normalizer_result(normalizer)); 33 | 34 | process(clock) is 35 | begin 36 | if rising_edge(clock) 37 | then 38 | create_normalizer(normalizer); 39 | create_adder(adder); 40 | create_float_multiplier(multiplier); 41 | 42 | add_array <= add_array(add_array'high-1 downto 0) & hfloat_zero; 43 | 44 | if mpya_in.is_requested = '1' then 45 | request_float_multiplier(multiplier 46 | ,to_hfloat(mpya_in.mpy_a, hfloat_zero) 47 | ,to_hfloat(mpya_in.mpy_b, hfloat_zero)); 48 | add_array(0) <= to_hfloat(mpya_in.add_a, hfloat_zero); 49 | end if; 50 | 51 | if float_multiplier_is_ready(multiplier) then 52 | request_add(adder 53 | ,get_multiplier_result(multiplier) 54 | ,add_array(add_array'high)); 55 | end if; 56 | 57 | if adder_is_ready(adder) 58 | then 59 | request_normalizer(normalizer, get_result(adder)); 60 | end if; 61 | 62 | end if; -- rising edge 63 | end process; 64 | 65 | end hfloat; 66 | -------------------------------------------------------------------------------- /testbenches/adder_simulation/tb_subtract.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY ieee ; 2 | USE ieee.NUMERIC_STD.all ; 3 | USE ieee.std_logic_1164.all ; 4 | use ieee.math_real.all; 5 | 6 | use work.float_type_definitions_pkg.all; 7 | use work.float_arithmetic_operations_pkg.all; 8 | use work.float_adder_pkg.all; 9 | use work.float_to_real_conversions_pkg.all; 10 | 11 | library vunit_lib; 12 | use vunit_lib.run_pkg.all; 13 | 14 | entity tb_subtract is 15 | generic (runner_cfg : string); 16 | end; 17 | 18 | architecture vunit_simulation of tb_subtract is 19 | 20 | signal simulation_running : boolean; 21 | signal simulator_clock : std_logic; 22 | constant clock_per : time := 1 ns; 23 | constant clock_half_per : time := 0.5 ns; 24 | constant simtime_in_clocks : integer := 50; 25 | 26 | signal simulation_counter : natural := 0; 27 | ----------------------------------- 28 | -- simulation specific signals ---- 29 | 30 | signal test1 : float_record := to_float(0.0); 31 | signal test2 : float_record := to_float(2.0); 32 | 33 | signal signed_mantissa : signed(mantissa_length+1 downto 0) := get_signed_mantissa(test2); 34 | 35 | signal testjee : signed(t_mantissa'length+1 downto 0) := get_signed_mantissa(to_float(-2.5)); 36 | 37 | signal test3 : float_record := to_float(0.0001) + to_float(3.0); 38 | signal test3_real : real := to_real(test3); 39 | 40 | signal test5_real : real := 0.13835682354689 - 0.13835682354688; 41 | 42 | begin 43 | 44 | ------------------------------------------------------------------------ 45 | simtime : process 46 | begin 47 | test_runner_setup(runner, runner_cfg); 48 | simulation_running <= true; 49 | wait for simtime_in_clocks*clock_per; 50 | simulation_running <= false; 51 | test_runner_cleanup(runner); -- Simulation ends here 52 | wait; 53 | end process simtime; 54 | 55 | ------------------------------------------------------------------------ 56 | sim_clock_gen : process 57 | begin 58 | simulator_clock <= '0'; 59 | wait for clock_half_per; 60 | while simulation_running loop 61 | wait for clock_half_per; 62 | simulator_clock <= not simulator_clock; 63 | end loop; 64 | wait; 65 | end process; 66 | ------------------------------------------------------------------------ 67 | 68 | stimulus : process(simulator_clock) 69 | 70 | begin 71 | if rising_edge(simulator_clock) then 72 | simulation_counter <= simulation_counter + 1; 73 | 74 | 75 | end if; -- rising_edge 76 | end process stimulus; 77 | ------------------------------------------------------------------------ 78 | end vunit_simulation; 79 | -------------------------------------------------------------------------------- /testbenches/simulate_float_filter/tb_float_filter.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY ieee ; 2 | USE ieee.NUMERIC_STD.all ; 3 | USE ieee.std_logic_1164.all ; 4 | use ieee.math_real.all; 5 | 6 | use work.float_type_definitions_pkg.all; 7 | use work.float_arithmetic_operations_pkg.all; 8 | use work.float_to_real_conversions_pkg.all; 9 | use work.float_first_order_filter_pkg.all; 10 | use work.float_alu_pkg.all; 11 | 12 | library vunit_lib; 13 | use vunit_lib.run_pkg.all; 14 | 15 | entity float_filter_tb is 16 | generic (runner_cfg : string); 17 | end; 18 | 19 | architecture vunit_simulation of float_filter_tb is 20 | 21 | signal simulation_running : boolean; 22 | signal simulator_clock : std_logic := '0'; 23 | constant clock_per : time := 1 ns; 24 | constant clock_half_per : time := 0.5 ns; 25 | constant simtime_in_clocks : integer := 6500; 26 | 27 | signal simulation_counter : natural := 0; 28 | ----------------------------------- 29 | -- simulation specific signals ---- 30 | 31 | signal u : float_record := to_float(1.0); 32 | 33 | signal float_alu : float_alu_record := init_float_alu; 34 | signal alu_filter : first_order_filter_record := init_first_order_filter; 35 | signal alu_filter_out : real := 0.0; 36 | 37 | 38 | begin 39 | 40 | ------------------------------------------------------------------------ 41 | simtime : process 42 | begin 43 | test_runner_setup(runner, runner_cfg); 44 | wait for simtime_in_clocks*clock_per; 45 | test_runner_cleanup(runner); -- Simulation ends here 46 | wait; 47 | end process simtime; 48 | 49 | simulator_clock <= not simulator_clock after clock_per/2.0; 50 | ------------------------------------------------------------------------ 51 | 52 | stimulus : process(simulator_clock) 53 | 54 | begin 55 | if rising_edge(simulator_clock) then 56 | simulation_counter <= simulation_counter + 1; 57 | 58 | create_float_alu(float_alu); 59 | create_first_order_filter(alu_filter, float_alu, to_float(0.04)); 60 | 61 | if simulation_counter mod 100 = 0 then 62 | u <= -u; 63 | end if; 64 | 65 | 66 | if simulation_counter = 0 then 67 | request_float_filter(alu_filter, to_float(8.0)); 68 | end if; 69 | 70 | if float_filter_is_ready(alu_filter) then 71 | request_float_filter(alu_filter, to_float(8.0)); 72 | end if; 73 | 74 | 75 | alu_filter_out <= to_real(get_filter_output(alu_filter)); 76 | 77 | end if; -- rising_edge 78 | end process stimulus; 79 | ------------------------------------------------------------------------ 80 | end vunit_simulation; 81 | -------------------------------------------------------------------------------- /vhdl2008/altera/multiply_add_arch_agilex.vhd: -------------------------------------------------------------------------------- 1 | -- this is only used in Altera Agilex series FPGAs since it uses the hard float ip 2 | architecture agilex of multiply_add is 3 | 4 | use ieee.float_pkg.all; 5 | signal fp32_mult_a : std_logic_vector(31 downto 0) :=to_slv(to_float(0.0, float32'high)); -- fp32_mult_a 6 | signal fp32_mult_b : std_logic_vector(31 downto 0) :=to_slv(to_float(0.0, float32'high)); -- fp32_mult_b 7 | signal fp32_adder_a : std_logic_vector(31 downto 0) :=to_slv(to_float(0.0, float32'high)); -- fp32_chainin 8 | signal ena : std_logic_vector(2 downto 0) := (others => '1'); -- ena 9 | signal fp32_result : std_logic_vector(31 downto 0) ; -- fp32_result 10 | 11 | -- agilex 3 only, left as blackbox in efinix titanium 12 | ----------------------------------------------------- 13 | component native_fp32 is 14 | port ( 15 | fp32_mult_a : in std_logic_vector(31 downto 0) := (others => 'X'); -- fp32_mult_a 16 | fp32_mult_b : in std_logic_vector(31 downto 0) := (others => 'X'); -- fp32_mult_b 17 | fp32_adder_a : in std_logic_vector(31 downto 0) := (others => 'X'); -- fp32_adder_a 18 | clk : in std_logic := 'X'; -- clk 19 | ena : in std_logic_vector(2 downto 0) := (others => 'X'); -- ena 20 | fp32_result : out std_logic_vector(31 downto 0) -- fp32_result 21 | ); 22 | end component native_fp32; 23 | ----------------------------------------------------- 24 | 25 | 26 | signal ready_pipeline : std_logic_vector(2 downto 0) := (others => '0'); 27 | ----------------------------------------------------- 28 | ----------------------------------------------------- 29 | begin 30 | 31 | 32 | mpya_out.is_ready <= ready_pipeline(ready_pipeline'left); 33 | mpya_out.result <= fp32_result; 34 | 35 | ----------------------------------------------------- 36 | u0 : component native_fp32 37 | port map ( 38 | fp32_mult_a => mpya_in.mpy_a -- fp32_mult_a.fp32_mult_a 39 | ,fp32_mult_b => mpya_in.mpy_b -- fp32_mult_b.fp32_mult_b 40 | ,fp32_adder_a => mpya_in.add_a -- fp32_mult_b.fp32_mult_b 41 | ,clk => clock -- clk.clk 42 | ,ena => ena -- ena.ena 43 | ,fp32_result => fp32_result -- fp32_result.fp32_result 44 | ); 45 | 46 | ----------------------------------------------------- 47 | create_ready_pipeline : process(clock) is 48 | begin 49 | if rising_edge(clock) 50 | then 51 | ready_pipeline <= ready_pipeline(ready_pipeline'left-1 downto 0) & mpya_in.is_requested; 52 | end if; -- rising edge 53 | end process; 54 | ----------------------------------------------------- 55 | end agilex; 56 | -------------------------------------------------------------------------------- /testbenches/float_to_real_simulation/tb_fp_2_real_functions.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY ieee ; 2 | USE ieee.NUMERIC_STD.all ; 3 | USE ieee.std_logic_1164.all ; 4 | use ieee.math_real.all; 5 | 6 | use work.float_type_definitions_pkg.all; 7 | use work.float_to_real_conversions_pkg.all; 8 | use work.float_to_real_functions_pkg.all; 9 | 10 | library vunit_lib; 11 | use vunit_lib.run_pkg.all; 12 | 13 | entity fp2real_functions_tb is 14 | generic (runner_cfg : string); 15 | end; 16 | 17 | architecture vunit_simulation of fp2real_functions_tb is 18 | 19 | signal simulation_running : boolean; 20 | signal simulator_clock : std_logic; 21 | constant clock_per : time := 1 ns; 22 | constant clock_half_per : time := 0.5 ns; 23 | constant simtime_in_clocks : integer := 50; 24 | 25 | signal simulation_counter : natural := 0; 26 | ----------------------------------- 27 | -- simulation specific signals ---- 28 | constant tested_number : real := 8.0; 29 | 30 | constant init_test4 : float_record := to_float(tested_number); 31 | signal test_4 : float_record := init_test4; 32 | signal test_4_real : real := to_real(init_test4); 33 | 34 | /* constant init_test5 : float_record := to_float(tested_number); */ 35 | signal test_5 : float_record := to_float(0.0002); 36 | signal test_5_real : real := to_real(init_test4); 37 | 38 | signal test_exponent : t_exponent := get_exponent(tested_number); 39 | signal test_mantissa : t_mantissa := get_mantissa(tested_number); 40 | signal test_get_mantissa : real := get_mantissa(tested_number); 41 | 42 | begin 43 | 44 | ------------------------------------------------------------------------ 45 | simtime : process 46 | begin 47 | test_runner_setup(runner, runner_cfg); 48 | simulation_running <= true; 49 | wait for simtime_in_clocks*clock_per; 50 | simulation_running <= false; 51 | test_runner_cleanup(runner); -- Simulation ends here 52 | wait; 53 | end process simtime; 54 | 55 | ------------------------------------------------------------------------ 56 | sim_clock_gen : process 57 | begin 58 | simulator_clock <= '0'; 59 | wait for clock_half_per; 60 | while simulation_running loop 61 | wait for clock_half_per; 62 | simulator_clock <= not simulator_clock; 63 | end loop; 64 | wait; 65 | end process; 66 | ------------------------------------------------------------------------ 67 | 68 | stimulus : process(simulator_clock) 69 | 70 | begin 71 | if rising_edge(simulator_clock) then 72 | simulation_counter <= simulation_counter + 1; 73 | 74 | 75 | end if; -- rising_edge 76 | end process stimulus; 77 | ------------------------------------------------------------------------ 78 | end vunit_simulation; 79 | -------------------------------------------------------------------------------- /testbenches/adder_simulation/tb_pipelined_add.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY ieee ; 2 | USE ieee.NUMERIC_STD.all ; 3 | USE ieee.std_logic_1164.all ; 4 | use ieee.math_real.all; 5 | 6 | use work.float_type_definitions_pkg.all; 7 | use work.denormalizer_pkg.all; 8 | use work.float_to_real_conversions_pkg.all; 9 | use work.float_arithmetic_operations_pkg.all; 10 | use work.float_adder_pkg.all; 11 | 12 | library vunit_lib; 13 | use vunit_lib.run_pkg.all; 14 | 15 | entity pipelined_add_tb is 16 | generic (runner_cfg : string); 17 | end; 18 | 19 | architecture vunit_simulation of pipelined_add_tb is 20 | 21 | signal simulation_running : boolean; 22 | signal simulator_clock : std_logic; 23 | constant clock_per : time := 1 ns; 24 | constant clock_half_per : time := 0.5 ns; 25 | constant simtime_in_clocks : integer := 50; 26 | 27 | signal simulation_counter : natural := 0; 28 | ----------------------------------- 29 | -- simulation specific signals ---- 30 | 31 | signal adder : float_adder_record := init_adder; 32 | signal result : real := 0.0; 33 | 34 | begin 35 | 36 | ------------------------------------------------------------------------ 37 | simtime : process 38 | begin 39 | test_runner_setup(runner, runner_cfg); 40 | simulation_running <= true; 41 | wait for simtime_in_clocks*clock_per; 42 | simulation_running <= false; 43 | test_runner_cleanup(runner); -- Simulation ends here 44 | wait; 45 | end process simtime; 46 | 47 | ------------------------------------------------------------------------ 48 | sim_clock_gen : process 49 | begin 50 | simulator_clock <= '0'; 51 | wait for clock_half_per; 52 | while simulation_running loop 53 | wait for clock_half_per; 54 | simulator_clock <= not simulator_clock; 55 | end loop; 56 | wait; 57 | end process; 58 | ------------------------------------------------------------------------ 59 | 60 | stimulus : process(simulator_clock) 61 | 62 | begin 63 | if rising_edge(simulator_clock) then 64 | simulation_counter <= simulation_counter + 1; 65 | create_adder(adder); 66 | CASE simulation_counter is 67 | WHEN 0 => request_add(adder, to_float(1.5), to_float(0.5)); 68 | WHEN 1 => request_add(adder, to_float(2.5), to_float(0.5)); 69 | WHEN 2 => request_add(adder, to_float(-1.5), to_float(0.5)); 70 | WHEN 3 => request_subtraction(adder, to_float(-1.5), to_float(0.5)); 71 | WHEN others => -- do nothing 72 | end CASE; 73 | 74 | if adder_is_ready(adder) then 75 | result <= to_real(get_result(adder)); 76 | end if; 77 | 78 | 79 | end if; -- rising_edge 80 | end process stimulus; 81 | ------------------------------------------------------------------------ 82 | end vunit_simulation; 83 | -------------------------------------------------------------------------------- /testbenches/vhdl2008/normalizer_tb.vhd: -------------------------------------------------------------------------------- 1 | 2 | LIBRARY ieee ; 3 | USE ieee.NUMERIC_STD.all ; 4 | USE ieee.std_logic_1164.all ; 5 | use ieee.math_real.all; 6 | 7 | library vunit_lib; 8 | context vunit_lib.vunit_context; 9 | 10 | entity tb_normalizer is 11 | generic (runner_cfg : string); 12 | end; 13 | 14 | architecture vunit_simulation of tb_normalizer is 15 | 16 | signal simulation_running : boolean; 17 | signal simulator_clock : std_logic := '0'; 18 | constant clock_per : time := 1 ns; 19 | constant clock_half_per : time := 0.5 ns; 20 | constant simtime_in_clocks : integer := 50; 21 | 22 | signal simulation_counter : natural := 0; 23 | ----------------------------------- 24 | -- simulation specific signals ---- 25 | use ieee.float_pkg.all; 26 | 27 | function to_float32 (a : real) return float32 is 28 | begin 29 | return to_float(a, float32'high); 30 | end to_float32; 31 | 32 | use work.float_typedefs_generic_pkg.all; 33 | use work.normalizer_generic_pkg.all; 34 | 35 | constant hfloat_zero : hfloat_record :=(sign => '0', exponent => (7 downto 0 => x"00"), mantissa => (23 downto 0 => x"000000")); 36 | 37 | constant init_normalizer : normalizer_record := normalizer_typeref(2, floatref => hfloat_zero); 38 | 39 | signal normalizer : init_normalizer'subtype := init_normalizer; 40 | signal conv_result : hfloat_zero'subtype := hfloat_zero; 41 | signal float32_conv_result : float32 := to_float32(0.0); 42 | 43 | 44 | signal convref : float32 := to_float32(-4.0); 45 | 46 | begin 47 | 48 | ------------------------------------------------------------------------ 49 | simtime : process 50 | begin 51 | test_runner_setup(runner, runner_cfg); 52 | simulation_running <= true; 53 | wait for simtime_in_clocks*clock_per; 54 | check(convref = float32_conv_result, "conversions did not match "); 55 | simulation_running <= false; 56 | test_runner_cleanup(runner); -- Simulation ends here 57 | wait; 58 | end process simtime; 59 | 60 | ------------------------------------------------------------------------ 61 | simulator_clock <= not simulator_clock after clock_per/2.0; 62 | ------------------------------------------------------------------------ 63 | 64 | stimulus : process(simulator_clock) 65 | 66 | begin 67 | if rising_edge(simulator_clock) then 68 | simulation_counter <= simulation_counter + 1; 69 | 70 | create_normalizer(normalizer); 71 | 72 | if simulation_counter = 0 then 73 | convert_integer_to_hfloat(normalizer, -4, 0, hfloat_zero); 74 | end if; 75 | if normalizer_is_ready(normalizer) then 76 | conv_result <= get_normalizer_result(normalizer); 77 | float32_conv_result <= to_ieee_float32(get_normalizer_result(normalizer)); 78 | end if; 79 | 80 | end if; -- rising_edge 81 | end process stimulus; 82 | ------------------------------------------------------------------------ 83 | end vunit_simulation; 84 | -------------------------------------------------------------------------------- /testbenches/float_to_integer_simulation/tb_float_to_integer_converter.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY ieee ; 2 | USE ieee.NUMERIC_STD.all ; 3 | USE ieee.std_logic_1164.all ; 4 | 5 | library vunit_lib; 6 | context vunit_lib.vunit_context; 7 | 8 | use work.float_type_definitions_pkg.all; 9 | use work.float_to_real_conversions_pkg.all; 10 | use work.denormalizer_pkg.all; 11 | 12 | entity tb_float_to_integer_converter is 13 | generic (runner_cfg : string); 14 | end; 15 | 16 | architecture vunit_simulation of tb_float_to_integer_converter is 17 | 18 | signal simulator_clock : std_logic := '0'; 19 | constant clock_period : time := 1 ns; 20 | constant simtime_in_clocks : integer := 50; 21 | 22 | signal simulation_counter : natural := 0; 23 | ----------------------------------- 24 | -- simulation specific signals ---- 25 | 26 | signal denormalizer : denormalizer_record := init_denormalizer; 27 | signal result_index : natural := 0; 28 | 29 | begin 30 | 31 | ------------------------------------------------------------------------ 32 | simtime : process 33 | begin 34 | test_runner_setup(runner, runner_cfg); 35 | wait for simtime_in_clocks*clock_period; 36 | test_runner_cleanup(runner); -- Simulation ends here 37 | wait; 38 | end process simtime; 39 | 40 | simulator_clock <= not simulator_clock after clock_period/2.0; 41 | ------------------------------------------------------------------------ 42 | 43 | stimulus : process(simulator_clock) 44 | 45 | begin 46 | if rising_edge(simulator_clock) then 47 | simulation_counter <= simulation_counter + 1; 48 | create_denormalizer(denormalizer); 49 | 50 | CASE simulation_counter is 51 | WHEN 0 => request_scaling(denormalizer , to_float(1.0) , 12); 52 | WHEN 1 => request_scaling(denormalizer , to_float(5.0) , 12); 53 | WHEN 2 => request_scaling(denormalizer , to_float(-11.0) , 12); 54 | WHEN 3 => request_scaling(denormalizer , to_float(-0.0) , 12); 55 | WHEN 4 => request_scaling(denormalizer , to_float(0.0) , 12); 56 | WHEN others => -- do nothing 57 | end CASE; 58 | 59 | if denormalizer_is_ready(denormalizer) then 60 | result_index <= result_index + 1; 61 | CASE result_index is 62 | WHEN 0 => check(get_integer(denormalizer) = 4096 , "fail"); 63 | WHEN 1 => check(get_integer(denormalizer) = 5*4096 , "fail"); 64 | WHEN 2 => check(get_integer(denormalizer) = -11*4096 , "fail"); 65 | WHEN 3 => check(get_integer(denormalizer) = 0 , "fail"); 66 | WHEN 4 => check(get_integer(denormalizer) = 0 , "fail"); 67 | WHEN others => -- do nothing 68 | end CASE; 69 | end if; 70 | 71 | end if; -- rising_edge 72 | end process stimulus; 73 | ------------------------------------------------------------------------ 74 | end vunit_simulation; 75 | -------------------------------------------------------------------------------- /testbenches/float_to_real_simulation/tb_float_conversions.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY ieee ; 2 | USE ieee.NUMERIC_STD.all ; 3 | USE ieee.std_logic_1164.all ; 4 | use ieee.math_real.all; 5 | 6 | use work.float_type_definitions_pkg.all; 7 | use work.float_arithmetic_operations_pkg.all; 8 | use work.float_to_real_conversions_pkg.all; 9 | 10 | library vunit_lib; 11 | use vunit_lib.run_pkg.all; 12 | 13 | entity float_conversions_tb is 14 | generic (runner_cfg : string); 15 | end; 16 | 17 | architecture vunit_simulation of float_conversions_tb is 18 | 19 | signal simulation_running : boolean; 20 | signal simulator_clock : std_logic; 21 | constant clock_per : time := 1 ns; 22 | constant clock_half_per : time := 0.5 ns; 23 | constant simtime_in_clocks : integer := 50; 24 | 25 | signal simulation_counter : natural := 0; 26 | ----------------------------------- 27 | -- simulation specific signals ---- 28 | constant init_test_1 : float_record := to_float(568996.25); 29 | constant init_test_2 : float_record := to_float(4.0); 30 | constant init_test_3 : float_record := to_float(-3.2); 31 | constant init_test_4 : float_record := to_float(8.0); 32 | 33 | signal test_1 : float_record := init_test_1; 34 | signal test_2 : float_record := init_test_2; 35 | signal test_3 : float_record := init_test_3; 36 | signal test_4 : float_record := init_test_4; 37 | 38 | signal test_1_real: real := to_real(init_test_1); 39 | signal test_2_real: real := to_real(init_test_2); 40 | signal test_3_real: real := to_real(init_test_3); 41 | signal test_4_real: real := to_real(init_test_4); 42 | 43 | constant init_test_float : float_record := to_float(22.1346836); 44 | signal test_float : float_record := init_test_float; 45 | signal test_real : real := to_real(init_test_float); 46 | 47 | 48 | ------------------------------------------------------------------------ 49 | 50 | begin 51 | 52 | ------------------------------------------------------------------------ 53 | simtime : process 54 | begin 55 | test_runner_setup(runner, runner_cfg); 56 | simulation_running <= true; 57 | wait for simtime_in_clocks*clock_per; 58 | simulation_running <= false; 59 | test_runner_cleanup(runner); -- Simulation ends here 60 | wait; 61 | end process simtime; 62 | 63 | ------------------------------------------------------------------------ 64 | sim_clock_gen : process 65 | begin 66 | simulator_clock <= '0'; 67 | wait for clock_half_per; 68 | while simulation_running loop 69 | wait for clock_half_per; 70 | simulator_clock <= not simulator_clock; 71 | end loop; 72 | wait; 73 | end process; 74 | ------------------------------------------------------------------------ 75 | 76 | stimulus : process(simulator_clock) 77 | 78 | begin 79 | if rising_edge(simulator_clock) then 80 | simulation_counter <= simulation_counter + 1; 81 | 82 | end if; -- rising_edge 83 | end process stimulus; 84 | ------------------------------------------------------------------------ 85 | end vunit_simulation; 86 | -------------------------------------------------------------------------------- /testbenches/denormalized_numbers/saturated_add_tb.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY ieee ; 2 | USE ieee.NUMERIC_STD.all ; 3 | USE ieee.std_logic_1164.all ; 4 | use ieee.math_real.all; 5 | 6 | library vunit_lib; 7 | context vunit_lib.vunit_context; 8 | 9 | use work.float_to_real_conversions_pkg.all; 10 | use work.float_type_definitions_pkg.all; 11 | use work.float_alu_pkg.all; 12 | 13 | entity saturated_add_tb is 14 | generic (runner_cfg : string); 15 | end; 16 | architecture vunit_simulation of saturated_add_tb is 17 | 18 | constant clock_period : time := 1 ns; 19 | constant simtime_in_clocks : integer := 400; 20 | 21 | signal simulator_clock : std_logic := '0'; 22 | signal simulation_counter : natural := 0; 23 | ----------------------------------- 24 | -- simulation specific signals ---- 25 | 26 | signal counter : real := 1.0; 27 | signal test_counter : real := 1.0; 28 | signal float_counter : float_record := to_float(1.0); 29 | signal counter2 : real := 1.0; 30 | signal test_counter2 : real := 0.0; 31 | signal float_counter2 : float_record := to_float(1.0); 32 | signal float_alu : float_alu_record := init_float_alu; 33 | signal float_alu2 : float_alu_record := init_float_alu; 34 | 35 | signal testi : signed(4 downto 0) := "00001"; 36 | signal testi2 : signed(4 downto 0) := shift_right(testi,4); 37 | signal testi3 : signed(4 downto 0) := shift_right(testi,5); 38 | 39 | begin 40 | 41 | ------------------------------------------------------------------------ 42 | simtime : process 43 | begin 44 | test_runner_setup(runner, runner_cfg); 45 | wait for simtime_in_clocks*clock_period; 46 | test_runner_cleanup(runner); -- Simulation ends here 47 | wait; 48 | end process simtime; 49 | 50 | simulator_clock <= not simulator_clock after clock_period/2.0; 51 | ------------------------------------------------------------------------ 52 | 53 | stimulus : process(simulator_clock) 54 | 55 | begin 56 | if rising_edge(simulator_clock) then 57 | simulation_counter <= simulation_counter + 1; 58 | create_float_alu(float_alu); 59 | create_float_alu(float_alu2); 60 | 61 | if simulation_counter = 0 then 62 | add(float_alu , float_counter , to_float(3.0)); 63 | multiply(float_alu2 , float_counter2 , to_float(0.5)); 64 | end if; 65 | 66 | if add_is_ready(float_alu) then 67 | add(float_alu, get_add_result(float_alu), to_float(3.0)); 68 | float_counter <= get_add_result(float_alu); 69 | counter <= to_real(get_add_result(float_alu)); 70 | 71 | multiply(float_alu2, get_multiplier_result(float_alu2), to_float(0.5)); 72 | float_counter2 <= get_multiplier_result(float_alu2); 73 | counter2 <= to_real(get_multiplier_result(float_alu2)); 74 | end if; 75 | 76 | end if; -- rising_edge 77 | end process stimulus; 78 | ------------------------------------------------------------------------ 79 | end vunit_simulation; 80 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # High level vhdl floating point library 2 | simple floating point library for synthesis in fpga coded in object oriented style. This is a synthesizable version of a floating point filter, which has been tested with most common FPGAs 3 | 4 | ```vhdl 5 | floating_point_filter : process(clock) 6 | begin 7 | if rising_edge(clock) then 8 | 9 | create_float_alu(float_alu); 10 | create_float_to_integer_converter(float_to_integer_converter); 11 | ------------------------------------------------------------------------ 12 | filter_is_ready <= false; 13 | CASE filter_counter is 14 | WHEN 0 => 15 | subtract(float_alu, u, y); 16 | filter_counter <= filter_counter + 1; 17 | WHEN 1 => 18 | if add_is_ready(float_alu) then 19 | multiply(float_alu , get_add_result(float_alu) , filter_gain); 20 | filter_counter <= filter_counter + 1; 21 | end if; 22 | 23 | WHEN 2 => 24 | if multiplier_is_ready(float_alu) then 25 | add(float_alu, get_multiplier_result(float_alu), y); 26 | filter_counter <= filter_counter + 1; 27 | end if; 28 | WHEN 3 => 29 | if add_is_ready(float_alu) then 30 | y <= get_add_result(float_alu); 31 | filter_counter <= filter_counter + 1; 32 | filter_is_ready <= true; 33 | end if; 34 | WHEN others => -- wait for start 35 | end CASE; 36 | ------------------------------------------------------------------------ 37 | 38 | if example_filter_input.filter_is_requested then 39 | convert_integer_to_float(float_to_integer_converter, example_filter_input.filter_input, 15); 40 | end if; 41 | 42 | if int_to_float_conversion_is_ready(float_to_integer_converter) then 43 | request_float_filter(float_filter, get_converted_float(float_to_integer_converter)); 44 | end if; 45 | 46 | convert_float_to_integer(float_to_integer_converter, get_filter_output(float_filter), 14); 47 | 48 | end if; --rising_edge 49 | end process floating_point_filter; 50 | 51 | ``` 52 | 53 | Also includes float to real and real to float conversion functions for simple constant assignment like 54 | 55 | float_number <= to_float(3.14); 56 | 57 | 58 | run all test benches with vunit+ghdl+gtkwave using 59 | 60 | ``` 61 | python vunit_run_float.py -p 8 --gtkwave-fmt ghw 62 | ``` 63 | 64 | An iir low pass filter has been tested on an example project for the hVHDL project and can be found here 65 | https://hvhdl.readthedocs.io/en/latest/hvhdl_example_project/hvhdl_example_project.html#floating-point-filter-implementation 66 | 67 | There is a blog post on the bit level design of the floating point module 68 | https://hardwaredescriptions.com/floating-point-in-vhdl/ 69 | 70 | The floating point alu is also documented in 71 | https://hardwaredescriptions.com/high-level-floating-point-alu-in-synthesizable-vhdl/ 72 | -------------------------------------------------------------------------------- /testbenches/float_to_integer_simulation/integer_to_float_simulation_tb.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY ieee ; 2 | USE ieee.NUMERIC_STD.all ; 3 | USE ieee.std_logic_1164.all ; 4 | use ieee.math_real.all; 5 | 6 | library vunit_lib; 7 | context vunit_lib.vunit_context; 8 | 9 | use work.float_type_definitions_pkg.all; 10 | use work.float_to_real_conversions_pkg.all; 11 | use work.normalizer_pkg.all; 12 | 13 | entity tb_integer_to_float_simulation_tb is 14 | generic (runner_cfg : string); 15 | end; 16 | 17 | architecture vunit_simulation of tb_integer_to_float_simulation_tb is 18 | 19 | signal simulator_clock : std_logic := '0'; 20 | constant clock_period : time := 1 ns; 21 | constant simtime_in_clocks : integer := 50; 22 | 23 | signal simulation_counter : natural := 0; 24 | ----------------------------------- 25 | -- simulation specific signals ---- 26 | 27 | signal normalizer : normalizer_record := init_normalizer; 28 | 29 | signal float_result : float_record := zero; 30 | signal real_result : real := 0.0; 31 | signal result_index : integer := 0; 32 | 33 | begin 34 | 35 | ------------------------------------------------------------------------ 36 | simtime : process 37 | begin 38 | test_runner_setup(runner, runner_cfg); 39 | wait for simtime_in_clocks*clock_period; 40 | test_runner_cleanup(runner); -- Simulation ends here 41 | wait; 42 | end process simtime; 43 | 44 | simulator_clock <= not simulator_clock after clock_period/2.0; 45 | ------------------------------------------------------------------------ 46 | 47 | stimulus : process(simulator_clock) 48 | 49 | begin 50 | if rising_edge(simulator_clock) then 51 | simulation_counter <= simulation_counter + 1; 52 | create_normalizer(normalizer); 53 | 54 | CASE simulation_counter is 55 | WHEN 0 => to_float(normalizer, 65536, 16); 56 | WHEN 1 => to_float(normalizer, -65536, 16); 57 | WHEN 2 => to_float(normalizer, integer(2.0**16*3.2), 16); 58 | WHEN 3 => to_float(normalizer, integer(2.0**15*3.2), 15); 59 | WHEN others => -- do nothing 60 | end CASE; 61 | 62 | if normalizer_is_ready(normalizer) then 63 | float_result <= get_normalizer_result(normalizer); 64 | real_result <= to_real(get_normalizer_result(normalizer)); 65 | result_index <= result_index + 1; 66 | CASE result_index is 67 | WHEN 0 => check(abs(to_real(get_normalizer_result(normalizer)) - 1.0) < 0.001, "fail"); 68 | WHEN 1 => check(abs(to_real(get_normalizer_result(normalizer)) + 1.0) < 0.001, "fail"); 69 | WHEN 2 => check(abs(to_real(get_normalizer_result(normalizer)) - 3.2) < 0.001, "fail"); 70 | WHEN 3 => check(abs(to_real(get_normalizer_result(normalizer)) - 3.2) < 0.001, "fail"); 71 | WHEN others => -- do nothing 72 | end CASE; 73 | end if; 74 | 75 | end if; -- rising_edge 76 | end process stimulus; 77 | ------------------------------------------------------------------------ 78 | end vunit_simulation; 79 | -------------------------------------------------------------------------------- /testbenches/vhdl2008/type_conversions_tb.vhd: -------------------------------------------------------------------------------- 1 | 2 | LIBRARY ieee ; 3 | USE ieee.NUMERIC_STD.all ; 4 | USE ieee.std_logic_1164.all ; 5 | use ieee.math_real.all; 6 | 7 | library vunit_lib; 8 | context vunit_lib.vunit_context; 9 | 10 | entity type_conversions_tb is 11 | generic (runner_cfg : string); 12 | end; 13 | 14 | architecture vunit_simulation of type_conversions_tb is 15 | 16 | signal simulation_running : boolean; 17 | signal simulator_clock : std_logic := '0'; 18 | constant clock_per : time := 1 ns; 19 | constant clock_half_per : time := 0.5 ns; 20 | constant simtime_in_clocks : integer := 150; 21 | 22 | signal simulation_counter : natural := 0; 23 | ----------------------------------- 24 | -- simulation specific signals ---- 25 | use ieee.float_pkg.all; 26 | 27 | function to_float32 (a : real) return float32 is 28 | begin 29 | return to_float(a, float32'high); 30 | end to_float32; 31 | 32 | constant check_value : real := -84.5; 33 | 34 | use work.float_typedefs_generic_pkg.all; 35 | use work.float_to_real_conversions_pkg.all; 36 | 37 | function to_hfloat(a : real; mantissa_length : natural := 18) return hfloat_record is 38 | begin 39 | return to_hfloat(a,8,mantissa_length); 40 | end to_hfloat; 41 | 42 | constant hfloat_zero : hfloat_record := to_hfloat(0.0); 43 | 44 | signal float32_conv_result : float32 := to_float32(0.0); 45 | signal convref : float32 := to_float32(check_value); 46 | signal conv_result : hfloat_zero'subtype := hfloat_zero; 47 | 48 | constant float1 : hfloat_zero'subtype := to_hfloat(-84.5); 49 | constant float2 : hfloat_zero'subtype := to_hfloat(1.5); 50 | constant float3 : hfloat_zero'subtype := to_hfloat(84.5/2.0); 51 | 52 | use work.float_typedefs_generic_pkg.to_ieee_float32; 53 | 54 | constant ref : real := math_pi; 55 | constant fref : float32 := to_float32(ref); 56 | constant slvref : std_logic_vector := to_slv(fref); 57 | signal href : hfloat_zero'subtype := to_hfloat(ref); 58 | signal href2 : hfloat_zero'subtype := to_hfloat(fref, hfloat_zero); 59 | signal href3 : hfloat_zero'subtype := to_hfloat(to_float(slvref, 8, 23), hfloat_zero); 60 | 61 | begin 62 | 63 | ------------------------------------------------------------------------ 64 | simtime : process 65 | begin 66 | test_runner_setup(runner, runner_cfg); 67 | simulation_running <= true; 68 | wait for simtime_in_clocks*clock_per; 69 | simulation_running <= false; 70 | test_runner_cleanup(runner); -- Simulation ends here 71 | wait; 72 | end process simtime; 73 | 74 | ------------------------------------------------------------------------ 75 | simulator_clock <= not simulator_clock after clock_per/2.0; 76 | ------------------------------------------------------------------------ 77 | 78 | stimulus : process(simulator_clock) 79 | 80 | begin 81 | if rising_edge(simulator_clock) then 82 | simulation_counter <= simulation_counter + 1; 83 | 84 | end if; -- rising_edge 85 | end process stimulus; 86 | ------------------------------------------------------------------------ 87 | end vunit_simulation; 88 | -------------------------------------------------------------------------------- /testbenches/denormalizer_simulation/tb_denormalizer.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY ieee ; 2 | USE ieee.NUMERIC_STD.all ; 3 | USE ieee.std_logic_1164.all ; 4 | use ieee.math_real.all; 5 | 6 | use work.float_type_definitions_pkg.all; 7 | use work.denormalizer_pkg.all; 8 | use work.float_to_real_conversions_pkg.all; 9 | use work.float_arithmetic_operations_pkg.all; 10 | 11 | library vunit_lib; 12 | use vunit_lib.run_pkg.all; 13 | 14 | entity denormalizer_tb is 15 | generic (runner_cfg : string); 16 | end; 17 | 18 | architecture vunit_simulation of denormalizer_tb is 19 | 20 | signal simulation_running : boolean; 21 | signal simulator_clock : std_logic := '0'; 22 | constant clock_per : time := 1 ns; 23 | constant clock_half_per : time := 0.5 ns; 24 | constant simtime_in_clocks : integer := 50; 25 | 26 | signal simulation_counter : natural := 0; 27 | ----------------------------------- 28 | -- simulation specific signals ---- 29 | signal larger : float_record := to_float(8563.0); 30 | signal smaller : float_record := to_float(37.0); 31 | 32 | signal test_float : float_record := to_float(1.65); 33 | signal test_denormalizer : float_record := denormalize_float(test_float,3); 34 | 35 | signal denormalizer : denormalizer_record := init_denormalizer; 36 | signal denormalization_result : float_record := to_float(0.0); 37 | 38 | begin 39 | 40 | ------------------------------------------------------------------------ 41 | simtime : process 42 | begin 43 | test_runner_setup(runner, runner_cfg); 44 | simulation_running <= true; 45 | wait for simtime_in_clocks*clock_per; 46 | simulation_running <= false; 47 | test_runner_cleanup(runner); -- Simulation ends here 48 | wait; 49 | end process simtime; 50 | simulator_clock <= not simulator_clock after clock_per/2.0; 51 | 52 | ------------------------------------------------------------------------ 53 | stimulus : process(simulator_clock) 54 | 55 | begin 56 | if rising_edge(simulator_clock) then 57 | simulation_counter <= simulation_counter + 1; 58 | 59 | create_denormalizer(denormalizer); 60 | 61 | CASE simulation_counter is 62 | -- WHEN 0 => request_denormalizer(denormalizer, (to_float(1.5)), 5); 63 | -- WHEN 1 => request_denormalizer(denormalizer, (to_float(1.5)), 6); 64 | -- WHEN 2 => request_denormalizer(denormalizer, (to_float(1.5)), 7); 65 | 66 | WHEN 0 => request_scaling(denormalizer , to_float(1.5) , to_float(7.5)); 67 | WHEN 1 => request_scaling(denormalizer , to_float(1.5) , to_float(8.5)); 68 | WHEN 2 => request_scaling(denormalizer , to_float(-100.5) , to_float(-9.5)); 69 | WHEN 3 => request_scaling(denormalizer , to_float(0.0) , to_float(-9.5)); 70 | WHEN others => -- do nothing 71 | end CASE; 72 | 73 | if denormalizer_is_ready(denormalizer) then 74 | denormalization_result <= get_denormalized_result(denormalizer); 75 | end if; 76 | 77 | end if; -- rising_edge 78 | end process stimulus; 79 | ------------------------------------------------------------------------ 80 | end vunit_simulation; 81 | -------------------------------------------------------------------------------- /float_to_real_conversions/float_to_real_conversions_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | use ieee.math_real.all; 5 | 6 | use work.float_type_definitions_pkg.all; 7 | use work.float_to_real_functions_pkg.all; 8 | use work.normalizer_pkg.all; 9 | 10 | package float_to_real_conversions_pkg is 11 | ------------------------------------------------------------------------ 12 | function to_float ( real_number : real) 13 | return float_record; 14 | ------------------------------------------------------------------------ 15 | function to_real ( float_number : float_record) 16 | return real; 17 | ------------------------------------------------------------------------ 18 | function to_float ( float : std_logic_vector) 19 | return float_record ; 20 | ------------------------------------------------------------------------ 21 | function to_std_logic_vector ( float : float_record) 22 | return std_logic_vector; 23 | ------------------------------------------------------------------------ 24 | end package float_to_real_conversions_pkg; 25 | 26 | package body float_to_real_conversions_pkg is 27 | 28 | ------------------------------------------------------------------------ 29 | function to_float 30 | ( 31 | real_number : real 32 | ) 33 | return float_record 34 | is 35 | 36 | begin 37 | 38 | return normalize((sign => get_sign(real_number), 39 | exponent => get_exponent(real_number), 40 | mantissa => get_mantissa(real_number))); 41 | 42 | end to_float; 43 | ------------------------------------------------------------------------ 44 | function to_real 45 | ( 46 | float_number : float_record 47 | ) 48 | return real 49 | is 50 | variable mantissa : real := 0.0; 51 | variable sign : real := 0.0; 52 | variable exponent : real := 0.0; 53 | begin 54 | 55 | sign := get_sign(float_number); 56 | mantissa := real(to_integer(float_number.mantissa))/2.0**(mantissa_length); 57 | exponent := (2.0**real(to_integer(float_number.exponent))); 58 | 59 | return sign * exponent * mantissa; 60 | 61 | end to_real; 62 | ------------------------------------------------------------------------ 63 | function to_float 64 | ( 65 | float : std_logic_vector 66 | ) 67 | return float_record 68 | is 69 | variable retval : float_record; 70 | begin 71 | retval.sign := float(float'left); 72 | retval.exponent := signed(float(float'left-1 downto float'left-1-exponent_high)); 73 | retval.mantissa := unsigned(float(float'left-exponent_high-2 downto 0)); 74 | 75 | return retval; 76 | end to_float; 77 | ------------------------------------------------------------------------ 78 | function to_std_logic_vector 79 | ( 80 | float : float_record 81 | ) 82 | return std_logic_vector 83 | is 84 | variable retval : std_logic_vector(mantissa_high+exponent_high+2 downto 0); 85 | begin 86 | retval := float.sign & std_logic_vector(float.exponent) & std_logic_vector(float.mantissa); 87 | 88 | return retval; 89 | 90 | end to_std_logic_vector; 91 | ------------------------------------------------------------------------ 92 | 93 | end package body float_to_real_conversions_pkg; 94 | -------------------------------------------------------------------------------- /float_adder/float_adder_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | use work.float_type_definitions_pkg.all; 6 | use work.float_arithmetic_operations_pkg.all; 7 | use work.denormalizer_pkg.all; 8 | 9 | package float_adder_pkg is 10 | ------------------------------------------------------------------------ 11 | type float_adder_record is record 12 | denormalizer : denormalizer_record; 13 | adder_result : float_record; 14 | adder_is_done : boolean; 15 | end record; 16 | 17 | constant init_adder : float_adder_record := (init_denormalizer, zero, false); 18 | constant init_float_adder : float_adder_record := init_adder; 19 | ------------------------------------------------------------------------ 20 | procedure create_adder ( 21 | signal self : inout float_adder_record); 22 | ------------------------------------------------------------------------ 23 | procedure request_add ( 24 | signal self : out float_adder_record; 25 | left, right : float_record); 26 | ------------------------------------------------------------------------ 27 | procedure request_subtraction ( 28 | signal self : out float_adder_record; 29 | left, right : float_record); 30 | ------------------------------------------------------------------------ 31 | function adder_is_ready (float_self : float_adder_record) 32 | return boolean; 33 | ------------------------------------------------------------------------ 34 | function get_result ( self : float_adder_record) 35 | return float_record; 36 | ------------------------------------------------------------------------ 37 | end package float_adder_pkg; 38 | 39 | package body float_adder_pkg is 40 | ------------------------------------------------------------------------ 41 | procedure create_adder 42 | ( 43 | signal self : inout float_adder_record 44 | ) is 45 | begin 46 | create_denormalizer(self.denormalizer); 47 | self.adder_result <= (self.denormalizer.feedthrough_pipeline(number_of_denormalizer_pipeline_stages) + self.denormalizer.denormalizer_pipeline(number_of_denormalizer_pipeline_stages)); 48 | self.adder_is_done <= denormalizer_is_ready(self.denormalizer); 49 | 50 | end create_adder; 51 | 52 | ------------------------------------------------------------------------ 53 | procedure request_add 54 | ( 55 | signal self : out float_adder_record; 56 | left, right : float_record 57 | ) is 58 | begin 59 | request_scaling(self.denormalizer, left, right); 60 | end request_add; 61 | 62 | ------------------------------------------------------------------------ 63 | procedure request_subtraction 64 | ( 65 | signal self : out float_adder_record; 66 | left, right : float_record 67 | ) is 68 | begin 69 | request_scaling(self.denormalizer, left, -right); 70 | end request_subtraction; 71 | ------------------------------------------------------------------------ 72 | function adder_is_ready 73 | ( 74 | float_self : float_adder_record 75 | ) 76 | return boolean 77 | is 78 | begin 79 | return float_self.adder_is_done; 80 | end adder_is_ready; 81 | 82 | ------------------------------------------------------------------------ 83 | function get_result 84 | ( 85 | self : float_adder_record 86 | ) 87 | return float_record 88 | is 89 | begin 90 | return self.adder_result; 91 | end get_result; 92 | ------------------------------------------------------------------------ 93 | end package body float_adder_pkg; 94 | -------------------------------------------------------------------------------- /testbenches/vhdl2008/mult_add_entity_agilex_tb.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY ieee ; 2 | USE ieee.NUMERIC_STD.all ; 3 | USE ieee.std_logic_1164.all ; 4 | use ieee.math_real.all; 5 | 6 | library vunit_lib; 7 | context vunit_lib.vunit_context; 8 | 9 | entity mult_add_entity_agilex_tb is 10 | generic (runner_cfg : string); 11 | end; 12 | 13 | architecture vunit_simulation of mult_add_entity_agilex_tb is 14 | 15 | signal simulation_running : boolean; 16 | signal simulator_clock : std_logic := '0'; 17 | constant clock_per : time := 1 ns; 18 | constant clock_half_per : time := 0.5 ns; 19 | constant simtime_in_clocks : integer := 150; 20 | 21 | signal simulation_counter : natural := 0; 22 | ----------------------------------- 23 | -- simulation specific signals ---- 24 | use ieee.float_pkg.all; 25 | 26 | function to_float32 (a : real) return float32 is 27 | begin 28 | return to_float(a, float32'high); 29 | end to_float32; 30 | 31 | constant check_value : real := -84.5; 32 | 33 | signal float32_conv_result : float32 := to_float32(0.0); 34 | signal convref : float32 := to_float32(check_value); 35 | 36 | constant float1 : float32 := to_float32(-84.5); 37 | constant float2 : float32 := to_float32(1.5); 38 | constant float3 : float32 := to_float32(84.5/2.0); 39 | 40 | use work.multiply_add_pkg.all; 41 | constant agilex_mpya_ref : mpya_subtype_record := create_mpya_typeref; 42 | signal agilex_mpya_in : agilex_mpya_ref.mpya_in'subtype := agilex_mpya_ref.mpya_in; 43 | signal agilex_mpya_out : agilex_mpya_ref.mpya_out'subtype := agilex_mpya_ref.mpya_out; 44 | 45 | signal mpya_result : float32 := (others => '0'); 46 | signal real_mpya_result : real := 0.0; 47 | 48 | begin 49 | 50 | ------------------------------------------------------------------------ 51 | simtime : process 52 | begin 53 | test_runner_setup(runner, runner_cfg); 54 | simulation_running <= true; 55 | wait for simtime_in_clocks*clock_per; 56 | check(convref = float32_conv_result); 57 | simulation_running <= false; 58 | test_runner_cleanup(runner); -- Simulation ends here 59 | wait; 60 | end process simtime; 61 | 62 | ------------------------------------------------------------------------ 63 | simulator_clock <= not simulator_clock after clock_per/2.0; 64 | ------------------------------------------------------------------------ 65 | 66 | stimulus : process(simulator_clock) 67 | begin 68 | if rising_edge(simulator_clock) then 69 | simulation_counter <= simulation_counter + 1; 70 | 71 | init_multiply_add(agilex_mpya_in); 72 | 73 | -- 74 | CASE simulation_counter is 75 | WHEN 1 => 76 | multiply_add(agilex_mpya_in 77 | ,to_slv(float1) 78 | ,to_slv(float2) 79 | ,to_slv(float3)); 80 | 81 | WHEN others => -- do nothing 82 | end CASE; 83 | -- 84 | if mpya_is_ready(agilex_mpya_out) 85 | then 86 | float32_conv_result <= to_float(get_mpya_result(agilex_mpya_out)); 87 | real_mpya_result <= to_real(to_float(get_mpya_result(agilex_mpya_out))); 88 | -- float32_conv_result <= to_ieee_float32(to_hfloat(get_mpya_result(agilex_mpya_out), hfloat_zero)); 89 | end if; 90 | 91 | end if; -- rising_edge 92 | end process stimulus; 93 | ------------------------------------------------------------------------ 94 | dut : entity work.multiply_add(agilex) 95 | port map( 96 | simulator_clock 97 | ,agilex_mpya_in 98 | ,agilex_mpya_out); 99 | ------------------------------------------------------------------------ 100 | end vunit_simulation; 101 | -------------------------------------------------------------------------------- /testbenches/float_to_real_simulation/fp2real_functions_tb.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY ieee ; 2 | USE ieee.NUMERIC_STD.all ; 3 | USE ieee.std_logic_1164.all ; 4 | use ieee.math_real.all; 5 | 6 | use work.float_type_definitions_pkg.all; 7 | use work.float_to_real_conversions_pkg.all; 8 | use work.float_to_real_functions_pkg.all; 9 | 10 | library vunit_lib; 11 | use vunit_lib.run_pkg.all; 12 | 13 | entity fp2real_functions_tb is 14 | generic (runner_cfg : string); 15 | end; 16 | 17 | architecture vunit_simulation of fp2real_functions_tb is 18 | 19 | signal simulation_running : boolean; 20 | signal simulator_clock : std_logic; 21 | constant clock_per : time := 1 ns; 22 | constant clock_half_per : time := 0.5 ns; 23 | constant simtime_in_clocks : integer := 50; 24 | 25 | signal simulation_counter : natural := 0; 26 | ----------------------------------- 27 | -- simulation specific signals ---- 28 | constant tested_number : real := 8.0; 29 | signal test_4 : float_record := to_float(tested_number); 30 | signal test_4_real : real := to_real(test_4); 31 | 32 | signal test_5 : float_record := to_float(0.0002); 33 | signal test_5_real : real := to_real(test_4); 34 | 35 | signal test_exponent : t_exponent := get_exponent(tested_number); 36 | signal test_mantissa : t_mantissa := get_mantissa(tested_number); 37 | signal test_get_mantissa : real := get_mantissa(tested_number); 38 | 39 | function real_2_float 40 | ( 41 | number : real 42 | ) 43 | return float_record 44 | is 45 | variable retval : float_record := zero; 46 | variable temp : real; 47 | variable temp2 : real; 48 | begin 49 | 50 | if number < 0.0 then 51 | retval.sign := '1'; 52 | else 53 | retval.sign := '0'; 54 | end if; 55 | 56 | temp := abs(number); 57 | for i in t_exponent'range loop 58 | if temp >= 2.0**(i) then 59 | retval.exponent(i) := '1'; 60 | temp := temp - 2.0**(i); 61 | else 62 | retval.exponent(i) := '0'; 63 | end if; 64 | end loop; 65 | 66 | temp2 := number / (2.0**real(to_integer(retval.exponent))); 67 | 68 | for i in t_mantissa'range loop 69 | if temp2 >= 2.0**(t_mantissa'high - i) then 70 | retval.mantissa(i) := '1'; 71 | temp2 := temp2 - 2.0**(t_mantissa'high - i); 72 | else 73 | retval.mantissa(i) := '0'; 74 | end if; 75 | end loop; 76 | 77 | return retval; 78 | end real_2_float; 79 | 80 | signal testi1 : float_record := real_2_float(4.5); 81 | signal testi2 : float_record := real_2_float(85.846); 82 | 83 | begin 84 | 85 | ------------------------------------------------------------------------ 86 | simtime : process 87 | begin 88 | test_runner_setup(runner, runner_cfg); 89 | simulation_running <= true; 90 | wait for simtime_in_clocks*clock_per; 91 | simulation_running <= false; 92 | test_runner_cleanup(runner); -- Simulation ends here 93 | wait; 94 | end process simtime; 95 | 96 | ------------------------------------------------------------------------ 97 | sim_clock_gen : process 98 | begin 99 | simulator_clock <= '0'; 100 | wait for clock_half_per; 101 | while simulation_running loop 102 | wait for clock_half_per; 103 | simulator_clock <= not simulator_clock; 104 | end loop; 105 | wait; 106 | end process; 107 | ------------------------------------------------------------------------ 108 | 109 | stimulus : process(simulator_clock) 110 | 111 | begin 112 | if rising_edge(simulator_clock) then 113 | simulation_counter <= simulation_counter + 1; 114 | 115 | 116 | end if; -- rising_edge 117 | end process stimulus; 118 | ------------------------------------------------------------------------ 119 | end vunit_simulation; 120 | -------------------------------------------------------------------------------- /testbenches/denormalized_numbers/tb_denormal_conversions.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY ieee ; 2 | USE ieee.NUMERIC_STD.all ; 3 | USE ieee.std_logic_1164.all ; 4 | use ieee.math_real.all; 5 | 6 | library vunit_lib; 7 | context vunit_lib.vunit_context; 8 | 9 | use work.float_to_real_conversions_pkg.all; 10 | use work.float_type_definitions_pkg.all; 11 | 12 | entity denormal_conversions_tb is 13 | generic (runner_cfg : string); 14 | end; 15 | architecture vunit_simulation of denormal_conversions_tb is 16 | 17 | constant clock_period : time := 1 ns; 18 | constant simtime_in_clocks : integer := 80; 19 | 20 | signal simulator_clock : std_logic := '0'; 21 | signal simulation_counter : natural := 0; 22 | ----------------------------------- 23 | -- simulation specific signals ---- 24 | 25 | constant test_result : real := 0.00055435133453; 26 | constant test : real := to_real(to_float(to_std_logic_vector(to_float(test_result)))); 27 | signal should_be_zero : real := test_result - test; 28 | signal testi : real := test; 29 | 30 | 31 | signal counter : real := 1.0; 32 | signal test_counter : real := 1.0; 33 | signal float_counter : float_record := to_float(1.0); 34 | signal counter2 : real := 0.0; 35 | signal test_counter2 : real := 0.0; 36 | signal float_counter2 : float_record := to_float(0.0); 37 | 38 | signal test_add_saturation : t_exponent := (others => '0'); 39 | ------------------------------------------------------------------------ 40 | function saturated_add 41 | ( 42 | left, right : signed 43 | ) 44 | return signed 45 | is 46 | variable retval : signed(right'length - 1 downto 0); 47 | begin 48 | 49 | retval := left + right; 50 | 51 | if left(left'high) = '1' and right(right'high) = '1' and retval(retval'high) = '0' then 52 | retval(retval'high) := '1'; 53 | retval(retval'high-1 downto 0) := (others=>'0'); 54 | 55 | elsif left(left'high) = '0' and right(right'high) = '0' and retval(retval'high) = '1' then 56 | retval(retval'high) := '0'; 57 | retval(retval'high-1 downto 0) := (others=>'1'); 58 | end if; 59 | 60 | return retval; 61 | 62 | end saturated_add; 63 | ------------------------------------------------------------------------ 64 | 65 | function "+" 66 | ( 67 | left, right : signed 68 | ) 69 | return signed 70 | is 71 | begin 72 | return saturated_add(left,right); 73 | end "+"; 74 | 75 | begin 76 | 77 | ------------------------------------------------------------------------ 78 | simtime : process 79 | begin 80 | test_runner_setup(runner, runner_cfg); 81 | wait for simtime_in_clocks*clock_period; 82 | check(abs(should_be_zero) < 0.01, "got " & real'image(should_be_zero)); 83 | test_runner_cleanup(runner); -- Simulation ends here 84 | wait; 85 | end process simtime; 86 | 87 | simulator_clock <= not simulator_clock after clock_period/2.0; 88 | ------------------------------------------------------------------------ 89 | 90 | stimulus : process(simulator_clock) 91 | 92 | begin 93 | if rising_edge(simulator_clock) then 94 | simulation_counter <= simulation_counter + 1; 95 | 96 | counter <= counter * 0.90; 97 | test_counter <= to_real(to_float(counter * 0.90)); 98 | float_counter <= to_float(counter * 0.90); 99 | 100 | counter2 <= counter2 - 2.0; 101 | test_counter2 <= to_real(to_float(counter2 - 2.0)); 102 | float_counter2 <= to_float(counter2 - 2.0); 103 | 104 | if simulation_counter < 10 then 105 | test_add_saturation <= test_add_saturation + to_signed(7, test_add_saturation'length); 106 | else 107 | test_add_saturation <= test_add_saturation + to_signed(-8, test_add_saturation'length); 108 | end if; 109 | 110 | end if; -- rising_edge 111 | end process stimulus; 112 | ------------------------------------------------------------------------ 113 | end vunit_simulation; 114 | -------------------------------------------------------------------------------- /float_type_definitions/float_type_definitions_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | use ieee.math_real.all; 5 | 6 | use work.float_word_length_pkg; 7 | 8 | package float_type_definitions_pkg is 9 | 10 | constant mantissa_length : integer := float_word_length_pkg.mantissa_bits; 11 | constant exponent_length : integer := float_word_length_pkg.exponent_bits; 12 | 13 | constant mantissa_high : integer := mantissa_length - 1; 14 | constant exponent_high : integer := exponent_length - 1; 15 | 16 | subtype t_mantissa is unsigned(mantissa_high downto 0); 17 | subtype t_exponent is signed(exponent_high downto 0); 18 | 19 | type float_record is record 20 | sign : std_logic; 21 | exponent : t_exponent; 22 | mantissa : t_mantissa; 23 | end record; 24 | 25 | function init_float ( 26 | sign : std_logic; 27 | exponent : integer range -2**t_exponent'high to 2**t_exponent'high-1; 28 | mantissa : t_mantissa) 29 | return float_record; 30 | 31 | type float_array is array (natural range <>) of float_record; 32 | 33 | constant zero : float_record := ('0', (others => '0'), (others => '0')); 34 | constant pos_max : float_record := ('0', (exponent_high => '0', others => '1'), (others => '1')); 35 | 36 | ------------------------------------------------------------------------ 37 | function get_signed_mantissa ( float_object : float_record) 38 | return signed; 39 | ------------------------------------------------------------------------ 40 | function get_exponent ( float_number : float_record) 41 | return integer; 42 | ------------------------------------------------------------------------ 43 | function get_mantissa ( float_number : float_record) 44 | return integer; 45 | ------------------------------------------------------------------------ 46 | function get_sign ( float_number : float_record) 47 | return std_logic ; 48 | ------------------------------------------------------------------------ 49 | 50 | end package float_type_definitions_pkg; 51 | 52 | package body float_type_definitions_pkg is 53 | 54 | function init_float 55 | ( 56 | sign : std_logic; 57 | exponent : integer range -2**t_exponent'high to 2**t_exponent'high-1; 58 | mantissa : t_mantissa 59 | ) 60 | return float_record 61 | is 62 | begin 63 | return (sign => sign, 64 | exponent => to_signed(exponent,t_exponent'length), 65 | mantissa => mantissa); 66 | end init_float; 67 | 68 | function get_signed_mantissa 69 | ( 70 | float_object : float_record 71 | ) 72 | return signed 73 | is 74 | variable signed_mantissa : signed(mantissa_length+1 downto 0) := (others => '0'); 75 | 76 | begin 77 | signed_mantissa(t_mantissa'range) := signed(float_object.mantissa); 78 | if float_object.sign = '1' then 79 | signed_mantissa := -signed_mantissa; 80 | end if; 81 | 82 | return signed_mantissa; 83 | 84 | end get_signed_mantissa; 85 | ------------------------------------------------------------------------ 86 | function get_exponent 87 | ( 88 | float_number : float_record 89 | ) 90 | return integer 91 | is 92 | begin 93 | return to_integer(float_number.exponent); 94 | 95 | end get_exponent; 96 | 97 | ------------------------------------------------------------------------ 98 | function get_mantissa 99 | ( 100 | float_number : float_record 101 | ) 102 | return integer 103 | is 104 | begin 105 | return to_integer(float_number.mantissa); 106 | 107 | end get_mantissa; 108 | 109 | ------------------------------------------------------------------------ 110 | function get_sign 111 | ( 112 | float_number : float_record 113 | ) 114 | return std_logic 115 | is 116 | begin 117 | return float_number.sign; 118 | end get_sign; 119 | ------------------------------------------------------------------------ 120 | 121 | end package body float_type_definitions_pkg; 122 | -------------------------------------------------------------------------------- /testbenches/simulate_normalizer/tb_normalizer.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY ieee ; 2 | USE ieee.NUMERIC_STD.all ; 3 | USE ieee.std_logic_1164.all ; 4 | use ieee.math_real.all; 5 | 6 | use work.float_type_definitions_pkg.all; 7 | use work.float_arithmetic_operations_pkg.all; 8 | use work.float_to_real_conversions_pkg.all; 9 | use work.normalizer_pkg.all; 10 | 11 | library vunit_lib; 12 | use vunit_lib.run_pkg.all; 13 | 14 | entity tb_normalizer is 15 | generic (runner_cfg : string); 16 | end; 17 | 18 | architecture vunit_simulation of tb_normalizer is 19 | 20 | signal simulation_running : boolean; 21 | signal simulator_clock : std_logic; 22 | constant clock_per : time := 1 ns; 23 | constant clock_half_per : time := 0.5 ns; 24 | constant simtime_in_clocks : integer := 50; 25 | 26 | signal simulation_counter : natural := 0; 27 | ----------------------------------- 28 | -- simulation specific signals ---- 29 | 30 | signal smaller : float_record := to_float(0.5); 31 | signal larger : float_record := to_float(6.0); 32 | 33 | signal normalizer : normalizer_record := init_normalizer; 34 | 35 | constant test_vector : float_record := ('0', to_signed(0, exponent_length), (0 => '1', others => '0')); 36 | 37 | signal test_float_normalization : float_record := test_vector; 38 | signal test_float_normalization2 : float_record := ('0', to_signed(9, exponent_length), (0 => '1', others => '1')); 39 | signal test_float_normalization3 : float_record := ('0', to_signed(15, exponent_length), (4 => '1', others => '0')); 40 | 41 | signal number_zeroes : integer := number_of_leading_zeroes(test_vector.mantissa, 5); 42 | 43 | signal normalizer_array : float_array(0 to 3) := (zero,zero,zero,zero); 44 | signal normalizer_result : float_record := zero; 45 | 46 | begin 47 | 48 | ------------------------------------------------------------------------ 49 | simtime : process 50 | begin 51 | test_runner_setup(runner, runner_cfg); 52 | simulation_running <= true; 53 | wait for simtime_in_clocks*clock_per; 54 | simulation_running <= false; 55 | test_runner_cleanup(runner); -- Simulation ends here 56 | wait; 57 | end process simtime; 58 | 59 | ------------------------------------------------------------------------ 60 | sim_clock_gen : process 61 | begin 62 | simulator_clock <= '0'; 63 | wait for clock_half_per; 64 | while simulation_running loop 65 | wait for clock_half_per; 66 | simulator_clock <= not simulator_clock; 67 | end loop; 68 | wait; 69 | end process; 70 | ------------------------------------------------------------------------ 71 | 72 | stimulus : process(simulator_clock) 73 | 74 | begin 75 | if rising_edge(simulator_clock) then 76 | simulation_counter <= simulation_counter + 1; 77 | 78 | create_normalizer(normalizer); 79 | 80 | CASE simulation_counter is 81 | WHEN 0 => 82 | request_normalizer(normalizer, test_float_normalization); 83 | WHEN 1 => 84 | request_normalizer(normalizer, test_float_normalization2); 85 | WHEN 2 => 86 | request_normalizer(normalizer, test_float_normalization3); 87 | WHEN others => -- do nothing 88 | end CASE; 89 | 90 | normalizer_array(0) <= normalize(test_float_normalization , mantissa_high/4); 91 | normalizer_array(1) <= normalize(normalizer_array(0) , mantissa_high/4); 92 | normalizer_array(2) <= normalize(normalizer_array(1) , mantissa_high/4); 93 | normalizer_array(3) <= normalize(normalizer_array(2) , mantissa_high/4); 94 | 95 | if normalizer_is_ready(normalizer) then 96 | normalizer_result <= get_normalizer_result(normalizer); 97 | end if; 98 | 99 | smaller <= normalize(smaller); 100 | 101 | end if; -- rising_edge 102 | end process stimulus; 103 | ------------------------------------------------------------------------ 104 | end vunit_simulation; 105 | -------------------------------------------------------------------------------- /vhdl2008/float_adder_generic_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | use work.float_typedefs_generic_pkg.all; 6 | use work.denormalizer_generic_pkg.all; 7 | 8 | package float_adder_pkg is 9 | ------------------------------------------------------------------------ 10 | type float_adder_record is record 11 | denormalizer : denormalizer_record; 12 | adder_result : hfloat_record; 13 | adder_is_done : boolean; 14 | end record; 15 | 16 | function adder_typeref(denorm_pipeline_stages : natural := 2; floatref : hfloat_record) 17 | return float_adder_record; 18 | ------------------------------------------------------------------------ 19 | procedure create_adder ( 20 | signal self : inout float_adder_record); 21 | ------------------------------------------------------------------------ 22 | procedure request_add ( 23 | signal self : out float_adder_record; 24 | left, right : hfloat_record); 25 | ------------------------------------------------------------------------ 26 | procedure request_subtraction ( 27 | signal self : out float_adder_record; 28 | left, right : hfloat_record); 29 | ------------------------------------------------------------------------ 30 | function adder_is_ready (float_self : float_adder_record) 31 | return boolean; 32 | ------------------------------------------------------------------------ 33 | function get_result ( self : float_adder_record) 34 | return hfloat_record; 35 | ------------------------------------------------------------------------ 36 | end package float_adder_pkg; 37 | 38 | package body float_adder_pkg is 39 | ------------------------------------------------------------------------ 40 | function adder_typeref(denorm_pipeline_stages : natural := 2; floatref : hfloat_record) return float_adder_record 41 | is 42 | constant init_adder : float_adder_record := ( 43 | denormalizer => denormalizer_typeref(denorm_pipeline_stages, floatref) 44 | ,adder_result => floatref 45 | ,adder_is_done => false); 46 | begin 47 | return init_adder; 48 | end adder_typeref; 49 | ------------------------------------------------------------------------ 50 | procedure create_adder 51 | ( 52 | signal self : inout float_adder_record 53 | ) is 54 | constant number_of_denormalizer_pipeline_stages : natural := self.denormalizer.feedthrough_pipeline'high; 55 | begin 56 | create_denormalizer(self.denormalizer); 57 | self.adder_result <= 58 | (self.denormalizer.feedthrough_pipeline(number_of_denormalizer_pipeline_stages) 59 | + self.denormalizer.denormalizer_pipeline(number_of_denormalizer_pipeline_stages)); 60 | self.adder_is_done <= denormalizer_is_ready(self.denormalizer); 61 | 62 | end create_adder; 63 | 64 | ------------------------------------------------------------------------ 65 | procedure request_add 66 | ( 67 | signal self : out float_adder_record; 68 | left, right : hfloat_record 69 | ) is 70 | begin 71 | request_scaling(self.denormalizer, left, right); 72 | end request_add; 73 | 74 | ------------------------------------------------------------------------ 75 | procedure request_subtraction 76 | ( 77 | signal self : out float_adder_record; 78 | left, right : hfloat_record 79 | ) is 80 | begin 81 | request_scaling(self.denormalizer, left, -right); 82 | end request_subtraction; 83 | ------------------------------------------------------------------------ 84 | function adder_is_ready 85 | ( 86 | float_self : float_adder_record 87 | ) 88 | return boolean 89 | is 90 | begin 91 | return float_self.adder_is_done; 92 | end adder_is_ready; 93 | 94 | ------------------------------------------------------------------------ 95 | function get_result 96 | ( 97 | self : float_adder_record 98 | ) 99 | return hfloat_record 100 | is 101 | begin 102 | return self.adder_result; 103 | end get_result; 104 | ------------------------------------------------------------------------ 105 | end package body float_adder_pkg; 106 | -------------------------------------------------------------------------------- /testbenches/vhdl2008/mult_add_entity_tb.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY ieee ; 2 | USE ieee.NUMERIC_STD.all ; 3 | USE ieee.std_logic_1164.all ; 4 | use ieee.math_real.all; 5 | 6 | library vunit_lib; 7 | context vunit_lib.vunit_context; 8 | 9 | entity mult_add_entity_tb is 10 | generic (runner_cfg : string); 11 | end; 12 | 13 | architecture vunit_simulation of mult_add_entity_tb is 14 | 15 | signal simulation_running : boolean; 16 | signal simulator_clock : std_logic := '0'; 17 | constant clock_per : time := 1 ns; 18 | constant clock_half_per : time := 0.5 ns; 19 | constant simtime_in_clocks : integer := 150; 20 | 21 | signal simulation_counter : natural := 0; 22 | ----------------------------------- 23 | -- simulation specific signals ---- 24 | use ieee.float_pkg.all; 25 | 26 | function to_float32 (a : real) return float32 is 27 | begin 28 | return to_float(a, float32'high); 29 | end to_float32; 30 | 31 | constant check_value : real := -84.5; 32 | 33 | use work.float_typedefs_generic_pkg.all; 34 | use work.float_to_real_conversions_pkg.all; 35 | 36 | function to_hfloat(a : real) return hfloat_record is 37 | begin 38 | return to_hfloat(a,8,30); 39 | end to_hfloat; 40 | 41 | constant hfloat_zero : hfloat_record := to_hfloat(0.0); 42 | 43 | signal float32_conv_result : float32 := to_float32(0.0); 44 | signal convref : float32 := to_float32(check_value); 45 | signal conv_result : hfloat_zero'subtype := hfloat_zero; 46 | 47 | constant float1 : hfloat_zero'subtype := to_hfloat(-84.5); 48 | constant float2 : hfloat_zero'subtype := to_hfloat(1.5); 49 | constant float3 : hfloat_zero'subtype := to_hfloat(84.5/2.0); 50 | 51 | use work.multiply_add_pkg.all; 52 | constant mpya_ref : mpya_subtype_record := create_mpya_typeref(hfloat_zero); 53 | 54 | signal mpya_in : mpya_ref.mpya_in'subtype := mpya_ref.mpya_in; 55 | signal mpya_out : mpya_ref.mpya_out'subtype := mpya_ref.mpya_out; 56 | 57 | signal mpya_result : hfloat_zero'subtype := hfloat_zero; 58 | signal real_mpya_result : real := 0.0; 59 | 60 | use work.float_typedefs_generic_pkg.to_ieee_float32; 61 | 62 | begin 63 | 64 | ------------------------------------------------------------------------ 65 | simtime : process 66 | begin 67 | test_runner_setup(runner, runner_cfg); 68 | simulation_running <= true; 69 | wait for simtime_in_clocks*clock_per; 70 | check(convref = float32_conv_result); 71 | simulation_running <= false; 72 | test_runner_cleanup(runner); -- Simulation ends here 73 | wait; 74 | end process simtime; 75 | 76 | ------------------------------------------------------------------------ 77 | simulator_clock <= not simulator_clock after clock_per/2.0; 78 | ------------------------------------------------------------------------ 79 | 80 | stimulus : process(simulator_clock) 81 | begin 82 | if rising_edge(simulator_clock) then 83 | simulation_counter <= simulation_counter + 1; 84 | 85 | init_multiply_add(mpya_in); 86 | 87 | -- 88 | CASE simulation_counter is 89 | WHEN 0 => 90 | multiply_add(mpya_in 91 | ,to_std_logic(float1) 92 | ,to_std_logic(float2) 93 | ,to_std_logic(float3)); 94 | 95 | WHEN others => -- do nothing 96 | end CASE; 97 | -- 98 | if mpya_is_ready(mpya_out) 99 | then 100 | mpya_result <= to_hfloat(get_mpya_result(mpya_out), hfloat_zero); 101 | real_mpya_result <= to_real(to_hfloat(get_mpya_result(mpya_out), hfloat_zero)); 102 | float32_conv_result <= to_ieee_float32(to_hfloat(get_mpya_result(mpya_out), hfloat_zero)); 103 | end if; 104 | 105 | end if; -- rising_edge 106 | end process stimulus; 107 | ------------------------------------------------------------------------ 108 | dut : entity work.multiply_add(hfloat) 109 | generic map(hfloat_zero) 110 | port map( 111 | simulator_clock 112 | ,mpya_in 113 | ,mpya_out); 114 | ------------------------------------------------------------------------ 115 | end vunit_simulation; 116 | -------------------------------------------------------------------------------- /testbenches/adder_simulation/tb_float_adder.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY ieee ; 2 | USE ieee.NUMERIC_STD.all ; 3 | USE ieee.std_logic_1164.all ; 4 | use ieee.math_real.all; 5 | 6 | use work.float_type_definitions_pkg.all; 7 | use work.normalizer_pkg.normalize; 8 | use work.float_arithmetic_operations_pkg.all; 9 | use work.float_adder_pkg.all; 10 | use work.float_to_real_conversions_pkg.all; 11 | 12 | library vunit_lib; 13 | context vunit_lib.vunit_context; 14 | 15 | entity tb_float_adder is 16 | generic (runner_cfg : string); 17 | end; 18 | 19 | architecture vunit_simulation of tb_float_adder is 20 | 21 | signal simulation_running : boolean; 22 | signal simulator_clock : std_logic; 23 | constant clock_per : time := 1 ns; 24 | constant clock_half_per : time := 0.5 ns; 25 | constant simtime_in_clocks : integer := 100000; 26 | 27 | signal simulation_counter : natural := 0; 28 | ----------------------------------- 29 | -- simulation specific signals ---- 30 | 31 | signal number1 : float_record := normalize(('0', to_signed(-6,8), (9 => '1', others => '0'))); 32 | signal result : float_record := zero; 33 | 34 | ------------------------------------------------------------------------ 35 | signal adder : float_adder_record := init_adder; 36 | 37 | ------------------------------------------------------------------------ 38 | 39 | signal real_result : real := 0.0; 40 | signal random_value : real := 0.0; 41 | signal random_value1 : real := 1.0; 42 | signal test_random_sum : real := 0.0; 43 | signal difference : real := 0.0; 44 | 45 | signal input1 : real := 0.0; 46 | signal input2 : real := 0.0; 47 | 48 | signal max_value : real := 0.0; 49 | 50 | begin 51 | 52 | ------------------------------------------------------------------------ 53 | simtime : process 54 | begin 55 | test_runner_setup(runner, runner_cfg); 56 | simulation_running <= true; 57 | wait for simtime_in_clocks*clock_per; 58 | check(abs(max_value) < 1.0e1, "error larger than 10"); 59 | simulation_running <= false; 60 | test_runner_cleanup(runner); -- Simulation ends here 61 | wait; 62 | end process simtime; 63 | 64 | ------------------------------------------------------------------------ 65 | sim_clock_gen : process 66 | begin 67 | simulator_clock <= '0'; 68 | wait for clock_half_per; 69 | while simulation_running loop 70 | wait for clock_half_per; 71 | simulator_clock <= not simulator_clock; 72 | end loop; 73 | wait; 74 | end process; 75 | ------------------------------------------------------------------------ 76 | 77 | stimulus : process(simulator_clock) 78 | 79 | variable seed1 : integer := 1359; 80 | variable seed2 : integer := 1; 81 | variable rand_out : real := 0.0; 82 | 83 | begin 84 | if rising_edge(simulator_clock) then 85 | simulation_counter <= simulation_counter + 1; 86 | 87 | uniform(seed1, seed2, rand_out); 88 | random_value <= (rand_out-0.5)*2.0e25; 89 | random_value1 <= random_value; 90 | 91 | create_adder(adder); 92 | 93 | if simulation_counter = 0 or adder_is_ready(adder) then 94 | request_subtraction(adder, to_float(random_value1), to_float(random_value)); 95 | test_random_sum <= random_value1 - random_value; 96 | input1 <= (random_value1); 97 | input2 <= (random_value); 98 | 99 | end if; 100 | 101 | if adder_is_ready(adder) then 102 | result <= normalize(get_result(adder)); 103 | real_result <= to_real(normalize(get_result(adder))); 104 | 105 | difference <= (test_random_sum - to_real(normalize(get_result(adder))))/test_random_sum; 106 | 107 | if (test_random_sum - to_real(normalize(get_result(adder))))/test_random_sum > max_value then 108 | max_value <= (test_random_sum - to_real(normalize(get_result(adder))))/test_random_sum; 109 | end if; 110 | end if; 111 | 112 | 113 | end if; -- rising_edge 114 | end process stimulus; 115 | ------------------------------------------------------------------------ 116 | end vunit_simulation; 117 | -------------------------------------------------------------------------------- /float_first_order_filter/float_first_order_filter_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | use ieee.math_real.all; 5 | 6 | use work.float_type_definitions_pkg.all; 7 | use work.float_to_real_conversions_pkg.all; 8 | use work.float_alu_pkg.all; 9 | 10 | package float_first_order_filter_pkg is 11 | 12 | ------------------------------------------------------------------------ 13 | type first_order_filter_record is record 14 | filter_counter : integer range 0 to 7 ; 15 | u : float_record; 16 | y : float_record; 17 | filter_is_ready : boolean; 18 | end record; 19 | 20 | constant init_first_order_filter : first_order_filter_record := ( 21 | 7, to_float(0.0), to_float(0.0), false); 22 | 23 | ------------------------------------------------------------------------ 24 | procedure create_first_order_filter ( 25 | signal self : inout first_order_filter_record; 26 | signal float_alu : inout float_alu_record; 27 | filter_gain : in float_record); 28 | 29 | ------------------------------------------------------------------------ 30 | procedure request_float_filter ( 31 | signal self : inout first_order_filter_record; 32 | filter_data : in float_record); 33 | 34 | ------------------------------------------------------------------------ 35 | function float_filter_is_ready ( self : first_order_filter_record) 36 | return boolean; 37 | ------------------------------------------------------------------------ 38 | function get_filter_output ( self : first_order_filter_record) 39 | return float_record; 40 | ------------------------------------------------------------------------ 41 | end package float_first_order_filter_pkg; 42 | 43 | package body float_first_order_filter_pkg is 44 | 45 | ------------------------------------------------------------------------ 46 | procedure create_first_order_filter 47 | ( 48 | signal self : inout first_order_filter_record; 49 | signal float_alu : inout float_alu_record; 50 | filter_gain : in float_record 51 | 52 | ) is 53 | begin 54 | 55 | CASE self.filter_counter is 56 | WHEN 0 => 57 | subtract(float_alu, self.u, self.y); 58 | self.filter_counter <= self.filter_counter + 1; 59 | self.filter_is_ready <= false; 60 | WHEN 1 => 61 | self.filter_is_ready <= false; 62 | if add_is_ready(float_alu) then 63 | multiply(float_alu , get_add_result(float_alu) , filter_gain); 64 | self.filter_counter <= self.filter_counter + 1; 65 | end if; 66 | 67 | WHEN 2 => 68 | self.filter_is_ready <= false; 69 | if multiplier_is_ready(float_alu) then 70 | add(float_alu, get_multiplier_result(float_alu), self.y); 71 | self.filter_counter <= self.filter_counter + 1; 72 | end if; 73 | WHEN 3 => 74 | if add_is_ready(float_alu) then 75 | self.filter_is_ready <= true; 76 | self.y <= get_add_result(float_alu); 77 | self.filter_counter <= self.filter_counter + 1; 78 | else 79 | self.filter_is_ready <= false; 80 | end if; 81 | WHEN others => -- filter is ready 82 | end CASE; 83 | end create_first_order_filter; 84 | ------------------------------------------------------------------------ 85 | procedure request_float_filter 86 | ( 87 | signal self : inout first_order_filter_record; 88 | filter_data : in float_record 89 | ) is 90 | begin 91 | 92 | self.u <= filter_data; 93 | self.filter_counter <= 0; 94 | 95 | end request_float_filter; 96 | ------------------------------------------------------------------------ 97 | function float_filter_is_ready 98 | ( 99 | self : first_order_filter_record 100 | ) 101 | return boolean 102 | is 103 | begin 104 | return self.filter_is_ready; 105 | end float_filter_is_ready; 106 | ------------------------------------------------------------------------ 107 | function get_filter_output 108 | ( 109 | self : first_order_filter_record 110 | ) 111 | return float_record 112 | is 113 | begin 114 | return self.y; 115 | end get_filter_output; 116 | 117 | end package body float_first_order_filter_pkg; 118 | -------------------------------------------------------------------------------- /float_to_real_conversions/float_to_real_functions_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | use ieee.math_real.all; 5 | 6 | use work.float_type_definitions_pkg.all; 7 | 8 | package float_to_real_functions_pkg is 9 | 10 | ------------------------------------------------------------------------ 11 | function get_exponent ( number : real) 12 | return real; 13 | ------------------------------------------------------------------------ 14 | function get_mantissa ( number : real) 15 | return real; 16 | ------------------------------------------------------------------------ 17 | function get_sign ( number : float_record) 18 | return real; 19 | ------------------------------------------------------------------------ 20 | function get_mantissa ( number : real) 21 | return unsigned; 22 | ------------------------------------------------------------------------ 23 | function get_exponent ( number : real) 24 | return t_exponent; 25 | ------------------------------------------------------------------------ 26 | function get_sign ( number : real) 27 | return std_logic; 28 | ------------------------------------------------------------------------ 29 | function get_data ( 30 | int_number : integer; 31 | real_number : real) 32 | return signed ; 33 | ------------------------------------------------------------------------ 34 | 35 | end package float_to_real_functions_pkg; 36 | 37 | 38 | package body float_to_real_functions_pkg is 39 | 40 | ------------------------------------------------------------------------ 41 | function get_exponent 42 | ( 43 | number : real 44 | ) 45 | return real 46 | is 47 | variable retval : real; 48 | begin 49 | if number = 0.0 then 50 | retval := 0.0; 51 | else 52 | retval := floor(log2(abs(number)))+1.0; 53 | end if; 54 | if retval >= 2.0**(exponent_high)-1.0 then 55 | retval := 2.0**(exponent_high)-1.0; 56 | end if; 57 | 58 | return retval; 59 | 60 | end get_exponent; 61 | ------------------------------------------------------------------------ 62 | function get_mantissa 63 | ( 64 | number : real 65 | ) 66 | return real 67 | is 68 | begin 69 | return (abs(number)/2.0**get_exponent(number)); 70 | end get_mantissa; 71 | ------------------------------------------------------------------------ 72 | function get_sign 73 | ( 74 | number : float_record 75 | ) 76 | return real 77 | is 78 | variable returned_real : real; 79 | begin 80 | if number.sign = '1' then 81 | returned_real := -1.0; 82 | else 83 | returned_real := 1.0; 84 | end if; 85 | 86 | return returned_real; 87 | end get_sign; 88 | 89 | ------------------------------------------------------------------------ 90 | function get_mantissa 91 | ( 92 | number : real 93 | ) 94 | return unsigned 95 | is 96 | begin 97 | return to_unsigned(integer(get_mantissa(number) * 2.0**mantissa_high), mantissa_length); 98 | end get_mantissa; 99 | ------------------------------------------------------------------------ 100 | function get_exponent 101 | ( 102 | number : real 103 | ) 104 | return t_exponent 105 | is 106 | variable result : real := 0.0; 107 | begin 108 | result := get_exponent(number); 109 | return to_signed(integer(result),exponent_length) + 1; 110 | end get_exponent; 111 | ------------------------------------------------------------------------ 112 | function get_sign 113 | ( 114 | number : real 115 | ) 116 | return std_logic 117 | is 118 | variable result : std_logic; 119 | begin 120 | 121 | if number >= 0.0 then 122 | result := '0'; 123 | else 124 | result := '1'; 125 | end if; 126 | 127 | return result; 128 | 129 | end get_sign; 130 | ------------------------------------------------------------------------ 131 | function get_data 132 | ( 133 | int_number : integer; 134 | real_number : real 135 | ) 136 | return signed 137 | is 138 | variable returned_signed : t_exponent; 139 | begin 140 | if real_number >= 0.0 then 141 | returned_signed := to_signed(int_number, exponent_length); 142 | else 143 | returned_signed := -to_signed(int_number, exponent_length); 144 | end if; 145 | 146 | return returned_signed; 147 | 148 | end get_data; 149 | ------------------------------------------------------------------------ 150 | 151 | end package body float_to_real_functions_pkg; 152 | 153 | -------------------------------------------------------------------------------- /float_to_integer_converter/float_to_integer_converter_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | use work.float_type_definitions_pkg.all; 6 | use work.normalizer_pkg.all; 7 | use work.denormalizer_pkg.all; 8 | 9 | package float_to_integer_converter_pkg is 10 | 11 | type float_to_integer_converter_record is record 12 | normalizer : normalizer_record; 13 | denormalizer : denormalizer_record; 14 | end record; 15 | 16 | constant init_float_to_integer_converter : float_to_integer_converter_record := (init_normalizer, init_denormalizer); 17 | ------------------------------------------------------------------------ 18 | procedure create_float_to_integer_converter ( 19 | signal self : inout float_to_integer_converter_record); 20 | ------------------------------------------------------------------------ 21 | procedure convert_float_to_integer ( 22 | signal self : out float_to_integer_converter_record; 23 | number_to_be_converted : float_record; 24 | desired_radix : in integer); 25 | ------------------------------------------------------------------------ 26 | function float_to_int_conversion_is_ready ( self : float_to_integer_converter_record) 27 | return boolean; 28 | -------------------------------------------------- 29 | function get_converted_integer ( self : float_to_integer_converter_record) 30 | return integer; 31 | ------------------------------------------------------------------------ 32 | ------------------------------------------------------------------------ 33 | procedure convert_integer_to_float ( 34 | signal self : out float_to_integer_converter_record; 35 | number_to_be_converted : in integer; 36 | radix_of_converted_number : in integer); 37 | -------------------------------------------------- 38 | function int_to_float_conversion_is_ready ( self : float_to_integer_converter_record) 39 | return boolean; 40 | -------------------------------------------------- 41 | function get_converted_float ( self : float_to_integer_converter_record) 42 | return float_record; 43 | ------------------------------------------------------------------------ 44 | end package float_to_integer_converter_pkg; 45 | 46 | package body float_to_integer_converter_pkg is 47 | 48 | ------------------------------------------------------------------------ 49 | procedure create_float_to_integer_converter 50 | ( 51 | signal self : inout float_to_integer_converter_record 52 | ) is 53 | begin 54 | create_normalizer(self.normalizer); 55 | create_denormalizer(self.denormalizer); 56 | end create_float_to_integer_converter; 57 | 58 | ------------------------------------------------------------------------ 59 | ------------------------------------------------------------------------ 60 | procedure convert_float_to_integer 61 | ( 62 | signal self : out float_to_integer_converter_record; 63 | number_to_be_converted : float_record; 64 | desired_radix : in integer 65 | ) is 66 | begin 67 | request_scaling(self.denormalizer, number_to_be_converted, desired_radix); 68 | 69 | end convert_float_to_integer; 70 | 71 | -------------------------------------------------- 72 | function float_to_int_conversion_is_ready 73 | ( 74 | self : float_to_integer_converter_record 75 | ) 76 | return boolean 77 | is 78 | begin 79 | return denormalizer_is_ready(self.denormalizer); 80 | end float_to_int_conversion_is_ready; 81 | 82 | -------------------------------------------------- 83 | function get_converted_integer 84 | ( 85 | self : float_to_integer_converter_record 86 | ) 87 | return integer 88 | is 89 | begin 90 | return get_integer(self.denormalizer); 91 | end get_converted_integer; 92 | 93 | ------------------------------------------------------------------------ 94 | ------------------------------------------------------------------------ 95 | procedure convert_integer_to_float 96 | ( 97 | signal self : out float_to_integer_converter_record; 98 | number_to_be_converted : in integer; 99 | radix_of_converted_number : in integer 100 | ) is 101 | begin 102 | to_float(self.normalizer, number_to_be_converted, radix_of_converted_number); 103 | 104 | end convert_integer_to_float; 105 | 106 | -------------------------------------------------- 107 | function int_to_float_conversion_is_ready 108 | ( 109 | self : float_to_integer_converter_record 110 | ) 111 | return boolean 112 | is 113 | begin 114 | return normalizer_is_ready(self.normalizer); 115 | end int_to_float_conversion_is_ready; 116 | 117 | -------------------------------------------------- 118 | function get_converted_float 119 | ( 120 | self : float_to_integer_converter_record 121 | ) 122 | return float_record 123 | is 124 | begin 125 | return get_normalizer_result(self.normalizer); 126 | end get_converted_float; 127 | ------------------------------------------------------------------------ 128 | end package body float_to_integer_converter_pkg; 129 | -------------------------------------------------------------------------------- /testbenches/float_multiplier_simulation/tb_float_multiplier.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY ieee ; 2 | USE ieee.NUMERIC_STD.all ; 3 | USE ieee.std_logic_1164.all ; 4 | use ieee.math_real.all; 5 | 6 | use work.float_type_definitions_pkg.all; 7 | use work.normalizer_pkg.normalize; 8 | use work.float_multiplier_pkg.all; 9 | use work.float_to_real_conversions_pkg.all; 10 | 11 | library vunit_lib; 12 | context vunit_lib.vunit_context; 13 | 14 | entity tb_float_multiplier is 15 | generic (runner_cfg : string); 16 | end; 17 | 18 | architecture vunit_simulation of tb_float_multiplier is 19 | 20 | signal simulation_running : boolean; 21 | signal simulator_clock : std_logic; 22 | constant clock_per : time := 1 ns; 23 | constant clock_half_per : time := 0.5 ns; 24 | constant simtime_in_clocks : integer := 5000; 25 | 26 | signal simulation_counter : natural := 0; 27 | ----------------------------------- 28 | -- simulation specific signals ---- 29 | 30 | ------------------------------------------------------------------------ 31 | constant left_multiplier : real := 3.0; 32 | constant right_multiplier : real := 2.5/1000.0; 33 | signal float1 : float_record := to_float(left_multiplier); 34 | signal float2 : float_record := to_float(right_multiplier); 35 | signal float_resutl : float_record := normalize(float1 * (float2)); 36 | 37 | signal real_result : real := to_real(float_resutl); 38 | signal float_reference : real := left_multiplier*right_multiplier; 39 | signal multiplier_error : real := 1.0-abs(real_result/float_reference); 40 | ------------------------------------------------------------------------ 41 | signal float_multiplier : float_multiplier_record := init_float_multiplier; 42 | signal multiplier_result : real := 0.0; 43 | signal multiplier_reference_result : real := 0.0; 44 | 45 | signal float_multiplier2 : float_multiplier_record := init_float_multiplier; 46 | signal float_test : float_record := to_float(1.0); 47 | signal real_test : real := 0.0; 48 | 49 | constant testi1 : float_record := init_float('0', 0, ("1011", others => '0')); 50 | constant testi2 : float_record := init_float('0', 0, ("1011", others => '0')); 51 | signal result : unsigned(t_mantissa'high*2+1 downto 0) := testi1.mantissa * testi2.mantissa; 52 | 53 | ------------------------------------------------------------------------ 54 | begin 55 | 56 | ------------------------------------------------------------------------ 57 | simtime : process 58 | begin 59 | test_runner_setup(runner, runner_cfg); 60 | simulation_running <= true; 61 | wait for simtime_in_clocks*clock_per; 62 | simulation_running <= false; 63 | check(1.0-abs(real_result/float_reference) < 1.0e-3, "float multiplier error higher than 1.0e-3"); 64 | test_runner_cleanup(runner); -- Simulation ends here 65 | wait; 66 | end process simtime; 67 | 68 | ------------------------------------------------------------------------ 69 | sim_clock_gen : process 70 | begin 71 | simulator_clock <= '0'; 72 | wait for clock_half_per; 73 | while simulation_running loop 74 | wait for clock_half_per; 75 | simulator_clock <= not simulator_clock; 76 | end loop; 77 | wait; 78 | end process; 79 | ------------------------------------------------------------------------ 80 | 81 | stimulus : process(simulator_clock) 82 | 83 | begin 84 | if rising_edge(simulator_clock) then 85 | simulation_counter <= simulation_counter + 1; 86 | 87 | create_float_multiplier(float_multiplier); 88 | create_float_multiplier(float_multiplier2); 89 | 90 | CASE simulation_counter is 91 | WHEN 2 => request_float_multiplier(float_multiplier, to_float(0.0), to_float(0.0)); 92 | WHEN 3 => request_float_multiplier(float_multiplier, to_float(1.5298432), to_float(1.0)); 93 | WHEN 4 => request_float_multiplier(float_multiplier, to_float(2.29846209), to_float(-1.0)); 94 | WHEN 5 => request_float_multiplier(float_multiplier, to_float(31.72935720), to_float(1.0)); 95 | WHEN 7 => request_float_multiplier(float_multiplier, to_float(101.509220), to_float(-1.0)); 96 | WHEN 8 => request_float_multiplier(float_multiplier, to_float(-5.5), to_float(-1.0)); 97 | WHEN others => -- do nothing 98 | end CASE; 99 | 100 | if simulation_counter = 0 then 101 | request_float_multiplier(float_multiplier2 , float_test , to_float(0.93)); 102 | end if; 103 | 104 | if float_multiplier_is_ready(float_multiplier2) then 105 | request_float_multiplier(float_multiplier2 , get_multiplier_result(float_multiplier2) , to_float(0.93)); 106 | float_test <= get_multiplier_result(float_multiplier2); 107 | real_test <= to_real(get_multiplier_result(float_multiplier2)); 108 | end if; 109 | 110 | if float_multiplier_is_ready(float_multiplier) then 111 | multiplier_result <= to_real(get_multiplier_result(float_multiplier)); 112 | end if; 113 | 114 | 115 | end if; -- rising_edge 116 | end process stimulus; 117 | ------------------------------------------------------------------------ 118 | end vunit_simulation; 119 | -------------------------------------------------------------------------------- /vhdl2008/fast_hfloat_pkg.vhd: -------------------------------------------------------------------------------- 1 | 2 | LIBRARY ieee ; 3 | USE ieee.NUMERIC_STD.all ; 4 | USE ieee.std_logic_1164.all ; 5 | 6 | use work.float_typedefs_generic_pkg.hfloat_record; 7 | use work.float_typedefs_generic_pkg.to_hfloat; 8 | 9 | package fast_hfloat_pkg is 10 | 11 | function get_result_slice (a : unsigned; offset : integer ; hfloatref : hfloat_record) return unsigned; 12 | function get_shift_width(a, b, c : signed ; mantissa : unsigned) return integer; 13 | function get_shift(a : std_logic_vector; b : std_logic_vector ; c : std_logic_vector ; floatref : hfloat_record) return unsigned; 14 | function max (a, b : integer) return integer; 15 | function max(a,b : signed) return signed; 16 | function shift(a : unsigned; b : integer) return unsigned; 17 | function get_operation (mpy_a,mpy_b, add_a : hfloat_record) return std_logic; 18 | 19 | type sign_array is array (natural range <>) of std_logic_vector(2 downto 0); 20 | function get_result_sign(pipe : natural ; sign_pipe : sign_array ; high_bit : STD_LOGIC ; op_pipe_sub_when_1 : STD_LOGIC_VECTOR) return std_logic; 21 | 22 | end package; 23 | 24 | package body fast_hfloat_pkg is 25 | 26 | function get_shift_width(a, b, c : signed ; mantissa : unsigned) return integer is 27 | 28 | variable shiftwidth : integer; 29 | 30 | begin 31 | shiftwidth := to_integer(c - a - b); 32 | 33 | if shiftwidth > (mantissa'length)*2 34 | then 35 | shiftwidth := (mantissa'length)*2; 36 | end if; 37 | 38 | if shiftwidth < -(mantissa'length) 39 | then 40 | shiftwidth := -(mantissa'length); 41 | end if; 42 | 43 | return shiftwidth + mantissa'length; 44 | 45 | end get_shift_width; 46 | 47 | ---------------------------- 48 | function get_result_slice (a : unsigned; offset : integer ; hfloatref : hfloat_record) return unsigned is 49 | variable safe_offset : integer := 0; 50 | begin 51 | safe_offset := offset; 52 | if safe_offset > hfloatref.mantissa'length 53 | then 54 | safe_offset := hfloatref.mantissa'length; 55 | end if; 56 | 57 | if safe_offset < -hfloatref.mantissa'length 58 | then 59 | safe_offset := -hfloatref.mantissa'length; 60 | end if; 61 | 62 | return (a(hfloatref.mantissa'length*2-1+(safe_offset) downto hfloatref.mantissa'length+(safe_offset))); 63 | end get_result_slice; 64 | 65 | function get_shift(a : std_logic_vector; b : std_logic_vector ; c : std_logic_vector ; floatref : hfloat_record) return unsigned is 66 | 67 | variable retval : unsigned(floatref.mantissa'length * 2-1 downto 0) := (others => '0'); 68 | 69 | begin 70 | retval(get_shift_width( 71 | to_hfloat(a,floatref).exponent 72 | , to_hfloat(b,floatref).exponent 73 | , to_hfloat(c,floatref).exponent 74 | , floatref.mantissa 75 | )) := '1'; 76 | return retval; 77 | 78 | end get_shift; 79 | --------------------- 80 | function max (a, b : integer) return integer is 81 | variable retval : integer := 0; 82 | begin 83 | if a > b 84 | then 85 | retval := a; 86 | else 87 | retval := b; 88 | end if; 89 | 90 | return retval; 91 | end max; 92 | 93 | function max(a,b : signed) return signed is 94 | variable retval : a'subtype; 95 | begin 96 | if a > b then 97 | retval := a; 98 | else 99 | retval := b; 100 | end if; 101 | return retval; 102 | end max; 103 | 104 | function shift(a : unsigned; b : integer) return unsigned is 105 | variable retval : a'subtype; 106 | begin 107 | if b >= 0 then 108 | retval := shift_left(a,b); 109 | else 110 | retval := shift_right(a,-b); 111 | end if; 112 | 113 | return retval; 114 | end shift; 115 | ---------------------------- 116 | function get_result_sign(pipe : natural ; sign_pipe : sign_array ; high_bit : STD_LOGIC ; op_pipe_sub_when_1 : STD_LOGIC_VECTOR) return std_logic is 117 | --------- 118 | variable retval : std_logic; 119 | --------- 120 | begin 121 | CASE sign_pipe(pipe) is 122 | WHEN "111" => retval := op_pipe_sub_when_1(pipe); 123 | WHEN "001" => retval := op_pipe_sub_when_1(pipe); 124 | WHEN "010" => retval := not op_pipe_sub_when_1(pipe); 125 | WHEN "100" => retval := not op_pipe_sub_when_1(pipe); 126 | -- 127 | WHEN "000" => retval := '0'; 128 | WHEN "011" => retval := '1'; 129 | WHEN "101" => retval := '1'; 130 | WHEN "110" => retval := '0'; 131 | WHEN others => --do nothing 132 | end CASE; 133 | 134 | return retval xor high_bit; 135 | end function; 136 | 137 | ---------------------------- 138 | function get_operation (mpy_a,mpy_b, add_a : hfloat_record) return std_logic is 139 | variable add_when_0_neg_when_1 : std_logic; 140 | variable sign_vector : std_logic_vector(2 downto 0); 141 | /* 142 | sign propagation to operation 143 | ++|+ => + 144 | --|+ => + 145 | -+|- => + 146 | +-|- => + 147 | 148 | --|- => - 149 | -+|+ => - 150 | +-|+ => - 151 | ++|- => - 152 | */ 153 | begin 154 | sign_vector := (mpy_a.sign & mpy_b.sign & add_a.sign); 155 | CASE sign_vector is 156 | -- add 157 | WHEN "000" 158 | |"110" 159 | |"101" 160 | |"011" => add_when_0_neg_when_1 := '0'; 161 | 162 | -- sub 163 | WHEN "111" 164 | |"100" 165 | |"010" 166 | |"001" => add_when_0_neg_when_1 := '1'; 167 | 168 | WHEN others => --do nothing 169 | end CASE; 170 | 171 | return add_when_0_neg_when_1; 172 | 173 | end get_operation; 174 | ----------------------------- 175 | end package body; 176 | -------------------------------------------------------------------------------- /float_multiplier/float_multiplier_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | use work.float_type_definitions_pkg.all; 6 | use work.float_arithmetic_operations_pkg.all; 7 | 8 | package float_multiplier_pkg is 9 | ------------------------------------------------------------------------ 10 | constant float_multiplier_pipeline_depth : natural := 3; 11 | ------------------------------------------------------------------------ 12 | type float_multiplier_record is record 13 | 14 | left : float_record; 15 | right : float_record; 16 | result : float_record; 17 | 18 | sign : std_logic; 19 | exponent : t_exponent; 20 | mantissa_multiplication_result : unsigned(mantissa_high*2+1 downto 0); 21 | shift_register : std_logic_vector(float_multiplier_pipeline_depth-1 downto 0); 22 | end record; 23 | 24 | constant init_float_multiplier : float_multiplier_record := (zero, zero, zero, '0', (others => '0'),(others => '0'), (others => '0')); 25 | ------------------------------------------------------------------------ 26 | procedure create_float_multiplier ( 27 | signal self : inout float_multiplier_record); 28 | ------------------------------------------------------------------------ 29 | procedure request_float_multiplier ( 30 | signal self : out float_multiplier_record; 31 | left, right : float_record); 32 | ------------------------------------------------------------------------ 33 | function float_multiplier_is_ready (self : float_multiplier_record) 34 | return boolean; 35 | ------------------------------------------------------------------------ 36 | function get_multiplier_result ( self : float_multiplier_record) 37 | return float_record; 38 | ------------------------------------------------------------------------ 39 | function "*" ( left, right : float_record) 40 | return float_record; 41 | ------------------------------------------------------------------------ 42 | function float_multiplier_is_busy ( self : float_multiplier_record) 43 | return boolean; 44 | ------------------------------------------------------------------------ 45 | end package float_multiplier_pkg; 46 | 47 | package body float_multiplier_pkg is 48 | ------------------------------------------------------------------------ 49 | function "*" 50 | ( 51 | left, right : float_record 52 | ) return float_record 53 | is 54 | variable result : float_record := zero; 55 | variable raw_result : unsigned(mantissa_high*2+1 downto 0) := (others => '0'); 56 | begin 57 | 58 | result.sign := left.sign xor right.sign; 59 | result.exponent := left.exponent + right.exponent; 60 | raw_result := left.mantissa * right.mantissa; 61 | if raw_result(mantissa_high*2+1) = '1' then 62 | result.mantissa := raw_result(mantissa_high*2+1 downto mantissa_high+1); 63 | else 64 | result.mantissa := raw_result(mantissa_high*2 downto mantissa_high); 65 | result.exponent := left.exponent + right.exponent - 1; 66 | end if; 67 | return result; 68 | 69 | end function; 70 | 71 | ------------------------------------------------------------------------ 72 | procedure create_float_multiplier 73 | ( 74 | signal self : inout float_multiplier_record 75 | ) 76 | is 77 | begin 78 | 79 | self.shift_register <= self.shift_register(self.shift_register'left-1 downto 0) & '0'; 80 | self.sign <= self.left.sign xor self.right.sign; 81 | self.exponent <= self.left.exponent + self.right.exponent; 82 | self.mantissa_multiplication_result <= self.left.mantissa * self.right.mantissa; 83 | 84 | if self.mantissa_multiplication_result(mantissa_high*2+1) = '1' then 85 | self.result <= ( 86 | sign => self.sign, 87 | exponent => self.exponent, 88 | mantissa => self.mantissa_multiplication_result(mantissa_high*2+1 downto mantissa_high+1) 89 | ); 90 | else 91 | self.result <= ( 92 | sign => self.sign, 93 | exponent => self.exponent - 1, 94 | mantissa => self.mantissa_multiplication_result(mantissa_high*2 downto mantissa_high) 95 | ); 96 | end if; 97 | 98 | end procedure; 99 | 100 | ------------------------------------------------------------------------ 101 | procedure request_float_multiplier 102 | ( 103 | signal self : out float_multiplier_record; 104 | left, right : float_record 105 | ) is 106 | begin 107 | self.shift_register(0) <= '1'; 108 | self.left <= left; 109 | self.right <= right; 110 | 111 | end request_float_multiplier; 112 | 113 | ------------------------------------------------------------------------ 114 | function float_multiplier_is_ready 115 | ( 116 | self : float_multiplier_record 117 | ) 118 | return boolean 119 | is 120 | begin 121 | return self.shift_register(self.shift_register'left) = '1'; 122 | end float_multiplier_is_ready; 123 | 124 | ------------------------------------------------------------------------ 125 | function get_multiplier_result 126 | ( 127 | self : float_multiplier_record 128 | ) 129 | return float_record 130 | is 131 | begin 132 | return self.result; 133 | end get_multiplier_result; 134 | ------------------------------------------------------------------------ 135 | function float_multiplier_is_busy 136 | ( 137 | self : float_multiplier_record 138 | ) 139 | return boolean 140 | is 141 | begin 142 | return to_integer(signed(self.shift_register)) = 0; 143 | end float_multiplier_is_busy; 144 | ------------------------------------------------------------------------ 145 | end package body float_multiplier_pkg; 146 | -------------------------------------------------------------------------------- /testbenches/float_alu_simulation/tb_alu_lc_filter_pkg.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY ieee ; 2 | USE ieee.NUMERIC_STD.all ; 3 | USE ieee.std_logic_1164.all ; 4 | use ieee.math_real.all; 5 | 6 | library vunit_lib; 7 | use vunit_lib.run_pkg.all; 8 | 9 | use work.float_alu_pkg.all; 10 | use work.float_arithmetic_operations_pkg.all; 11 | use work.float_type_definitions_pkg.all; 12 | use work.float_to_real_conversions_pkg.all; 13 | 14 | entity alu_lc_filter_tb is 15 | generic (runner_cfg : string); 16 | end; 17 | 18 | architecture vunit_simulation of alu_lc_filter_tb is 19 | 20 | signal simulation_running : boolean; 21 | signal simulator_clock : std_logic; 22 | constant clock_per : time := 1 ns; 23 | constant clock_half_per : time := 0.5 ns; 24 | constant simtime_in_clocks : integer := 18e3; 25 | 26 | signal simulation_counter : natural := 0; 27 | ----------------------------------- 28 | -- simulation specific signals ---- 29 | 30 | signal float_alu : float_alu_record := init_float_alu; 31 | signal voltage : real := 0.0; 32 | signal inductor_current : real := 0.0; 33 | signal input_voltage : float_record := to_float(10.0); 34 | 35 | type lc_filter_record is record 36 | current : float_record; 37 | capacitor_voltage : float_record; 38 | integrator_gain : float_record; 39 | current_delta : float_record; 40 | voltage_delta : float_record; 41 | process_counter : integer; 42 | end record; 43 | 44 | constant init_lc_filter : lc_filter_record := (to_float(0.0) , 45 | to_float(0.0) , 46 | to_float(0.0) , 47 | to_float(0.1) , 48 | to_float(0.0) , 49 | 0 ); 50 | 51 | signal lc_filter_model : lc_filter_record := init_lc_filter; 52 | 53 | 54 | 55 | procedure create_lc_filter_model 56 | ( 57 | signal lc_filter_object : inout lc_filter_record; 58 | signal lc_filter_alu : inout float_alu_record; 59 | uin : in float_record 60 | ) is 61 | alias current is lc_filter_object.current; 62 | alias capacitor_voltage is lc_filter_object.capacitor_voltage; 63 | alias integrator_gain is lc_filter_object.integrator_gain; 64 | alias current_delta is lc_filter_object.current_delta; 65 | alias voltage_delta is lc_filter_object.voltage_delta; 66 | alias process_counter is lc_filter_object.process_counter; 67 | alias alu is lc_filter_alu; 68 | begin 69 | CASE process_counter is 70 | WHEN 0 => 71 | subtract(alu, uin, capacitor_voltage); 72 | process_counter <= process_counter + 1; 73 | WHEN 1 => 74 | if add_is_ready(alu) then 75 | multiply(alu, get_add_result(alu), to_float(0.5)); 76 | process_counter <= process_counter + 1; 77 | end if; 78 | WHEN 2 => 79 | if multiplier_is_ready(alu) then 80 | add(alu, get_multiplier_result(alu), current); 81 | process_counter <= process_counter + 1; 82 | end if; 83 | WHEN 3 => 84 | if add_is_ready(alu) then 85 | current <= get_add_result(alu); 86 | -- calculate capacitor voltage equation 87 | multiply(alu, capacitor_voltage, to_float(0.01)); 88 | process_counter <= process_counter + 1; 89 | end if; 90 | WHEN 4 => 91 | if multiplier_is_ready(alu) then 92 | subtract(alu, current, get_multiplier_result(alu)); 93 | process_counter <= process_counter + 1; 94 | end if; 95 | WHEN 5 => 96 | if add_is_ready(alu) then 97 | multiply(alu, get_add_result(alu), to_float(0.5)); 98 | process_counter <= process_counter + 1; 99 | end if; 100 | WHEN 6 => 101 | if multiplier_is_ready(alu) then 102 | add(alu, get_multiplier_result(alu), capacitor_voltage); 103 | process_counter <= process_counter + 1; 104 | end if; 105 | WHEN 7 => 106 | if add_is_ready(alu) then 107 | capacitor_voltage <= get_add_result(alu); 108 | process_counter <= 0; 109 | end if; 110 | 111 | WHEN others => -- do nothing 112 | end CASE; --process_counter 113 | 114 | end create_lc_filter_model; 115 | 116 | begin 117 | 118 | ------------------------------------------------------------------------ 119 | simtime : process 120 | begin 121 | test_runner_setup(runner, runner_cfg); 122 | simulation_running <= true; 123 | wait for simtime_in_clocks*clock_per; 124 | simulation_running <= false; 125 | test_runner_cleanup(runner); -- Simulation ends here 126 | wait; 127 | end process simtime; 128 | 129 | ------------------------------------------------------------------------ 130 | sim_clock_gen : process 131 | begin 132 | simulator_clock <= '0'; 133 | wait for clock_half_per; 134 | while simulation_running loop 135 | wait for clock_half_per; 136 | simulator_clock <= not simulator_clock; 137 | end loop; 138 | wait; 139 | end process; 140 | ------------------------------------------------------------------------ 141 | 142 | stimulus : process(simulator_clock) 143 | 144 | begin 145 | if rising_edge(simulator_clock) then 146 | simulation_counter <= simulation_counter + 1; 147 | create_float_alu(float_alu); 148 | create_lc_filter_model(lc_filter_model, float_alu, input_voltage); 149 | 150 | voltage <= to_real(lc_filter_model.capacitor_voltage); 151 | inductor_current <= to_real(lc_filter_model.current); 152 | 153 | if simulation_counter mod 12e3 = 0 then 154 | input_voltage <= -input_voltage; 155 | end if; 156 | 157 | end if; -- rising_edge 158 | end process stimulus; 159 | ------------------------------------------------------------------------ 160 | end vunit_simulation; 161 | -------------------------------------------------------------------------------- /testbenches/float_fused_multiply_add/fused_multiply_add_tb.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY ieee ; 2 | USE ieee.NUMERIC_STD.all ; 3 | USE ieee.std_logic_1164.all ; 4 | use ieee.math_real.all; 5 | 6 | use work.float_alu_pkg.all; 7 | use work.float_type_definitions_pkg.all; 8 | use work.float_to_real_conversions_pkg.all; 9 | use work.float_adder_pkg.all; 10 | use work.float_multiplier_pkg.all; 11 | use work.normalizer_pkg.all; 12 | use work.denormalizer_pkg.all; 13 | 14 | library vunit_lib; 15 | context vunit_lib.vunit_context; 16 | 17 | entity fused_multiply_add_tb is 18 | generic (runner_cfg : string); 19 | end; 20 | 21 | architecture vunit_simulation of fused_multiply_add_tb is 22 | 23 | signal simulation_running : boolean; 24 | signal simulator_clock : std_logic; 25 | constant clock_per : time := 1 ns; 26 | constant clock_half_per : time := 0.5 ns; 27 | constant simtime_in_clocks : integer := 50; 28 | 29 | signal simulation_counter : natural := 0; 30 | ----------------------------------- 31 | -- simulation specific signals ---- 32 | 33 | signal float_alu : float_alu_record := init_float_alu; 34 | signal test_multiplier : real := 0.0; 35 | signal add_result : float_record := to_float(0.0); 36 | signal add_result_real : real := 0.0; 37 | 38 | subtype float_array is real_vector(natural range 0 to 4); 39 | constant left : float_array := ( 40 | 5.2948629, 41 | 37.2853628, 42 | 21.7988346, 43 | 15.3825920, 44 | 1.9349673); 45 | ------------------------------------------------------------------------ 46 | constant right : float_array := ( 47 | 1.296720, 48 | 3.238572, 49 | 5.746730, 50 | -7.92395, 51 | -9.10365); 52 | ------------------------------------------------------------------------ 53 | 54 | function multiplier_result_values return float_array 55 | is 56 | variable retval : float_array; 57 | begin 58 | for i in left'range loop 59 | retval(i) := left(i) * right(i); 60 | end loop; 61 | 62 | return retval; 63 | 64 | end multiplier_result_values; 65 | ------------------------------------------------------------------------ 66 | 67 | constant multiply_results : float_array := multiplier_result_values; 68 | ------------------------------------------------------------------------ 69 | 70 | function adder_result_values return float_array 71 | is 72 | variable retval : float_array; 73 | begin 74 | for i in left'range loop 75 | retval(i) := left(i) + right(i); 76 | end loop; 77 | 78 | return retval; 79 | 80 | end adder_result_values; 81 | ------------------------------------------------------------------------ 82 | 83 | constant add_results : float_array := adder_result_values; 84 | ------------------------------------------------------------------------ 85 | 86 | signal mult_index : natural := 0; 87 | signal add_index : natural := 0; 88 | 89 | alias self is float_alu; 90 | 91 | signal mac_result : real := 0.0; 92 | 93 | signal request_pipeline : std_logic_vector(alu_timing.madd_pipeline_depth-1 downto 0); 94 | signal a : real_vector(request_pipeline'range) := (others => 0.0); 95 | signal b : real_vector(request_pipeline'range) := (others => 0.0); 96 | signal c : real_vector(request_pipeline'range) := (others => 0.0); 97 | 98 | 99 | begin 100 | 101 | ------------------------------------------------------------------------ 102 | simtime : process 103 | begin 104 | test_runner_setup(runner, runner_cfg); 105 | simulation_running <= true; 106 | wait for simtime_in_clocks*clock_per; 107 | simulation_running <= false; 108 | test_runner_cleanup(runner); -- Simulation ends here 109 | wait; 110 | end process simtime; 111 | 112 | ------------------------------------------------------------------------ 113 | sim_clock_gen : process 114 | begin 115 | simulator_clock <= '0'; 116 | wait for clock_half_per; 117 | while simulation_running loop 118 | wait for clock_half_per; 119 | simulator_clock <= not simulator_clock; 120 | end loop; 121 | wait; 122 | end process; 123 | ------------------------------------------------------------------------ 124 | 125 | stimulus : process(simulator_clock) 126 | 127 | variable test_result : real := 0.0; 128 | 129 | procedure test_fmadd 130 | ( 131 | left, right, add : real 132 | ) is 133 | begin 134 | fmac(float_alu, to_float(left), to_float(right), to_float(add)); 135 | request_pipeline(0) <= '1'; 136 | a(0) <= left; 137 | b(0) <= right; 138 | c(0) <= add; 139 | 140 | end test_fmadd; 141 | procedure test_fmadd 142 | ( 143 | left, right, add : integer 144 | ) is 145 | begin 146 | test_fmadd(real(left), real(right), real(add)); 147 | end test_fmadd; 148 | 149 | begin 150 | if rising_edge(simulator_clock) then 151 | simulation_counter <= simulation_counter + 1; 152 | 153 | create_float_alu(self); 154 | request_pipeline <= request_pipeline(request_pipeline'left-1 downto 0) & '0'; 155 | a <= a(a'left-1 downto 0) & 0.0; 156 | b <= b(a'left-1 downto 0) & 0.0; 157 | c <= c(a'left-1 downto 0) & 0.0; 158 | 159 | CASE simulation_counter is 160 | WHEN 2 => test_fmadd(1.9273592, 3.2835729, -5.2935); 161 | WHEN 3 => test_fmadd(1,2,3); 162 | WHEN 4 => test_fmadd(2.0,3.0,-4.0); 163 | WHEN 5 => test_fmadd(10.0,-10.0,100.1); 164 | WHEN 9 => test_fmadd(-10.0,10.0,-100.1); 165 | WHEN others => -- do nothing 166 | end CASE; 167 | 168 | check(add_is_ready(float_alu) = (request_pipeline(request_pipeline'left) = '1')); 169 | 170 | if add_is_ready(float_alu) then 171 | mac_result <= to_real(get_add_result(float_alu)); 172 | check(abs(to_real(get_add_result(float_alu)) - (a(a'left)*b(b'left) + c(c'left))) < 1.0e-5, "error was " & real'image(to_real(get_add_result(float_alu)) - (a(a'left)*b(b'left) + c(c'left)))); 173 | end if; 174 | 175 | end if; -- rising_edge 176 | end process stimulus; 177 | ------------------------------------------------------------------------ 178 | end vunit_simulation; 179 | -------------------------------------------------------------------------------- /vunit_run_vhdl_float.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from pathlib import Path 4 | from vunit import VUnit 5 | import argparse 6 | 7 | # Parse extra arguments 8 | parser = argparse.ArgumentParser() 9 | parser.add_argument( 10 | "--dump-arrays", 11 | action="store_true", 12 | help="Enable dumping arrays in the NVC simulator" 13 | ) 14 | args, vunit_args = parser.parse_known_args() 15 | # ROOT 16 | ROOT = Path(__file__).resolve().parent 17 | VU = VUnit.from_argv(vunit_args) 18 | # from_argv(compile_builtins=False) 19 | 20 | # float_lib = VU.add_library("float_lib") 21 | # float_lib.add_source_files(ROOT / "float_type_definitions/float_word_length_24_bit_pkg.vhd") 22 | # float_lib.add_source_files(ROOT / "float_type_definitions/float_type_definitions_pkg.vhd") 23 | # float_lib.add_source_files(ROOT / "float_arithmetic_operations/float_arithmetic_operations_pkg.vhd") 24 | # 25 | # float_lib.add_source_files(ROOT / "normalizer/normalizer_configuration/normalizer_with_1_stage_pipe_pkg.vhd") 26 | # float_lib.add_source_files(ROOT / "normalizer/normalizer_pkg.vhd") 27 | # 28 | # float_lib.add_source_files(ROOT / "denormalizer/denormalizer_configuration/denormalizer_with_1_stage_pipe_pkg.vhd") 29 | # float_lib.add_source_files(ROOT / "denormalizer/denormalizer_pkg.vhd") 30 | # 31 | # float_lib.add_source_files(ROOT / "float_to_real_conversions/float_to_real_functions_pkg.vhd") 32 | # float_lib.add_source_files(ROOT / "float_to_real_conversions/float_to_real_conversions_pkg.vhd") 33 | # 34 | # float_lib.add_source_files(ROOT / "float_adder/float_adder_pkg.vhd") 35 | # 36 | # float_lib.add_source_files(ROOT / "float_multiplier/float_multiplier_pkg.vhd") 37 | # 38 | # float_lib.add_source_files(ROOT / "float_alu/float_alu_pkg.vhd") 39 | # 40 | # float_lib.add_source_files(ROOT / "float_first_order_filter/float_first_order_filter_pkg.vhd") 41 | # 42 | # 43 | # float_lib.add_source_files(ROOT / "testbenches/simulate_normalizer/*.vhd") 44 | # float_lib.add_source_files(ROOT / "testbenches/denormalizer_simulation/*.vhd") 45 | # float_lib.add_source_files(ROOT / "testbenches/float_to_real_simulation" / "*.vhd") 46 | # float_lib.add_source_files(ROOT / "testbenches/adder_simulation/*.vhd") 47 | # float_lib.add_source_files(ROOT / "testbenches/float_multiplier_simulation/*.vhd") 48 | # float_lib.add_source_files(ROOT / "testbenches/float_alu_simulation/*.vhd") 49 | # float_lib.add_source_files(ROOT / "testbenches/simulate_float_filter/*.vhd") 50 | # float_lib.add_source_files(ROOT / "testbenches/float_to_integer_simulation/*.vhd") 51 | # 52 | # float_lib.add_source_files(ROOT / "testbenches/float_fused_multiply_add/fused_multiply_add_tb.vhd") 53 | # 54 | # float_lib.add_source_files(ROOT / "testbenches/tb_float_comparisons.vhd") 55 | # 56 | # #denormalized numbers tests, not yet developed 57 | # 58 | # denormal = VU.add_library("denormal") 59 | # denormal.add_source_files(ROOT / "float_type_definitions/float_word_length_20_bit_pkg.vhd") 60 | # denormal.add_source_files(ROOT / "float_type_definitions/float_type_definitions_pkg.vhd") 61 | # denormal.add_source_files(ROOT / "float_arithmetic_operations/float_arithmetic_operations_pkg.vhd") 62 | # 63 | # denormal.add_source_files(ROOT / "normalizer/normalizer_configuration/normalizer_with_1_stage_pipe_pkg.vhd") 64 | # denormal.add_source_files(ROOT / "normalizer/normalizer_pkg.vhd") 65 | # 66 | # denormal.add_source_files(ROOT / "denormalizer/denormalizer_configuration/denormalizer_with_1_stage_pipe_pkg.vhd") 67 | # denormal.add_source_files(ROOT / "denormalizer/denormalizer_pkg.vhd") 68 | # 69 | # denormal.add_source_files(ROOT / "float_to_real_conversions/float_to_real_functions_pkg.vhd") 70 | # denormal.add_source_files(ROOT / "float_to_real_conversions/float_to_real_conversions_pkg.vhd") 71 | # 72 | # denormal.add_source_files(ROOT / "float_adder/float_adder_pkg.vhd") 73 | # denormal.add_source_files(ROOT / "float_multiplier/float_multiplier_pkg.vhd") 74 | # denormal.add_source_files(ROOT / "float_alu/float_alu_pkg.vhd") 75 | # denormal.add_source_files(ROOT / "float_first_order_filter/float_first_order_filter_pkg.vhd") 76 | # 77 | # denormal.add_source_files(ROOT / "testbenches/simulate_normalizer/*.vhd") 78 | # denormal.add_source_files(ROOT / "testbenches/denormalizer_simulation/*.vhd") 79 | # denormal.add_source_files(ROOT / "testbenches/float_to_real_simulation" / "*.vhd") 80 | # denormal.add_source_files(ROOT / "testbenches/adder_simulation/*.vhd") 81 | # denormal.add_source_files(ROOT / "testbenches/float_multiplier_simulation/*.vhd") 82 | # denormal.add_source_files(ROOT / "testbenches/float_alu_simulation/*.vhd") 83 | # denormal.add_source_files(ROOT / "testbenches/simulate_float_filter/*.vhd") 84 | # denormal.add_source_files(ROOT / "testbenches/float_to_integer_simulation/*.vhd") 85 | # 86 | # # denormal.add_source_files(ROOT / "testbenches/denormalized_numbers/tb_denormal_conversions.vhd") 87 | # denormal.add_source_files(ROOT / "testbenches/denormalized_numbers/saturated_add_tb.vhd") 88 | 89 | generic_lib = VU.add_library("generic_lib") 90 | generic_lib.add_source_files(ROOT / "vhdl2008/float_typedefs_generic_pkg.vhd") 91 | generic_lib.add_source_files(ROOT / "vhdl2008/normalizer_generic_pkg.vhd") 92 | generic_lib.add_source_files(ROOT / "vhdl2008/denormalizer_generic_pkg.vhd") 93 | generic_lib.add_source_files(ROOT / "vhdl2008/float_multiplier_generic_pkg.vhd") 94 | generic_lib.add_source_files(ROOT / "vhdl2008/float_adder_generic_pkg.vhd") 95 | generic_lib.add_source_files(ROOT / "vhdl2008/float_to_real_conversions_pkg.vhd") 96 | generic_lib.add_source_files(ROOT / "vhdl2008/multiply_add_entity.vhd") 97 | generic_lib.add_source_files(ROOT / "vhdl2008/multiply_add_arch_hfloat.vhd") 98 | generic_lib.add_source_files(ROOT / "vhdl2008/multiply_add_arch_fast_hfloat.vhd") 99 | 100 | generic_lib.add_source_files(ROOT / "vhdl2008/fast_hfloat_pkg.vhd") 101 | 102 | generic_lib.add_source_files(ROOT / "vhdl2008/altera/multiply_add_arch_agilex.vhd") 103 | generic_lib.add_source_files(ROOT / "vhdl2008/altera/sim_native_fp32.vhd") 104 | 105 | generic_lib.add_source_files(ROOT / "testbenches/vhdl2008/normalizer_tb.vhd") 106 | generic_lib.add_source_files(ROOT / "testbenches/vhdl2008/mult_add_entity_tb.vhd") 107 | generic_lib.add_source_files(ROOT / "testbenches/vhdl2008/fast_multiply_add_tb.vhd") 108 | generic_lib.add_source_files(ROOT / "testbenches/vhdl2008/fast_multiply_add_pkg_tb.vhd") 109 | generic_lib.add_source_files(ROOT / "testbenches/vhdl2008/fast_multiply_add_v2_tb.vhd") 110 | 111 | generic_lib.add_source_files(ROOT / "testbenches/vhdl2008/mult_add_entity_agilex_tb.vhd") 112 | 113 | generic_lib.add_source_files(ROOT / "testbenches/vhdl2008/type_conversions_tb.vhd") 114 | 115 | if args.dump_arrays: 116 | VU.set_sim_option("nvc.sim_flags", ["-w", "--dump-arrays"]) 117 | 118 | VU.main() 119 | -------------------------------------------------------------------------------- /normalizer/normalizer_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | use work.float_type_definitions_pkg.all; 6 | use work.normalizer_pipeline_pkg.normalizer_pipeline_configuration; 7 | use work.float_arithmetic_operations_pkg.number_of_leading_zeroes; 8 | 9 | package normalizer_pkg is 10 | ------------------------------------------------------------------------ 11 | alias number_of_normalizer_pipeline_stages is normalizer_pipeline_configuration; 12 | 13 | type normalizer_record is record 14 | normalizer_is_requested : std_logic_vector(number_of_normalizer_pipeline_stages downto 0); 15 | normalized_data : float_array(0 to number_of_normalizer_pipeline_stages); 16 | end record; 17 | 18 | subtype float_normalizer_record is normalizer_record; 19 | constant init_normalizer : normalizer_record := ((others => '0'), (others => zero)); 20 | alias init_float_normalizer is init_normalizer; 21 | ------------------------------------------------------------------------ 22 | procedure create_normalizer ( 23 | signal self : inout normalizer_record); 24 | ------------------------------------------------------------------------ 25 | procedure request_normalizer ( 26 | signal self : out normalizer_record; 27 | float_input : in float_record); 28 | ------------------------------------------------------------------------ 29 | function normalizer_is_ready (self : normalizer_record) 30 | return boolean; 31 | ------------------------------------------------------------------------ 32 | function get_normalizer_result ( self : normalizer_record) 33 | return float_record; 34 | ------------------------------------------------------------------------ 35 | procedure to_float ( 36 | signal self : out normalizer_record; 37 | int_input : in integer; 38 | radix : in integer); 39 | ------------------------------------------------------------------------ 40 | function normalize 41 | ( 42 | float_number : float_record; 43 | max_shift : integer 44 | ) 45 | return float_record; 46 | 47 | function normalize ( float_number : float_record) 48 | return float_record; 49 | ------------------------------------------------------------------------ 50 | procedure convert_integer_to_float 51 | ( 52 | signal self : out normalizer_record; 53 | number_to_be_converted : in integer; 54 | radix_of_converted_number : in integer); 55 | ------------------------------------------------------------------------ 56 | end package normalizer_pkg; 57 | 58 | package body normalizer_pkg is 59 | ------------------------------------------------------------------------ 60 | procedure create_normalizer 61 | ( 62 | signal self : inout normalizer_record 63 | ) 64 | is 65 | begin 66 | 67 | self.normalizer_is_requested(0) <= '0'; 68 | for i in 1 to number_of_normalizer_pipeline_stages loop 69 | self.normalizer_is_requested(i) <= self.normalizer_is_requested(i-1); 70 | self.normalized_data(i) <= normalize(self.normalized_data(i-1), mantissa_high/number_of_normalizer_pipeline_stages); 71 | end loop; 72 | end procedure; 73 | 74 | ------------------------------------------------------------------------ 75 | procedure request_normalizer 76 | ( 77 | signal self : out normalizer_record; 78 | float_input : in float_record 79 | ) is 80 | begin 81 | self.normalizer_is_requested(self.normalizer_is_requested'low) <= '1'; 82 | self.normalized_data(self.normalized_data'low) <= float_input; 83 | 84 | end request_normalizer; 85 | 86 | procedure to_float 87 | ( 88 | signal self : out normalizer_record; 89 | int_input : in integer; 90 | radix : in integer 91 | ) is 92 | variable float_to_be_scaled : float_record; 93 | variable float_sign : std_logic; 94 | begin 95 | if int_input < 0 then 96 | float_sign := '1'; 97 | else 98 | float_sign := '0'; 99 | end if; 100 | float_to_be_scaled := (sign => float_sign, 101 | exponent => to_signed(mantissa_length - radix, exponent_length), 102 | mantissa => to_unsigned(abs(int_input), mantissa_length)); 103 | 104 | self.normalizer_is_requested(self.normalizer_is_requested'low) <= '1'; 105 | self.normalized_data(self.normalized_data'low) <= float_to_be_scaled; 106 | 107 | end to_float; 108 | 109 | ------------------------------------------------------------------------ 110 | function normalizer_is_ready 111 | ( 112 | self : normalizer_record 113 | ) 114 | return boolean 115 | is 116 | begin 117 | return self.normalizer_is_requested(self.normalizer_is_requested'high) = '1'; 118 | end normalizer_is_ready; 119 | 120 | ------------------------------------------------------------------------ 121 | function get_normalizer_result 122 | ( 123 | self : normalizer_record 124 | ) 125 | return float_record 126 | is 127 | begin 128 | return self.normalized_data(self.normalized_data'high); 129 | end get_normalizer_result; 130 | ------------------------------------------------------------------------ 131 | function normalize 132 | ( 133 | float_number : float_record; 134 | max_shift : integer 135 | ) 136 | return float_record 137 | is 138 | variable number_of_zeroes : natural := 0; 139 | 140 | begin 141 | number_of_zeroes := number_of_leading_zeroes(float_number.mantissa, max_shift); 142 | 143 | return (sign => float_number.sign, 144 | exponent => float_number.exponent - number_of_zeroes, 145 | mantissa => shift_left(float_number.mantissa, number_of_zeroes)); 146 | end normalize; 147 | 148 | ---------- 149 | 150 | function normalize 151 | ( 152 | float_number : float_record 153 | ) 154 | return float_record 155 | is 156 | variable number_of_zeroes : natural := 0; 157 | begin 158 | 159 | return normalize(float_number => float_number, max_shift => mantissa_high); 160 | end normalize; 161 | ------------------------------------------------------------------------ 162 | procedure convert_integer_to_float 163 | ( 164 | signal self : out normalizer_record; 165 | number_to_be_converted : in integer; 166 | radix_of_converted_number : in integer 167 | ) is 168 | begin 169 | to_float(self, number_to_be_converted, radix_of_converted_number); 170 | 171 | end convert_integer_to_float; 172 | 173 | -------------------------------------------------- 174 | end package body normalizer_pkg; 175 | -------------------------------------------------------------------------------- /float_arithmetic_operations/float_arithmetic_operations_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | use work.float_type_definitions_pkg.all; 6 | 7 | package float_arithmetic_operations_pkg is 8 | 9 | ------------------------------------------------------------------------ 10 | function "+" ( left, right : float_record) 11 | return float_record; 12 | ------------------------------------------------------------------------ 13 | function "/" ( 14 | left : float_record; 15 | constant right : integer) 16 | return float_record; 17 | ------------------------------------------------------------------------ 18 | function "=" ( left, right : float_record) 19 | return boolean; 20 | ------------------------------------------------------------------------ 21 | function "-" ( right : float_record) 22 | return float_record; 23 | 24 | function ">" ( left, right : float_record) 25 | return boolean; 26 | 27 | ------------------------------------------------------------------------ 28 | function number_of_leading_zeroes ( 29 | data : unsigned; 30 | max_shift : integer) 31 | return integer; 32 | ------------------------------------------------------------------------ 33 | function to_std_logic ( float_number : float_record) 34 | return std_logic_vector; 35 | ------------------------------------------------------------------------ 36 | end package float_arithmetic_operations_pkg; 37 | 38 | 39 | package body float_arithmetic_operations_pkg is 40 | 41 | ------------------------------------------------------------------------ 42 | function ">" 43 | ( 44 | left, right : float_record 45 | ) 46 | return boolean 47 | is 48 | variable retval : boolean := false; 49 | begin 50 | 51 | retval := false; 52 | if left.exponent > right.exponent then 53 | retval := true; 54 | end if; 55 | 56 | if left.exponent = right.exponent then 57 | if left.mantissa > right.mantissa then 58 | retval := true; 59 | end if; 60 | end if; 61 | 62 | if ((left.sign = '1') and (right.sign = '0')) then 63 | retval := false; 64 | end if; 65 | 66 | if ((left.sign = '0') and (right.sign = '1')) then 67 | retval := true; 68 | end if; 69 | 70 | if ((left.sign = '1') and (right.sign = '1')) then 71 | retval := not retval; 72 | end if; 73 | 74 | return retval; 75 | 76 | end ">"; 77 | ------------------------------------------------------------------------ 78 | function "+" 79 | ( 80 | left, right : float_record 81 | ) 82 | return float_record 83 | is 84 | variable signed_left_mantissa, signed_right_mantissa : signed(t_mantissa'high+2 downto 0); 85 | variable res : signed(t_mantissa'high+2 downto 0); 86 | variable abs_res : signed(t_mantissa'high+2 downto 0); 87 | variable result_exponent : signed(t_exponent'high+1 downto 0) := resize(left.exponent, t_exponent'length+1); 88 | variable returned_value : float_record; 89 | begin 90 | signed_left_mantissa := get_signed_mantissa(left); 91 | signed_right_mantissa := get_signed_mantissa(right); 92 | 93 | res := signed_left_mantissa + signed_right_mantissa; 94 | 95 | abs_res := abs(res); 96 | if abs_res(t_mantissa'high+1) = '1' then 97 | result_exponent := result_exponent + 1; 98 | abs_res := shift_right(abs_res,1); 99 | end if; 100 | 101 | 102 | returned_value := ( res(res'high), 103 | result_exponent(t_exponent'range), 104 | unsigned(abs_res(t_mantissa'range))); 105 | 106 | return returned_value; 107 | end "+"; 108 | ------------------------------------------------------------------------ 109 | function "/" 110 | ( 111 | left : float_record; 112 | constant right : integer 113 | ) 114 | return float_record 115 | is 116 | begin 117 | assert right - 2 = 0 report "only division by 2 allowed in floats" severity failure; 118 | return (left.sign, 119 | left.exponent-1, 120 | left.mantissa); 121 | end "/"; 122 | ------------------------------------------------------------------------ 123 | function "=" 124 | ( 125 | left, right : float_record 126 | ) 127 | return boolean 128 | is 129 | begin 130 | return left.sign = right.sign and 131 | left.exponent = right.exponent and 132 | left.mantissa = right.mantissa; 133 | end "="; 134 | ------------------------------------------------------------------------ 135 | function number_of_leading_zeroes 136 | ( 137 | data : std_logic_vector; 138 | max_shift : integer 139 | ) 140 | return integer 141 | is 142 | variable number_of_zeroes : integer := 0; 143 | begin 144 | for i in data'high - max_shift to data'high loop 145 | if data(i) = '0' then 146 | number_of_zeroes := number_of_zeroes + 1; 147 | else 148 | number_of_zeroes := 0; 149 | end if; 150 | end loop; 151 | 152 | return number_of_zeroes; 153 | 154 | end number_of_leading_zeroes; 155 | 156 | ------------------------------------------------------------------------ 157 | function number_of_leading_zeroes 158 | ( 159 | data : unsigned; 160 | max_shift : integer 161 | ) 162 | return integer 163 | is 164 | begin 165 | 166 | return number_of_leading_zeroes(std_logic_vector(data), max_shift); 167 | 168 | end number_of_leading_zeroes; 169 | 170 | ------------------------------------------------------------------------ 171 | ------------------------------------------------------------------------ 172 | function "-" 173 | ( 174 | right : float_record 175 | ) 176 | return float_record 177 | is 178 | variable returned_float : float_record; 179 | begin 180 | returned_float := (sign => not right.sign, 181 | exponent => right.exponent, 182 | mantissa => right.mantissa); 183 | return returned_float; 184 | end "-"; 185 | ------------------------------------------------------------------------ 186 | function to_std_logic 187 | ( 188 | float_number : float_record 189 | ) 190 | return std_logic_vector 191 | is 192 | begin 193 | return float_number.sign & std_logic_vector(float_number.exponent) & std_logic_vector(float_number.mantissa); 194 | end to_std_logic; 195 | ------------------------------------------------------------------------ 196 | end package body float_arithmetic_operations_pkg; 197 | -------------------------------------------------------------------------------- /vhdl2008/multiply_add_entity.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY ieee ; 2 | USE ieee.NUMERIC_STD.all ; 3 | USE ieee.std_logic_1164.all ; 4 | 5 | use work.float_typedefs_generic_pkg.hfloat_record; 6 | 7 | package multiply_add_pkg is 8 | 9 | ----------------------------------------------------- 10 | type multiply_add_in_record is record 11 | mpy_a : std_logic_vector; 12 | mpy_b : std_logic_vector; 13 | add_a : std_logic_vector; 14 | is_requested : std_logic; 15 | end record; 16 | 17 | ----------------------------------------------------- 18 | type multiply_add_out_record is record 19 | result : std_logic_vector; 20 | is_ready : std_logic; 21 | end record; 22 | 23 | ----------------------------------------------------- 24 | type mpya_subtype_record is record 25 | mpya_in : multiply_add_in_record; 26 | mpya_out : multiply_add_out_record; 27 | end record; 28 | 29 | ----------------------------------------------------- 30 | function create_mpya_typeref( 31 | exponent_length : natural := 8 32 | ;mantissa_length : natural := 23) 33 | return mpya_subtype_record; 34 | 35 | ----------------------------------------------------- 36 | function create_mpya_typeref(floatref : hfloat_record) 37 | return mpya_subtype_record; 38 | ----------------------------------------------------- 39 | procedure init_multiply_add(signal self_in : out multiply_add_in_record); 40 | 41 | ----------------------------------------------------- 42 | procedure multiply_add(signal self_in : out multiply_add_in_record 43 | ;a : std_logic_vector 44 | ;b : std_logic_vector 45 | ;c : std_logic_vector); 46 | ----------------------------------------------------- 47 | function mpya_is_ready(mpya_out : multiply_add_out_record) 48 | return boolean; 49 | ----------------------------------------------------- 50 | function get_mpya_result(mpya_out : multiply_add_out_record) return std_logic_vector; 51 | ----------------------------------------------------- 52 | 53 | end package multiply_add_pkg; 54 | 55 | package body multiply_add_pkg is 56 | 57 | ----------------------------------------------------- 58 | function create_mpya_typeref(exponent_length : natural := 8 ; mantissa_length : natural := 23) 59 | return mpya_subtype_record is 60 | 61 | constant retval : mpya_subtype_record :=( 62 | mpya_in => ( 63 | mpy_a => (exponent_length + mantissa_length downto 0 => '0') 64 | ,mpy_b => (exponent_length + mantissa_length downto 0 => '0') 65 | ,add_a => (exponent_length + mantissa_length downto 0 => '0') 66 | ,is_requested => '0') 67 | ,mpya_out => ( 68 | result => (exponent_length + mantissa_length downto 0 => '0') 69 | ,is_ready => '0') 70 | ); 71 | 72 | begin 73 | 74 | return retval; 75 | 76 | end create_mpya_typeref; 77 | 78 | ----------------------------------------------------- 79 | function create_mpya_typeref(floatref : hfloat_record) 80 | return mpya_subtype_record is 81 | 82 | constant exponent_length : natural := floatref.exponent'length; 83 | constant mantissa_length : natural := floatref.mantissa'length; 84 | 85 | constant retval : mpya_subtype_record :=( 86 | mpya_in => ( 87 | mpy_a => (exponent_length + mantissa_length downto 0 => '0') 88 | ,mpy_b => (exponent_length + mantissa_length downto 0 => '0') 89 | ,add_a => (exponent_length + mantissa_length downto 0 => '0') 90 | ,is_requested => '0') 91 | ,mpya_out => ( 92 | result => (exponent_length + mantissa_length downto 0 => '0') 93 | ,is_ready => '0') 94 | ); 95 | 96 | begin 97 | return retval; 98 | end create_mpya_typeref; 99 | 100 | ----------------------------------------------------- 101 | function mpya_is_ready(mpya_out : multiply_add_out_record) return boolean 102 | is 103 | begin 104 | return mpya_out.is_ready = '1'; 105 | end mpya_is_ready; 106 | ----------------------------------------------------- 107 | function get_mpya_result(mpya_out : multiply_add_out_record) return std_logic_vector 108 | is 109 | begin 110 | return mpya_out.result; 111 | end get_mpya_result; 112 | ----------------------------------------------------- 113 | procedure init_multiply_add(signal self_in : out multiply_add_in_record) 114 | is 115 | begin 116 | self_in.mpy_a <= self_in.mpy_a; 117 | self_in.mpy_b <= self_in.mpy_b; 118 | self_in.add_a <= self_in.add_a; 119 | self_in.is_requested <= '0'; 120 | end procedure; 121 | 122 | ----------------------------------------------------- 123 | procedure multiply_add(signal self_in : out multiply_add_in_record 124 | ;a : std_logic_vector 125 | ;b : std_logic_vector 126 | ;c : std_logic_vector 127 | ) 128 | is 129 | begin 130 | self_in.mpy_a <= a; 131 | self_in.mpy_b <= b; 132 | self_in.add_a <= c; 133 | self_in.is_requested <= '1'; 134 | end procedure; 135 | 136 | ----------------------------------------------------- 137 | procedure multiply(signal self_in : out multiply_add_in_record 138 | ;a : std_logic_vector 139 | ;b : std_logic_vector 140 | ) 141 | is 142 | begin 143 | self_in.mpy_a <= a; 144 | self_in.mpy_b <= b; 145 | self_in.add_a <= (self_in.add_a'range => '0'); 146 | self_in.is_requested <= '1'; 147 | end procedure; 148 | 149 | ----------------------------------------------------- 150 | procedure add(signal self_in : out multiply_add_in_record 151 | ;a : std_logic_vector 152 | ;b : std_logic_vector 153 | ) 154 | is 155 | begin 156 | self_in.mpy_a <= a; 157 | self_in.mpy_b <= a; -- should be 1.0 158 | self_in.add_a <= b; 159 | self_in.is_requested <= '0'; 160 | end procedure; 161 | 162 | ----------------------------------------------------- 163 | procedure sub(signal self_in : out multiply_add_in_record 164 | ;a : std_logic_vector 165 | ;b : std_logic_vector 166 | ) 167 | is 168 | begin 169 | self_in.mpy_a <= a; 170 | self_in.mpy_b <= a; -- should be 1.0 171 | self_in.add_a <= b; -- should be inverted 172 | self_in.is_requested <= '0'; 173 | end procedure; 174 | ----------------------------------------------------- 175 | 176 | end package body multiply_add_pkg; 177 | 178 | LIBRARY ieee ; 179 | USE ieee.NUMERIC_STD.all ; 180 | USE ieee.std_logic_1164.all ; 181 | 182 | use work.multiply_add_pkg.all; 183 | use work.float_typedefs_generic_pkg.all; 184 | 185 | entity multiply_add is 186 | generic( 187 | g_floatref : hfloat_record := 188 | (sign => '0' 189 | ,exponent => (7 downto 0 => '0') 190 | ,mantissa => (23 downto 0 => '0')) 191 | ); 192 | port(clock : in std_logic 193 | ;mpya_in : in multiply_add_in_record 194 | ;mpya_out : out multiply_add_out_record 195 | ); 196 | end multiply_add; 197 | -------------------------------------------------------------------------------- /vhdl2008/float_multiplier_generic_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | use work.float_typedefs_generic_pkg.all; 6 | 7 | package float_multiplier_pkg is 8 | ------------------------------------------------------------------------ 9 | constant float_multiplier_pipeline_depth : natural := 3; 10 | ------------------------------------------------------------------------ 11 | type float_multiplier_record is record 12 | 13 | left : hfloat_record; 14 | right : hfloat_record; 15 | result : hfloat_record; 16 | sign : std_logic; 17 | exponent : signed; 18 | mantissa_multiplication_result : unsigned; -- (mantissa_high*2+1 downto 0); 19 | shift_register : std_logic_vector; --(float_multiplier_pipeline_depth-1 downto 0); 20 | end record; 21 | 22 | function multiplier_typeref(floatref : hfloat_record) 23 | return float_multiplier_record; 24 | ------------------------------------------------------------------------ 25 | procedure create_float_multiplier ( 26 | signal self : inout float_multiplier_record); 27 | ------------------------------------------------------------------------ 28 | procedure request_float_multiplier ( 29 | signal self : out float_multiplier_record; 30 | left, right : hfloat_record); 31 | ------------------------------------------------------------------------ 32 | function float_multiplier_is_ready (self : float_multiplier_record) 33 | return boolean; 34 | ------------------------------------------------------------------------ 35 | function get_multiplier_result ( self : float_multiplier_record) 36 | return hfloat_record; 37 | ------------------------------------------------------------------------ 38 | function "*" ( left, right : hfloat_record) 39 | return hfloat_record; 40 | ------------------------------------------------------------------------ 41 | function float_multiplier_is_busy ( self : float_multiplier_record) 42 | return boolean; 43 | ------------------------------------------------------------------------ 44 | end package float_multiplier_pkg; 45 | 46 | package body float_multiplier_pkg is 47 | ------------------------------------------------------------------------ 48 | function multiplier_typeref(floatref : hfloat_record) return float_multiplier_record 49 | is 50 | constant zero : floatref'subtype := (sign => '0', mantissa => (others => '0'), exponent => (others => '0')); 51 | constant mpy : unsigned(floatref.mantissa'high*2+1 downto 0) := (others => '0'); 52 | constant shift_register : std_logic_vector(2 downto 0) := (others => '0'); 53 | 54 | constant init_multiplier : float_multiplier_record := ( 55 | left => zero 56 | ,right => zero 57 | ,result => zero 58 | ,sign => '0' 59 | ,exponent => zero.exponent 60 | ,mantissa_multiplication_result => mpy 61 | ,shift_register => shift_register 62 | ); 63 | 64 | begin 65 | return init_multiplier; 66 | end multiplier_typeref; 67 | ------------------------------------------------------------------------ 68 | function "*" 69 | ( 70 | left, right : hfloat_record 71 | ) return hfloat_record 72 | is 73 | variable result : left'subtype; 74 | constant mantissa_high : natural := left.mantissa'high; 75 | variable raw_result : unsigned(mantissa_high*2+1 downto 0) := (others => '0'); 76 | begin 77 | 78 | result.sign := left.sign xor right.sign; 79 | result.exponent := left.exponent + right.exponent; 80 | raw_result := left.mantissa * right.mantissa; 81 | if raw_result(mantissa_high*2+1) = '1' then 82 | result.mantissa := raw_result(mantissa_high*2+1 downto mantissa_high+1); 83 | else 84 | result.mantissa := raw_result(mantissa_high*2 downto mantissa_high); 85 | result.exponent := left.exponent + right.exponent - 1; 86 | end if; 87 | return result; 88 | 89 | end function; 90 | 91 | ------------------------------------------------------------------------ 92 | procedure create_float_multiplier 93 | ( 94 | signal self : inout float_multiplier_record 95 | ) 96 | is 97 | constant mantissa_high : natural := self.left.mantissa'high; 98 | begin 99 | 100 | self.shift_register <= self.shift_register(self.shift_register'left-1 downto 0) & '0'; 101 | self.sign <= self.left.sign xor self.right.sign; 102 | self.exponent <= self.left.exponent + self.right.exponent; 103 | self.mantissa_multiplication_result <= self.left.mantissa * self.right.mantissa; 104 | 105 | if self.mantissa_multiplication_result(mantissa_high*2+1) = '1' then 106 | self.result <= ( 107 | sign => self.sign, 108 | exponent => self.exponent, 109 | mantissa => self.mantissa_multiplication_result(mantissa_high*2+1 downto mantissa_high+1) 110 | ); 111 | else 112 | self.result <= ( 113 | sign => self.sign, 114 | exponent => self.exponent - 1, 115 | mantissa => self.mantissa_multiplication_result(mantissa_high*2 downto mantissa_high) 116 | ); 117 | end if; 118 | 119 | end procedure; 120 | 121 | ------------------------------------------------------------------------ 122 | procedure request_float_multiplier 123 | ( 124 | signal self : out float_multiplier_record; 125 | left, right : hfloat_record 126 | ) is 127 | begin 128 | self.shift_register(0) <= '1'; 129 | self.left <= left; 130 | self.right <= right; 131 | 132 | end request_float_multiplier; 133 | 134 | ------------------------------------------------------------------------ 135 | function float_multiplier_is_ready 136 | ( 137 | self : float_multiplier_record 138 | ) 139 | return boolean 140 | is 141 | begin 142 | return self.shift_register(self.shift_register'left) = '1'; 143 | end float_multiplier_is_ready; 144 | 145 | ------------------------------------------------------------------------ 146 | function get_multiplier_result 147 | ( 148 | self : float_multiplier_record 149 | ) 150 | return hfloat_record 151 | is 152 | begin 153 | return self.result; 154 | end get_multiplier_result; 155 | ------------------------------------------------------------------------ 156 | function float_multiplier_is_busy 157 | ( 158 | self : float_multiplier_record 159 | ) 160 | return boolean 161 | is 162 | begin 163 | return to_integer(signed(self.shift_register)) = 0; 164 | end float_multiplier_is_busy; 165 | ------------------------------------------------------------------------ 166 | end package body float_multiplier_pkg; 167 | -------------------------------------------------------------------------------- /testbenches/float_alu_simulation/tb_float_alu.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY ieee ; 2 | USE ieee.NUMERIC_STD.all ; 3 | USE ieee.std_logic_1164.all ; 4 | use ieee.math_real.all; 5 | 6 | use work.float_alu_pkg.all; 7 | use work.float_type_definitions_pkg.all; 8 | use work.float_to_real_conversions_pkg.all; 9 | 10 | library vunit_lib; 11 | context vunit_lib.vunit_context; 12 | 13 | entity float_alu_tb is 14 | generic (runner_cfg : string); 15 | end; 16 | 17 | architecture vunit_simulation of float_alu_tb is 18 | 19 | signal simulation_running : boolean; 20 | signal simulator_clock : std_logic; 21 | constant clock_per : time := 1 ns; 22 | constant clock_half_per : time := 0.5 ns; 23 | constant simtime_in_clocks : integer := 100; 24 | 25 | signal simulation_counter : natural := 0; 26 | ----------------------------------- 27 | -- simulation specific signals ---- 28 | 29 | signal float_alu : float_alu_record := init_float_alu; 30 | signal test_multiplier : real := 0.0; 31 | signal add_result : float_record := to_float(0.0); 32 | signal add_result_real : real := 0.0; 33 | 34 | subtype float_array is real_vector(natural range 0 to 4); 35 | constant left : float_array := ( 36 | 5.2948629, 37 | 37.2853628, 38 | 21.7988346, 39 | 15.3825920, 40 | 1.9349673); 41 | 42 | constant right : float_array := ( 43 | 1.296720, 44 | 3.238572, 45 | 5.746730, 46 | -7.92395, 47 | -9.10365); 48 | 49 | function multiplier_result_values return float_array 50 | is 51 | variable retval : float_array; 52 | begin 53 | for i in left'range loop 54 | retval(i) := left(i) * right(i); 55 | end loop; 56 | 57 | return retval; 58 | 59 | end multiplier_result_values; 60 | 61 | constant multiply_results : float_array := multiplier_result_values; 62 | 63 | function adder_result_values return float_array 64 | is 65 | variable retval : float_array; 66 | begin 67 | for i in left'range loop 68 | retval(i) := left(i) + right(i); 69 | end loop; 70 | 71 | return retval; 72 | 73 | end adder_result_values; 74 | 75 | constant add_results : float_array := adder_result_values; 76 | 77 | signal mult_index : natural := 0; 78 | signal add_index : natural := 0; 79 | 80 | signal int_to_float_sequencer : natural := 0; 81 | 82 | signal float_to_int_ready : boolean := false; 83 | signal int_to_float_ready : boolean := false; 84 | 85 | signal add_request_pipeline : std_logic_vector(alu_timing.add_pipeline_depth-1 downto 0); 86 | signal a : real_vector(add_request_pipeline'range) := (others => 0.0); 87 | signal b : real_vector(add_request_pipeline'range) := (others => 0.0); 88 | signal c : real_vector(add_request_pipeline'range) := (others => 0.0); 89 | 90 | signal mult_request_pipeline : std_logic_vector(alu_timing.mult_pipeline_depth-1 downto 0); 91 | 92 | begin 93 | 94 | ------------------------------------------------------------------------ 95 | simtime : process 96 | begin 97 | test_runner_setup(runner, runner_cfg); 98 | simulation_running <= true; 99 | wait for simtime_in_clocks*clock_per; 100 | simulation_running <= false; 101 | test_runner_cleanup(runner); -- Simulation ends here 102 | wait; 103 | end process simtime; 104 | 105 | ------------------------------------------------------------------------ 106 | sim_clock_gen : process 107 | begin 108 | simulator_clock <= '0'; 109 | wait for clock_half_per; 110 | while simulation_running loop 111 | wait for clock_half_per; 112 | simulator_clock <= not simulator_clock; 113 | end loop; 114 | wait; 115 | end process; 116 | ------------------------------------------------------------------------ 117 | 118 | stimulus : process(simulator_clock) 119 | 120 | variable test_result : real := 0.0; 121 | 122 | begin 123 | if rising_edge(simulator_clock) then 124 | simulation_counter <= simulation_counter + 1; 125 | 126 | create_float_alu(float_alu); 127 | add_request_pipeline <= add_request_pipeline(add_request_pipeline'left-1 downto 0) & '0'; 128 | mult_request_pipeline <= mult_request_pipeline(mult_request_pipeline'left-1 downto 0) & '0'; 129 | a <= a(a'left-1 downto 0) & 0.0; 130 | b <= b(a'left-1 downto 0) & 0.0; 131 | c <= c(a'left-1 downto 0) & 0.0; 132 | 133 | CASE simulation_counter is 134 | WHEN 3 => multiply(float_alu, to_float(left(0)), to_float(right(0))); 135 | mult_request_pipeline(0) <= '1'; 136 | WHEN 4 => multiply(float_alu, to_float(left(1)), to_float(right(1))); 137 | mult_request_pipeline(0) <= '1'; 138 | WHEN 5 => multiply(float_alu, to_float(left(2)), to_float(right(2))); 139 | mult_request_pipeline(0) <= '1'; 140 | WHEN 6 => multiply(float_alu, to_float(left(3)), to_float(right(3))); 141 | mult_request_pipeline(0) <= '1'; 142 | WHEN 7 => multiply(float_alu, to_float(left(4)), to_float(right(4))); 143 | mult_request_pipeline(0) <= '1'; 144 | WHEN others => -- do nothing 145 | end CASE; 146 | 147 | CASE simulation_counter is 148 | WHEN 3 => add(float_alu, to_float(left(0)), to_float(right(0))); 149 | add_request_pipeline(0) <= '1'; 150 | WHEN 4 => add(float_alu, to_float(left(1)), to_float(right(1))); 151 | add_request_pipeline(0) <= '1'; 152 | WHEN 5 => add(float_alu, to_float(left(2)), to_float(right(2))); 153 | add_request_pipeline(0) <= '1'; 154 | WHEN 6 => add(float_alu, to_float(left(3)), to_float(right(3))); 155 | add_request_pipeline(0) <= '1'; 156 | WHEN 7 => add(float_alu, to_float(left(4)), to_float(right(4))); 157 | add_request_pipeline(0) <= '1'; 158 | WHEN others => -- do nothing 159 | end CASE; 160 | 161 | check(add_is_ready(float_alu) = (add_request_pipeline(add_request_pipeline'left)='1')); 162 | check(multiplier_is_ready(float_alu) = (mult_request_pipeline(mult_request_pipeline'left)='1')); 163 | 164 | if multiplier_is_ready(float_alu) then 165 | mult_index <= mult_index + 1; 166 | test_multiplier <= to_real(get_multiplier_result(float_alu)); 167 | test_result := to_real(get_multiplier_result(float_alu)) - multiply_results(mult_index); 168 | check(abs(test_result) < 1.0e-3, "multiply error is " & real'image(test_result)); 169 | end if; 170 | 171 | if add_is_ready(float_alu) then 172 | add_result <= get_add_result(float_alu); 173 | add_result_real <= to_real(get_add_result(float_alu)); 174 | 175 | add_index <= add_index + 1; 176 | test_result := to_real(get_add_result(float_alu)) - add_results(add_index); 177 | check(abs(test_result) < 1.0e-3, "adder error is " & real'image(test_result)); 178 | end if; 179 | 180 | if add_index >= right'length then 181 | if int_to_float_sequencer < right'length then 182 | int_to_float_sequencer <= int_to_float_sequencer + 1; 183 | convert_float_to_integer(float_alu, to_float(left(int_to_float_sequencer)), 24); 184 | convert_integer_to_float(float_alu, int_to_float_sequencer, 0); 185 | end if; 186 | end if; 187 | float_to_int_ready <= float_to_int_is_ready(float_alu); 188 | int_to_float_ready <= int_to_float_is_ready(float_alu); 189 | 190 | end if; -- rising_edge 191 | end process stimulus; 192 | ------------------------------------------------------------------------ 193 | end vunit_simulation; 194 | -------------------------------------------------------------------------------- /vhdl2008/normalizer_generic_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | use ieee.float_pkg.float32; 6 | use work.float_typedefs_generic_pkg.all; 7 | 8 | package normalizer_generic_pkg is 9 | ------------------------------------------------------------------------ 10 | type normalizer_record is record 11 | normalizer_is_requested : std_logic_vector; 12 | normalized_data : float_array; 13 | end record; 14 | 15 | function normalizer_typeref (number_of_pipeline_stages : natural := 2; floatref : hfloat_record) 16 | return normalizer_record; 17 | 18 | ------------------------------------------------------------------------ 19 | procedure create_normalizer ( 20 | signal self : inout normalizer_record); 21 | ------------------------------------------------------------------------ 22 | procedure request_normalizer ( 23 | signal self : out normalizer_record; 24 | float_input : in hfloat_record); 25 | ------------------------------------------------------------------------ 26 | function normalizer_is_ready (self : normalizer_record) 27 | return boolean; 28 | ------------------------------------------------------------------------ 29 | function get_normalizer_result ( self : normalizer_record) 30 | return hfloat_record; 31 | ------------------------------------------------------------------------ 32 | procedure convert_to_hfloat ( 33 | signal self : out normalizer_record; 34 | int_input : in integer; 35 | radix : in integer 36 | ;ref : in hfloat_record); 37 | ------------------------------------------------------------------------ 38 | function normalize ( float_number : hfloat_record; max_shift : integer) 39 | return hfloat_record; 40 | 41 | function normalize ( float_number : hfloat_record) 42 | return hfloat_record; 43 | ------------------------------------------------------------------------ 44 | procedure convert_integer_to_hfloat ( 45 | signal self : out normalizer_record 46 | ;number_to_be_converted : in integer 47 | ;radix_of_converted_number : in integer 48 | ;ref : in hfloat_record); 49 | ------------------------------------------------------------------------ 50 | function get_ieee_float32_result ( self : normalizer_record) return float32; 51 | ------------------------------------------------------------------------ 52 | end package normalizer_generic_pkg; 53 | 54 | package body normalizer_generic_pkg is 55 | ------------------------------------------------------------------------ 56 | function normalizer_typeref (number_of_pipeline_stages : natural := 2; floatref : hfloat_record) 57 | return normalizer_record is 58 | 59 | constant init_normalizer : normalizer_record := ( 60 | normalizer_is_requested => (number_of_pipeline_stages-1 downto 0 => '0') 61 | ,normalized_data => (number_of_pipeline_stages-1 downto 0 => floatref)); 62 | 63 | begin 64 | return init_normalizer; 65 | end normalizer_typeref; 66 | 67 | ------------------------------------------------------------------------ 68 | procedure create_normalizer 69 | ( 70 | signal self : inout normalizer_record 71 | ) 72 | is 73 | constant number_of_normalizer_pipeline_stages : natural := self.normalized_data'high; 74 | constant mantissa_high : natural := self.normalized_data(0).mantissa'high; 75 | begin 76 | 77 | self.normalizer_is_requested(0) <= '0'; 78 | for i in 1 to number_of_normalizer_pipeline_stages loop 79 | self.normalizer_is_requested(i) <= self.normalizer_is_requested(i-1); 80 | self.normalized_data(i) <= normalize(self.normalized_data(i-1), mantissa_high/number_of_normalizer_pipeline_stages); 81 | end loop; 82 | end procedure; 83 | 84 | ------------------------------------------------------------------------ 85 | procedure request_normalizer 86 | ( 87 | signal self : out normalizer_record; 88 | float_input : in hfloat_record 89 | ) is 90 | begin 91 | self.normalizer_is_requested(self.normalizer_is_requested'low) <= '1'; 92 | self.normalized_data(self.normalized_data'low) <= float_input; 93 | 94 | end request_normalizer; 95 | 96 | procedure convert_to_hfloat 97 | ( 98 | signal self : out normalizer_record 99 | ;int_input : in integer 100 | ;radix : in integer 101 | ;ref : in hfloat_record 102 | ) is 103 | variable float_to_be_scaled : ref'subtype; 104 | variable float_sign : std_logic; 105 | constant mantissa_length : natural := self.normalized_data(0).mantissa'length; 106 | constant exponent_length : natural := self.normalized_data(0).exponent'length; 107 | begin 108 | if int_input < 0 then 109 | float_sign := '1'; 110 | else 111 | float_sign := '0'; 112 | end if; 113 | float_to_be_scaled := (sign => float_sign, 114 | exponent => to_signed(mantissa_length - radix, exponent_length), 115 | mantissa => to_unsigned(abs(int_input), mantissa_length)); 116 | 117 | self.normalizer_is_requested(self.normalizer_is_requested'low) <= '1'; 118 | self.normalized_data(self.normalized_data'low) <= float_to_be_scaled; 119 | 120 | end convert_to_hfloat; 121 | 122 | ------------------------------------------------------------------------ 123 | function normalizer_is_ready 124 | ( 125 | self : normalizer_record 126 | ) 127 | return boolean 128 | is 129 | begin 130 | return self.normalizer_is_requested(self.normalizer_is_requested'high) = '1'; 131 | end normalizer_is_ready; 132 | 133 | ------------------------------------------------------------------------ 134 | function get_normalizer_result 135 | ( 136 | self : normalizer_record 137 | ) 138 | return hfloat_record 139 | is 140 | begin 141 | return self.normalized_data(self.normalized_data'high); 142 | end get_normalizer_result; 143 | ------------------------------------------------------------------------ 144 | function normalize 145 | ( 146 | float_number : hfloat_record; 147 | max_shift : integer 148 | ) 149 | return hfloat_record 150 | is 151 | variable number_of_zeroes : natural := 0; 152 | 153 | begin 154 | number_of_zeroes := number_of_leading_zeroes(float_number.mantissa, max_shift); 155 | 156 | return (sign => float_number.sign, 157 | exponent => float_number.exponent - number_of_zeroes, 158 | mantissa => shift_left(float_number.mantissa, number_of_zeroes)); 159 | end normalize; 160 | 161 | ---------- 162 | 163 | function normalize 164 | ( 165 | float_number : hfloat_record 166 | ) 167 | return hfloat_record 168 | is 169 | variable number_of_zeroes : natural := 0; 170 | constant mantissa_high : natural := float_number.mantissa'high; 171 | begin 172 | 173 | return normalize(float_number => float_number, max_shift => mantissa_high); 174 | end normalize; 175 | ------------------------------------------------------------------------ 176 | procedure convert_integer_to_hfloat 177 | ( 178 | signal self : out normalizer_record 179 | ;number_to_be_converted : in integer 180 | ;radix_of_converted_number : in integer 181 | ;ref : in hfloat_record 182 | ) is 183 | begin 184 | convert_to_hfloat(self, number_to_be_converted, radix_of_converted_number, ref); 185 | 186 | end convert_integer_to_hfloat; 187 | 188 | -------------------------------------------------- 189 | function to_hfloat(a : float32; hfloatref : hfloat_record) return hfloat_record is 190 | variable retval : hfloatref'subtype; 191 | -- variable mantissa : 192 | begin 193 | return hfloatref; 194 | end to_hfloat; 195 | -------------------------------------------------- 196 | function get_ieee_float32_result 197 | ( 198 | self : normalizer_record 199 | ) 200 | return float32 201 | is 202 | begin 203 | return to_ieee_float32(self.normalized_data(self.normalized_data'high)); 204 | end get_ieee_float32_result; 205 | ------------------------------------------------------------------------ 206 | 207 | end package body normalizer_generic_pkg; 208 | -------------------------------------------------------------------------------- /denormalizer/denormalizer_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | use work.float_type_definitions_pkg.all; 6 | use work.float_arithmetic_operations_pkg.all; 7 | use work.denormalizer_pipeline_pkg.pipeline_configuration; 8 | 9 | package denormalizer_pkg is 10 | 11 | alias number_of_denormalizer_pipeline_stages is pipeline_configuration; 12 | ------------------------------------------------------------------------ 13 | type intarray is array (integer range number_of_denormalizer_pipeline_stages downto 0) of integer range -2**exponent_high to 2**exponent_high-1; 14 | ------------------------------------------------------------------------ 15 | type denormalizer_record is record 16 | denormalizer_pipeline : float_array(number_of_denormalizer_pipeline_stages downto 0); 17 | feedthrough_pipeline : float_array(number_of_denormalizer_pipeline_stages downto 0); 18 | shift_register : std_logic_vector(number_of_denormalizer_pipeline_stages downto 0); 19 | target_scale_pipeline : intarray; 20 | end record; 21 | 22 | constant init_denormalizer : denormalizer_record := ( 23 | denormalizer_pipeline => (others => zero), 24 | feedthrough_pipeline => (others => zero), 25 | shift_register => (others => '0'), 26 | target_scale_pipeline => (others => 0)); 27 | 28 | ------------------------------------------------------------------------ 29 | procedure create_denormalizer ( 30 | signal self : inout denormalizer_record); 31 | ------------------------------------------------------------------------ 32 | procedure request_denormalizer ( 33 | signal self : out denormalizer_record; 34 | denormalized_number : in float_record; 35 | target_scale : in integer); 36 | ------------------------------------------------------------------------ 37 | procedure request_scaling ( 38 | signal self : out denormalizer_record; 39 | left,right : in float_record); 40 | 41 | procedure request_scaling ( 42 | signal self : out denormalizer_record; 43 | left : in float_record; 44 | right : in integer); 45 | ------------------------------------------------------------------------ 46 | function denormalizer_is_ready (self : denormalizer_record) 47 | return boolean; 48 | ------------------------------------------------------------------------ 49 | function get_denormalized_result ( self : denormalizer_record) 50 | return float_record; 51 | ------------------------------------------------------------------------ 52 | function get_integer ( self : denormalizer_record) 53 | return integer; 54 | ------------------------------------------------------------------------ 55 | function denormalize_float ( 56 | right : float_record; 57 | set_exponent_to : integer) 58 | return float_record; 59 | 60 | function denormalize_float ( 61 | right : float_record; 62 | set_exponent_to : integer; 63 | max_shift : integer) 64 | return float_record; 65 | ------------------------------------------------------------------------ 66 | procedure convert_float_to_integer ( 67 | signal self : out denormalizer_record; 68 | number_to_be_converted : float_record; 69 | desired_radix : in integer); 70 | ------------------------------------------------------------------------ 71 | end package denormalizer_pkg; 72 | 73 | package body denormalizer_pkg is 74 | ------------------------------------------------------------------------ 75 | procedure create_denormalizer 76 | ( 77 | signal self : inout denormalizer_record 78 | ) 79 | is 80 | begin 81 | 82 | self.shift_register(0) <= '0'; 83 | for i in 1 to number_of_denormalizer_pipeline_stages loop 84 | self.denormalizer_pipeline(i) <= denormalize_float(self.denormalizer_pipeline(i-1), self.target_scale_pipeline(i-1), mantissa_length/number_of_denormalizer_pipeline_stages); 85 | self.feedthrough_pipeline(i) <= self.feedthrough_pipeline(i-1); 86 | self.target_scale_pipeline(i) <= self.target_scale_pipeline(i-1); 87 | self.shift_register(i) <= self.shift_register(i-1); 88 | end loop; 89 | 90 | end procedure; 91 | 92 | ------------------------------------------------------------------------ 93 | procedure request_denormalizer 94 | ( 95 | signal self : out denormalizer_record; 96 | denormalized_number : in float_record; 97 | target_scale : in integer 98 | ) is 99 | begin 100 | self.denormalizer_pipeline(0) <= denormalized_number; 101 | self.target_scale_pipeline(0) <= target_scale; 102 | self.shift_register(0) <= '1'; 103 | 104 | end request_denormalizer; 105 | ------------------------------------------------------------------------ 106 | procedure request_scaling 107 | ( 108 | signal self : out denormalizer_record; 109 | left,right : in float_record 110 | ) is 111 | begin 112 | self.shift_register(0) <= '1'; 113 | if get_exponent(left) < get_exponent(right) then 114 | self.denormalizer_pipeline(0) <= left; 115 | self.feedthrough_pipeline(0) <= right; 116 | self.target_scale_pipeline(0) <= get_exponent(right); 117 | else 118 | self.denormalizer_pipeline(0) <= right; 119 | self.feedthrough_pipeline(0) <= left; 120 | self.target_scale_pipeline(0) <= get_exponent(left); 121 | end if; 122 | 123 | end request_scaling; 124 | ------------------------------------------------------------------------ 125 | procedure request_scaling 126 | ( 127 | signal self : out denormalizer_record; 128 | left : in float_record; 129 | right : in integer 130 | ) is 131 | begin 132 | self.shift_register(0) <= '1'; 133 | self.denormalizer_pipeline(0) <= left; 134 | self.feedthrough_pipeline(0) <= left; 135 | self.target_scale_pipeline(0) <= mantissa_length - right; 136 | 137 | end request_scaling; 138 | 139 | function get_integer 140 | ( 141 | self : denormalizer_record 142 | 143 | ) 144 | return integer 145 | is 146 | variable returned_value : integer; 147 | begin 148 | if get_sign(self.feedthrough_pipeline(number_of_denormalizer_pipeline_stages)) = '0' then 149 | returned_value := (get_mantissa(get_denormalized_result(self))); 150 | else 151 | returned_value := -(get_mantissa(get_denormalized_result(self))); 152 | end if; 153 | return returned_value; 154 | 155 | end get_integer; 156 | 157 | ------------------------------------------------------------------------ 158 | function denormalizer_is_ready 159 | ( 160 | self : denormalizer_record 161 | ) 162 | return boolean 163 | is 164 | constant left : integer := (self.shift_register'left); 165 | begin 166 | return self.shift_register(left) = '1'; 167 | end denormalizer_is_ready; 168 | ------------------------------------------------------------------------ 169 | function get_denormalized_result 170 | ( 171 | self : denormalizer_record 172 | ) 173 | return float_record 174 | is 175 | begin 176 | return self.denormalizer_pipeline(self.denormalizer_pipeline'left); 177 | end get_denormalized_result; 178 | ------------------------------------------------------------------------ 179 | function denormalize_float 180 | ( 181 | right : float_record; 182 | set_exponent_to : integer; 183 | max_shift : integer 184 | ) 185 | return float_record 186 | is 187 | variable float : float_record := zero; 188 | variable shift_width : integer; 189 | begin 190 | shift_width := to_integer(set_exponent_to - right.exponent); 191 | if shift_width >= max_shift then 192 | shift_width := max_shift; 193 | end if; 194 | if shift_width < 0 then 195 | shift_width := 0; 196 | end if; 197 | float := (sign => right.sign, 198 | exponent => right.exponent + shift_width, 199 | mantissa => shift_right(right.mantissa , shift_width)); 200 | 201 | return float; 202 | 203 | end denormalize_float; 204 | ------------------------------------------------------------------------ 205 | function denormalize_float 206 | ( 207 | right : float_record; 208 | set_exponent_to : integer 209 | ) 210 | return float_record 211 | is 212 | begin 213 | 214 | return denormalize_float(right, set_exponent_to, mantissa_length); 215 | 216 | end denormalize_float; 217 | ------------------------------------------------------------------------ 218 | procedure convert_float_to_integer 219 | ( 220 | signal self : out denormalizer_record; 221 | number_to_be_converted : float_record; 222 | desired_radix : in integer 223 | ) is 224 | begin 225 | request_scaling(self, number_to_be_converted, desired_radix); 226 | 227 | end convert_float_to_integer; 228 | -------------------------------------------------- 229 | end package body denormalizer_pkg; 230 | -------------------------------------------------------------------------------- /vhdl2008/denormalizer_generic_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | use work.float_typedefs_generic_pkg.all; 6 | 7 | package denormalizer_generic_pkg is 8 | 9 | ------------------------------------------------------------------------ 10 | type intarray is array (integer range <>) of integer; 11 | ------------------------------------------------------------------------ 12 | type denormalizer_record is record 13 | denormalizer_pipeline : float_array; 14 | feedthrough_pipeline : float_array; 15 | shift_register : std_logic_vector; 16 | target_scale_pipeline : intarray; 17 | end record; 18 | 19 | function denormalizer_typeref (number_of_pipeline_stages : natural := 2; floatref : hfloat_record) 20 | return denormalizer_record; 21 | 22 | ------------------------------------------------------------------------ 23 | procedure create_denormalizer ( 24 | signal self : inout denormalizer_record); 25 | ------------------------------------------------------------------------ 26 | procedure request_denormalizer ( 27 | signal self : out denormalizer_record; 28 | denormalized_number : in hfloat_record; 29 | target_scale : in integer); 30 | ------------------------------------------------------------------------ 31 | procedure request_scaling ( 32 | signal self : out denormalizer_record; 33 | left,right : in hfloat_record); 34 | 35 | procedure request_scaling ( 36 | signal self : out denormalizer_record; 37 | left : in hfloat_record; 38 | right : in integer); 39 | ------------------------------------------------------------------------ 40 | function denormalizer_is_ready (self : denormalizer_record) 41 | return boolean; 42 | ------------------------------------------------------------------------ 43 | function get_denormalized_result ( self : denormalizer_record) 44 | return hfloat_record; 45 | ------------------------------------------------------------------------ 46 | function get_integer ( self : denormalizer_record) 47 | return integer; 48 | ------------------------------------------------------------------------ 49 | function denormalize_float ( 50 | right : hfloat_record; 51 | set_exponent_to : integer) 52 | return hfloat_record; 53 | 54 | function denormalize_float ( 55 | right : hfloat_record; 56 | set_exponent_to : integer; 57 | max_shift : integer) 58 | return hfloat_record; 59 | ------------------------------------------------------------------------ 60 | procedure convert_float_to_integer ( 61 | signal self : out denormalizer_record; 62 | number_to_be_converted : hfloat_record; 63 | desired_radix : in integer); 64 | ------------------------------------------------------------------------ 65 | end package denormalizer_generic_pkg; 66 | 67 | package body denormalizer_generic_pkg is 68 | ------------------------------------------------------------------------ 69 | function denormalizer_typeref (number_of_pipeline_stages : natural := 2; floatref : hfloat_record) 70 | return denormalizer_record is 71 | constant init_denormalizer : denormalizer_record := ( 72 | denormalizer_pipeline => (number_of_pipeline_stages-1 downto 0 => floatref) 73 | ,feedthrough_pipeline => (number_of_pipeline_stages-1 downto 0 => floatref) 74 | ,shift_register => (number_of_pipeline_stages-1 downto 0 => '0') 75 | ,target_scale_pipeline => (number_of_pipeline_stages-1 downto 0 => 0)); 76 | begin 77 | return init_denormalizer; 78 | end denormalizer_typeref; 79 | ------------------------------------------------------------------------ 80 | procedure create_denormalizer 81 | ( 82 | signal self : inout denormalizer_record 83 | ) 84 | is 85 | constant number_of_denormalizer_pipeline_stages : natural := self.denormalizer_pipeline'high; 86 | constant mantissa_length : natural := self.denormalizer_pipeline(0).mantissa'length; 87 | begin 88 | 89 | self.shift_register(0) <= '0'; 90 | for i in 1 to number_of_denormalizer_pipeline_stages loop 91 | self.denormalizer_pipeline(i) <= denormalize_float(self.denormalizer_pipeline(i-1), self.target_scale_pipeline(i-1), mantissa_length/number_of_denormalizer_pipeline_stages); 92 | self.feedthrough_pipeline(i) <= self.feedthrough_pipeline(i-1); 93 | self.target_scale_pipeline(i) <= self.target_scale_pipeline(i-1); 94 | self.shift_register(i) <= self.shift_register(i-1); 95 | end loop; 96 | 97 | end procedure; 98 | 99 | ------------------------------------------------------------------------ 100 | procedure request_denormalizer 101 | ( 102 | signal self : out denormalizer_record; 103 | denormalized_number : in hfloat_record; 104 | target_scale : in integer 105 | ) is 106 | begin 107 | self.denormalizer_pipeline(0) <= denormalized_number; 108 | self.target_scale_pipeline(0) <= target_scale; 109 | self.shift_register(0) <= '1'; 110 | 111 | end request_denormalizer; 112 | ------------------------------------------------------------------------ 113 | procedure request_scaling 114 | ( 115 | signal self : out denormalizer_record; 116 | left,right : in hfloat_record 117 | ) is 118 | begin 119 | self.shift_register(0) <= '1'; 120 | if get_exponent(left) < get_exponent(right) then 121 | self.denormalizer_pipeline(0) <= left; 122 | self.feedthrough_pipeline(0) <= right; 123 | self.target_scale_pipeline(0) <= get_exponent(right); 124 | else 125 | self.denormalizer_pipeline(0) <= right; 126 | self.feedthrough_pipeline(0) <= left; 127 | self.target_scale_pipeline(0) <= get_exponent(left); 128 | end if; 129 | 130 | end request_scaling; 131 | ------------------------------------------------------------------------ 132 | procedure request_scaling 133 | ( 134 | signal self : out denormalizer_record; 135 | left : in hfloat_record; 136 | right : in integer 137 | ) is 138 | constant mantissa_length : natural := self.denormalizer_pipeline(0).mantissa'length; 139 | begin 140 | self.shift_register(0) <= '1'; 141 | self.denormalizer_pipeline(0) <= left; 142 | self.feedthrough_pipeline(0) <= left; 143 | self.target_scale_pipeline(0) <= mantissa_length - right; 144 | 145 | end request_scaling; 146 | 147 | function get_integer 148 | ( 149 | self : denormalizer_record 150 | 151 | ) 152 | return integer 153 | is 154 | variable returned_value : integer; 155 | begin 156 | if get_sign(self.feedthrough_pipeline(self.feedthrough_pipeline'high)) = '0' then 157 | returned_value := (get_mantissa(get_denormalized_result(self))); 158 | else 159 | returned_value := -(get_mantissa(get_denormalized_result(self))); 160 | end if; 161 | return returned_value; 162 | 163 | end get_integer; 164 | 165 | ------------------------------------------------------------------------ 166 | function denormalizer_is_ready 167 | ( 168 | self : denormalizer_record 169 | ) 170 | return boolean 171 | is 172 | constant left : integer := (self.shift_register'left); 173 | begin 174 | return self.shift_register(left) = '1'; 175 | end denormalizer_is_ready; 176 | ------------------------------------------------------------------------ 177 | function get_denormalized_result 178 | ( 179 | self : denormalizer_record 180 | ) 181 | return hfloat_record 182 | is 183 | begin 184 | return self.denormalizer_pipeline(self.denormalizer_pipeline'left); 185 | end get_denormalized_result; 186 | ------------------------------------------------------------------------ 187 | function denormalize_float 188 | ( 189 | right : hfloat_record; 190 | set_exponent_to : integer; 191 | max_shift : integer 192 | ) 193 | return hfloat_record 194 | is 195 | variable retval : right'subtype; 196 | variable shift_width : integer; 197 | begin 198 | shift_width := to_integer(set_exponent_to - right.exponent); 199 | if shift_width >= max_shift then 200 | shift_width := max_shift; 201 | end if; 202 | if shift_width < 0 then 203 | shift_width := 0; 204 | end if; 205 | retval := (sign => right.sign, 206 | exponent => right.exponent + shift_width, 207 | mantissa => shift_right(right.mantissa , shift_width)); 208 | 209 | return retval; 210 | 211 | end denormalize_float; 212 | ------------------------------------------------------------------------ 213 | function denormalize_float 214 | ( 215 | right : hfloat_record; 216 | set_exponent_to : integer 217 | ) 218 | return hfloat_record 219 | is 220 | constant mantissa_length : natural := right.mantissa'length; 221 | begin 222 | 223 | return denormalize_float(right, set_exponent_to, mantissa_length); 224 | 225 | end denormalize_float; 226 | ------------------------------------------------------------------------ 227 | procedure convert_float_to_integer 228 | ( 229 | signal self : out denormalizer_record; 230 | number_to_be_converted : hfloat_record; 231 | desired_radix : in integer 232 | ) is 233 | begin 234 | request_scaling(self, number_to_be_converted, desired_radix); 235 | 236 | end convert_float_to_integer; 237 | -------------------------------------------------- 238 | end package body denormalizer_generic_pkg; 239 | -------------------------------------------------------------------------------- /vhdl2008/float_to_real_conversions_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | use ieee.math_real.all; 5 | 6 | use work.float_typedefs_generic_pkg.all; 7 | use work.normalizer_generic_pkg.all; 8 | 9 | package float_to_real_conversions_pkg is 10 | constant hfloat_zero : hfloat_record :=(sign => '0', exponent => (7 downto 0 => x"00"), mantissa => (23 downto 0 => x"000000")); 11 | ------------------------------------------------------------------------ 12 | function to_hfloat ( 13 | real_number : real 14 | ;exponent_length : natural 15 | ;mantissa_length : natural) return hfloat_record; 16 | ------------------------------------------------------------------------ 17 | function to_hfloat_slv_generic 18 | generic( 19 | exponent_length : natural 20 | ;word_length : natural 21 | )( 22 | real_number : real 23 | ) return std_logic_vector ; 24 | ------------------------------------------------------------------------ 25 | function to_real ( float_number : hfloat_record) 26 | return real; 27 | ------------------------------------------------------------------------ 28 | function get_sign ( number : real) 29 | return std_logic; 30 | ------------------------------------------------------------------------ 31 | function get_exponent ( number : real 32 | ;exponent_length : natural := 8) 33 | return real; 34 | ------------------------------------------------------------------------ 35 | function get_exponent ( 36 | number : real 37 | ;exponent_length : natural := 8) return signed; 38 | ------------------------------------------------------------------------ 39 | function get_mantissa 40 | ( 41 | number : real 42 | ;mantissa_length : natural 43 | ) 44 | return unsigned; 45 | ------------------------------------------------------------------------ 46 | function to_hfloat_generic 47 | generic( 48 | exponent_length : natural 49 | ;word_length : natural) 50 | ( 51 | real_number : real 52 | ) 53 | return hfloat_record; 54 | ------------------------------------------------------------------------ 55 | end package float_to_real_conversions_pkg; 56 | 57 | package body float_to_real_conversions_pkg is 58 | 59 | 60 | ------------------------------------------------------------------------ 61 | function to_std_logic_vector 62 | ( 63 | float : hfloat_record 64 | ) 65 | return std_logic_vector 66 | is 67 | constant exponent_high : natural := float.exponent'high; 68 | constant mantissa_high : natural := float.mantissa'high; 69 | variable retval : std_logic_vector(mantissa_high+exponent_high+2 downto 0); 70 | begin 71 | retval := float.sign & std_logic_vector(float.exponent) & std_logic_vector(float.mantissa); 72 | 73 | return retval; 74 | 75 | end to_std_logic_vector; 76 | ------------------------------------------------------------------------ 77 | function get_exponent 78 | ( 79 | number : real 80 | ;exponent_length : natural := 8 81 | ) 82 | return real 83 | is 84 | variable retval : real := 1.0; 85 | variable temp : real := abs(number); 86 | begin 87 | if number = 0.0 then 88 | retval := 0.0; 89 | else 90 | retval := round(log2(abs(number))); 91 | end if; 92 | if retval >= 2.0**(exponent_length-1)-1.0 then 93 | retval := 2.0**(exponent_length-1)-1.0; 94 | end if; 95 | 96 | return retval; 97 | 98 | end get_exponent; 99 | ------------------------------------------------------------------------ 100 | function get_sign 101 | ( 102 | number : real 103 | ) 104 | return std_logic 105 | is 106 | variable result : std_logic; 107 | begin 108 | 109 | if number >= 0.0 then 110 | result := '0'; 111 | else 112 | result := '1'; 113 | end if; 114 | 115 | return result; 116 | 117 | end get_sign; 118 | ------------------------------------------------------------------------ 119 | function get_exponent 120 | ( 121 | number : real 122 | ;exponent_length : natural := 8 123 | ) 124 | return signed 125 | is 126 | variable result : real := 0.0; 127 | begin 128 | result := get_exponent(number, exponent_length); 129 | return to_signed(integer(result),exponent_length) + 1; 130 | end get_exponent; 131 | ------------------------------------------------------------------------ 132 | function get_mantissa 133 | ( 134 | number : real 135 | ;exponent : natural := 8 136 | ) 137 | return real 138 | is 139 | begin 140 | return (abs(number)/2.0**get_exponent(number, exponent)); 141 | end get_mantissa; 142 | ------------------------------------------------------------------------ 143 | function get_mantissa 144 | ( 145 | number : real 146 | ;mantissa_length : natural 147 | ) 148 | return unsigned 149 | is 150 | variable real_exp : real := 0.0; 151 | variable real_mantissa : real := 0.0; 152 | variable retval : unsigned(mantissa_length-1 downto 0); 153 | begin 154 | real_exp := get_exponent(number); 155 | if real_exp = 0.0 156 | then 157 | real_mantissa := abs(number)*2.0**mantissa_length; 158 | else 159 | real_mantissa := (abs(number) / 2.0**real_exp)*2.0**(mantissa_length-1); 160 | end if; 161 | 162 | for i in retval'range loop 163 | if real_mantissa >= 2.0**i then 164 | real_mantissa := real_mantissa - 2.0**i; 165 | retval(i) := '1'; 166 | else 167 | retval(i) := '0'; 168 | end if; 169 | end loop; 170 | 171 | return retval; 172 | end get_mantissa; 173 | ------------------------------------------------------------------------ 174 | function to_hfloat 175 | ( 176 | real_number : real 177 | ;exponent_length : natural 178 | ;mantissa_length : natural 179 | ) 180 | return hfloat_record 181 | is 182 | 183 | constant hfloat_ref : hfloat_record := ( 184 | sign => '0' 185 | ,exponent => (exponent_length-1 downto 0 => '0') 186 | ,mantissa => (mantissa_length-1 downto 0 => '0') 187 | ); 188 | 189 | variable retval : hfloat_ref'subtype := hfloat_ref; 190 | 191 | begin 192 | 193 | retval := normalize((sign => get_sign(real_number), 194 | exponent => get_exponent(real_number, exponent_length), 195 | mantissa => get_mantissa(real_number , mantissa_length))); 196 | 197 | if retval.mantissa = hfloat_ref.mantissa 198 | then 199 | retval := hfloat_ref; 200 | end if; 201 | 202 | return retval; 203 | 204 | end to_hfloat; 205 | 206 | ------------------------------------------------------------------------ 207 | function to_hfloat_generic 208 | generic( 209 | exponent_length : natural 210 | ;word_length : natural) 211 | ( 212 | real_number : real 213 | ) 214 | return hfloat_record 215 | is 216 | constant mantissa_length : natural := word_length - exponent_length - 1; 217 | 218 | begin 219 | 220 | return normalize((sign => get_sign(real_number), 221 | exponent => get_exponent(real_number), 222 | mantissa => get_mantissa(real_number , mantissa_length))); 223 | 224 | end to_hfloat_generic; 225 | 226 | ------------------------------------------------------------------------ 227 | function to_hfloat_slv_generic 228 | generic( 229 | exponent_length : natural 230 | ;word_length : natural) 231 | ( 232 | real_number : real 233 | ) 234 | return std_logic_vector 235 | is 236 | constant mantissa_length : natural := word_length - exponent_length - 1; 237 | 238 | constant hfloat : hfloat_record := normalize( 239 | (sign => get_sign(real_number), 240 | exponent => get_exponent(real_number), 241 | mantissa => get_mantissa(real_number , mantissa_length))); 242 | 243 | begin 244 | 245 | return to_std_logic_vector(hfloat); 246 | 247 | end to_hfloat_slv_generic; 248 | ------------------------------------------------------------------------ 249 | 250 | function to_real 251 | ( 252 | float_number : hfloat_record 253 | ) 254 | return real 255 | is 256 | variable mantissa : real := 0.0; 257 | variable sign : real := 0.0; 258 | variable exponent : real := 0.0; 259 | function "*"(left : real; right : std_logic) return real is 260 | variable retval : real := 0.0; 261 | begin 262 | if right = '0' 263 | then 264 | retval := 0.0; 265 | else 266 | retval := left; 267 | end if; 268 | return retval; 269 | end function; 270 | 271 | begin 272 | 273 | if float_number.sign = '1' then 274 | sign := -1.0; 275 | else 276 | sign := 1.0; 277 | end if; 278 | 279 | for i in float_number.mantissa'range loop 280 | mantissa := mantissa + 2.0**(i)*float_number.mantissa(i)/ 2.0**(float_number.mantissa'length); 281 | end loop; 282 | 283 | -- mantissa := real(to_integer(float_number.mantissa))/2.0**(float_number.mantissa'length); 284 | exponent := (2.0**real(to_integer(float_number.exponent))); 285 | 286 | return sign * exponent * mantissa ; 287 | 288 | end to_real; 289 | ------------------------------------------------------------------------ 290 | function to_hfloat 291 | ( 292 | float : std_logic_vector 293 | ;ref : hfloat_record := hfloat_zero 294 | ) 295 | return hfloat_record 296 | is 297 | variable retval : ref'subtype; 298 | constant exponent_high : natural := ref.exponent'high; 299 | begin 300 | retval.sign := float(float'left); 301 | retval.exponent := signed(float(float'left-1 downto float'left-1-exponent_high)); 302 | retval.mantissa := unsigned(float(float'left-exponent_high-2 downto 0)); 303 | 304 | return retval; 305 | end to_hfloat; 306 | ------------------------------------------------------------------------ 307 | 308 | end package body float_to_real_conversions_pkg; 309 | --------------------------------------------------------------------------------