-- -------------------------------------------------------------------- -- "float_pkg" package contains functions for floating point math. -- Please see the documentation for the floating point package. -- This package should be compiled into "ieee_proposed" and used as follows: -- use ieee.std_logic_1164.all; -- use ieee.numeric_std.all; -- use ieee_proposed.math_utility.all; -- use ieee_proposed.fixed_pkg.all; -- use ieee_proposed.float_pkg.all; -- -- This verison is designed to work with the VHDL-93 compilers. Please -- note the "%%%" comments. These are where we diverge from the -- VHDL-200X LRM. -- -- -------------------------------------------------------------------- -- Version : $Revision: 1.14 $ -- Date : $Date: 2007-06-19 10:20:43-04 $ -- -------------------------------------------------------------------- use STD.TEXTIO.all; library IEEE; use IEEE.STD_LOGIC_1164.all; use IEEE.NUMERIC_STD.all; library ieee_proposed; use ieee_proposed.math_utility_pkg.all; use ieee_proposed.fixed_pkg.all; package float_pkg is -- generic ( -- Defaults for sizing routines, when you do a "to_float" this will be -- the default size. Example float32 would be 8 and 23 (8 downto -23) constant float_exponent_width : NATURAL := 8; constant float_fraction_width : NATURAL := 23; -- Rounding algorithm, "round_nearest" is default, other valid values -- are "round_zero" (truncation), "round_inf" (round up), and -- "round_neginf" (round down) constant float_round_style : round_type := round_nearest; -- Denormal numbers (very small numbers near zero) true or false constant float_denormalize : BOOLEAN := true; -- Turns on NAN processing (invalid numbers and overflow) true of false constant float_check_error : BOOLEAN := true; -- Guard bits are added to the bottom of every operation for rounding. -- any natural number (including 0) are valid. constant float_guard_bits : NATURAL := 3; -- If TRUE, then turn off warnings on "X" propagation constant no_warning : BOOLEAN := (false ); -- Author David Bishop (dbishop@vhdl.org) -- Note that the size of the vector is not defined here, but in -- the package which calls this one. type UNRESOLVED_float is array (INTEGER range <>) of STD_ULOGIC; -- main type subtype U_float is UNRESOLVED_float; subtype float is UNRESOLVED_float; ----------------------------------------------------------------------------- -- Use the float type to define your own floating point numbers. -- There must be a negative index or the packages will error out. -- Minimum supported is "subtype float7 is float (3 downto -3);" -- "subtype float16 is float (6 downto -9);" is probably the smallest -- practical one to use. ----------------------------------------------------------------------------- -- IEEE 754 single precision subtype UNRESOLVED_float32 is UNRESOLVED_float (8 downto -23); alias U_float32 is UNRESOLVED_float32; subtype float32 is float (8 downto -23); ----------------------------------------------------------------------------- -- IEEE-754 single precision floating point. This is a "float" -- in C, and a FLOAT in Fortran. The exponent is 8 bits wide, and -- the fraction is 23 bits wide. This format can hold roughly 7 decimal -- digits. Infinity is 2**127 = 1.7E38 in this number system. -- The bit representation is as follows: -- 1 09876543 21098765432109876543210 -- 8 76543210 12345678901234567890123 -- 0 00000000 00000000000000000000000 -- 8 7 0 -1 -23 -- +/- exp. fraction ----------------------------------------------------------------------------- -- IEEE 754 double precision subtype UNRESOLVED_float64 is UNRESOLVED_float (11 downto -52); alias U_float64 is UNRESOLVED_float64; subtype float64 is float (11 downto -52); ----------------------------------------------------------------------------- -- IEEE-754 double precision floating point. This is a "double float" -- in C, and a FLOAT*8 in Fortran. The exponent is 11 bits wide, and -- the fraction is 52 bits wide. This format can hold roughly 15 decimal -- digits. Infinity is 2**2047 in this number system. -- The bit representation is as follows: -- 3 21098765432 1098765432109876543210987654321098765432109876543210 -- 1 09876543210 1234567890123456789012345678901234567890123456789012 -- S EEEEEEEEEEE FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -- 11 10 0 -1 -52 -- +/- exponent fraction ----------------------------------------------------------------------------- -- IEEE 854 & C extended precision subtype UNRESOLVED_float128 is UNRESOLVED_float (15 downto -112); alias U_float128 is UNRESOLVED_float128; subtype float128 is float (15 downto -112); ----------------------------------------------------------------------------- -- The 128 bit floating point number is "long double" in C (on -- some systems this is a 70 bit floating point number) and FLOAT*32 -- in Fortran. The exponent is 15 bits wide and the fraction is 112 -- bits wide. This number can handle approximately 33 decimal digits. -- Infinity is 2**32,767 in this number system. ----------------------------------------------------------------------------- -- purpose: Checks for a valid floating point number type valid_fpstate is (nan, -- Signaling NaN (C FP_NAN) quiet_nan, -- Quiet NaN (C FP_NAN) neg_inf, -- Negative infinity (C FP_INFINITE) neg_normal, -- negative normalized nonzero neg_denormal, -- negative denormalized (FP_SUBNORMAL) neg_zero, -- -0 (C FP_ZERO) pos_zero, -- +0 (C FP_ZERO) pos_denormal, -- Positive denormalized (FP_SUBNORMAL) pos_normal, -- positive normalized nonzero pos_inf, -- positive infinity isx); -- at least one input is unknown -- This deferred constant will tell you if the package body is synthesizable -- or implemented as real numbers. constant fphdlsynth_or_real : BOOLEAN; -- deferred constant -- Returns the class which X falls into function Classfp ( x : UNRESOLVED_float; -- floating point input check_error : BOOLEAN := float_check_error) -- check for errors return valid_fpstate; -- Arithmetic functions, these operators do not require parameters. function "abs" (arg : UNRESOLVED_float) return UNRESOLVED_float; function "-" (arg : UNRESOLVED_float) return UNRESOLVED_float; -- These allows the base math functions to use the default values -- of their parameters. Thus they do full IEEE floating point. function "+" (l, r : UNRESOLVED_float) return UNRESOLVED_float; function "-" (l, r : UNRESOLVED_float) return UNRESOLVED_float; function "*" (l, r : UNRESOLVED_float) return UNRESOLVED_float; function "/" (l, r : UNRESOLVED_float) return UNRESOLVED_float; function "rem" (l, r : UNRESOLVED_float) return UNRESOLVED_float; function "mod" (l, r : UNRESOLVED_float) return UNRESOLVED_float; -- Basic parameter list -- round_style - Selects the rounding algorithm to use -- guard - extra bits added to the end if the operation to add precision -- check_error - When "false" turns off NAN and overflow checks -- denormalize - When "false" turns off denormal number processing function add ( l, r : UNRESOLVED_float; -- floating point input constant round_style : round_type := float_round_style; -- rounding option constant guard : NATURAL := float_guard_bits; -- number of guard bits constant check_error : BOOLEAN := float_check_error; -- check for errors constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP return UNRESOLVED_float; function subtract ( l, r : UNRESOLVED_float; -- floating point input constant round_style : round_type := float_round_style; -- rounding option constant guard : NATURAL := float_guard_bits; -- number of guard bits constant check_error : BOOLEAN := float_check_error; -- check for errors constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP return UNRESOLVED_float; function multiply ( l, r : UNRESOLVED_float; -- floating point input constant round_style : round_type := float_round_style; -- rounding option constant guard : NATURAL := float_guard_bits; -- number of guard bits constant check_error : BOOLEAN := float_check_error; -- check for errors constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP return UNRESOLVED_float; function divide ( l, r : UNRESOLVED_float; -- floating point input constant round_style : round_type := float_round_style; -- rounding option constant guard : NATURAL := float_guard_bits; -- number of guard bits constant check_error : BOOLEAN := float_check_error; -- check for errors constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP return UNRESOLVED_float; function remainder ( l, r : UNRESOLVED_float; -- floating point input constant round_style : round_type := float_round_style; -- rounding option constant guard : NATURAL := float_guard_bits; -- number of guard bits constant check_error : BOOLEAN := float_check_error; -- check for errors constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP return UNRESOLVED_float; function modulo ( l, r : UNRESOLVED_float; -- floating point input constant round_style : round_type := float_round_style; -- rounding option constant guard : NATURAL := float_guard_bits; -- number of guard bits constant check_error : BOOLEAN := float_check_error; -- check for errors constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP return UNRESOLVED_float; -- reciprocal function reciprocal ( arg : UNRESOLVED_float; -- floating point input constant round_style : round_type := float_round_style; -- rounding option constant guard : NATURAL := float_guard_bits; -- number of guard bits constant check_error : BOOLEAN := float_check_error; -- check for errors constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP return UNRESOLVED_float; function dividebyp2 ( l, r : UNRESOLVED_float; -- floating point input constant round_style : round_type := float_round_style; -- rounding option constant guard : NATURAL := float_guard_bits; -- number of guard bits constant check_error : BOOLEAN := float_check_error; -- check for errors constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP return UNRESOLVED_float; -- Multiply accumulate result = l*r + c function mac ( l, r, c : UNRESOLVED_float; -- floating point input constant round_style : round_type := float_round_style; -- rounding option constant guard : NATURAL := float_guard_bits; -- number of guard bits constant check_error : BOOLEAN := float_check_error; -- check for errors constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP return UNRESOLVED_float; -- Square root (all 754 based implementations need this) function sqrt ( arg : UNRESOLVED_float; -- floating point input constant round_style : round_type := float_round_style; constant guard : NATURAL := float_guard_bits; constant check_error : BOOLEAN := float_check_error; constant denormalize : BOOLEAN := float_denormalize) return UNRESOLVED_float; function Is_Negative (arg : UNRESOLVED_float) return BOOLEAN; ----------------------------------------------------------------------------- -- compare functions -- =, /=, >=, <=, <, >, maximum, minimum function eq ( -- equal = l, r : UNRESOLVED_float; -- floating point input constant check_error : BOOLEAN := float_check_error; constant denormalize : BOOLEAN := float_denormalize) return BOOLEAN; function ne ( -- not equal /= l, r : UNRESOLVED_float; -- floating point input constant check_error : BOOLEAN := float_check_error; constant denormalize : BOOLEAN := float_denormalize) return BOOLEAN; function lt ( -- less than < l, r : UNRESOLVED_float; -- floating point input constant check_error : BOOLEAN := float_check_error; constant denormalize : BOOLEAN := float_denormalize) return BOOLEAN; function gt ( -- greater than > l, r : UNRESOLVED_float; -- floating point input constant check_error : BOOLEAN := float_check_error; constant denormalize : BOOLEAN := float_denormalize) return BOOLEAN; function le ( -- less than or equal to <= l, r : UNRESOLVED_float; -- floating point input constant check_error : BOOLEAN := float_check_error; constant denormalize : BOOLEAN := float_denormalize) return BOOLEAN; function ge ( -- greater than or equal to >= l, r : UNRESOLVED_float; -- floating point input constant check_error : BOOLEAN := float_check_error; constant denormalize : BOOLEAN := float_denormalize) return BOOLEAN; -- Need to overload the default versions of these function "=" (l, r : UNRESOLVED_float) return BOOLEAN; function "/=" (l, r : UNRESOLVED_float) return BOOLEAN; function ">=" (l, r : UNRESOLVED_float) return BOOLEAN; function "<=" (l, r : UNRESOLVED_float) return BOOLEAN; function ">" (l, r : UNRESOLVED_float) return BOOLEAN; function "<" (l, r : UNRESOLVED_float) return BOOLEAN; function \?=\ (l, r : UNRESOLVED_float) return STD_ULOGIC; function \?/=\ (l, r : UNRESOLVED_float) return STD_ULOGIC; function \?>\ (l, r : UNRESOLVED_float) return STD_ULOGIC; function \?>=\ (l, r : UNRESOLVED_float) return STD_ULOGIC; function \?<\ (l, r : UNRESOLVED_float) return STD_ULOGIC; function \?<=\ (l, r : UNRESOLVED_float) return STD_ULOGIC; function std_match (l, r : UNRESOLVED_float) return BOOLEAN; function find_rightmost (arg : UNRESOLVED_float; y : STD_ULOGIC) return INTEGER; function find_leftmost (arg : UNRESOLVED_float; y : STD_ULOGIC) return INTEGER; function maximum (l, r : UNRESOLVED_float) return UNRESOLVED_float; function minimum (l, r : UNRESOLVED_float) return UNRESOLVED_float; -- conversion functions -- Converts one floating point number into another. function resize ( arg : UNRESOLVED_float; -- Floating point input constant exponent_width : NATURAL := float_exponent_width; -- length of FP output exponent constant fraction_width : NATURAL := float_fraction_width; -- length of FP output fraction constant round_style : round_type := float_round_style; -- rounding option constant check_error : BOOLEAN := float_check_error; constant denormalize_in : BOOLEAN := float_denormalize; -- Use IEEE extended FP constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP return UNRESOLVED_float; function resize ( arg : UNRESOLVED_float; -- Floating point input size_res : UNRESOLVED_float; constant round_style : round_type := float_round_style; -- rounding option constant check_error : BOOLEAN := float_check_error; constant denormalize_in : BOOLEAN := float_denormalize; -- Use IEEE extended FP constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP return UNRESOLVED_float; function to_float32 ( arg : UNRESOLVED_float; constant round_style : round_type := float_round_style; -- rounding option constant check_error : BOOLEAN := float_check_error; constant denormalize_in : BOOLEAN := float_denormalize; -- Use IEEE extended FP constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP return UNRESOLVED_float32; function to_float64 ( arg : UNRESOLVED_float; constant round_style : round_type := float_round_style; -- rounding option constant check_error : BOOLEAN := float_check_error; constant denormalize_in : BOOLEAN := float_denormalize; -- Use IEEE extended FP constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP return UNRESOLVED_float64; function to_float128 ( arg : UNRESOLVED_float; constant round_style : round_type := float_round_style; -- rounding option constant check_error : BOOLEAN := float_check_error; constant denormalize_in : BOOLEAN := float_denormalize; -- Use IEEE extended FP constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP return UNRESOLVED_float128; -- Converts an fp into an SLV (needed for synthesis) function to_slv (arg : UNRESOLVED_float) return STD_LOGIC_VECTOR; alias to_StdLogicVector is to_slv [UNRESOLVED_float return STD_LOGIC_VECTOR]; alias to_Std_Logic_Vector is to_slv [UNRESOLVED_float return STD_LOGIC_VECTOR]; -- Converts an fp into an SULV function to_suv (arg : UNRESOLVED_float) return STD_ULOGIC_VECTOR; alias to_StdULogicVector is to_suv [UNRESOLVED_float return STD_ULOGIC_VECTOR]; alias to_Std_ULogic_Vector is to_suv [UNRESOLVED_float return STD_ULOGIC_VECTOR]; -- std_ulogic_vector to float function to_float ( arg : STD_ULOGIC_VECTOR; constant exponent_width : NATURAL := float_exponent_width; -- length of FP output exponent constant fraction_width : NATURAL := float_fraction_width) -- length of FP output fraction return UNRESOLVED_float; -- Integer to float function to_float ( arg : INTEGER; constant exponent_width : NATURAL := float_exponent_width; -- length of FP output exponent constant fraction_width : NATURAL := float_fraction_width; -- length of FP output fraction constant round_style : round_type := float_round_style) -- rounding option return UNRESOLVED_float; -- real to float function to_float ( arg : REAL; constant exponent_width : NATURAL := float_exponent_width; -- length of FP output exponent constant fraction_width : NATURAL := float_fraction_width; -- length of FP output fraction constant round_style : round_type := float_round_style; -- rounding option constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP return UNRESOLVED_float; -- unsigned to float function to_float ( arg : UNSIGNED; constant exponent_width : NATURAL := float_exponent_width; -- length of FP output exponent constant fraction_width : NATURAL := float_fraction_width; -- length of FP output fraction constant round_style : round_type := float_round_style) -- rounding option return UNRESOLVED_float; -- signed to float function to_float ( arg : SIGNED; constant exponent_width : NATURAL := float_exponent_width; -- length of FP output exponent constant fraction_width : NATURAL := float_fraction_width; -- length of FP output fraction constant round_style : round_type := float_round_style) -- rounding option return UNRESOLVED_float; -- unsigned fixed point to float function to_float ( arg : UNRESOLVED_ufixed; -- unsigned fixed point input constant exponent_width : NATURAL := float_exponent_width; -- width of exponent constant fraction_width : NATURAL := float_fraction_width; -- width of fraction constant round_style : round_type := float_round_style; -- rounding constant denormalize : BOOLEAN := float_denormalize) -- use ieee extensions return UNRESOLVED_float; -- signed fixed point to float function to_float ( arg : UNRESOLVED_sfixed; constant exponent_width : NATURAL := float_exponent_width; -- length of FP output exponent constant fraction_width : NATURAL := float_fraction_width; -- length of FP output fraction constant round_style : round_type := float_round_style; -- rounding constant denormalize : BOOLEAN := float_denormalize) -- rounding option return UNRESOLVED_float; -- size_res functions -- Integer to float function to_float ( arg : INTEGER; size_res : UNRESOLVED_float; constant round_style : round_type := float_round_style) -- rounding option return UNRESOLVED_float; -- real to float function to_float ( arg : REAL; size_res : UNRESOLVED_float; constant round_style : round_type := float_round_style; -- rounding option constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP return UNRESOLVED_float; -- unsigned to float function to_float ( arg : UNSIGNED; size_res : UNRESOLVED_float; constant round_style : round_type := float_round_style) -- rounding option return UNRESOLVED_float; -- signed to float function to_float ( arg : SIGNED; size_res : UNRESOLVED_float; constant round_style : round_type := float_round_style) -- rounding option return UNRESOLVED_float; -- sulv to float function to_float ( arg : STD_ULOGIC_VECTOR; size_res : UNRESOLVED_float) return UNRESOLVED_float; -- unsigned fixed point to float function to_float ( arg : UNRESOLVED_ufixed; -- unsigned fixed point input size_res : UNRESOLVED_float; constant round_style : round_type := float_round_style; -- rounding constant denormalize : BOOLEAN := float_denormalize) -- use ieee extensions return UNRESOLVED_float; -- signed fixed point to float function to_float ( arg : UNRESOLVED_sfixed; size_res : UNRESOLVED_float; constant round_style : round_type := float_round_style; -- rounding constant denormalize : BOOLEAN := float_denormalize) -- rounding option return UNRESOLVED_float; -- float to unsigned function to_unsigned ( arg : UNRESOLVED_float; -- floating point input constant size : NATURAL; -- length of output constant check_error : BOOLEAN := float_check_error; -- check for errors constant round_style : round_type := float_round_style) -- rounding option return UNSIGNED; -- float to signed function to_signed ( arg : UNRESOLVED_float; -- floating point input constant size : NATURAL; -- length of output constant check_error : BOOLEAN := float_check_error; -- check for errors constant round_style : round_type := float_round_style) -- rounding option return SIGNED; -- purpose: Converts a float to unsigned fixed point function to_ufixed ( arg : UNRESOLVED_float; -- fp input constant left_index : INTEGER; -- integer part constant right_index : INTEGER; -- fraction part constant round_style : fixed_round_style_type := fixed_round_style; -- rounding constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; -- saturate constant check_error : BOOLEAN := float_check_error; -- check for errors constant denormalize : BOOLEAN := float_denormalize) return UNRESOLVED_ufixed; -- float to signed fixed point function to_sfixed ( arg : UNRESOLVED_float; -- fp input constant left_index : INTEGER; -- integer part constant right_index : INTEGER; -- fraction part constant round_style : fixed_round_style_type := fixed_round_style; -- rounding constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; -- saturate constant check_error : BOOLEAN := float_check_error; -- check for errors constant denormalize : BOOLEAN := float_denormalize) return UNRESOLVED_sfixed; -- size_res versions -- float to unsigned function to_unsigned ( arg : UNRESOLVED_float; -- floating point input size_res : UNSIGNED; constant check_error : BOOLEAN := float_check_error; -- check for errors constant round_style : round_type := float_round_style) -- rounding option return UNSIGNED; -- float to signed function to_signed ( arg : UNRESOLVED_float; -- floating point input size_res : SIGNED; constant check_error : BOOLEAN := float_check_error; -- check for errors constant round_style : round_type := float_round_style) -- rounding option return SIGNED; -- purpose: Converts a float to unsigned fixed point function to_ufixed ( arg : UNRESOLVED_float; -- fp input size_res : UNRESOLVED_ufixed; constant round_style : fixed_round_style_type := fixed_round_style; -- rounding constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; -- saturate constant check_error : BOOLEAN := float_check_error; -- check for errors constant denormalize : BOOLEAN := float_denormalize) return UNRESOLVED_ufixed; -- float to signed fixed point function to_sfixed ( arg : UNRESOLVED_float; -- fp input size_res : UNRESOLVED_sfixed; constant round_style : fixed_round_style_type := fixed_round_style; -- rounding constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; -- saturate constant check_error : BOOLEAN := float_check_error; -- check for errors constant denormalize : BOOLEAN := float_denormalize) return UNRESOLVED_sfixed; -- float to real function to_real ( arg : UNRESOLVED_float; -- floating point input constant round_style : round_type := float_round_style; -- rounding option constant check_error : BOOLEAN := float_check_error; -- check for errors constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP return REAL; -- float to integer function to_integer ( arg : UNRESOLVED_float; -- floating point input constant check_error : BOOLEAN := float_check_error; -- check for errors constant round_style : round_type := float_round_style) -- rounding option return INTEGER; -- Maps metalogical values function to_01 ( arg : UNRESOLVED_float; -- floating point input XMAP : STD_LOGIC := '0') return UNRESOLVED_float; function Is_X (arg : UNRESOLVED_float) return BOOLEAN; function to_X01 (arg : UNRESOLVED_float) return UNRESOLVED_float; function to_X01Z (arg : UNRESOLVED_float) return UNRESOLVED_float; function to_UX01 (arg : UNRESOLVED_float) return UNRESOLVED_float; -- These two procedures were copied out of the body because they proved -- very useful for vendor specific algorithm development -- Break_number converts a floating point number into it's parts -- Exponent is biased by -1 procedure break_number ( arg : in UNRESOLVED_float; denormalize : in BOOLEAN := float_denormalize; check_error : in BOOLEAN := float_check_error; fract : out UNSIGNED; expon : out SIGNED; -- NOTE: Add 1 to get the real exponent! sign : out STD_ULOGIC); procedure break_number ( arg : in UNRESOLVED_float; denormalize : in BOOLEAN := float_denormalize; check_error : in BOOLEAN := float_check_error; fract : out ufixed; -- a number between 1.0 and 2.0 expon : out SIGNED; -- NOTE: Add 1 to get the real exponent! sign : out STD_ULOGIC); -- Normalize takes a fraction and and exponent and converts them into -- a floating point number. Does the shifting and the rounding. -- Exponent is assumed to be biased by -1 function normalize ( fract : UNSIGNED; -- fraction, unnormalized expon : SIGNED; -- exponent - 1, normalized sign : STD_ULOGIC; -- sign bit sticky : STD_ULOGIC := '0'; -- Sticky bit (rounding) constant exponent_width : NATURAL := float_exponent_width; -- size of output exponent constant fraction_width : NATURAL := float_fraction_width; -- size of output fraction constant round_style : round_type := float_round_style; -- rounding option constant denormalize : BOOLEAN := float_denormalize; -- Use IEEE extended FP constant nguard : NATURAL := float_guard_bits) -- guard bits return UNRESOLVED_float; -- Exponent is assumed to be biased by -1 function normalize ( fract : ufixed; -- unsigned fixed point expon : SIGNED; -- exponent - 1, normalized sign : STD_ULOGIC; -- sign bit sticky : STD_ULOGIC := '0'; -- Sticky bit (rounding) constant exponent_width : NATURAL := float_exponent_width; -- size of output exponent constant fraction_width : NATURAL := float_fraction_width; -- size of output fraction constant round_style : round_type := float_round_style; -- rounding option constant denormalize : BOOLEAN := float_denormalize; -- Use IEEE extended FP constant nguard : NATURAL := float_guard_bits) -- guard bits return UNRESOLVED_float; function normalize ( fract : UNSIGNED; -- unsigned expon : SIGNED; -- exponent - 1, normalized sign : STD_ULOGIC; -- sign bit sticky : STD_ULOGIC := '0'; -- Sticky bit (rounding) size_res : UNRESOLVED_float; -- used for sizing only constant round_style : round_type := float_round_style; -- rounding option constant denormalize : BOOLEAN := float_denormalize; -- Use IEEE extended FP constant nguard : NATURAL := float_guard_bits) -- guard bits return UNRESOLVED_float; -- Exponent is assumed to be biased by -1 function normalize ( fract : ufixed; -- unsigned fixed point expon : SIGNED; -- exponent - 1, normalized sign : STD_ULOGIC; -- sign bit sticky : STD_ULOGIC := '0'; -- Sticky bit (rounding) size_res : UNRESOLVED_float; -- used for sizing only constant round_style : round_type := float_round_style; -- rounding option constant denormalize : BOOLEAN := float_denormalize; -- Use IEEE extended FP constant nguard : NATURAL := float_guard_bits) -- guard bits return UNRESOLVED_float; -- overloaded versions function "+" (l : UNRESOLVED_float; r : REAL) return UNRESOLVED_float; function "+" (l : REAL; r : UNRESOLVED_float) return UNRESOLVED_float; function "+" (l : UNRESOLVED_float; r : INTEGER) return UNRESOLVED_float; function "+" (l : INTEGER; r : UNRESOLVED_float) return UNRESOLVED_float; function "-" (l : UNRESOLVED_float; r : REAL) return UNRESOLVED_float; function "-" (l : REAL; r : UNRESOLVED_float) return UNRESOLVED_float; function "-" (l : UNRESOLVED_float; r : INTEGER) return UNRESOLVED_float; function "-" (l : INTEGER; r : UNRESOLVED_float) return UNRESOLVED_float; function "*" (l : UNRESOLVED_float; r : REAL) return UNRESOLVED_float; function "*" (l : REAL; r : UNRESOLVED_float) return UNRESOLVED_float; function "*" (l : UNRESOLVED_float; r : INTEGER) return UNRESOLVED_float; function "*" (l : INTEGER; r : UNRESOLVED_float) return UNRESOLVED_float; function "/" (l : UNRESOLVED_float; r : REAL) return UNRESOLVED_float; function "/" (l : REAL; r : UNRESOLVED_float) return UNRESOLVED_float; function "/" (l : UNRESOLVED_float; r : INTEGER) return UNRESOLVED_float; function "/" (l : INTEGER; r : UNRESOLVED_float) return UNRESOLVED_float; function "rem" (l : UNRESOLVED_float; r : REAL) return UNRESOLVED_float; function "rem" (l : REAL; r : UNRESOLVED_float) return UNRESOLVED_float; function "rem" (l : UNRESOLVED_float; r : INTEGER) return UNRESOLVED_float; function "rem" (l : INTEGER; r : UNRESOLVED_float) return UNRESOLVED_float; function "mod" (l : UNRESOLVED_float; r : REAL) return UNRESOLVED_float; function "mod" (l : REAL; r : UNRESOLVED_float) return UNRESOLVED_float; function "mod" (l : UNRESOLVED_float; r : INTEGER) return UNRESOLVED_float; function "mod" (l : INTEGER; r : UNRESOLVED_float) return UNRESOLVED_float; -- overloaded compare functions function "=" (l : UNRESOLVED_float; r : REAL) return BOOLEAN; function "/=" (l : UNRESOLVED_float; r : REAL) return BOOLEAN; function ">=" (l : UNRESOLVED_float; r : REAL) return BOOLEAN; function "<=" (l : UNRESOLVED_float; r : REAL) return BOOLEAN; function ">" (l : UNRESOLVED_float; r : REAL) return BOOLEAN; function "<" (l : UNRESOLVED_float; r : REAL) return BOOLEAN; function "=" (l : REAL; r : UNRESOLVED_float) return BOOLEAN; function "/=" (l : REAL; r : UNRESOLVED_float) return BOOLEAN; function ">=" (l : REAL; r : UNRESOLVED_float) return BOOLEAN; function "<=" (l : REAL; r : UNRESOLVED_float) return BOOLEAN; function ">" (l : REAL; r : UNRESOLVED_float) return BOOLEAN; function "<" (l : REAL; r : UNRESOLVED_float) return BOOLEAN; function "=" (l : UNRESOLVED_float; r : INTEGER) return BOOLEAN; function "/=" (l : UNRESOLVED_float; r : INTEGER) return BOOLEAN; function ">=" (l : UNRESOLVED_float; r : INTEGER) return BOOLEAN; function "<=" (l : UNRESOLVED_float; r : INTEGER) return BOOLEAN; function ">" (l : UNRESOLVED_float; r : INTEGER) return BOOLEAN; function "<" (l : UNRESOLVED_float; r : INTEGER) return BOOLEAN; function "=" (l : INTEGER; r : UNRESOLVED_float) return BOOLEAN; function "/=" (l : INTEGER; r : UNRESOLVED_float) return BOOLEAN; function ">=" (l : INTEGER; r : UNRESOLVED_float) return BOOLEAN; function "<=" (l : INTEGER; r : UNRESOLVED_float) return BOOLEAN; function ">" (l : INTEGER; r : UNRESOLVED_float) return BOOLEAN; function "<" (l : INTEGER; r : UNRESOLVED_float) return BOOLEAN; function \?=\ (l : UNRESOLVED_float; r : REAL) return STD_ULOGIC; function \?/=\ (l : UNRESOLVED_float; r : REAL) return STD_ULOGIC; function \?>\ (l : UNRESOLVED_float; r : REAL) return STD_ULOGIC; function \?>=\ (l : UNRESOLVED_float; r : REAL) return STD_ULOGIC; function \?<\ (l : UNRESOLVED_float; r : REAL) return STD_ULOGIC; function \?<=\ (l : UNRESOLVED_float; r : REAL) return STD_ULOGIC; function \?=\ (l : REAL; r : UNRESOLVED_float) return STD_ULOGIC; function \?/=\ (l : REAL; r : UNRESOLVED_float) return STD_ULOGIC; function \?>\ (l : REAL; r : UNRESOLVED_float) return STD_ULOGIC; function \?>=\ (l : REAL; r : UNRESOLVED_float) return STD_ULOGIC; function \?<\ (l : REAL; r : UNRESOLVED_float) return STD_ULOGIC; function \?<=\ (l : REAL; r : UNRESOLVED_float) return STD_ULOGIC; function \?=\ (l : UNRESOLVED_float; r : INTEGER) return STD_ULOGIC; function \?/=\ (l : UNRESOLVED_float; r : INTEGER) return STD_ULOGIC; function \?>\ (l : UNRESOLVED_float; r : INTEGER) return STD_ULOGIC; function \?>=\ (l : UNRESOLVED_float; r : INTEGER) return STD_ULOGIC; function \?<\ (l : UNRESOLVED_float; r : INTEGER) return STD_ULOGIC; function \?<=\ (l : UNRESOLVED_float; r : INTEGER) return STD_ULOGIC; function \?=\ (l : INTEGER; r : UNRESOLVED_float) return STD_ULOGIC; function \?/=\ (l : INTEGER; r : UNRESOLVED_float) return STD_ULOGIC; function \?>\ (l : INTEGER; r : UNRESOLVED_float) return STD_ULOGIC; function \?>=\ (l : INTEGER; r : UNRESOLVED_float) return STD_ULOGIC; function \?<\ (l : INTEGER; r : UNRESOLVED_float) return STD_ULOGIC; function \?<=\ (l : INTEGER; r : UNRESOLVED_float) return STD_ULOGIC; -- minimum and maximum overloads function maximum (l : UNRESOLVED_float; r : REAL) return UNRESOLVED_float; function minimum (l : UNRESOLVED_float; r : REAL) return UNRESOLVED_float; function maximum (l : REAL; r : UNRESOLVED_float) return UNRESOLVED_float; function minimum (l : REAL; r : UNRESOLVED_float) return UNRESOLVED_float; function maximum (l : UNRESOLVED_float; r : INTEGER) return UNRESOLVED_float; function minimum (l : UNRESOLVED_float; r : INTEGER) return UNRESOLVED_float; function maximum (l : INTEGER; r : UNRESOLVED_float) return UNRESOLVED_float; function minimum (l : INTEGER; r : UNRESOLVED_float) return UNRESOLVED_float; ---------------------------------------------------------------------------- -- logical functions ---------------------------------------------------------------------------- function "not" (l : UNRESOLVED_float) return UNRESOLVED_float; function "and" (l, r : UNRESOLVED_float) return UNRESOLVED_float; function "or" (l, r : UNRESOLVED_float) return UNRESOLVED_float; function "nand" (l, r : UNRESOLVED_float) return UNRESOLVED_float; function "nor" (l, r : UNRESOLVED_float) return UNRESOLVED_float; function "xor" (l, r : UNRESOLVED_float) return UNRESOLVED_float; function "xnor" (l, r : UNRESOLVED_float) return UNRESOLVED_float; -- Vector and std_ulogic functions, same as functions in numeric_std function "and" (l : STD_ULOGIC; r : UNRESOLVED_float) return UNRESOLVED_float; function "and" (l : UNRESOLVED_float; r : STD_ULOGIC) return UNRESOLVED_float; function "or" (l : STD_ULOGIC; r : UNRESOLVED_float) return UNRESOLVED_float; function "or" (l : UNRESOLVED_float; r : STD_ULOGIC) return UNRESOLVED_float; function "nand" (l : STD_ULOGIC; r : UNRESOLVED_float) return UNRESOLVED_float; function "nand" (l : UNRESOLVED_float; r : STD_ULOGIC) return UNRESOLVED_float; function "nor" (l : STD_ULOGIC; r : UNRESOLVED_float) return UNRESOLVED_float; function "nor" (l : UNRESOLVED_float; r : STD_ULOGIC) return UNRESOLVED_float; function "xor" (l : STD_ULOGIC; r : UNRESOLVED_float) return UNRESOLVED_float; function "xor" (l : UNRESOLVED_float; r : STD_ULOGIC) return UNRESOLVED_float; function "xnor" (l : STD_ULOGIC; r : UNRESOLVED_float) return UNRESOLVED_float; function "xnor" (l : UNRESOLVED_float; r : STD_ULOGIC) return UNRESOLVED_float; -- Reduction operators, same as numeric_std functions function and_reduce (l : UNRESOLVED_float) return STD_ULOGIC; function nand_reduce (l : UNRESOLVED_float) return STD_ULOGIC; function or_reduce (l : UNRESOLVED_float) return STD_ULOGIC; function nor_reduce (l : UNRESOLVED_float) return STD_ULOGIC; function xor_reduce (l : UNRESOLVED_float) return STD_ULOGIC; function xnor_reduce (l : UNRESOLVED_float) return STD_ULOGIC; -- Note: "sla", "sra", "sll", "slr", "rol" and "ror" not implemented. ----------------------------------------------------------------------------- -- Recommended Functions from the IEEE 754 Appendix ----------------------------------------------------------------------------- -- returns x with the sign of y. function Copysign (x, y : UNRESOLVED_float) return UNRESOLVED_float; -- Returns y * 2**n for integral values of N without computing 2**n function Scalb ( y : UNRESOLVED_float; -- floating point input N : INTEGER; -- exponent to add constant round_style : round_type := float_round_style; -- rounding option constant check_error : BOOLEAN := float_check_error; -- check for errors constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP return UNRESOLVED_float; -- Returns y * 2**n for integral values of N without computing 2**n function Scalb ( y : UNRESOLVED_float; -- floating point input N : SIGNED; -- exponent to add constant round_style : round_type := float_round_style; -- rounding option constant check_error : BOOLEAN := float_check_error; -- check for errors constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP return UNRESOLVED_float; -- returns the unbiased exponent of x function Logb (x : UNRESOLVED_float) return INTEGER; function Logb (x : UNRESOLVED_float) return SIGNED; -- returns the next representable neighbor of x in the direction toward y function Nextafter ( x, y : UNRESOLVED_float; -- floating point input constant check_error : BOOLEAN := float_check_error; -- check for errors constant denormalize : BOOLEAN := float_denormalize) return UNRESOLVED_float; -- Returns TRUE if X is unordered with Y. function Unordered (x, y : UNRESOLVED_float) return BOOLEAN; function Finite (x : UNRESOLVED_float) return BOOLEAN; function Isnan (x : UNRESOLVED_float) return BOOLEAN; -- Function to return constants. function zerofp ( constant exponent_width : NATURAL := float_exponent_width; -- exponent constant fraction_width : NATURAL := float_fraction_width) -- fraction return UNRESOLVED_float; function nanfp ( constant exponent_width : NATURAL := float_exponent_width; -- exponent constant fraction_width : NATURAL := float_fraction_width) -- fraction return UNRESOLVED_float; function qnanfp ( constant exponent_width : NATURAL := float_exponent_width; -- exponent constant fraction_width : NATURAL := float_fraction_width) -- fraction return UNRESOLVED_float; function pos_inffp ( constant exponent_width : NATURAL := float_exponent_width; -- exponent constant fraction_width : NATURAL := float_fraction_width) -- fraction return UNRESOLVED_float; function neg_inffp ( constant exponent_width : NATURAL := float_exponent_width; -- exponent constant fraction_width : NATURAL := float_fraction_width) -- fraction return UNRESOLVED_float; function neg_zerofp ( constant exponent_width : NATURAL := float_exponent_width; -- exponent constant fraction_width : NATURAL := float_fraction_width) -- fraction return UNRESOLVED_float; -- size_res versions function zerofp ( size_res : UNRESOLVED_float) -- variable is only use for sizing return UNRESOLVED_float; function nanfp ( size_res : UNRESOLVED_float) -- variable is only use for sizing return UNRESOLVED_float; function qnanfp ( size_res : UNRESOLVED_float) -- variable is only use for sizing return UNRESOLVED_float; function pos_inffp ( size_res : UNRESOLVED_float) -- variable is only use for sizing return UNRESOLVED_float; function neg_inffp ( size_res : UNRESOLVED_float) -- variable is only use for sizing return UNRESOLVED_float; function neg_zerofp ( size_res : UNRESOLVED_float) -- variable is only use for sizing return UNRESOLVED_float; -- =========================================================================== -- string and textio Functions -- =========================================================================== -- rtl_synthesis off -- pragma synthesis_off -- writes S:EEEE:FFFFFFFF procedure WRITE ( L : inout LINE; -- access type (pointer) VALUE : in UNRESOLVED_float; -- value to write JUSTIFIED : in SIDE := right; -- which side to justify text FIELD : in WIDTH := 0); -- width of field -- Reads SEEEEFFFFFFFF, "." and ":" are ignored procedure READ (L : inout LINE; VALUE : out UNRESOLVED_float); procedure READ (L : inout LINE; VALUE : out UNRESOLVED_float; GOOD : out BOOLEAN); alias BREAD is READ [LINE, UNRESOLVED_float, BOOLEAN]; alias BREAD is READ [LINE, UNRESOLVED_float]; alias BWRITE is WRITE [LINE, UNRESOLVED_float, SIDE, WIDTH]; alias BINARY_READ is READ [LINE, UNRESOLVED_FLOAT, BOOLEAN]; alias BINARY_READ is READ [LINE, UNRESOLVED_FLOAT]; alias BINARY_WRITE is WRITE [LINE, UNRESOLVED_float, SIDE, WIDTH]; procedure OWRITE ( L : inout LINE; -- access type (pointer) VALUE : in UNRESOLVED_float; -- value to write JUSTIFIED : in SIDE := right; -- which side to justify text FIELD : in WIDTH := 0); -- width of field -- Octal read with padding, no separators used procedure OREAD (L : inout LINE; VALUE : out UNRESOLVED_float); procedure OREAD (L : inout LINE; VALUE : out UNRESOLVED_float; GOOD : out BOOLEAN); alias OCTAL_READ is OREAD [LINE, UNRESOLVED_FLOAT, BOOLEAN]; alias OCTAL_READ is OREAD [LINE, UNRESOLVED_FLOAT]; alias OCTAL_WRITE is OWRITE [LINE, UNRESOLVED_FLOAT, SIDE, WIDTH]; -- Hex write with padding, no separators procedure HWRITE ( L : inout LINE; -- access type (pointer) VALUE : in UNRESOLVED_float; -- value to write JUSTIFIED : in SIDE := right; -- which side to justify text FIELD : in WIDTH := 0); -- width of field -- Hex read with padding, no separators used procedure HREAD (L : inout LINE; VALUE : out UNRESOLVED_float); procedure HREAD (L : inout LINE; VALUE : out UNRESOLVED_float; GOOD : out BOOLEAN); alias HEX_READ is HREAD [LINE, UNRESOLVED_FLOAT, BOOLEAN]; alias HEX_READ is HREAD [LINE, UNRESOLVED_FLOAT]; alias HEX_WRITE is HWRITE [LINE, UNRESOLVED_FLOAT, SIDE, WIDTH]; -- returns "S:EEEE:FFFFFFFF" function to_string (value : UNRESOLVED_float) return STRING; alias TO_BSTRING is TO_STRING [UNRESOLVED_FLOAT return STRING]; alias TO_BINARY_STRING is TO_STRING [UNRESOLVED_FLOAT return STRING]; -- Returns a HEX string, with padding function to_hstring (value : UNRESOLVED_float) return STRING; alias TO_HEX_STRING is TO_HSTRING [UNRESOLVED_FLOAT return STRING]; -- Returns and octal string, with padding function to_ostring (value : UNRESOLVED_float) return STRING; alias TO_OCTAL_STRING is TO_OSTRING [UNRESOLVED_FLOAT return STRING]; function from_string ( bstring : STRING; -- binary string constant exponent_width : NATURAL := float_exponent_width; constant fraction_width : NATURAL := float_fraction_width) return UNRESOLVED_float; alias from_bstring is from_string [STRING, NATURAL, NATURAL return UNRESOLVED_float]; alias from_binary_string is from_string [STRING, NATURAL, NATURAL return UNRESOLVED_float]; function from_ostring ( ostring : STRING; -- Octal string constant exponent_width : NATURAL := float_exponent_width; constant fraction_width : NATURAL := float_fraction_width) return UNRESOLVED_float; alias from_octal_string is from_ostring [STRING, NATURAL, NATURAL return UNRESOLVED_float]; function from_hstring ( hstring : STRING; -- hex string constant exponent_width : NATURAL := float_exponent_width; constant fraction_width : NATURAL := float_fraction_width) return UNRESOLVED_float; alias from_hex_string is from_hstring [STRING, NATURAL, NATURAL return UNRESOLVED_float]; function from_string ( bstring : STRING; -- binary string size_res : UNRESOLVED_float) -- used for sizing only return UNRESOLVED_float; alias from_bstring is from_string [STRING, UNRESOLVED_float return UNRESOLVED_float]; alias from_binary_string is from_string [STRING, UNRESOLVED_float return UNRESOLVED_float]; function from_ostring ( ostring : STRING; -- Octal string size_res : UNRESOLVED_float) -- used for sizing only return UNRESOLVED_float; alias from_octal_string is from_ostring [STRING, UNRESOLVED_float return UNRESOLVED_float]; function from_hstring ( hstring : STRING; -- hex string size_res : UNRESOLVED_float) -- used for sizing only return UNRESOLVED_float; alias from_hex_string is from_hstring [STRING, UNRESOLVED_float return UNRESOLVED_float]; -- rtl_synthesis on -- pragma synthesis_on -- IN VHDL-2006 std_logic_vector is a subtype of std_ulogic_vector, so these -- extra functions are needed for compatability. function to_float ( arg : STD_LOGIC_VECTOR; constant exponent_width : NATURAL := float_exponent_width; -- length of FP output exponent constant fraction_width : NATURAL := float_fraction_width) -- length of FP output fraction return UNRESOLVED_float; function to_float ( arg : STD_LOGIC_VECTOR; size_res : UNRESOLVED_float) return UNRESOLVED_float; end package float_pkg; ------------------------------------------------------------------------------- -- Proposed package body for the VHDL-200x-FT float_pkg package -- This version is optimized for Synthesis, and not for simulation. -- Note that there are functional differences between the synthesis and -- simulation packages bodies. The Synthesis version is preferred. -- This package body supplies a recommended implementation of these functions -- Version : $Revision: 1.14 $ -- Date : $Date: 2007-06-19 10:20:43-04 $ -- -- Created for VHDL-200X par, David Bishop (dbishop@vhdl.org) ------------------------------------------------------------------------------- package body float_pkg is -- Author David Bishop (dbishop@vhdl.org) ----------------------------------------------------------------------------- -- type declarations ----------------------------------------------------------------------------- -- This deferred constant will tell you if the package body is synthesizable -- or implemented as real numbers, set to "true" if synthesizable. constant fphdlsynth_or_real : BOOLEAN := true; -- deferred constant -- types of boundary conditions type boundary_type is (normal, infinity, zero, denormal); -- null range array constant constant NAFP : UNRESOLVED_float (0 downto 1) := (others => '0'); constant NSLV : STD_ULOGIC_VECTOR (0 downto 1) := (others => '0'); -- %%% Replicated functions -- These funcitons are replicated so that we don't need to reference the new -- 2006 package std.standard, std_logic_1164 and numeric_std. function maximum ( l, r : INTEGER) -- inputs return INTEGER is begin -- function max if l > r then return l; else return r; end if; end function maximum; function minimum ( l, r : INTEGER) -- inputs return INTEGER is begin -- function min if l > r then return r; else return l; end if; end function minimum; function or_reduce (arg : STD_ULOGIC_VECTOR) return STD_LOGIC is variable Upper, Lower : STD_ULOGIC; variable Half : INTEGER; variable BUS_int : STD_ULOGIC_VECTOR (arg'length - 1 downto 0); variable Result : STD_ULOGIC; begin if (arg'length < 1) then -- In the case of a NULL range Result := '0'; else BUS_int := to_ux01 (arg); if (BUS_int'length = 1) then Result := BUS_int (BUS_int'left); elsif (BUS_int'length = 2) then Result := BUS_int (BUS_int'right) or BUS_int (BUS_int'left); else Half := (BUS_int'length + 1) / 2 + BUS_int'right; Upper := or_reduce (BUS_int (BUS_int'left downto Half)); Lower := or_reduce (BUS_int (Half - 1 downto BUS_int'right)); Result := Upper or Lower; end if; end if; return Result; end function or_reduce; function or_reduce (arg : UNSIGNED) return STD_ULOGIC is begin return or_reduce (STD_ULOGIC_VECTOR (arg)); end function or_reduce; function or_reduce (arg : SIGNED) return STD_ULOGIC is begin return or_reduce (STD_ULOGIC_VECTOR (arg)); end function or_reduce; function or_reduce (arg : STD_LOGIC_VECTOR) return STD_ULOGIC is begin return or_reduce (STD_ULOGIC_VECTOR (arg)); end function or_reduce; -- purpose: AND all of the bits in a vector together -- This is a copy of the proposed "and_reduce" from 1076.3 function and_reduce (arg : STD_ULOGIC_VECTOR) return STD_LOGIC is variable Upper, Lower : STD_ULOGIC; variable Half : INTEGER; variable BUS_int : STD_ULOGIC_VECTOR (arg'length - 1 downto 0); variable Result : STD_ULOGIC; begin if (arg'length < 1) then -- In the case of a NULL range Result := '1'; else BUS_int := to_ux01 (arg); if (BUS_int'length = 1) then Result := BUS_int (BUS_int'left); elsif (BUS_int'length = 2) then Result := BUS_int (BUS_int'right) and BUS_int (BUS_int'left); else Half := (BUS_int'length + 1) / 2 + BUS_int'right; Upper := and_reduce (BUS_int (BUS_int'left downto Half)); Lower := and_reduce (BUS_int (Half - 1 downto BUS_int'right)); Result := Upper and Lower; end if; end if; return Result; end function and_reduce; function and_reduce (arg : UNSIGNED) return STD_ULOGIC is begin return and_reduce (STD_ULOGIC_VECTOR (arg)); end function and_reduce; function and_reduce (arg : SIGNED) return STD_ULOGIC is begin return and_reduce (STD_ULOGIC_VECTOR (arg)); end function and_reduce; function xor_reduce (arg : STD_ULOGIC_VECTOR) return STD_ULOGIC is variable Upper, Lower : STD_ULOGIC; variable Half : INTEGER; variable BUS_int : STD_ULOGIC_VECTOR (arg'length - 1 downto 0); variable Result : STD_ULOGIC := '0'; -- In the case of a NULL range begin if (arg'length >= 1) then BUS_int := to_ux01 (arg); if (BUS_int'length = 1) then Result := BUS_int (BUS_int'left); elsif (BUS_int'length = 2) then Result := BUS_int(BUS_int'right) xor BUS_int(BUS_int'left); else Half := (BUS_int'length + 1) / 2 + BUS_int'right; Upper := xor_reduce (BUS_int (BUS_int'left downto Half)); Lower := xor_reduce (BUS_int (Half - 1 downto BUS_int'right)); Result := Upper xor Lower; end if; end if; return Result; end function xor_reduce; function nand_reduce(arg : STD_ULOGIC_VECTOR) return STD_ULOGIC is begin return not and_reduce (arg); end function nand_reduce; function nor_reduce(arg : STD_ULOGIC_VECTOR) return STD_ULOGIC is begin return not or_reduce (arg); end function nor_reduce; function xnor_reduce(arg : STD_ULOGIC_VECTOR) return STD_ULOGIC is begin return not xor_reduce (arg); end function xnor_reduce; function find_leftmost (ARG : UNSIGNED; Y : STD_ULOGIC) return INTEGER is begin for INDEX in ARG'range loop if ARG(INDEX) = Y then return INDEX; end if; end loop; return -1; end function find_leftmost; -- Match table, copied form new std_logic_1164 type stdlogic_table is array(STD_ULOGIC, STD_ULOGIC) of STD_ULOGIC; constant match_logic_table : stdlogic_table := ( ----------------------------------------------------- -- U X 0 1 Z W L H - | | ----------------------------------------------------- ('U', 'U', 'U', 'U', 'U', 'U', 'U', 'U', '1'), -- | U | ('U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', '1'), -- | X | ('U', 'X', '1', '0', 'X', 'X', '1', '0', '1'), -- | 0 | ('U', 'X', '0', '1', 'X', 'X', '0', '1', '1'), -- | 1 | ('U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', '1'), -- | Z | ('U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', '1'), -- | W | ('U', 'X', '1', '0', 'X', 'X', '1', '0', '1'), -- | L | ('U', 'X', '0', '1', 'X', 'X', '0', '1', '1'), -- | H | ('1', '1', '1', '1', '1', '1', '1', '1', '1') -- | - | ); constant no_match_logic_table : stdlogic_table := ( ----------------------------------------------------- -- U X 0 1 Z W L H - | | ----------------------------------------------------- ('U', 'U', 'U', 'U', 'U', 'U', 'U', 'U', '0'), -- | U | ('U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', '0'), -- | X | ('U', 'X', '0', '1', 'X', 'X', '0', '1', '0'), -- | 0 | ('U', 'X', '1', '0', 'X', 'X', '1', '0', '0'), -- | 1 | ('U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', '0'), -- | Z | ('U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', '0'), -- | W | ('U', 'X', '0', '1', 'X', 'X', '0', '1', '0'), -- | L | ('U', 'X', '1', '0', 'X', 'X', '1', '0', '0'), -- | H | ('0', '0', '0', '0', '0', '0', '0', '0', '0') -- | - | ); ------------------------------------------------------------------- -- ?= functions, Similar to "std_match", but returns "std_ulogic". ------------------------------------------------------------------- -- %%% FUNCTION "?=" ( l, r : std_ulogic ) RETURN std_ulogic IS function \?=\ (l, r : STD_ULOGIC) return STD_ULOGIC is begin return match_logic_table (l, r); end function \?=\; -- %%% END FUNCTION "?="; -- %%% FUNCTION "?/=" ( l, r : std_ulogic ) RETURN std_ulogic is function \?/=\ (l, r : STD_ULOGIC) return STD_ULOGIC is begin return no_match_logic_table (l, r); end function \?/=\; -- %%% END FUNCTION "?/="; function \?=\ (l, r : STD_ULOGIC_VECTOR) return STD_ULOGIC is begin return \?=\ (ufixed(l), ufixed(r)); end function \?=\; function Is_X (s : UNSIGNED) return BOOLEAN is begin return Is_X (STD_LOGIC_VECTOR (s)); end function Is_X; function Is_X (s : SIGNED) return BOOLEAN is begin return Is_X (STD_LOGIC_VECTOR (s)); end function Is_X; -- %%% END replicated functions -- Special version of "minimum" to do some boundary checking function mine (L, R : INTEGER) return INTEGER is begin -- function minimum if (L = INTEGER'low or R = INTEGER'low) then report float_pkg'instance_name & " Unbounded number passed, was a literal used?" severity error; return 0; end if; return minimum (L, R); end function mine; -- Generates the base number for the exponent normalization offset. function gen_expon_base ( constant exponent_width : NATURAL) return SIGNED is variable result : SIGNED (exponent_width-1 downto 0); begin result := (others => '1'); result (exponent_width-1) := '0'; return result; end function gen_expon_base; -- Integer version of the "log2" command (contributed by Peter Ashenden) function log2 (A : NATURAL) return NATURAL is variable quotient : NATURAL; variable result : NATURAL := 0; begin quotient := A / 2; while quotient > 0 loop quotient := quotient / 2; result := result + 1; end loop; return result; end function log2; -- Function similar to the ILOGB function in MATH_REAL function log2 (A : REAL) return INTEGER is variable Y : REAL; variable N : INTEGER := 0; begin if (A = 1.0 or A = 0.0) then return 0; end if; Y := A; if(A > 1.0) then while Y >= 2.0 loop Y := Y / 2.0; N := N + 1; end loop; return N; end if; -- O < Y < 1 while Y < 1.0 loop Y := Y * 2.0; N := N - 1; end loop; return N; end function log2; -- purpose: Test the boundary conditions of a Real number procedure test_boundary ( arg : in REAL; -- Input, converted to real constant fraction_width : in NATURAL; -- length of FP output fraction constant exponent_width : in NATURAL; -- length of FP exponent constant denormalize : in BOOLEAN := true; -- Use IEEE extended FP variable btype : out boundary_type; variable log2i : out INTEGER ) is constant expon_base : SIGNED (exponent_width-1 downto 0) := gen_expon_base(exponent_width); -- exponent offset constant exp_min : SIGNED (12 downto 0) := -(resize(expon_base, 13)) + 1; -- Minimum normal exponent constant exp_ext_min : SIGNED (12 downto 0) := exp_min - fraction_width; -- Minimum for denormal exponent variable log2arg : INTEGER; -- log2 of argument begin -- function test_boundary -- Check to see if the exponent is big enough -- Note that the argument is always an absolute value at this point. log2arg := log2(arg); if arg = 0.0 then btype := zero; elsif exponent_width > 11 then -- Exponent for Real is 11 (64 bit) btype := normal; else if log2arg < to_integer(exp_min) then if denormalize then if log2arg < to_integer(exp_ext_min) then btype := zero; else btype := denormal; end if; else if log2arg < to_integer(exp_min)-1 then btype := zero; else btype := normal; -- Can still represent this number end if; end if; elsif exponent_width < 11 then if log2arg > to_integer(expon_base)+1 then btype := infinity; else btype := normal; end if; else btype := normal; end if; end if; log2i := log2arg; end procedure test_boundary; -- purpose: Rounds depending on the state of the "round_style" -- Logic taken from -- "What Every Computer Scientist Should Know About Floating Point Arithmetic" -- by David Goldberg (1991) function check_round ( fract_in : STD_ULOGIC; -- input fraction sign : STD_ULOGIC; -- sign bit remainder : UNSIGNED; -- remainder to round from sticky : STD_ULOGIC := '0'; -- Sticky bit constant round_style : round_type) -- rounding type return BOOLEAN is variable result : BOOLEAN; variable or_reduced : STD_ULOGIC; begin -- function check_round result := false; if (remainder'length > 0) then -- if remainder in a null array or_reduced := or_reduce (remainder & sticky); rounding_case : case round_style is when round_nearest => -- Round Nearest, default mode if remainder(remainder'high) = '1' then -- round if (remainder'length > 1) then if ((or_reduce (remainder(remainder'high-1 downto remainder'low)) = '1' or sticky = '1') or fract_in = '1') then -- Make the bottom bit zero if possible if we are at 1/2 result := true; end if; else result := (fract_in = '1' or sticky = '1'); end if; end if; when round_inf => -- round up if positive, else truncate. if or_reduced = '1' and sign = '0' then result := true; end if; when round_neginf => -- round down if negative, else truncate. if or_reduced = '1' and sign = '1' then result := true; end if; when round_zero => -- round toward 0 Truncate null; end case rounding_case; end if; return result; end function check_round; -- purpose: Rounds depending on the state of the "round_style" -- unsigned version procedure fp_round ( fract_in : in UNSIGNED; -- input fraction expon_in : in SIGNED; -- input exponent fract_out : out UNSIGNED; -- output fraction expon_out : out SIGNED) is -- output exponent begin -- procedure fp_round if and_reduce (fract_in) = '1' then -- Fraction is all "1" expon_out := expon_in + 1; fract_out := to_unsigned(0, fract_out'high+1); else expon_out := expon_in; fract_out := fract_in + 1; end if; end procedure fp_round; -- This version of break_number doesn't call "classfp" procedure break_number ( -- internal version arg : in UNRESOLVED_float; fptyp : in valid_fpstate; denormalize : in BOOLEAN := true; fract : out UNSIGNED; expon : out SIGNED) is constant fraction_width : NATURAL := -arg'low; -- length of FP output fraction constant exponent_width : NATURAL := arg'high; -- length of FP output exponent constant expon_base : SIGNED (exponent_width-1 downto 0) := gen_expon_base(exponent_width); -- exponent offset variable exp : SIGNED (expon'range); begin fract (fraction_width-1 downto 0) := UNSIGNED (to_slv(arg(-1 downto -fraction_width))); breakcase : case fptyp is when pos_zero | neg_zero => fract (fraction_width) := '0'; exp := -expon_base; when pos_denormal | neg_denormal => if denormalize then exp := -expon_base; fract (fraction_width) := '0'; else exp := -expon_base - 1; fract (fraction_width) := '1'; end if; when pos_normal | neg_normal | pos_inf | neg_inf => fract (fraction_width) := '1'; exp := SIGNED(arg(exponent_width-1 downto 0)); exp (exponent_width-1) := not exp(exponent_width-1); when others => assert NO_WARNING report float_pkg'instance_name & "BREAK_NUMBER: " & "Meta state detected in fp_break_number process" severity warning; -- complete the case, if a NAN goes in, a NAN comes out. exp := (others => '1'); fract (fraction_width) := '1'; end case breakcase; expon := exp; end procedure break_number; -- purpose: floating point to UNSIGNED -- Used by to_integer, to_unsigned, and to_signed functions procedure float_to_unsigned ( arg : in UNRESOLVED_float; -- floating point input variable sign : out STD_ULOGIC; -- sign of output variable frac : out UNSIGNED; -- unsigned biased output constant denormalize : in BOOLEAN; -- turn on denormalization constant bias : in NATURAL; -- bias for fixed point constant round_style : in round_type) is -- rounding method constant fraction_width : INTEGER := -mine(arg'low, arg'low); -- length of FP output fraction constant exponent_width : INTEGER := arg'high; -- length of FP output exponent variable fract : UNSIGNED (frac'range); -- internal version of frac variable isign : STD_ULOGIC; -- internal version of sign variable exp : INTEGER; -- Exponent variable expon : SIGNED (exponent_width-1 downto 0); -- Vectorized exp -- Base to divide fraction by variable frac_shift : UNSIGNED (frac'high+3 downto 0); -- Fraction shifted variable shift : INTEGER; variable remainder : UNSIGNED (2 downto 0); variable round : STD_ULOGIC; -- round BIT begin isign := to_x01(arg(arg'high)); -- exponent /= '0', normal floating point expon := to_01(SIGNED(arg (exponent_width-1 downto 0)), 'X'); expon(exponent_width-1) := not expon(exponent_width-1); exp := to_integer (expon); -- Figure out the fraction fract := (others => '0'); -- fill with zero fract (fract'high) := '1'; -- Add the "1.0". shift := (fract'high-1) - exp; if fraction_width > fract'high then -- Can only use size-2 bits fract (fract'high-1 downto 0) := UNSIGNED (to_slv (arg(-1 downto -fract'high))); else -- can use all bits fract (fract'high-1 downto fract'high-fraction_width) := UNSIGNED (to_slv (arg(-1 downto -fraction_width))); end if; frac_shift := fract & "000"; if shift < 0 then -- Overflow fract := (others => '1'); else frac_shift := shift_right (frac_shift, shift); fract := frac_shift (frac_shift'high downto 3); remainder := frac_shift (2 downto 0); -- round (round_zero will bypass this and truncate) case round_style is when round_nearest => round := remainder(2) and (fract (0) or (or_reduce (remainder (1 downto 0)))); when round_inf => round := remainder(2) and not isign; when round_neginf => round := remainder(2) and isign; when others => round := '0'; end case; if round = '1' then fract := fract + 1; end if; end if; frac := fract; sign := isign; end procedure float_to_unsigned; -- purpose: returns a part of a vector, this function is here because -- or (fractr (to_integer(shiftx) downto 0)); -- can't be synthesized in some synthesis tools. function smallfract ( arg : UNSIGNED; shift : NATURAL) return STD_ULOGIC is variable orx : STD_ULOGIC; begin orx := arg(shift); for i in arg'range loop if i < shift then orx := arg(i) or orx; end if; end loop; return orx; end function smallfract; --------------------------------------------------------------------------- -- Visible functions --------------------------------------------------------------------------- -- purpose: converts the negative index to a positive one -- negative indices are illegal in 1164 and 1076.3 function to_suv ( arg : UNRESOLVED_float) -- fp vector return STD_ULOGIC_VECTOR is variable result : STD_ULOGIC_VECTOR (arg'length-1 downto 0); begin -- function to_std_ulogic_vector if arg'length < 1 then return NSLV; end if; result := STD_ULOGIC_VECTOR (arg); return result; end function to_suv; -- Converts an fp into an SULV function to_slv (arg : UNRESOLVED_float) return STD_LOGIC_VECTOR is begin return to_stdlogicvector (to_suv (arg)); end function to_slv; -- purpose: normalizes a floating point number -- This version assumes an "unsigned" input with function normalize ( fract : UNSIGNED; -- fraction, unnormalized expon : SIGNED; -- exponent, normalized by -1 sign : STD_ULOGIC; -- sign BIT sticky : STD_ULOGIC := '0'; -- Sticky bit (rounding) constant exponent_width : NATURAL := float_exponent_width; -- size of output exponent constant fraction_width : NATURAL := float_fraction_width; -- size of output fraction constant round_style : round_type := float_round_style; -- rounding option constant denormalize : BOOLEAN := float_denormalize; -- Use IEEE extended FP constant nguard : NATURAL := float_guard_bits) -- guard bits return UNRESOLVED_float is variable sfract : UNSIGNED (fract'high downto 0); -- shifted fraction variable rfract : UNSIGNED (fraction_width-1 downto 0); -- fraction variable exp : SIGNED (exponent_width+1 downto 0); -- exponent variable rexp : SIGNED (exponent_width+1 downto 0); -- result exponent variable rexpon : UNSIGNED (exponent_width-1 downto 0); -- exponent variable result : UNRESOLVED_float (exponent_width downto -fraction_width); -- result variable shiftr : INTEGER; -- shift amount constant expon_base : SIGNED (exponent_width-1 downto 0) := gen_expon_base(exponent_width); -- exponent offset variable round : BOOLEAN; begin -- function normalize result (exponent_width) := sign; -- sign bit round := false; shiftr := find_leftmost (to_01(fract), '1') -- Find the first "1" - fraction_width - nguard; -- subtract the length we want exp := resize (expon, exp'length) + shiftr; if (or_reduce (fract) = '0') then -- Zero result := zerofp (fraction_width => fraction_width, exponent_width => exponent_width); elsif ((exp <= -resize(expon_base, exp'length)-1) and denormalize) or ((exp < -resize(expon_base, exp'length)-1) and not denormalize) then if (exp >= -resize(expon_base, exp'length)-fraction_width-1) and denormalize then exp := -resize(expon_base, exp'length); shiftr := to_integer (expon + expon_base); -- new shift sfract := fract sll shiftr; -- shift if nguard > 0 then round := check_round ( fract_in => sfract (nguard), sign => sign, remainder => sfract(nguard-1 downto 0), round_style => round_style); end if; if round then fp_round(fract_in => sfract (fraction_width-1+nguard downto nguard), expon_in => exp, fract_out => rfract, expon_out => rexp); else rfract := sfract (fraction_width-1+nguard downto nguard); rexp := exp; end if; rexpon := UNSIGNED ((rexp(exponent_width-1 downto 0))-1); rexpon(exponent_width-1) := not rexpon(exponent_width-1); result (rexpon'range) := UNRESOLVED_float(rexpon); result (-1 downto -fraction_width) := UNRESOLVED_float(rfract); else -- return zero result := zerofp (fraction_width => fraction_width, exponent_width => exponent_width); end if; elsif (exp > expon_base-1) then -- infinity result := pos_inffp (fraction_width => fraction_width, exponent_width => exponent_width); result (exponent_width) := sign; -- redo sign bit for neg inf. else -- normal number sfract := fract srl shiftr; -- shift if nguard > 0 then round := check_round ( fract_in => sfract (nguard), sign => sign, remainder => sfract(nguard-1 downto 0), sticky => sticky, round_style => round_style); end if; if round then fp_round(fract_in => sfract (fraction_width-1+nguard downto nguard), expon_in => exp(rexp'range), fract_out => rfract, expon_out => rexp); else rfract := sfract (fraction_width-1+nguard downto nguard); rexp := exp(rexp'range); end if; -- result rexpon := UNSIGNED (rexp(exponent_width-1 downto 0)); rexpon(exponent_width-1) := not rexpon(exponent_width-1); result (rexpon'range) := UNRESOLVED_float(rexpon); result (-1 downto -fraction_width) := UNRESOLVED_float(rfract); end if; return result; end function normalize; -- purpose: normalizes a floating point number -- This version assumes a "ufixed" input function normalize ( fract : ufixed; -- unsigned fixed point expon : SIGNED; -- exponent, normalized by -1 sign : STD_ULOGIC; -- sign bit sticky : STD_ULOGIC := '0'; -- Sticky bit (rounding) constant exponent_width : NATURAL := float_exponent_width; -- size of output exponent constant fraction_width : NATURAL := float_fraction_width; -- size of output fraction constant round_style : round_type := float_round_style; -- rounding option constant denormalize : BOOLEAN := float_denormalize; -- Use IEEE extended FP constant nguard : NATURAL := float_guard_bits) -- guard bits return UNRESOLVED_float is variable result : UNRESOLVED_float (exponent_width downto -fraction_width); variable arguns : UNSIGNED (fract'high + fraction_width + nguard downto 0) := (others => '0'); begin -- function normalize arguns (arguns'high downto maximum (arguns'high-fract'length+1, 0)) := UNSIGNED (to_slv (fract)); result := normalize (fract => arguns, expon => expon, sign => sign, sticky => sticky, fraction_width => fraction_width, exponent_width => exponent_width, round_style => round_style, denormalize => denormalize, nguard => nguard); return result; end function normalize; -- purpose: normalizes a floating point number -- This version assumes a "ufixed" input with a "size_res" input function normalize ( fract : ufixed; -- unsigned fixed point expon : SIGNED; -- exponent, normalized by -1 sign : STD_ULOGIC; -- sign bit sticky : STD_ULOGIC := '0'; -- Sticky bit (rounding) size_res : UNRESOLVED_float; -- used for sizing only constant round_style : round_type := float_round_style; -- rounding option constant denormalize : BOOLEAN := float_denormalize; -- Use IEEE extended FP constant nguard : NATURAL := float_guard_bits) -- guard bits return UNRESOLVED_float is constant fraction_width : NATURAL := -size_res'low; constant exponent_width : NATURAL := size_res'high; variable result : UNRESOLVED_float (exponent_width downto -fraction_width); variable arguns : UNSIGNED (fract'high + fraction_width + nguard downto 0) := (others => '0'); begin -- function normalize arguns (arguns'high downto maximum (arguns'high-fract'length+1, 0)) := UNSIGNED (to_slv (fract)); result := normalize (fract => arguns, expon => expon, sign => sign, sticky => sticky, fraction_width => fraction_width, exponent_width => exponent_width, round_style => round_style, denormalize => denormalize, nguard => nguard); return result; end function normalize; -- Regular "normalize" function with a "size_res" input. function normalize ( fract : UNSIGNED; -- unsigned expon : SIGNED; -- exponent - 1, normalized sign : STD_ULOGIC; -- sign bit sticky : STD_ULOGIC := '0'; -- Sticky bit (rounding) size_res : UNRESOLVED_float; -- used for sizing only constant round_style : round_type := float_round_style; -- rounding option constant denormalize : BOOLEAN := float_denormalize; -- Use IEEE extended FP constant nguard : NATURAL := float_guard_bits) -- guard bits return UNRESOLVED_float is begin return normalize (fract => fract, expon => expon, sign => sign, sticky => sticky, fraction_width => -size_res'low, exponent_width => size_res'high, round_style => round_style, denormalize => denormalize, nguard => nguard); end function normalize; -- Returns the class which X falls into function Classfp ( x : UNRESOLVED_float; -- floating point input check_error : BOOLEAN := float_check_error) -- check for errors return valid_fpstate is constant fraction_width : INTEGER := -mine(x'low, x'low); -- length of FP output fraction constant exponent_width : INTEGER := x'high; -- length of FP output exponent variable arg : UNRESOLVED_float (exponent_width downto -fraction_width); begin -- classfp if (arg'length < 1 or fraction_width < 3 or exponent_width < 3 or x'left < x'right) then report float_pkg'instance_name & "CLASSFP: " & "Floating point number detected with a bad range" severity error; return isx; end if; -- Check for "X". arg := to_01 (x, 'X'); if (arg(0) = 'X') then return isx; -- If there is an X in the number -- Special cases, check for illegal number elsif check_error and (and_reduce (STD_ULOGIC_VECTOR (arg (exponent_width-1 downto 0))) = '1') then -- Exponent is all "1". if or_reduce (to_slv (arg (-1 downto -fraction_width))) /= '0' then -- Fraction must be all "0" or this is not a number. if (arg(-1) = '1') then -- From "W. Khan - IEEE standard return nan; -- 754 binary FP Signaling nan (Not a number) else return quiet_nan; end if; -- Check for infinity elsif arg(exponent_width) = '0' then return pos_inf; -- Positive infinity else return neg_inf; -- Negative infinity end if; -- check for "0" elsif or_reduce (STD_LOGIC_VECTOR (arg (exponent_width-1 downto 0))) = '0' then -- Exponent is all "0" if or_reduce (to_slv (arg (-1 downto -fraction_width))) = '0' then -- Fraction is all "0" if arg(exponent_width) = '0' then return pos_zero; -- Zero else return neg_zero; end if; else if arg(exponent_width) = '0' then return pos_denormal; -- Denormal number (ieee extended fp) else return neg_denormal; end if; end if; else if arg(exponent_width) = '0' then return pos_normal; -- Normal FP number else return neg_normal; end if; end if; end function Classfp; procedure break_number ( arg : in UNRESOLVED_float; denormalize : in BOOLEAN := float_denormalize; check_error : in BOOLEAN := float_check_error; fract : out UNSIGNED; expon : out SIGNED; sign : out STD_ULOGIC) is constant fraction_width : NATURAL := -mine(arg'low, arg'low); -- length of FP output fraction variable fptyp : valid_fpstate; begin fptyp := Classfp (arg, check_error); sign := to_x01(arg(arg'high)); break_number ( arg => arg, fptyp => fptyp, denormalize => denormalize, fract => fract, expon => expon); end procedure break_number; procedure break_number ( arg : in UNRESOLVED_float; denormalize : in BOOLEAN := float_denormalize; check_error : in BOOLEAN := float_check_error; fract : out ufixed; -- 1 downto -fraction_width expon : out SIGNED; -- exponent_width-1 downto 0 sign : out STD_ULOGIC) is constant fraction_width : NATURAL := -mine(arg'low, arg'low); -- length of FP output fraction variable fptyp : valid_fpstate; variable ufract : UNSIGNED (fraction_width downto 0); -- unsigned fraction begin fptyp := Classfp (arg, check_error); sign := to_x01(arg(arg'high)); break_number ( arg => arg, fptyp => fptyp, denormalize => denormalize, fract => ufract, expon => expon); fract (0 downto -fraction_width) := ufixed (ufract); end procedure break_number; -- Arithmetic functions function "abs" ( arg : UNRESOLVED_float) -- floating point input return UNRESOLVED_float is variable result : UNRESOLVED_float (arg'range); -- result begin if (arg'length > 0) then result := to_01 (arg, 'X'); result (arg'high) := '0'; -- set the sign bit to positive return result; else return NAFP; end if; end function "abs"; -- IEEE 754 "negative" function function "-" ( arg : UNRESOLVED_float) -- floating point input return UNRESOLVED_float is variable result : UNRESOLVED_float (arg'range); -- result begin if (arg'length > 0) then result := to_01 (arg, 'X'); result (arg'high) := not result (arg'high); -- invert sign bit return result; else return NAFP; end if; end function "-"; -- Addition, adds two floating point numbers function add ( l, r : UNRESOLVED_float; -- floating point input constant round_style : round_type := float_round_style; -- rounding option constant guard : NATURAL := float_guard_bits; -- number of guard bits constant check_error : BOOLEAN := float_check_error; -- check for errors constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP return UNRESOLVED_float is constant fraction_width : NATURAL := -mine(l'low, r'low); -- length of FP output fraction constant exponent_width : NATURAL := maximum(l'high, r'high); -- length of FP output exponent constant addguard : NATURAL := guard; -- add one guard bit variable lfptype, rfptype : valid_fpstate; variable fpresult : UNRESOLVED_float (exponent_width downto -fraction_width); variable fractl, fractr : UNSIGNED (fraction_width+1+addguard downto 0); -- fractions variable fractc, fracts : UNSIGNED (fractl'range); -- constant and shifted variables variable urfract, ulfract : UNSIGNED (fraction_width downto 0); variable ufract : UNSIGNED (fraction_width+1+addguard downto 0); variable exponl, exponr : SIGNED (exponent_width-1 downto 0); -- exponents variable rexpon : SIGNED (exponent_width downto 0); -- result exponent variable shiftx : SIGNED (exponent_width downto 0); -- shift fractions variable sign : STD_ULOGIC; -- sign of the output variable leftright : BOOLEAN; -- left or right used variable lresize, rresize : UNRESOLVED_float (exponent_width downto -fraction_width); variable sticky : STD_ULOGIC; -- Holds precision for rounding begin -- addition if (fraction_width = 0 or l'length < 7 or r'length < 7) then lfptype := isx; else lfptype := classfp (l, check_error); rfptype := classfp (r, check_error); end if; if (lfptype = isx or rfptype = isx) then fpresult := (others => 'X'); elsif (lfptype = nan or lfptype = quiet_nan or rfptype = nan or rfptype = quiet_nan) -- Return quiet NAN, IEEE754-1985-7.1,1 or (lfptype = pos_inf and rfptype = neg_inf) or (lfptype = neg_inf and rfptype = pos_inf) then -- Return quiet NAN, IEEE754-1985-7.1,2 fpresult := qnanfp (fraction_width => fraction_width, exponent_width => exponent_width); elsif (lfptype = pos_inf or rfptype = pos_inf) then -- x + inf = inf fpresult := pos_inffp (fraction_width => fraction_width, exponent_width => exponent_width); elsif (lfptype = neg_inf or rfptype = neg_inf) then -- x - inf = -inf fpresult := neg_inffp (fraction_width => fraction_width, exponent_width => exponent_width); else lresize := resize (arg => to_x01(l), exponent_width => exponent_width, fraction_width => fraction_width, denormalize_in => denormalize, denormalize => denormalize); lfptype := classfp (lresize, false); -- errors already checked rresize := resize (arg => to_x01(r), exponent_width => exponent_width, fraction_width => fraction_width, denormalize_in => denormalize, denormalize => denormalize); rfptype := classfp (rresize, false); -- errors already checked break_number ( arg => lresize, fptyp => lfptype, denormalize => denormalize, fract => ulfract, expon => exponl); fractl := (others => '0'); fractl (fraction_width+addguard downto addguard) := ulfract; break_number ( arg => rresize, fptyp => rfptype, denormalize => denormalize, fract => urfract, expon => exponr); fractr := (others => '0'); fractr (fraction_width+addguard downto addguard) := urfract; shiftx := (exponl(exponent_width-1) & exponl) - exponr; if shiftx < -fractl'high then rexpon := exponr(exponent_width-1) & exponr; fractc := fractr; fracts := (others => '0'); -- add zero leftright := false; sticky := or_reduce (fractl); elsif shiftx < 0 then shiftx := - shiftx; fracts := shift_right (fractl, to_integer(shiftx)); fractc := fractr; rexpon := exponr(exponent_width-1) & exponr; leftright := false; -- sticky := or_reduce (fractl (to_integer(shiftx) downto 0)); sticky := smallfract (fractl, to_integer(shiftx)); elsif shiftx = 0 then rexpon := exponl(exponent_width-1) & exponl; sticky := '0'; if fractr > fractl then fractc := fractr; fracts := fractl; leftright := false; else fractc := fractl; fracts := fractr; leftright := true; end if; elsif shiftx > fractr'high then rexpon := exponl(exponent_width-1) & exponl; fracts := (others => '0'); -- add zero fractc := fractl; leftright := true; sticky := or_reduce (fractr); elsif shiftx > 0 then fracts := shift_right (fractr, to_integer(shiftx)); fractc := fractl; rexpon := exponl(exponent_width-1) & exponl; leftright := true; -- sticky := or_reduce (fractr (to_integer(shiftx) downto 0)); sticky := smallfract (fractr, to_integer(shiftx)); end if; -- add fracts (0) := fracts (0) or sticky; -- Or the sticky bit into the LSB if l(l'high) = r(r'high) then ufract := fractc + fracts; sign := l(l'high); else -- signs are different ufract := fractc - fracts; -- always positive result if leftright then -- Figure out which sign to use sign := l(l'high); else sign := r(r'high); end if; end if; -- normalize fpresult := normalize (fract => ufract, expon => rexpon, sign => sign, sticky => sticky, fraction_width => fraction_width, exponent_width => exponent_width, round_style => round_style, denormalize => denormalize, nguard => addguard); end if; return fpresult; end function add; -- Subtraction, Calls "add". function subtract ( l, r : UNRESOLVED_float; -- floating point input constant round_style : round_type := float_round_style; -- rounding option constant guard : NATURAL := float_guard_bits; -- number of guard bits constant check_error : BOOLEAN := float_check_error; -- check for errors constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP return UNRESOLVED_float is variable negr : UNRESOLVED_float (r'range); -- negative version of r begin negr := -r; -- r := -r return add (l => l, r => negr, round_style => round_style, guard => guard, check_error => check_error, denormalize => denormalize); end function subtract; -- Floating point multiply function multiply ( l, r : UNRESOLVED_float; -- floating point input constant round_style : round_type := float_round_style; -- rounding option constant guard : NATURAL := float_guard_bits; -- number of guard bits constant check_error : BOOLEAN := float_check_error; -- check for errors constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP return UNRESOLVED_float is constant fraction_width : NATURAL := -mine(l'low, r'low); -- length of FP output fraction constant exponent_width : NATURAL := maximum(l'high, r'high); -- length of FP output exponent constant multguard : NATURAL := guard; -- guard bits variable lfptype, rfptype : valid_fpstate; variable fpresult : UNRESOLVED_float (exponent_width downto -fraction_width); variable fractl, fractr : UNSIGNED (fraction_width downto 0); -- fractions variable rfract : UNSIGNED ((2*(fraction_width))+1 downto 0); -- result fraction variable sfract : UNSIGNED (fraction_width+1+multguard downto 0); -- result fraction variable shifty : INTEGER; -- denormal shift variable exponl, exponr : SIGNED (exponent_width-1 downto 0); -- exponents variable rexpon : SIGNED (exponent_width+1 downto 0); -- result exponent variable fp_sign : STD_ULOGIC; -- sign of result variable lresize, rresize : UNRESOLVED_float (exponent_width downto -fraction_width); variable sticky : STD_ULOGIC; -- Holds precision for rounding begin -- multiply if (fraction_width = 0 or l'length < 7 or r'length < 7) then lfptype := isx; else lfptype := classfp (l, check_error); rfptype := classfp (r, check_error); end if; if (lfptype = isx or rfptype = isx) then fpresult := (others => 'X'); elsif ((lfptype = nan or lfptype = quiet_nan or rfptype = nan or rfptype = quiet_nan)) then -- Return quiet NAN, IEEE754-1985-7.1,1 fpresult := qnanfp (fraction_width => fraction_width, exponent_width => exponent_width); elsif (((lfptype = pos_inf or lfptype = neg_inf) and (rfptype = pos_zero or rfptype = neg_zero)) or ((rfptype = pos_inf or rfptype = neg_inf) and (lfptype = pos_zero or lfptype = neg_zero))) then -- 0 * inf -- Return quiet NAN, IEEE754-1985-7.1,3 fpresult := qnanfp (fraction_width => fraction_width, exponent_width => exponent_width); elsif (lfptype = pos_inf or rfptype = pos_inf or lfptype = neg_inf or rfptype = neg_inf) then -- x * inf = inf fpresult := pos_inffp (fraction_width => fraction_width, exponent_width => exponent_width); -- figure out the sign fp_sign := l(l'high) xor r(r'high); -- figure out the sign fpresult (exponent_width) := fp_sign; else fp_sign := l(l'high) xor r(r'high); -- figure out the sign lresize := resize (arg => to_x01(l), exponent_width => exponent_width, fraction_width => fraction_width, denormalize_in => denormalize, denormalize => denormalize); lfptype := classfp (lresize, false); -- errors already checked rresize := resize (arg => to_x01(r), exponent_width => exponent_width, fraction_width => fraction_width, denormalize_in => denormalize, denormalize => denormalize); rfptype := classfp (rresize, false); -- errors already checked break_number ( arg => lresize, fptyp => lfptype, denormalize => denormalize, fract => fractl, expon => exponl); break_number ( arg => rresize, fptyp => rfptype, denormalize => denormalize, fract => fractr, expon => exponr); if (rfptype = pos_denormal or rfptype = neg_denormal) then shifty := fraction_width - find_leftmost(fractr, '1'); fractr := shift_left (fractr, shifty); elsif (lfptype = pos_denormal or lfptype = neg_denormal) then shifty := fraction_width - find_leftmost(fractl, '1'); fractl := shift_left (fractl, shifty); else shifty := 0; -- Note that a denormal number * a denormal number is always zero. end if; -- multiply -- add the exponents rexpon := resize (exponl, rexpon'length) + exponr - shifty + 1; rfract := fractl * fractr; -- Multiply the fraction sfract := rfract (rfract'high downto rfract'high - (fraction_width+1+multguard)); sticky := or_reduce (rfract (rfract'high-(fraction_width+1+multguard) downto 0)); -- normalize fpresult := normalize (fract => sfract, expon => rexpon, sign => fp_sign, sticky => sticky, fraction_width => fraction_width, exponent_width => exponent_width, round_style => round_style, denormalize => denormalize, nguard => multguard); end if; return fpresult; end function multiply; function short_divide ( lx, rx : UNSIGNED) return UNSIGNED is -- This is a special divider for the floating point routines. -- For a true unsigned divider, "stages" needs to = lx'high constant stages : INTEGER := lx'high - rx'high; -- number of stages variable partial : UNSIGNED (lx'range); variable q : UNSIGNED (stages downto 0); variable partial_argl : SIGNED (rx'high + 2 downto 0); variable partial_arg : SIGNED (rx'high + 2 downto 0); begin partial := lx; for i in stages downto 0 loop partial_argl := resize ("0" & SIGNED (partial(lx'high downto i)), partial_argl'length); partial_arg := partial_argl - SIGNED ("0" & rx); if (partial_arg (partial_arg'high) = '1') then -- negative q(i) := '0'; else q(i) := '1'; partial (lx'high+i-stages downto lx'high+i-stages-rx'high) := UNSIGNED (partial_arg(rx'range)); end if; end loop; -- to make the output look like that of the unsigned IEEE divide. return resize (q, lx'length); end function short_divide; -- 1/X function. Needed for algorithm development. function reciprocal ( arg : UNRESOLVED_float; constant round_style : round_type := float_round_style; -- rounding option constant guard : NATURAL := float_guard_bits; -- number of guard bits constant check_error : BOOLEAN := float_check_error; -- check for errors constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP return UNRESOLVED_float is constant fraction_width : NATURAL := -mine(arg'low, arg'low); -- length of FP output fraction constant exponent_width : NATURAL := arg'high; -- length of FP output exponent constant divguard : NATURAL := guard; -- guard bits function onedivy ( arg : UNSIGNED) return UNSIGNED is variable q : UNSIGNED((2*arg'high)+1 downto 0); variable one : UNSIGNED (q'range); begin one := (others => '0'); one(one'high) := '1'; q := short_divide (one, arg); -- Unsigned divide return resize (q, arg'length+1); end function onedivy; variable fptype : valid_fpstate; variable expon : SIGNED (exponent_width-1 downto 0); -- exponents variable denorm_offset : NATURAL range 0 to 2; variable fract : UNSIGNED (fraction_width downto 0); variable fractg : UNSIGNED (fraction_width+divguard downto 0); variable sfract : UNSIGNED (fraction_width+1+divguard downto 0); -- result fraction variable fpresult : UNRESOLVED_float (exponent_width downto -fraction_width); begin -- reciprocal fptype := classfp(arg, check_error); classcase : case fptype is when isx => fpresult := (others => 'X'); when nan | quiet_nan => -- Return quiet NAN, IEEE754-1985-7.1,1 fpresult := qnanfp (fraction_width => fraction_width, exponent_width => exponent_width); when pos_inf | neg_inf => -- 1/inf, return 0 fpresult := zerofp (fraction_width => fraction_width, exponent_width => exponent_width); when neg_zero | pos_zero => -- 1/0 report float_pkg'instance_name & "RECIPROCAL: Floating Point divide by zero" severity error; fpresult := pos_inffp (fraction_width => fraction_width, exponent_width => exponent_width); when others => if (fptype = pos_denormal or fptype = neg_denormal) and ((arg (-1) or arg(-2)) /= '1') then -- 1/denormal = infinity, with the exception of 2**-expon_base fpresult := pos_inffp (fraction_width => fraction_width, exponent_width => exponent_width); fpresult (exponent_width) := to_x01 (arg (exponent_width)); else break_number ( arg => arg, fptyp => fptype, denormalize => denormalize, fract => fract, expon => expon); fractg := (others => '0'); if (fptype = pos_denormal or fptype = neg_denormal) then -- The reciprocal of a denormal number is typically zero, -- except for two special cases which are trapped here. if (to_x01(arg (-1)) = '1') then fractg (fractg'high downto divguard+1) := fract (fract'high-1 downto 0); -- Shift to not denormal denorm_offset := 1; -- add 1 to exponent compensate else -- arg(-2) = '1' fractg (fractg'high downto divguard+2) := fract (fract'high-2 downto 0); -- Shift to not denormal denorm_offset := 2; -- add 2 to exponent compensate end if; else fractg (fractg'high downto divguard) := fract; denorm_offset := 0; end if; expon := - expon - 3 + denorm_offset; sfract := onedivy (fractg); -- normalize fpresult := normalize (fract => sfract, expon => expon, sign => arg(exponent_width), sticky => '1', fraction_width => fraction_width, exponent_width => exponent_width, round_style => round_style, denormalize => denormalize, nguard => divguard); end if; end case classcase; return fpresult; end function reciprocal; -- floating point division function divide ( l, r : UNRESOLVED_float; -- floating point input constant round_style : round_type := float_round_style; -- rounding option constant guard : NATURAL := float_guard_bits; -- number of guard bits constant check_error : BOOLEAN := float_check_error; -- check for errors constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP return UNRESOLVED_float is constant fraction_width : NATURAL := -mine(l'low, r'low); -- length of FP output fraction constant exponent_width : NATURAL := maximum(l'high, r'high); -- length of FP output exponent constant divguard : NATURAL := guard; -- division guard bits variable lfptype, rfptype : valid_fpstate; variable fpresult : UNRESOLVED_float (exponent_width downto -fraction_width); variable ulfract, urfract : UNSIGNED (fraction_width downto 0); variable fractl : UNSIGNED ((2*(fraction_width+divguard)+1) downto 0); -- left variable fractr : UNSIGNED (fraction_width+divguard downto 0); -- right variable rfract : UNSIGNED (fractl'range); -- result fraction variable sfract : UNSIGNED (fraction_width+1+divguard downto 0); -- result fraction variable exponl, exponr : SIGNED (exponent_width-1 downto 0); -- exponents variable rexpon : SIGNED (exponent_width+1 downto 0); -- result exponent variable fp_sign : STD_ULOGIC; -- sign of result variable shifty, shiftx : INTEGER; -- denormal number shift variable lresize, rresize : UNRESOLVED_float (exponent_width downto -fraction_width); begin -- divide if (fraction_width = 0 or l'length < 7 or r'length < 7) then lfptype := isx; else lfptype := classfp (l, check_error); rfptype := classfp (r, check_error); end if; classcase : case rfptype is when isx => fpresult := (others => 'X'); when nan | quiet_nan => -- Return quiet NAN, IEEE754-1985-7.1,1 fpresult := qnanfp (fraction_width => fraction_width, exponent_width => exponent_width); when pos_inf | neg_inf => if lfptype = pos_inf or lfptype = neg_inf -- inf / inf or lfptype = quiet_nan or lfptype = nan then -- Return quiet NAN, IEEE754-1985-7.1,4 fpresult := qnanfp (fraction_width => fraction_width, exponent_width => exponent_width); else -- x / inf = 0 fpresult := zerofp (fraction_width => fraction_width, exponent_width => exponent_width); fp_sign := l(l'high) xor r(r'high); -- sign fpresult (fpresult'high) := fp_sign; -- sign end if; when pos_zero | neg_zero => if lfptype = pos_zero or lfptype = neg_zero -- 0 / 0 or lfptype = quiet_nan or lfptype = nan then -- Return quiet NAN, IEEE754-1985-7.1,4 fpresult := qnanfp (fraction_width => fraction_width, exponent_width => exponent_width); else report float_pkg'instance_name & "DIVIDE: Floating Point divide by zero" severity error; -- Infinity, define in 754-1985-7.2 fpresult := pos_inffp (fraction_width => fraction_width, exponent_width => exponent_width); fp_sign := l(l'high) xor r(r'high); -- sign fpresult (fpresult'high) := fp_sign; -- sign end if; when others => classcase2 : case lfptype is when isx => fpresult := (others => 'X'); when nan | quiet_nan => -- Return quiet NAN, IEEE754-1985-7.1,1 fpresult := qnanfp (fraction_width => fraction_width, exponent_width => exponent_width); when pos_inf | neg_inf => -- inf / x = inf fpresult := pos_inffp (fraction_width => fraction_width, exponent_width => exponent_width); fp_sign := l(l'high) xor r(r'high); -- sign fpresult(exponent_width) := fp_sign; when pos_zero | neg_zero => -- 0 / X = 0 fpresult := zerofp (fraction_width => fraction_width, exponent_width => exponent_width); when others => fp_sign := l(l'high) xor r(r'high); -- sign lresize := resize (arg => to_x01(l), exponent_width => exponent_width, fraction_width => fraction_width, denormalize_in => denormalize, denormalize => denormalize); lfptype := classfp (lresize, false); -- errors already checked rresize := resize (arg => to_x01(r), exponent_width => exponent_width, fraction_width => fraction_width, denormalize_in => denormalize, denormalize => denormalize); rfptype := classfp (rresize, false); -- errors already checked break_number ( arg => lresize, fptyp => lfptype, denormalize => denormalize, fract => ulfract, expon => exponl); -- right side break_number ( arg => rresize, fptyp => rfptype, denormalize => denormalize, fract => urfract, expon => exponr); -- Compute the exponent rexpon := resize (exponl, rexpon'length) - exponr - 2; if (rfptype = pos_denormal or rfptype = neg_denormal) then -- Do the shifting here not after. That way we have a smaller -- shifter, and need a smaller divider, because the top -- bit in the divisor will always be a "1". shifty := fraction_width - find_leftmost(urfract, '1'); urfract := shift_left (urfract, shifty); rexpon := rexpon + shifty; end if; fractr := (others => '0'); fractr (fraction_width+divguard downto divguard) := urfract; if (lfptype = pos_denormal or lfptype = neg_denormal) then shiftx := fraction_width - find_leftmost(ulfract, '1'); ulfract := shift_left (ulfract, shiftx); rexpon := rexpon - shiftx; end if; fractl := (others => '0'); fractl (fractl'high downto fractl'high-fraction_width) := ulfract; -- divide rfract := short_divide (fractl, fractr); -- unsigned divide sfract := rfract (sfract'range); -- lower bits -- normalize fpresult := normalize (fract => sfract, expon => rexpon, sign => fp_sign, sticky => '1', fraction_width => fraction_width, exponent_width => exponent_width, round_style => round_style, denormalize => denormalize, nguard => divguard); end case classcase2; end case classcase; return fpresult; end function divide; -- division by a power of 2 function dividebyp2 ( l, r : UNRESOLVED_float; -- floating point input constant round_style : round_type := float_round_style; -- rounding option constant guard : NATURAL := float_guard_bits; -- number of guard bits constant check_error : BOOLEAN := float_check_error; -- check for errors constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP return UNRESOLVED_float is constant fraction_width : NATURAL := -mine(l'low, r'low); -- length of FP output fraction constant exponent_width : NATURAL := maximum(l'high, r'high); -- length of FP output exponent variable lfptype, rfptype : valid_fpstate; variable fpresult : UNRESOLVED_float (exponent_width downto -fraction_width); variable ulfract, urfract : UNSIGNED (fraction_width downto 0); variable exponl, exponr : SIGNED(exponent_width-1 downto 0); -- exponents variable rexpon : SIGNED(exponent_width downto 0); -- result exponent variable fp_sign : STD_ULOGIC; -- sign of result variable lresize, rresize : UNRESOLVED_float (exponent_width downto -fraction_width); begin -- divisionbyp2 if (fraction_width = 0 or l'length < 7 or r'length < 7) then lfptype := isx; else lfptype := classfp (l, check_error); rfptype := classfp (r, check_error); end if; fp_sign := l(l'high) xor r(r'high); -- sign classcase : case rfptype is when isx => fpresult := (others => 'X'); when nan | quiet_nan => -- Return quiet NAN, IEEE754-1985-7.1,1 fpresult := qnanfp (fraction_width => fraction_width, exponent_width => exponent_width); when pos_inf | neg_inf => if lfptype = pos_inf or lfptype = neg_inf then -- inf / inf -- Return quiet NAN, IEEE754-1985-7.1,4 fpresult := qnanfp (fraction_width => fraction_width, exponent_width => exponent_width); else -- x / inf = 0 fpresult := zerofp (fraction_width => fraction_width, exponent_width => exponent_width); fpresult (fpresult'high) := fp_sign; -- sign end if; when pos_zero | neg_zero => if lfptype = pos_zero or lfptype = neg_zero then -- 0 / 0 -- Return quiet NAN, IEEE754-1985-7.1,4 fpresult := qnanfp (fraction_width => fraction_width, exponent_width => exponent_width); else report float_pkg'instance_name & "DIVIDEBYP2: Floating Point divide by zero" severity error; -- Infinity, define in 754-1985-7.2 fpresult := pos_inffp (fraction_width => fraction_width, exponent_width => exponent_width); fpresult (fpresult'high) := fp_sign; -- sign end if; when others => classcase2 : case lfptype is when isx => fpresult := (others => 'X'); when nan | quiet_nan => -- Return quiet NAN, IEEE754-1985-7.1,1 fpresult := qnanfp (fraction_width => fraction_width, exponent_width => exponent_width); when pos_inf | neg_inf => -- inf / x = inf fpresult := pos_inffp (fraction_width => fraction_width, exponent_width => exponent_width); fpresult (exponent_width) := fp_sign; -- sign when pos_zero | neg_zero => -- 0 / X = 0 fpresult := zerofp (fraction_width => fraction_width, exponent_width => exponent_width); fpresult (exponent_width) := fp_sign; -- sign when others => lresize := resize (arg => to_x01(l), exponent_width => exponent_width, fraction_width => fraction_width, denormalize_in => denormalize, denormalize => denormalize); lfptype := classfp (lresize, false); -- errors already checked rresize := resize (arg => to_x01(r), exponent_width => exponent_width, fraction_width => fraction_width, denormalize_in => denormalize, denormalize => denormalize); rfptype := classfp (rresize, false); -- errors already checked break_number ( arg => lresize, fptyp => lfptype, denormalize => denormalize, fract => ulfract, expon => exponl); -- right side break_number ( arg => rresize, fptyp => rfptype, denormalize => denormalize, fract => urfract, expon => exponr); assert (or_reduce (urfract (fraction_width-1 downto 0)) = '0') report float_pkg'instance_name & "DIVIDEBYP2: " & "Dividebyp2 called with a non power of two divisor" severity error; rexpon := (exponl(exponl'high)&exponl) - (exponr(exponr'high)&exponr) - 1; -- normalize fpresult := normalize (fract => ulfract, expon => rexpon, sign => fp_sign, sticky => '1', fraction_width => fraction_width, exponent_width => exponent_width, round_style => round_style, denormalize => denormalize, nguard => 0); end case classcase2; end case classcase; return fpresult; end function dividebyp2; -- Multiply accumulate result = l*r + c function mac ( l, r, c : UNRESOLVED_float; -- floating point input constant round_style : round_type := float_round_style; -- rounding option constant guard : NATURAL := float_guard_bits; -- number of guard bits constant check_error : BOOLEAN := float_check_error; -- check for errors constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP return UNRESOLVED_float is constant fraction_width : NATURAL := -mine (mine(l'low, r'low), c'low); -- length of FP output fraction constant exponent_width : NATURAL := maximum (maximum(l'high, r'high), c'high); -- length of FP output exponent variable lfptype, rfptype, cfptype : valid_fpstate; variable fpresult : UNRESOLVED_float (exponent_width downto -fraction_width); variable fractl, fractr : UNSIGNED (fraction_width downto 0); -- fractions variable fractx : UNSIGNED (fraction_width+guard downto 0); variable fractc, fracts : UNSIGNED (fraction_width+1+guard downto 0); variable rfract : UNSIGNED ((2*(fraction_width))+1 downto 0); -- result fraction variable sfract, ufract : UNSIGNED (fraction_width+1+guard downto 0); -- result fraction variable exponl, exponr, exponc : SIGNED (exponent_width-1 downto 0); -- exponents variable rexpon, rexpon2 : SIGNED (exponent_width+1 downto 0); -- result exponent variable shifty : INTEGER; -- denormal shift variable shiftx : SIGNED (rexpon'range); -- shift fractions variable fp_sign : STD_ULOGIC; -- sign of result variable lresize, rresize : UNRESOLVED_float (exponent_width downto -fraction_width); variable cresize : UNRESOLVED_float (exponent_width downto -fraction_width - guard); variable leftright : BOOLEAN; -- left or right used variable sticky : STD_ULOGIC; -- Holds precision for rounding begin -- multiply if (fraction_width = 0 or l'length < 7 or r'length < 7 or c'length < 7) then lfptype := isx; else lfptype := classfp (l, check_error); rfptype := classfp (r, check_error); cfptype := classfp (c, check_error); end if; if (lfptype = isx or rfptype = isx or cfptype = isx) then fpresult := (others => 'X'); elsif (lfptype = nan or lfptype = quiet_nan or rfptype = nan or rfptype = quiet_nan or cfptype = nan or cfptype = quiet_nan) then -- Return quiet NAN, IEEE754-1985-7.1,1 fpresult := qnanfp (fraction_width => fraction_width, exponent_width => exponent_width); elsif (((lfptype = pos_inf or lfptype = neg_inf) and (rfptype = pos_zero or rfptype = neg_zero)) or ((rfptype = pos_inf or rfptype = neg_inf) and (lfptype = pos_zero or lfptype = neg_zero))) then -- 0 * inf -- Return quiet NAN, IEEE754-1985-7.1,3 fpresult := qnanfp (fraction_width => fraction_width, exponent_width => exponent_width); elsif (lfptype = pos_inf or rfptype = pos_inf or lfptype = neg_inf or rfptype = neg_inf -- x * inf = inf or cfptype = neg_inf or cfptype = pos_inf) then -- x + inf = inf fpresult := pos_inffp (fraction_width => fraction_width, exponent_width => exponent_width); -- figure out the sign fpresult (exponent_width) := l(l'high) xor r(r'high); else fp_sign := l(l'high) xor r(r'high); -- figure out the sign lresize := resize (arg => to_x01(l), exponent_width => exponent_width, fraction_width => fraction_width, denormalize_in => denormalize, denormalize => denormalize); lfptype := classfp (lresize, false); -- errors already checked rresize := resize (arg => to_x01(r), exponent_width => exponent_width, fraction_width => fraction_width, denormalize_in => denormalize, denormalize => denormalize); rfptype := classfp (rresize, false); -- errors already checked cresize := resize (arg => to_x01(c), exponent_width => exponent_width, fraction_width => -cresize'low, denormalize_in => denormalize, denormalize => denormalize); cfptype := classfp (cresize, false); -- errors already checked break_number ( arg => lresize, fptyp => lfptype, denormalize => denormalize, fract => fractl, expon => exponl); break_number ( arg => rresize, fptyp => rfptype, denormalize => denormalize, fract => fractr, expon => exponr); break_number ( arg => cresize, fptyp => cfptype, denormalize => denormalize, fract => fractx, expon => exponc); if (rfptype = pos_denormal or rfptype = neg_denormal) then shifty := fraction_width - find_leftmost(fractr, '1'); fractr := shift_left (fractr, shifty); elsif (lfptype = pos_denormal or lfptype = neg_denormal) then shifty := fraction_width - find_leftmost(fractl, '1'); fractl := shift_left (fractl, shifty); else shifty := 0; -- Note that a denormal number * a denormal number is always zero. end if; -- multiply rfract := fractl * fractr; -- Multiply the fraction -- add the exponents rexpon := resize (exponl, rexpon'length) + exponr - shifty + 1; shiftx := rexpon - exponc; if shiftx < -fractl'high then rexpon2 := resize (exponc, rexpon2'length); fractc := "0" & fractx; fracts := (others => '0'); sticky := or_reduce (rfract); elsif shiftx < 0 then shiftx := - shiftx; fracts := shift_right (rfract (rfract'high downto rfract'high - fracts'length+1), to_integer(shiftx)); fractc := "0" & fractx; rexpon2 := resize (exponc, rexpon2'length); leftright := false; sticky := or_reduce (rfract (to_integer(shiftx)+rfract'high - fracts'length downto 0)); elsif shiftx = 0 then rexpon2 := resize (exponc, rexpon2'length); sticky := or_reduce (rfract (rfract'high - fractc'length downto 0)); if rfract (rfract'high downto rfract'high - fractc'length+1) > fractx then fractc := "0" & fractx; fracts := rfract (rfract'high downto rfract'high - fracts'length+1); leftright := false; else fractc := rfract (rfract'high downto rfract'high - fractc'length+1); fracts := "0" & fractx; leftright := true; end if; elsif shiftx > fractx'high then rexpon2 := rexpon; fracts := (others => '0'); fractc := rfract (rfract'high downto rfract'high - fractc'length+1); leftright := true; sticky := or_reduce (fractx & rfract (rfract'high - fractc'length downto 0)); else -- fractx'high > shiftx > 0 rexpon2 := rexpon; fracts := "0" & shift_right (fractx, to_integer (shiftx)); fractc := rfract (rfract'high downto rfract'high - fractc'length+1); leftright := true; sticky := or_reduce (fractx (to_integer (shiftx) downto 0) & rfract (rfract'high - fractc'length downto 0)); end if; fracts (0) := fracts (0) or sticky; -- Or the sticky bit into the LSB if fp_sign = to_X01(c(c'high)) then ufract := fractc + fracts; fp_sign := fp_sign; else -- signs are different ufract := fractc - fracts; -- always positive result if leftright then -- Figure out which sign to use fp_sign := fp_sign; else fp_sign := c(c'high); end if; end if; -- normalize fpresult := normalize (fract => ufract, expon => rexpon2, sign => fp_sign, sticky => sticky, fraction_width => fraction_width, exponent_width => exponent_width, round_style => round_style, denormalize => denormalize, nguard => guard); end if; return fpresult; end function mac; -- "rem" function function remainder ( l, r : UNRESOLVED_float; -- floating point input constant round_style : round_type := float_round_style; -- rounding option constant guard : NATURAL := float_guard_bits; -- number of guard bits constant check_error : BOOLEAN := float_check_error; -- check for errors constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP return UNRESOLVED_float is constant fraction_width : NATURAL := -mine(l'low, r'low); -- length of FP output fraction constant exponent_width : NATURAL := maximum(l'high, r'high); -- length of FP output exponent constant divguard : NATURAL := guard; -- division guard bits variable lfptype, rfptype : valid_fpstate; variable fpresult : UNRESOLVED_float (exponent_width downto -fraction_width); variable ulfract, urfract : UNSIGNED (fraction_width downto 0); variable fractr, fractl : UNSIGNED (fraction_width+divguard downto 0); -- right variable rfract : UNSIGNED (fractr'range); -- result fraction variable sfract : UNSIGNED (fraction_width+divguard downto 0); -- result fraction variable exponl, exponr : SIGNED (exponent_width-1 downto 0); -- exponents variable rexpon : SIGNED (exponent_width downto 0); -- result exponent variable fp_sign : STD_ULOGIC; -- sign of result variable shifty : INTEGER; -- denormal number shift variable lresize, rresize : UNRESOLVED_float (exponent_width downto -fraction_width); begin -- remainder if (fraction_width = 0 or l'length < 7 or r'length < 7) then lfptype := isx; else lfptype := classfp (l, check_error); rfptype := classfp (r, check_error); end if; if (lfptype = isx or rfptype = isx) then fpresult := (others => 'X'); elsif (lfptype = nan or lfptype = quiet_nan) or (rfptype = nan or rfptype = quiet_nan) -- Return quiet NAN, IEEE754-1985-7.1,1 or (lfptype = pos_inf or lfptype = neg_inf) -- inf rem x -- Return quiet NAN, IEEE754-1985-7.1