git-svn-id: http://moon:8086/svn/vhdl/trunk@1073 cc03376c-175c-47c8-b038-4cd826a8556b
6134 lines
253 KiB
VHDL
6134 lines
253 KiB
VHDL
------------------------------------------------------------------------------
|
|
-- "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.float_pkg.all;
|
|
-- Last Modified: $Date: 2006-04-11 08:45:37-04 $
|
|
-- RCS ID: $Id: float_pkg_c.vhd,v 1.5 2006-04-11 08:45:37-04 l435385 Exp $
|
|
--
|
|
-- Created for VHDL-200X par, David Bishop (dbishop@vhdl.org)
|
|
------------------------------------------------------------------------------
|
|
library ieee, ieee_proposed;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
use ieee_proposed.fixed_pkg.all;
|
|
-- synthesis translate_off
|
|
use std.textio.all;
|
|
-- synthesis translate_on
|
|
|
|
package float_pkg is
|
|
--%%% Uncomment the Generics
|
|
-- new work.fixed_generic_pkg
|
|
-- generic map (
|
|
-- float_exponent_width => 8; -- float32'high
|
|
-- float_fraction_width => 23; -- -float32'low
|
|
-- float_round_style => round_nearest; -- round nearest algorithm
|
|
-- float_denormalize => true; -- Use IEEE extended floating
|
|
-- float_check_error => true; -- Turn on NAN and overflow processing
|
|
-- float_guard_bits => 3; -- number of guard bits
|
|
-- no_warning => false -- show warnings
|
|
-- );
|
|
--%%% REMOVE THE REST OF THIS FILE.
|
|
constant float_exponent_width : NATURAL := 8; -- float32'high
|
|
constant float_fraction_width : NATURAL := 23; -- -float32'low
|
|
constant float_round_style : round_type := round_nearest; -- round nearest algorithm
|
|
constant float_denormalize : BOOLEAN := true; -- Use IEEE extended floating
|
|
-- point (Denormalized numbers)
|
|
constant float_check_error : BOOLEAN := true; -- Turn on NAN and overflow processing
|
|
constant float_guard_bits : NATURAL := 3; -- number of guard bits
|
|
constant NO_WARNING : BOOLEAN := false;
|
|
-- Author David Bishop (dbishop@vhdl.org)
|
|
constant CopyRightNotice : STRING :=
|
|
"Copyright 2005 by IEEE. All rights reserved.";
|
|
-- Note that the size of the vector is not defined here, but in
|
|
-- the package which calls this one.
|
|
type float is array (INTEGER range <>) of STD_LOGIC; -- main type
|
|
-----------------------------------------------------------------------------
|
|
-- 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.
|
|
-----------------------------------------------------------------------------
|
|
subtype float32 is float (8 downto -23); -- IEEE 754 single precision
|
|
-----------------------------------------------------------------------------
|
|
-- 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
|
|
-----------------------------------------------------------------------------
|
|
subtype float64 is float (11 downto -52); -- IEEE 754 double precision
|
|
-----------------------------------------------------------------------------
|
|
-- 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
|
|
-----------------------------------------------------------------------------
|
|
subtype float128 is float (15 downto -112); -- IEEE 854 & C extended precision
|
|
-----------------------------------------------------------------------------
|
|
-- 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 handel 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 differed constant will tell you if the package body is synthesizable
|
|
-- or implemented as real numbers.
|
|
constant fphdlsynth_or_real : BOOLEAN; -- differed constant
|
|
-- Returns the class which X falls into
|
|
function Class (
|
|
x : 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 : float) return float;
|
|
function "-" (arg : float) return 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 : float) return float;
|
|
function "-" (l, r : float) return float;
|
|
function "*" (l, r : float) return float;
|
|
function "/" (l, r : float) return float;
|
|
function "rem" (l, r : float) return float;
|
|
function "mod" (l, r : float) return 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 : 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 float;
|
|
|
|
function subtract (
|
|
l, r : 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 float;
|
|
|
|
function multiply (
|
|
l, r : 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 float;
|
|
|
|
function divide (
|
|
l, r : 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 float;
|
|
|
|
function remainder (
|
|
l, r : 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 float;
|
|
|
|
function modulo (
|
|
l, r : 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 float;
|
|
|
|
-- reciprocal
|
|
function reciprocal (
|
|
arg : 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 float;
|
|
|
|
function dividebyp2 (
|
|
l, r : 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 float;
|
|
|
|
-- Multiply accumumlate result = l*r + c
|
|
function mac (
|
|
l, r, c : 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 float;
|
|
|
|
function Is_Negative (arg : float) return BOOLEAN;
|
|
|
|
-----------------------------------------------------------------------------
|
|
-- compare functions
|
|
-- =, /=, >=, <=, <, >, maximum, minimum
|
|
-- These functions are intentionally not implemented in this package,
|
|
-- use the "fphdl_pkg" to get this funcitonality.
|
|
function eq ( -- equal =
|
|
l, r : float; -- floating point input
|
|
constant check_error : BOOLEAN := float_check_error;
|
|
constant denormalize : BOOLEAN := float_denormalize)
|
|
return BOOLEAN;
|
|
|
|
function ne ( -- not equal /=
|
|
l, r : float; -- floating point input
|
|
constant check_error : BOOLEAN := float_check_error;
|
|
constant denormalize : BOOLEAN := float_denormalize)
|
|
return BOOLEAN;
|
|
|
|
function lt ( -- less than <
|
|
l, r : float; -- floating point input
|
|
constant check_error : BOOLEAN := float_check_error;
|
|
constant denormalize : BOOLEAN := float_denormalize)
|
|
return BOOLEAN;
|
|
|
|
function gt ( -- greater than >
|
|
l, r : 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 : 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 : 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 : float) return BOOLEAN;
|
|
function "/=" (l, r : float) return BOOLEAN;
|
|
function ">=" (l, r : float) return BOOLEAN;
|
|
function "<=" (l, r : float) return BOOLEAN;
|
|
function ">" (l, r : float) return BOOLEAN;
|
|
function "<" (l, r : float) return BOOLEAN;
|
|
--%%% Uncomment the following (new syntax)
|
|
-- function "?=" (l, r : float) return STD_ULOGIC;
|
|
-- function "?\=" (l, r : float) return STD_ULOGIC;
|
|
-- function "?>" (l, r : float) return STD_ULOGIC;
|
|
-- function "?>=" (l, r : float) return STD_ULOGIC;
|
|
-- function "?<" (l, r : float) return STD_ULOGIC;
|
|
-- function "?<=" (l, r : float) return STD_ULOGIC;
|
|
--%%% remove the following (old syntax)
|
|
function \?=\ (l, r : float) return STD_ULOGIC;
|
|
function \?/=\ (l, r : float) return STD_ULOGIC;
|
|
function \?>\ (l, r : float) return STD_ULOGIC;
|
|
function \?>=\ (l, r : float) return STD_ULOGIC;
|
|
function \?<\ (l, r : float) return STD_ULOGIC;
|
|
function \?<=\ (l, r : float) return STD_ULOGIC;
|
|
function std_match (l, r : float) return BOOLEAN;
|
|
function find_lsb (arg : float; y : STD_ULOGIC) return INTEGER;
|
|
function find_msb (arg : float; y : STD_ULOGIC) return INTEGER;
|
|
function maximum (l, r : float) return float;
|
|
function minimum (l, r : float) return float;
|
|
-- conversion functions
|
|
-- Converts one floating point number into another.
|
|
function resize (
|
|
arg : 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 float;
|
|
|
|
function resize (
|
|
arg : float; -- Floating point input
|
|
size_res : 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 float;
|
|
|
|
function to_float32 (
|
|
arg : 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 float;
|
|
|
|
function to_float64 (
|
|
arg : 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 float;
|
|
|
|
function to_float128 (
|
|
arg : 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 float;
|
|
|
|
-- Converts an fp into an SLV (needed for synthesis)
|
|
function to_slv (arg : float) return STD_LOGIC_VECTOR;
|
|
-- alias to_StdLogicVector is to_slv [float return STD_LOGIC_VECTOR];
|
|
-- alias to_Std_Logic_Vector is to_slv [float return STD_LOGIC_VECTOR];
|
|
|
|
-- Converts an fp into an SULV
|
|
function to_sulv (arg : float) return STD_ULOGIC_VECTOR;
|
|
-- alias to_StdULogicVector is to_sulv [float return STD_ULOGIC_VECTOR];
|
|
-- alias to_Std_ULogic_Vector is to_sulv [float return STD_ULOGIC_VECTOR];
|
|
|
|
-- std_logic_vector to float
|
|
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 float;
|
|
|
|
-- 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 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 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 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 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 float;
|
|
|
|
-- unsigned fixed point to float
|
|
function to_float (
|
|
arg : 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 extentions
|
|
return float;
|
|
|
|
-- signed fixed point to float
|
|
function to_float (
|
|
arg : 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 float;
|
|
|
|
-- size_res functions
|
|
-- Integer to float
|
|
function to_float (
|
|
arg : INTEGER;
|
|
size_res : float;
|
|
constant round_style : round_type := float_round_style) -- rounding option
|
|
return float;
|
|
|
|
-- real to float
|
|
function to_float (
|
|
arg : REAL;
|
|
size_res : float;
|
|
constant round_style : round_type := float_round_style; -- rounding option
|
|
constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP
|
|
return float;
|
|
|
|
-- unsigned to float
|
|
function to_float (
|
|
arg : UNSIGNED;
|
|
size_res : float;
|
|
constant round_style : round_type := float_round_style) -- rounding option
|
|
return float;
|
|
|
|
-- signed to float
|
|
function to_float (
|
|
arg : SIGNED;
|
|
size_res : float;
|
|
constant round_style : round_type := float_round_style) -- rounding option
|
|
return float;
|
|
|
|
-- slv to float
|
|
function to_float (
|
|
arg : STD_LOGIC_VECTOR;
|
|
size_res : float)
|
|
return float;
|
|
|
|
-- sulv to float
|
|
function to_float (
|
|
arg : STD_ULOGIC_VECTOR;
|
|
size_res : float)
|
|
return float;
|
|
|
|
-- unsigned fixed point to float
|
|
function to_float (
|
|
arg : ufixed; -- unsigned fixed point input
|
|
size_res : float;
|
|
constant round_style : round_type := float_round_style; -- rounding
|
|
constant denormalize : BOOLEAN := float_denormalize) -- use ieee extentions
|
|
return float;
|
|
|
|
-- signed fixed point to float
|
|
function to_float (
|
|
arg : sfixed;
|
|
size_res : float;
|
|
constant round_style : round_type := float_round_style; -- rounding
|
|
constant denormalize : BOOLEAN := float_denormalize) -- rounding option
|
|
return float;
|
|
|
|
-- float to unsigned
|
|
function to_unsigned (
|
|
arg : 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 : 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 : float; -- fp input
|
|
constant left_index : INTEGER; -- integer part
|
|
constant right_index : INTEGER; -- fraction part
|
|
constant round_style : BOOLEAN := fixed_round_style; -- rounding
|
|
constant overflow_style : BOOLEAN := fixed_overflow_style; -- saturate
|
|
constant check_error : BOOLEAN := float_check_error; -- check for errors
|
|
constant denormalize : BOOLEAN := float_denormalize)
|
|
return ufixed;
|
|
|
|
-- float to signed fixed point
|
|
function to_sfixed (
|
|
arg : float; -- fp input
|
|
constant left_index : INTEGER; -- integer part
|
|
constant right_index : INTEGER; -- fraction part
|
|
constant round_style : BOOLEAN := fixed_round_style; -- rounding
|
|
constant overflow_style : BOOLEAN := fixed_overflow_style; -- saturate
|
|
constant check_error : BOOLEAN := float_check_error; -- check for errors
|
|
constant denormalize : BOOLEAN := float_denormalize)
|
|
return sfixed;
|
|
|
|
-- size_res versions
|
|
-- float to unsigned
|
|
function to_unsigned (
|
|
arg : 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 : 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 : float; -- fp input
|
|
size_res : ufixed;
|
|
constant round_style : BOOLEAN := fixed_round_style; -- rounding
|
|
constant overflow_style : BOOLEAN := fixed_overflow_style; -- saturate
|
|
constant check_error : BOOLEAN := float_check_error; -- check for errors
|
|
constant denormalize : BOOLEAN := float_denormalize)
|
|
return ufixed;
|
|
|
|
-- float to signed fixed point
|
|
function to_sfixed (
|
|
arg : float; -- fp input
|
|
size_res : sfixed;
|
|
constant round_style : BOOLEAN := fixed_round_style; -- rounding
|
|
constant overflow_style : BOOLEAN := fixed_overflow_style; -- saturate
|
|
constant check_error : BOOLEAN := float_check_error; -- check for errors
|
|
constant denormalize : BOOLEAN := float_denormalize)
|
|
return sfixed;
|
|
|
|
-- float to real
|
|
function to_real (
|
|
arg : 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 : 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 : float; -- floating point input
|
|
XMAP : STD_LOGIC := '0')
|
|
return float;
|
|
|
|
function Is_X (arg : float) return BOOLEAN;
|
|
function to_X01 (arg : float) return float;
|
|
function to_X01Z (arg : float) return float;
|
|
function to_UX01 (arg : float) return 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
|
|
-- Exponend is biased by -1
|
|
procedure break_number (
|
|
arg : in 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 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.
|
|
-- Exponend 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 float;
|
|
|
|
-- Exponend 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 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 : 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 float;
|
|
|
|
-- Exponend 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 : 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 float;
|
|
|
|
-- overloaded versions
|
|
function "+" (l : float; r : REAL) return float;
|
|
function "+" (l : REAL; r : float) return float;
|
|
function "+" (l : float; r : INTEGER) return float;
|
|
function "+" (l : INTEGER; r : float) return float;
|
|
function "-" (l : float; r : REAL) return float;
|
|
function "-" (l : REAL; r : float) return float;
|
|
function "-" (l : float; r : INTEGER) return float;
|
|
function "-" (l : INTEGER; r : float) return float;
|
|
function "*" (l : float; r : REAL) return float;
|
|
function "*" (l : REAL; r : float) return float;
|
|
function "*" (l : float; r : INTEGER) return float;
|
|
function "*" (l : INTEGER; r : float) return float;
|
|
function "/" (l : float; r : REAL) return float;
|
|
function "/" (l : REAL; r : float) return float;
|
|
function "/" (l : float; r : INTEGER) return float;
|
|
function "/" (l : INTEGER; r : float) return float;
|
|
function "rem" (l : float; r : REAL) return float;
|
|
function "rem" (l : REAL; r : float) return float;
|
|
function "rem" (l : float; r : INTEGER) return float;
|
|
function "rem" (l : INTEGER; r : float) return float;
|
|
function "mod" (l : float; r : REAL) return float;
|
|
function "mod" (l : REAL; r : float) return float;
|
|
function "mod" (l : float; r : INTEGER) return float;
|
|
function "mod" (l : INTEGER; r : float) return float;
|
|
function "=" (l : float; r : REAL) return BOOLEAN;
|
|
function "/=" (l : float; r : REAL) return BOOLEAN;
|
|
function ">=" (l : float; r : REAL) return BOOLEAN;
|
|
function "<=" (l : float; r : REAL) return BOOLEAN;
|
|
function ">" (l : float; r : REAL) return BOOLEAN;
|
|
function "<" (l : float; r : REAL) return BOOLEAN;
|
|
function "=" (l : REAL; r : float) return BOOLEAN;
|
|
function "/=" (l : REAL; r : float) return BOOLEAN;
|
|
function ">=" (l : REAL; r : float) return BOOLEAN;
|
|
function "<=" (l : REAL; r : float) return BOOLEAN;
|
|
function ">" (l : REAL; r : float) return BOOLEAN;
|
|
function "<" (l : REAL; r : float) return BOOLEAN;
|
|
function "=" (l : float; r : INTEGER) return BOOLEAN;
|
|
function "/=" (l : float; r : INTEGER) return BOOLEAN;
|
|
function ">=" (l : float; r : INTEGER) return BOOLEAN;
|
|
function "<=" (l : float; r : INTEGER) return BOOLEAN;
|
|
function ">" (l : float; r : INTEGER) return BOOLEAN;
|
|
function "<" (l : float; r : INTEGER) return BOOLEAN;
|
|
function "=" (l : INTEGER; r : float) return BOOLEAN;
|
|
function "/=" (l : INTEGER; r : float) return BOOLEAN;
|
|
function ">=" (l : INTEGER; r : float) return BOOLEAN;
|
|
function "<=" (l : INTEGER; r : float) return BOOLEAN;
|
|
function ">" (l : INTEGER; r : float) return BOOLEAN;
|
|
function "<" (l : INTEGER; r : float) return BOOLEAN;
|
|
|
|
----------------------------------------------------------------------------
|
|
-- logical functions
|
|
----------------------------------------------------------------------------
|
|
function "not" (L : float) return float;
|
|
function "and" (L, R : float) return float;
|
|
function "or" (L, R : float) return float;
|
|
function "nand" (L, R : float) return float;
|
|
function "nor" (L, R : float) return float;
|
|
function "xor" (L, R : float) return float;
|
|
function "xnor" (L, R : float) return float;
|
|
-- Vector and std_ulogic functions, same as functions in numeric_std
|
|
function "and" (L : STD_ULOGIC; R : float) return float;
|
|
function "and" (L : float; R : STD_ULOGIC) return float;
|
|
function "or" (L : STD_ULOGIC; R : float) return float;
|
|
function "or" (L : float; R : STD_ULOGIC) return float;
|
|
function "nand" (L : STD_ULOGIC; R : float) return float;
|
|
function "nand" (L : float; R : STD_ULOGIC) return float;
|
|
function "nor" (L : STD_ULOGIC; R : float) return float;
|
|
function "nor" (L : float; R : STD_ULOGIC) return float;
|
|
function "xor" (L : STD_ULOGIC; R : float) return float;
|
|
function "xor" (L : float; R : STD_ULOGIC) return float;
|
|
function "xnor" (L : STD_ULOGIC; R : float) return float;
|
|
function "xnor" (L : float; R : STD_ULOGIC) return float;
|
|
-- Reduction operators, same as numeric_std functions
|
|
-- %%% remove 6 functions (old syntax)
|
|
function and_reduce (arg : float) return STD_ULOGIC;
|
|
function nand_reduce (arg : float) return STD_ULOGIC;
|
|
function or_reduce (arg : float) return STD_ULOGIC;
|
|
function nor_reduce (arg : float) return STD_ULOGIC;
|
|
function xor_reduce (arg : float) return STD_ULOGIC;
|
|
function xnor_reduce (arg : float) return STD_ULOGIC;
|
|
-- %%% Uncomment the following 6 functions (new syntax)
|
|
-- function "and" (arg : float) RETURN std_ulogic;
|
|
-- function "nand" (arg : float) RETURN std_ulogic;
|
|
-- function "or" (arg : float) RETURN std_ulogic;
|
|
-- function "nor" (arg : float) RETURN std_ulogic;
|
|
-- function "xor" (arg : float) RETURN std_ulogic;
|
|
-- function "xnor" (arg : float) RETURN std_ulogic;
|
|
|
|
-- Note: "sla", "sra", "sll", "slr", "rol" and "ror" not implemented.
|
|
-- Note: "find_msb" and "find_lsb" not implemented, use "logb".
|
|
-----------------------------------------------------------------------------
|
|
-- Recommended Functions from the IEEE 754 Appendix
|
|
-----------------------------------------------------------------------------
|
|
-- returns x with the sign of y.
|
|
function Copysign (x, y : float) return float;
|
|
|
|
-- Returns y * 2**n for intergral values of N without computing 2**n
|
|
function Scalb (
|
|
y : 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 float;
|
|
|
|
-- Returns y * 2**n for intergral values of N without computing 2**n
|
|
function Scalb (
|
|
y : 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 float;
|
|
|
|
-- returns the unbiased exponent of x
|
|
function Logb (x : float) return INTEGER;
|
|
function Logb (x : float) return SIGNED;
|
|
|
|
-- returns the next represtable neighbor of x in the direction toward y
|
|
function Nextafter (
|
|
x, y : float; -- floating point input
|
|
constant check_error : BOOLEAN := float_check_error; -- check for errors
|
|
constant denormalize : BOOLEAN := float_denormalize)
|
|
return float;
|
|
|
|
-- Returns TRUE if X is unordered with Y.
|
|
function Unordered (x, y : float) return BOOLEAN;
|
|
function Finite (x : float) return BOOLEAN;
|
|
function Isnan (x : 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 float;
|
|
function nanfp (
|
|
constant exponent_width : NATURAL := float_exponent_width; -- exponent
|
|
constant fraction_width : NATURAL := float_fraction_width) -- fraction
|
|
return float;
|
|
function qnanfp (
|
|
constant exponent_width : NATURAL := float_exponent_width; -- exponent
|
|
constant fraction_width : NATURAL := float_fraction_width) -- fraction
|
|
return float;
|
|
function pos_inffp (
|
|
constant exponent_width : NATURAL := float_exponent_width; -- exponent
|
|
constant fraction_width : NATURAL := float_fraction_width) -- fraction
|
|
return float;
|
|
function neg_inffp (
|
|
constant exponent_width : NATURAL := float_exponent_width; -- exponent
|
|
constant fraction_width : NATURAL := float_fraction_width) -- fraction
|
|
return float;
|
|
function neg_zerofp (
|
|
constant exponent_width : NATURAL := float_exponent_width; -- exponent
|
|
constant fraction_width : NATURAL := float_fraction_width) -- fraction
|
|
return float;
|
|
-- size_res versions
|
|
function zerofp (
|
|
size_res : float) -- variable is only use for sizing
|
|
return float;
|
|
function nanfp (
|
|
size_res : float) -- variable is only use for sizing
|
|
return float;
|
|
function qnanfp (
|
|
size_res : float) -- variable is only use for sizing
|
|
return float;
|
|
function pos_inffp (
|
|
size_res : float) -- variable is only use for sizing
|
|
return float;
|
|
function neg_inffp (
|
|
size_res : float) -- variable is only use for sizing
|
|
return float;
|
|
function neg_zerofp (
|
|
size_res : float) -- variable is only use for sizing
|
|
return float;
|
|
|
|
-- synthesis translate_off
|
|
-- rtl_synthesis off
|
|
-- impure functions
|
|
-- writes S:EEEE:FFFFFFFF
|
|
procedure write (
|
|
L : inout LINE; -- access type (pointer)
|
|
VALUE : in 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 float);
|
|
procedure READ(L : inout LINE; VALUE : out float; GOOD : out BOOLEAN);
|
|
|
|
alias bread is READ [LINE, float, BOOLEAN];
|
|
alias bread is READ [LINE, float];
|
|
alias bwrite is WRITE [LINE, float, SIDE, WIDTH];
|
|
|
|
procedure owrite (
|
|
L : inout LINE; -- access type (pointer)
|
|
VALUE : in 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 seperaters used
|
|
procedure OREAD(L : inout LINE; VALUE : out float);
|
|
procedure OREAD(L : inout LINE; VALUE : out float; GOOD : out BOOLEAN);
|
|
|
|
-- Hex write with padding, no seperators
|
|
procedure hwrite (
|
|
L : inout LINE; -- access type (pointer)
|
|
VALUE : in 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 seperaters used
|
|
procedure HREAD(L : inout LINE; VALUE : out float);
|
|
procedure HREAD(L : inout LINE; VALUE : out float; GOOD : out BOOLEAN);
|
|
|
|
-- returns "S:EEEE:FFFFFFFF"
|
|
function to_string (
|
|
value : float;
|
|
justified : SIDE := right;
|
|
field : WIDTH := 0
|
|
) return STRING;
|
|
|
|
-- Returns a HEX string, with padding
|
|
function to_hstring (
|
|
value : float;
|
|
justified : SIDE := right;
|
|
field : WIDTH := 0
|
|
) return STRING;
|
|
|
|
-- Returns and octal string, with padding
|
|
function to_ostring (
|
|
value : float;
|
|
justified : SIDE := right;
|
|
field : WIDTH := 0
|
|
) return STRING;
|
|
|
|
function from_string (
|
|
bstring : STRING; -- binary string
|
|
constant exponent_width : NATURAL := float_exponent_width;
|
|
constant fraction_width : NATURAL := float_fraction_width)
|
|
return float;
|
|
alias from_bstring is from_string [STRING, NATURAL, NATURAL return float];
|
|
|
|
function from_ostring (
|
|
ostring : STRING; -- Octal string
|
|
constant exponent_width : NATURAL := float_exponent_width;
|
|
constant fraction_width : NATURAL := float_fraction_width)
|
|
return float;
|
|
|
|
function from_hstring (
|
|
hstring : STRING; -- hex string
|
|
constant exponent_width : NATURAL := float_exponent_width;
|
|
constant fraction_width : NATURAL := float_fraction_width)
|
|
return float;
|
|
|
|
function from_string (
|
|
bstring : STRING; -- binary string
|
|
size_res : float) -- used for sizing only
|
|
return float;
|
|
alias from_bstring is from_string [STRING, float return float];
|
|
|
|
function from_ostring (
|
|
ostring : STRING; -- Octal string
|
|
size_res : float) -- used for sizing only
|
|
return float;
|
|
|
|
function from_hstring (
|
|
hstring : STRING; -- hex string
|
|
size_res : float) -- used for sizing only
|
|
return float;
|
|
|
|
-- synthesis translate_on
|
|
-- rtl_synthesis on
|
|
|
|
function to_StdLogicVector (arg : float) return std_logic_vector ;
|
|
function to_Std_Logic_Vector (arg : float) return std_logic_vector;
|
|
function to_StdULogicVector (arg : float) return std_ulogic_vector ;
|
|
function to_Std_ULogic_Vector (arg : float) return std_ulogic_vector;
|
|
|
|
end package float_pkg;
|
|
library ieee;
|
|
use ieee.math_real.all;
|
|
use ieee.std_logic_textio.all; -- %%% for testing only
|
|
package body float_pkg is
|
|
-- Author David Bishop (dbishop@vhdl.org)
|
|
-----------------------------------------------------------------------------
|
|
-- type declarations
|
|
-----------------------------------------------------------------------------
|
|
-- This differed 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; -- differed constant
|
|
-- types of boundary conditions
|
|
type boundary_type is (normal, infinity, zero, denormal);
|
|
-- null range array constant
|
|
constant NAFP : float (0 downto 1) := (others => '0');
|
|
constant NSLV : STD_LOGIC_VECTOR (0 downto 1) := (others => '0');
|
|
|
|
-- %%% These functions can be removed in the final release.
|
|
-- %%% Replace and_reducex with "and" (and all similar _reducex functions)
|
|
-- purpose: AND all of the bits in a vector together
|
|
-- This is a copy of the proposed "and_reduce" from 1076.3
|
|
function and_reducex (arg : STD_LOGIC_VECTOR)
|
|
return STD_LOGIC is
|
|
variable Upper, Lower : STD_LOGIC;
|
|
variable Half : INTEGER;
|
|
variable BUS_int : STD_LOGIC_VECTOR (arg'length - 1 downto 0);
|
|
variable Result : STD_LOGIC;
|
|
begin
|
|
if (arg'length < 1) then -- In the case of a NULL range
|
|
Result := '1'; -- Change for version 1.3
|
|
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_reducex (BUS_int (BUS_int'left downto Half));
|
|
Lower := and_reducex (BUS_int (Half - 1 downto BUS_int'right));
|
|
Result := Upper and Lower;
|
|
end if;
|
|
end if;
|
|
return Result;
|
|
end function and_reducex;
|
|
|
|
function and_reducex (arg : UNSIGNED)
|
|
return STD_LOGIC is
|
|
begin
|
|
return and_reducex (STD_LOGIC_VECTOR (arg));
|
|
end function and_reducex;
|
|
|
|
-- purpose: OR all of the bits in a vector together
|
|
-- This is a copy of the proposed "and_reduce" from 1076.3
|
|
function or_reducex (arg : STD_LOGIC_VECTOR)
|
|
return STD_LOGIC is
|
|
variable Upper, Lower : STD_LOGIC;
|
|
variable Half : INTEGER;
|
|
variable BUS_int : STD_LOGIC_VECTOR (arg'length - 1 downto 0);
|
|
variable Result : STD_LOGIC;
|
|
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_reducex (BUS_int (BUS_int'left downto Half));
|
|
Lower := or_reducex (BUS_int (Half - 1 downto BUS_int'right));
|
|
Result := Upper or Lower;
|
|
end if;
|
|
end if;
|
|
return Result;
|
|
end function or_reducex;
|
|
|
|
function or_reducex (arg : UNSIGNED)
|
|
return STD_LOGIC is
|
|
begin
|
|
return or_reducex (STD_LOGIC_VECTOR (arg));
|
|
end function or_reducex;
|
|
|
|
function xor_reducex (arg : STD_LOGIC_VECTOR) return STD_ULOGIC is
|
|
variable Upper, Lower : STD_ULOGIC;
|
|
variable Half : INTEGER;
|
|
variable BUS_int : STD_LOGIC_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_reducex (BUS_int (BUS_int'left downto Half));
|
|
Lower := xor_reducex (BUS_int (Half - 1 downto BUS_int'right));
|
|
Result := Upper xor Lower;
|
|
end if;
|
|
end if;
|
|
return Result;
|
|
end function xor_reducex;
|
|
|
|
-- purpose: To find the largest of 2 numbers
|
|
-- %%% Will be implicit in VHDL-200X
|
|
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;
|
|
|
|
-- purpose: Find the first "1" is a vector, starting from the MSB
|
|
-- %%% This is a copy of the proposed "find_msb" from 1076.3
|
|
function find_msb (
|
|
arg : UNSIGNED; -- vector argument
|
|
y : STD_ULOGIC) -- look for this bit
|
|
return INTEGER is
|
|
alias xarg : UNSIGNED(arg'length-1 downto 0) is arg;
|
|
begin
|
|
for_loop : for i in xarg'range loop
|
|
if xarg(i) = y then
|
|
return i;
|
|
end if;
|
|
end loop;
|
|
return -1;
|
|
end function find_msb;
|
|
-- %%% End remove
|
|
|
|
-- Special version of "minimum" to do some boundary checking
|
|
function minx (l, r : INTEGER)
|
|
return INTEGER is
|
|
begin -- function minimum
|
|
if (L = INTEGER'low or R = INTEGER'low) then
|
|
report "FLOAT_GENERIC_PKG: Unbounded number passed, was a literal used?"
|
|
severity error;
|
|
return 0;
|
|
end if;
|
|
if L > R then return R;
|
|
else return L;
|
|
end if;
|
|
end function minx;
|
|
|
|
-- 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;
|
|
|
|
-- purpose: Test the boundary conditions of a Real number
|
|
-- function test_boundary (
|
|
-- arg : REAL; -- Input, converted to real
|
|
-- constant fraction_width : NATURAL; -- length of FP output fraction
|
|
-- constant exponent_width : NATURAL; -- length of FP exponent
|
|
-- constant denormalize : BOOLEAN := true) -- Use IEEE extended FP
|
|
-- return boundary_type 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
|
|
-- 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.
|
|
-- if arg = 0.0 then
|
|
-- return zero;
|
|
-- elsif exponent_width > 11 then -- Exponent for Real is 11 (64 bit)
|
|
-- return normal;
|
|
-- else
|
|
-- if arg < 2.0 ** to_integer(exp_min) then
|
|
-- if denormalize then
|
|
-- if arg < 2.0 ** to_integer(exp_ext_min) then
|
|
-- return zero;
|
|
-- else
|
|
-- return denormal;
|
|
-- end if;
|
|
-- else
|
|
-- if arg < 2.0 ** to_integer(exp_min-1) then
|
|
-- return zero;
|
|
-- else
|
|
-- return normal; -- Can still represent this number
|
|
-- end if;
|
|
-- end if;
|
|
-- elsif exponent_width < 11 then
|
|
-- if arg >= 2.0 ** (to_integer(expon_base)+1) then
|
|
-- return infinity;
|
|
-- else
|
|
-- return normal;
|
|
-- end if;
|
|
-- else
|
|
-- return normal;
|
|
-- end if;
|
|
-- end if;
|
|
-- end function test_boundary;
|
|
|
|
-- Some synthesis tools don't like this function, so do it this way
|
|
-- (ignoring denormal and infinite numbers)
|
|
function test_boundary (
|
|
arg : REAL; -- Input, converted to real
|
|
constant fraction_width : NATURAL; -- length of FP output fraction
|
|
constant exponent_width : NATURAL; -- length of FP exponent
|
|
constant denormalize : BOOLEAN := true) -- Use IEEE extended FP
|
|
return boundary_type is
|
|
begin -- function test_boundary
|
|
if arg = 0.0 then
|
|
return zero;
|
|
else
|
|
return normal;
|
|
end if;
|
|
end function test_boundary;
|
|
|
|
-- purpose: Rounds depending on the state of the "round_style"
|
|
-- unsigned version
|
|
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_reducex (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_reducex (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_reducex(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;
|
|
|
|
-- Integer version of the "log2" command
|
|
-- Synthisable, used by to_float(integer) function
|
|
function log2(A : NATURAL) return NATURAL is
|
|
begin
|
|
for I in 1 to 30 loop -- Works for up to 32 bit integers
|
|
if (2**I > A) then return(I-1);
|
|
end if;
|
|
end loop;
|
|
return(30);
|
|
end function log2;
|
|
|
|
-- purpose: Look for the boundaries of the integer input
|
|
-- Synthisable
|
|
function fp_input_type (
|
|
arg : INTEGER; -- integer input
|
|
constant fraction_width : NATURAL; -- length of FP output fraction
|
|
constant exponent_width : NATURAL) -- length of FP output exponent
|
|
return boundary_type is
|
|
constant expon_base : SIGNED (exponent_width-1 downto 0) :=
|
|
gen_expon_base(exponent_width); -- exponent offset
|
|
variable maxint : INTEGER;
|
|
begin -- function fp_input_type
|
|
if arg = 0 then
|
|
return zero;
|
|
elsif exponent_width > 5 then -- largest possible integer = 2**31
|
|
return normal;
|
|
else
|
|
maxint := 2 ** (to_integer(expon_base)+1);
|
|
-- worry about infinity
|
|
if arg >= maxint then
|
|
return infinity;
|
|
else
|
|
return normal;
|
|
end if;
|
|
end if;
|
|
end function fp_input_type;
|
|
|
|
procedure break_number ( -- internal version
|
|
arg : in 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 =>
|
|
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_GENERIC_PKG.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 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 := -minx(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_reducex (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 string, this funciton is here because
|
|
-- or_reducex (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_slv (
|
|
arg : float) -- fp vector
|
|
return STD_LOGIC_VECTOR is
|
|
subtype t is STD_LOGIC_VECTOR(arg'length - 1 downto 0);
|
|
variable slv : t;
|
|
begin -- function to_std_logic_vector
|
|
if arg'length < 1 then
|
|
return NSLV;
|
|
end if;
|
|
slv := t(arg);
|
|
-- floop : for i in slv'range loop
|
|
-- slv(i) := arg(i + arg'low); -- slv(31) := arg (31-23)
|
|
-- end loop floop;
|
|
return slv;
|
|
end function to_slv;
|
|
|
|
-- Converts an fp into an SULV
|
|
function to_sulv (arg : float) return STD_ULOGIC_VECTOR is
|
|
begin
|
|
return to_stdulogicvector (to_slv(arg));
|
|
end function to_sulv;
|
|
|
|
-- 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 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 : 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_msb (to_01(fract), '1') -- Find the first "1"
|
|
- fraction_width - nguard; -- subtract the length we want
|
|
exp := resize (expon, exp'length) + shiftr;
|
|
if (or_reducex(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) := float(rexpon);
|
|
result (-1 downto -fraction_width) := 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) := float(rexpon);
|
|
result (-1 downto -fraction_width) := float(rfract);
|
|
end if;
|
|
return result;
|
|
end function normalize;
|
|
|
|
-- purpose: normalizes a floating point number
|
|
-- This version assumes a "ufixed" input with
|
|
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 float is
|
|
variable result : float (exponent_width downto -fraction_width);
|
|
variable arguns : UNSIGNED (fract'high + fraction_width + nguard
|
|
downto 0) := (others => '0');
|
|
begin -- function normalize
|
|
for i in arguns'high downto maximum (arguns'high-fract'length+1, 0) loop
|
|
arguns (i) := fract (fract'high + (i-arguns'high));
|
|
end loop;
|
|
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
|
|
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 : 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 float is
|
|
constant fraction_width : NATURAL := -size_res'low;
|
|
constant exponent_width : NATURAL := size_res'high;
|
|
variable result : float (exponent_width downto -fraction_width);
|
|
variable arguns : UNSIGNED (fract'high + fraction_width + nguard
|
|
downto 0) := (others => '0');
|
|
begin -- function normalize
|
|
for i in arguns'high downto maximum (arguns'high-fract'length+1, 0) loop
|
|
arguns (i) := fract (fract'high + (i-arguns'high));
|
|
end loop;
|
|
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;
|
|
|
|
function normalize (
|
|
fract : UNSIGNED; -- unsigned
|
|
expon : SIGNED; -- exponent - 1, normalized
|
|
sign : STD_ULOGIC; -- sign bit
|
|
sticky : STD_ULOGIC := '0'; -- Sticky bit (rounding)
|
|
size_res : 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 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
|
|
-- Synthisable
|
|
function Class (
|
|
x : float; -- floating point input
|
|
check_error : BOOLEAN := float_check_error) -- check for errors
|
|
return valid_fpstate is
|
|
constant fraction_width : INTEGER := -minx(x'low, x'low); -- length of FP output fraction
|
|
constant exponent_width : INTEGER := x'high; -- length of FP output exponent
|
|
variable arg : float (exponent_width downto -fraction_width);
|
|
begin -- class
|
|
if (arg'length < 1 or fraction_width < 3 or exponent_width < 3
|
|
or x'left < x'right) then
|
|
report "FLOAT_GENERIC_PKG.CLASS: " &
|
|
"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_reducex (STD_LOGIC_VECTOR (arg (exponent_width-1 downto 0)))
|
|
= '1' then -- Exponent is all "1".
|
|
if or_reducex (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_reducex (STD_LOGIC_VECTOR (arg (exponent_width-1 downto 0)))
|
|
= '0' then -- Exponent is all "0"
|
|
if or_reducex (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 Class;
|
|
|
|
procedure break_number (
|
|
arg : in 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 := -minx(arg'low, 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 fptyp : valid_fpstate;
|
|
variable exp : SIGNED (expon'range);
|
|
begin
|
|
fptyp := Class (arg, check_error);
|
|
fract (fraction_width-1 downto 0) :=
|
|
UNSIGNED (to_slv(arg(-1 downto -fraction_width)));
|
|
sign := to_x01(arg(arg'high));
|
|
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 := to_01(SIGNED(arg(exponent_width-1 downto 0)), 'X');
|
|
exp (exponent_width-1) := not exp(exponent_width-1);
|
|
when others =>
|
|
assert NO_WARNING
|
|
report "FLOAT_GENERIC_PKG.BREAK_NUMBER: " &
|
|
"Meta state detected in fp_break_number process"
|
|
severity warning;
|
|
-- complete the case, if a meta state goes in, a meta state comes out.
|
|
exp := (others => '1');
|
|
fract (fraction_width) := '1';
|
|
end case breakcase;
|
|
expon := exp;
|
|
end procedure break_number;
|
|
|
|
procedure break_number (
|
|
arg : in 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 := -minx(arg'low, 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 fptyp : valid_fpstate;
|
|
variable exp : SIGNED (expon'range);
|
|
begin
|
|
fptyp := Class (arg, check_error);
|
|
for i in -1 downto -fraction_width loop
|
|
fract(i) := arg(i);
|
|
end loop;
|
|
sign := to_x01(arg(arg'high));
|
|
breakcase : case fptyp is
|
|
when pos_zero | neg_zero =>
|
|
fract (0) := '0';
|
|
exp := -expon_base;
|
|
when pos_denormal | neg_denormal =>
|
|
if denormalize then
|
|
exp := -expon_base;
|
|
fract (0) := '0';
|
|
else
|
|
exp := -expon_base - 1;
|
|
fract (0) := '1';
|
|
end if;
|
|
when pos_normal | neg_normal | pos_inf | neg_inf =>
|
|
fract (0) := '1';
|
|
exp := to_01(SIGNED(arg(exponent_width-1 downto 0)), 'X');
|
|
exp (exponent_width-1) := not exp(exponent_width-1);
|
|
when others =>
|
|
assert NO_WARNING
|
|
report "FLOAT_GENERIC_PKG.BREAK_NUMBER: " &
|
|
"Meta state detected in fp_break_number process"
|
|
severity warning;
|
|
-- complete the case, if a meta state goes in, a meta state comes out.
|
|
exp := (others => '1');
|
|
fract (0) := '1';
|
|
end case breakcase;
|
|
expon := exp;
|
|
end procedure break_number;
|
|
|
|
-- Arithmetic functions
|
|
-- Synthisable
|
|
function "abs" (
|
|
arg : float) -- floating point input
|
|
return float is
|
|
variable result : 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
|
|
-- Synthisable
|
|
function "-" (
|
|
arg : float) -- floating point input
|
|
return float is
|
|
variable result : 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 "-";
|
|
|
|
-- Synthisable
|
|
function add (
|
|
l, r : 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 float is
|
|
constant fraction_width : NATURAL := -minx(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 : 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 : 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 := class (l, check_error);
|
|
rfptype := class (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 => l,
|
|
exponent_width => exponent_width,
|
|
fraction_width => fraction_width,
|
|
denormalize_in => denormalize,
|
|
denormalize => denormalize);
|
|
lfptype := class (lresize, false); -- errors already checked
|
|
rresize := resize (arg => r,
|
|
exponent_width => exponent_width,
|
|
fraction_width => fraction_width,
|
|
denormalize_in => denormalize,
|
|
denormalize => denormalize);
|
|
rfptype := class (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_reducex (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_reducex (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_reducex (fractr);
|
|
elsif shiftx > 0 then
|
|
fracts := shift_right (fractr, to_integer(shiftx));
|
|
fractc := fractl;
|
|
rexpon := exponl(exponent_width-1) & exponl;
|
|
leftright := true;
|
|
-- sticky := or_reducex (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;
|
|
|
|
-- Calls "add".
|
|
-- Synthisable
|
|
function subtract (
|
|
l, r : 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 float is
|
|
variable negr : 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;
|
|
|
|
function multiply (
|
|
l, r : 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 float is
|
|
constant fraction_width : NATURAL := -minx(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 : 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 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 : 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 := class (l, check_error);
|
|
rfptype := class (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
|
|
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 => l,
|
|
exponent_width => exponent_width,
|
|
fraction_width => fraction_width,
|
|
denormalize_in => denormalize,
|
|
denormalize => denormalize);
|
|
lfptype := class (lresize, false); -- errors already checked
|
|
rresize := resize (arg => r,
|
|
exponent_width => exponent_width,
|
|
fraction_width => fraction_width,
|
|
denormalize_in => denormalize,
|
|
denormalize => denormalize);
|
|
rfptype := class (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);
|
|
-- multiply
|
|
rfract := fractl * fractr; -- Multiply the fraction
|
|
sfract := rfract (rfract'high downto
|
|
rfract'high - (fraction_width+1+multguard));
|
|
sticky := or_reducex(rfract (rfract'high-(fraction_width+1+multguard)
|
|
downto 0));
|
|
-- add the exponents
|
|
rexpon := (exponl(exponl'high)&exponl) + (exponr(exponr'high)&exponr) +1;
|
|
-- 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 routies.
|
|
-- 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 : 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 float is
|
|
constant fraction_width : NATURAL := -minx(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); -- Unsiged 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 : float (exponent_width downto -fraction_width);
|
|
begin -- reciprocal
|
|
fptype := class(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_GENERIC_PKG.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,
|
|
-- execpt 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;
|
|
|
|
-- Synthisable
|
|
function divide (
|
|
l, r : 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 float is
|
|
constant fraction_width : NATURAL := -minx(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 : float (exponent_width downto -fraction_width);
|
|
variable ulfract, urfract : UNSIGNED (fraction_width downto 0);
|
|
-- variable fractl : unsigned((2*(fraction_width+1)+divguard+2) downto 0); -- left
|
|
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 downto 0); -- result exponent
|
|
variable fp_sign : STD_ULOGIC; -- sign of result
|
|
variable shifty : INTEGER; -- denormal number shift
|
|
variable lresize, rresize : 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 := class (l, check_error);
|
|
rfptype := class (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);
|
|
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_GENERIC_PKG.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);
|
|
end if;
|
|
when others =>
|
|
fp_sign := l(l'high) xor r(r'high); -- sign
|
|
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;
|
|
when pos_zero | neg_zero => -- 0 / X = 0
|
|
fpresult := zerofp (fraction_width => fraction_width,
|
|
exponent_width => exponent_width);
|
|
when others =>
|
|
lresize := resize (arg => l,
|
|
exponent_width => exponent_width,
|
|
fraction_width => fraction_width,
|
|
denormalize_in => denormalize,
|
|
denormalize => denormalize);
|
|
lfptype := class (lresize, false); -- errors already checked
|
|
rresize := resize (arg => r,
|
|
exponent_width => exponent_width,
|
|
fraction_width => fraction_width,
|
|
denormalize_in => denormalize,
|
|
denormalize => denormalize);
|
|
rfptype := class (rresize, false); -- errors already checked
|
|
fractl := (others => '0');
|
|
break_number (
|
|
arg => lresize,
|
|
fptyp => lfptype,
|
|
denormalize => denormalize,
|
|
fract => ulfract,
|
|
expon => exponl);
|
|
fractl (fractl'high downto fractl'high-fraction_width) := ulfract;
|
|
-- right side
|
|
fractr := (others => '0');
|
|
break_number (
|
|
arg => rresize,
|
|
fptyp => rfptype,
|
|
denormalize => denormalize,
|
|
fract => urfract,
|
|
expon => exponr);
|
|
fractr (fraction_width+divguard downto divguard) := urfract;
|
|
rexpon := (exponl(exponl'high)&exponl)
|
|
- (exponr(exponr'high)&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_msb(urfract, '1');
|
|
fractr := shift_left (fractr, shifty);
|
|
rexpon := rexpon + shifty;
|
|
end if;
|
|
-- 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 : 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 float is
|
|
constant fraction_width : NATURAL := -minx(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 : 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 : 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 := class (l, check_error);
|
|
rfptype := class (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 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);
|
|
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_GENERIC_PKG.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);
|
|
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) := l(exponent_width) xor r(exponent_width);
|
|
when pos_zero | neg_zero => -- 0 / X = 0
|
|
fpresult := zerofp (fraction_width => fraction_width,
|
|
exponent_width => exponent_width);
|
|
when others =>
|
|
lresize := resize (arg => l,
|
|
exponent_width => exponent_width,
|
|
fraction_width => fraction_width,
|
|
denormalize_in => denormalize,
|
|
denormalize => denormalize);
|
|
lfptype := class (lresize, false); -- errors already checked
|
|
rresize := resize (arg => r,
|
|
exponent_width => exponent_width,
|
|
fraction_width => fraction_width,
|
|
denormalize_in => denormalize,
|
|
denormalize => denormalize);
|
|
rfptype := class (rresize, false); -- errors already checked
|
|
fp_sign := l(l'high) xor r(r'high); -- sign
|
|
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_reducex (urfract (fraction_width-1 downto 0)) = '0')
|
|
report "FLOAT_GENERIC_PKG.DIVIDEBYP2: "
|
|
& "Divideby2 called with a none power of two denominator"
|
|
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 accumumlate result = l*r + c
|
|
function mac (
|
|
l, r, c : 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 float is
|
|
constant fraction_width : NATURAL :=
|
|
-minx (minx(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 : 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 shiftx : SIGNED(exponent_width downto 0); -- shift fractions
|
|
variable rexpon, rexpon2 : SIGNED(exponent_width downto 0); -- result exponent
|
|
variable fp_sign : STD_ULOGIC; -- sign of result
|
|
variable lresize, rresize : float (exponent_width downto -fraction_width);
|
|
variable cresize : 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 := class (l, check_error);
|
|
rfptype := class (r, check_error);
|
|
cfptype := class (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 => l,
|
|
exponent_width => exponent_width,
|
|
fraction_width => fraction_width,
|
|
denormalize_in => denormalize,
|
|
denormalize => denormalize);
|
|
lfptype := class (lresize, false); -- errors already checked
|
|
rresize := resize (arg => r,
|
|
exponent_width => exponent_width,
|
|
fraction_width => fraction_width,
|
|
denormalize_in => denormalize,
|
|
denormalize => denormalize);
|
|
rfptype := class (rresize, false); -- errors already checked
|
|
cresize := resize (arg => c,
|
|
exponent_width => exponent_width,
|
|
fraction_width => -cresize'low,
|
|
denormalize_in => denormalize,
|
|
denormalize => denormalize);
|
|
cfptype := class (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);
|
|
|
|
-- multiply
|
|
rfract := fractl * fractr; -- Multiply the fraction
|
|
-- add the exponents
|
|
rexpon := (exponl(exponl'high)&exponl) + (exponr(exponr'high)&exponr) +1;
|
|
shiftx := rexpon - exponc;
|
|
if shiftx < -fractl'high then
|
|
rexpon2 := exponc(exponent_width-1) & exponc;
|
|
fractc := "0" & fractx;
|
|
fracts := (others => '0');
|
|
sticky := or_reducex (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 := exponc(exponent_width-1) & exponc;
|
|
leftright := false;
|
|
sticky := or_reducex (rfract (to_integer(shiftx)+rfract'high
|
|
- fracts'length downto 0));
|
|
elsif shiftx = 0 then
|
|
rexpon2 := exponc(exponent_width-1) & exponc;
|
|
sticky := or_reducex (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_reducex (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_reducex (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;
|
|
|
|
function remainder (
|
|
l, r : 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 float is
|
|
constant fraction_width : NATURAL := -minx(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 : 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 : 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 := class (l, check_error);
|
|
rfptype := class (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,5
|
|
or (rfptype = pos_zero or rfptype = neg_zero) then -- x rem 0
|
|
-- Return quiet NAN, IEEE754-1985-7.1,5
|
|
fpresult := qnanfp (fraction_width => fraction_width,
|
|
exponent_width => exponent_width);
|
|
elsif (rfptype = pos_inf or rfptype = neg_inf) then -- x rem inf = 0
|
|
fpresult := zerofp (fraction_width => fraction_width,
|
|
exponent_width => exponent_width);
|
|
elsif (abs(l) < abs(r)) then
|
|
fpresult := l;
|
|
else
|
|
fp_sign := to_X01(l(l'high)); -- sign
|
|
lresize := resize (arg => l,
|
|
exponent_width => exponent_width,
|
|
fraction_width => fraction_width,
|
|
denormalize_in => denormalize,
|
|
denormalize => denormalize);
|
|
lfptype := class (lresize, false); -- errors already checked
|
|
rresize := resize (arg => r,
|
|
exponent_width => exponent_width,
|
|
fraction_width => fraction_width,
|
|
denormalize_in => denormalize,
|
|
denormalize => denormalize);
|
|
rfptype := class (rresize, false); -- errors already checked
|
|
fractl := (others => '0');
|
|
break_number (
|
|
arg => lresize,
|
|
fptyp => lfptype,
|
|
denormalize => denormalize,
|
|
fract => ulfract,
|
|
expon => exponl);
|
|
fractl (fraction_width+divguard downto divguard) := ulfract;
|
|
-- right side
|
|
fractr := (others => '0');
|
|
break_number (
|
|
arg => rresize,
|
|
fptyp => rfptype,
|
|
denormalize => denormalize,
|
|
fract => urfract,
|
|
expon => exponr);
|
|
fractr (fraction_width+divguard downto divguard) := urfract;
|
|
rexpon := (exponr(exponr'high)&exponr);
|
|
shifty := to_integer(exponl - rexpon);
|
|
if (shifty > 0) then
|
|
fractr := shift_right (fractr, shifty);
|
|
rexpon := rexpon + shifty;
|
|
end if;
|
|
if (fractr /= 0) then
|
|
-- rem
|
|
rfract := fractl rem fractr; -- unsigned rem
|
|
sfract := rfract (sfract'range); -- lower bits
|
|
-- normalize
|
|
fpresult := normalize (fract => sfract,
|
|
expon => rexpon,
|
|
sign => fp_sign,
|
|
fraction_width => fraction_width,
|
|
exponent_width => exponent_width,
|
|
round_style => round_style,
|
|
denormalize => denormalize,
|
|
nguard => divguard);
|
|
else
|
|
-- If we shift "fractr" so far that it becomes zero, return zero.
|
|
fpresult := zerofp (fraction_width => fraction_width,
|
|
exponent_width => exponent_width);
|
|
end if;
|
|
end if;
|
|
return fpresult;
|
|
end function remainder;
|
|
|
|
function modulo (
|
|
l, r : 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 float is
|
|
constant fraction_width : NATURAL := - minx(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 : float (exponent_width downto -fraction_width);
|
|
variable remres : 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 := class (l, check_error);
|
|
rfptype := class (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,5
|
|
or (rfptype = pos_zero or rfptype = neg_zero) then -- x rem 0
|
|
-- Return quiet NAN, IEEE754-1985-7.1,5
|
|
fpresult := qnanfp (fraction_width => fraction_width,
|
|
exponent_width => exponent_width);
|
|
elsif (rfptype = pos_inf or rfptype = neg_inf) then -- x rem inf = 0
|
|
fpresult := zerofp (fraction_width => fraction_width,
|
|
exponent_width => exponent_width);
|
|
else
|
|
remres := remainder (l => abs(l),
|
|
r => abs(r),
|
|
round_style => round_style,
|
|
guard => guard,
|
|
check_error => false,
|
|
denormalize => denormalize);
|
|
-- MOD is the same as REM, but you do something different with
|
|
-- negative values
|
|
if (is_negative (l)) then
|
|
remres := - remres;
|
|
end if;
|
|
if (is_negative (l) = is_negative (r) or remres = 0) then
|
|
fpresult := remres;
|
|
else
|
|
fpresult := add (l => remres,
|
|
r => r,
|
|
round_style => round_style,
|
|
guard => guard,
|
|
check_error => false,
|
|
denormalize => denormalize);
|
|
end if;
|
|
end if;
|
|
return fpresult;
|
|
end function modulo;
|
|
|
|
function Is_Negative (arg : float) return BOOLEAN is
|
|
begin
|
|
return (to_x01(arg(arg'high)) = '1');
|
|
end function Is_Negative;
|
|
|
|
-- compare functions
|
|
-- =, /=, >=, <=, <, >
|
|
|
|
-- Synthisable
|
|
function eq ( -- equal =
|
|
l, r : float; -- floating point input
|
|
constant check_error : BOOLEAN := float_check_error;
|
|
constant denormalize : BOOLEAN := float_denormalize)
|
|
return BOOLEAN is
|
|
variable lfptype, rfptype : valid_fpstate;
|
|
variable is_equal, is_unordered : BOOLEAN;
|
|
constant fraction_width : NATURAL := -minx(l'low, r'low); -- length of FP output fraction
|
|
constant exponent_width : NATURAL := maximum(l'high, r'high); -- length of FP output exponent
|
|
variable lresize, rresize : float (exponent_width downto -fraction_width);
|
|
begin -- equal
|
|
if (fraction_width = 0 or l'length < 7 or r'length < 7) then
|
|
return false;
|
|
else
|
|
lfptype := class (l, check_error);
|
|
rfptype := class (r, check_error);
|
|
end if;
|
|
if (lfptype = neg_zero or lfptype = pos_zero) and
|
|
(rfptype = neg_zero or rfptype = pos_zero) then
|
|
is_equal := true;
|
|
else
|
|
lresize := resize (arg => l,
|
|
exponent_width => exponent_width,
|
|
fraction_width => fraction_width,
|
|
denormalize_in => denormalize,
|
|
denormalize => denormalize);
|
|
rresize := resize (arg => r,
|
|
exponent_width => exponent_width,
|
|
fraction_width => fraction_width,
|
|
denormalize_in => denormalize,
|
|
denormalize => denormalize);
|
|
is_equal := (to_slv(lresize) = to_slv(rresize));
|
|
end if;
|
|
if (check_error) then
|
|
is_unordered := Unordered (x => l,
|
|
y => r);
|
|
else
|
|
is_unordered := false;
|
|
end if;
|
|
return is_equal and not is_unordered;
|
|
end function eq;
|
|
|
|
-- Synthisable
|
|
function lt ( -- less than <
|
|
l, r : float; -- floating point input
|
|
constant check_error : BOOLEAN := float_check_error;
|
|
constant denormalize : BOOLEAN := float_denormalize)
|
|
return BOOLEAN is
|
|
constant fraction_width : NATURAL := -minx(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 expl, expr : UNSIGNED (exponent_width-1 downto 0);
|
|
variable fractl, fractr : UNSIGNED (fraction_width-1 downto 0);
|
|
variable is_less_than, is_unordered : BOOLEAN;
|
|
variable lresize, rresize : float (exponent_width downto -fraction_width);
|
|
begin
|
|
if (fraction_width = 0 or l'length < 7 or r'length < 7) then
|
|
is_less_than := false;
|
|
else
|
|
lresize := resize (arg => l,
|
|
exponent_width => exponent_width,
|
|
fraction_width => fraction_width,
|
|
denormalize_in => denormalize,
|
|
denormalize => denormalize);
|
|
rresize := resize (arg => r,
|
|
exponent_width => exponent_width,
|
|
fraction_width => fraction_width,
|
|
denormalize_in => denormalize,
|
|
denormalize => denormalize);
|
|
if to_x01(l(l'high)) = to_x01(r(r'high)) then -- sign bits
|
|
expl := to_01(UNSIGNED(lresize(exponent_width-1 downto 0)), 'X');
|
|
expr := to_01(UNSIGNED(rresize(exponent_width-1 downto 0)), 'X');
|
|
if expl = expr then
|
|
fractl := UNSIGNED (to_slv(lresize(-1 downto -fraction_width)));
|
|
fractr := UNSIGNED (to_slv(rresize(-1 downto -fraction_width)));
|
|
if to_x01(l(l'high)) = '0' then -- positive number
|
|
is_less_than := (fractl < fractr);
|
|
else
|
|
is_less_than := (fractl > fractr); -- negative
|
|
end if;
|
|
else
|
|
if to_x01(l(l'high)) = '0' then -- positive number
|
|
is_less_than := (expl < expr);
|
|
else
|
|
is_less_than := (expl > expr); -- negative
|
|
end if;
|
|
end if;
|
|
else
|
|
lfptype := class (l, check_error);
|
|
rfptype := class (r, check_error);
|
|
if (lfptype = neg_zero and rfptype = pos_zero) then
|
|
is_less_than := false; -- -0 < 0 returns false.
|
|
else
|
|
is_less_than := (to_x01(l(l'high)) > to_x01(r(r'high)));
|
|
end if;
|
|
end if;
|
|
end if;
|
|
if check_error then
|
|
is_unordered := Unordered (x => l,
|
|
y => r);
|
|
else
|
|
is_unordered := false;
|
|
end if;
|
|
return is_less_than and not is_unordered;
|
|
end function lt;
|
|
|
|
-- Synthisable
|
|
function gt ( -- greater than >
|
|
l, r : float; -- floating point input
|
|
constant check_error : BOOLEAN := float_check_error;
|
|
constant denormalize : BOOLEAN := float_denormalize)
|
|
return BOOLEAN is
|
|
constant fraction_width : NATURAL := -minx(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 expl, expr : UNSIGNED (exponent_width-1 downto 0);
|
|
variable fractl, fractr : UNSIGNED (fraction_width-1 downto 0);
|
|
variable is_greater_than : BOOLEAN;
|
|
variable is_unordered : BOOLEAN;
|
|
variable lresize, rresize : float (exponent_width downto -fraction_width);
|
|
begin -- greater_than
|
|
if (fraction_width = 0 or l'length < 7 or r'length < 7) then
|
|
is_greater_than := false;
|
|
else
|
|
lresize := resize (arg => l,
|
|
exponent_width => exponent_width,
|
|
fraction_width => fraction_width,
|
|
denormalize_in => denormalize,
|
|
denormalize => denormalize);
|
|
rresize := resize (arg => r,
|
|
exponent_width => exponent_width,
|
|
fraction_width => fraction_width,
|
|
denormalize_in => denormalize,
|
|
denormalize => denormalize);
|
|
if to_x01(l(l'high)) = to_x01(r(r'high)) then -- sign bits
|
|
expl := to_01(UNSIGNED(lresize(exponent_width-1 downto 0)), 'X');
|
|
expr := to_01(UNSIGNED(rresize(exponent_width-1 downto 0)), 'X');
|
|
if expl = expr then
|
|
fractl := UNSIGNED (to_slv(lresize(-1 downto -fraction_width)));
|
|
fractr := UNSIGNED (to_slv(rresize(-1 downto -fraction_width)));
|
|
if to_x01(l(l'high)) = '0' then -- positive number
|
|
is_greater_than := fractl > fractr;
|
|
else
|
|
is_greater_than := fractl < fractr; -- negative
|
|
end if;
|
|
else
|
|
if to_x01(l(l'high)) = '0' then -- positive number
|
|
is_greater_than := expl > expr;
|
|
else
|
|
is_greater_than := expl < expr; -- negative
|
|
end if;
|
|
end if;
|
|
else
|
|
lfptype := class (l, check_error);
|
|
rfptype := class (r, check_error);
|
|
if (lfptype = pos_zero and rfptype = neg_zero) then
|
|
is_greater_than := false; -- 0 > -0 returns false.
|
|
else
|
|
is_greater_than := to_x01(l(l'high)) < to_x01(r(r'high));
|
|
end if;
|
|
end if;
|
|
end if;
|
|
if check_error then
|
|
is_unordered := Unordered (x => l,
|
|
y => r);
|
|
else
|
|
is_unordered := false;
|
|
end if;
|
|
return is_greater_than and not is_unordered;
|
|
end function gt;
|
|
|
|
-- purpose: /= function
|
|
function ne ( -- not equal /=
|
|
l, r : float;
|
|
constant check_error : BOOLEAN := float_check_error;
|
|
constant denormalize : BOOLEAN := float_denormalize)
|
|
return BOOLEAN is
|
|
variable is_equal, is_unordered : BOOLEAN;
|
|
begin
|
|
is_equal := eq (l => l,
|
|
r => r,
|
|
check_error => false,
|
|
denormalize => denormalize);
|
|
if check_error then
|
|
is_unordered := Unordered (x => l,
|
|
y => r);
|
|
else
|
|
is_unordered := false;
|
|
end if;
|
|
return not (is_equal and not is_unordered);
|
|
end function ne;
|
|
|
|
function le ( -- less than or equal to <=
|
|
l, r : float; -- floating point input
|
|
constant check_error : BOOLEAN := float_check_error;
|
|
constant denormalize : BOOLEAN := float_denormalize)
|
|
return BOOLEAN is
|
|
variable is_greater_than, is_unordered : BOOLEAN;
|
|
begin
|
|
is_greater_than := gt (l => l,
|
|
r => r,
|
|
check_error => false,
|
|
denormalize => denormalize);
|
|
if check_error then
|
|
is_unordered := Unordered (x => l,
|
|
y => r);
|
|
else
|
|
is_unordered := false;
|
|
end if;
|
|
return not is_greater_than and not is_unordered;
|
|
end function le;
|
|
|
|
function ge ( -- greather than or equal to >=
|
|
l, r : float; -- floating point input
|
|
constant check_error : BOOLEAN := float_check_error;
|
|
constant denormalize : BOOLEAN := float_denormalize)
|
|
return BOOLEAN is
|
|
variable is_less_than, is_unordered : BOOLEAN;
|
|
begin
|
|
is_less_than := lt (l => l,
|
|
r => r,
|
|
check_error => false,
|
|
denormalize => denormalize);
|
|
if check_error then
|
|
is_unordered := Unordered (x => l,
|
|
y => r);
|
|
else
|
|
is_unordered := false;
|
|
end if;
|
|
return not is_less_than and not is_unordered;
|
|
end function ge;
|
|
|
|
--%%% Uncomment the following function
|
|
-- function "?=" (L, R: float) return std_ulogic is
|
|
function \?=\ (L, R : float) return STD_ULOGIC is
|
|
constant fraction_width : NATURAL := -minx(l'low, r'low); -- length of FP output fraction
|
|
constant exponent_width : NATURAL := maximum(l'high, r'high); -- length of FP output exponent
|
|
variable lresize, rresize : float (exponent_width downto -fraction_width);
|
|
begin -- ?=
|
|
if (fraction_width = 0 or l'length < 7 or r'length < 7) then
|
|
return 'X';
|
|
else
|
|
lresize := resize (arg => l,
|
|
exponent_width => exponent_width,
|
|
fraction_width => fraction_width,
|
|
denormalize_in => float_denormalize,
|
|
denormalize => float_denormalize);
|
|
rresize := resize (arg => r,
|
|
exponent_width => exponent_width,
|
|
fraction_width => fraction_width,
|
|
denormalize_in => float_denormalize,
|
|
denormalize => float_denormalize);
|
|
return \?=\ (ufixed(lresize), ufixed(rresize));
|
|
--%%% return (to_slv(lresize) ?= to_slv(rresize));
|
|
end if;
|
|
end function \?=\;
|
|
--%%% end function "?=";
|
|
|
|
function \?/=\ (L, R : float) return STD_ULOGIC is
|
|
constant fraction_width : NATURAL := -minx(l'low, r'low); -- length of FP output fraction
|
|
constant exponent_width : NATURAL := maximum(l'high, r'high); -- length of FP output exponent
|
|
variable lresize, rresize : float (exponent_width downto -fraction_width);
|
|
begin -- ?/=
|
|
if (fraction_width = 0 or l'length < 7 or r'length < 7) then
|
|
return 'X';
|
|
else
|
|
lresize := resize (arg => l,
|
|
exponent_width => exponent_width,
|
|
fraction_width => fraction_width,
|
|
denormalize_in => float_denormalize,
|
|
denormalize => float_denormalize);
|
|
rresize := resize (arg => r,
|
|
exponent_width => exponent_width,
|
|
fraction_width => fraction_width,
|
|
denormalize_in => float_denormalize,
|
|
denormalize => float_denormalize);
|
|
return \?/=\ (ufixed(lresize), ufixed(rresize));
|
|
--%%% return (to_slv(lresize) ?/= to_slv(rresize));
|
|
end if;
|
|
end function \?/=\;
|
|
--%%% end function "?/=";
|
|
|
|
-- %%% function "?>" (L, R : float) return std_ulogic is
|
|
function \?>\ (L, R : float) return std_ulogic is
|
|
constant fraction_width : NATURAL := -minx(l'low, r'low);
|
|
begin
|
|
if (fraction_width = 0 or l'length < 7 or r'length < 7) then
|
|
return 'X';
|
|
elsif (find_msb (l, '-') /= l'low-1)
|
|
or (find_msb (r, '-') /= r'low-1) then
|
|
report "float_generic_pkg.""?>"": '-' found in compare string"
|
|
severity error;
|
|
return 'X';
|
|
else
|
|
if is_x(l) or is_x(r) then
|
|
return 'X';
|
|
elsif l > r then
|
|
return '1';
|
|
else
|
|
return '0';
|
|
end if;
|
|
end if;
|
|
end function \?>\;
|
|
-- %%% end function "?>";
|
|
|
|
-- %%% function "?>=" (L, R : float) return std_ulogic is
|
|
function \?>=\ (L, R : float) return std_ulogic is
|
|
constant fraction_width : NATURAL := -minx(l'low, r'low);
|
|
begin
|
|
if (fraction_width = 0 or l'length < 7 or r'length < 7) then
|
|
return 'X';
|
|
elsif (find_msb (l, '-') /= l'low-1)
|
|
or (find_msb (r, '-') /= r'low-1) then
|
|
report "float_generic_pkg.""?>="": '-' found in compare string"
|
|
severity error;
|
|
return 'X';
|
|
else
|
|
if is_x(l) or is_x(r) then
|
|
return 'X';
|
|
elsif l >= r then
|
|
return '1';
|
|
else
|
|
return '0';
|
|
end if;
|
|
end if;
|
|
end function \?>=\;
|
|
-- %%% end function "?>=";
|
|
|
|
-- %%% function "?<" (L, R : float) return std_ulogic is
|
|
function \?<\ (L, R : float) return std_ulogic is
|
|
constant fraction_width : NATURAL := -minx(l'low, r'low);
|
|
begin
|
|
if (fraction_width = 0 or l'length < 7 or r'length < 7) then
|
|
return 'X';
|
|
elsif (find_msb (l, '-') /= l'low-1)
|
|
or (find_msb (r, '-') /= r'low-1) then
|
|
report "float_generic_pkg.""?<"": '-' found in compare string"
|
|
severity error;
|
|
return 'X';
|
|
else
|
|
if is_x(l) or is_x(r) then
|
|
return 'X';
|
|
elsif l < r then
|
|
return '1';
|
|
else
|
|
return '0';
|
|
end if;
|
|
end if;
|
|
end function \?<\;
|
|
-- %%% end function "?<";
|
|
|
|
-- %%% function "?<=" (L, R : float) return std_ulogic is
|
|
function \?<=\ (L, R : float) return std_ulogic is
|
|
constant fraction_width : NATURAL := -minx(l'low, r'low);
|
|
begin
|
|
if (fraction_width = 0 or l'length < 7 or r'length < 7) then
|
|
return 'X';
|
|
elsif (find_msb (l, '-') /= l'low-1)
|
|
or (find_msb (r, '-') /= r'low-1) then
|
|
report "float_generic_pkg.""?<="": '-' found in compare string"
|
|
severity error;
|
|
return 'X';
|
|
else
|
|
if is_x(l) or is_x(r) then
|
|
return 'X';
|
|
elsif l <= r then
|
|
return '1';
|
|
else
|
|
return '0';
|
|
end if;
|
|
end if;
|
|
end function \?<=\;
|
|
-- %%% end function "?<=";
|
|
|
|
function std_match (L, R : float) return BOOLEAN is
|
|
begin
|
|
return std_match(to_slv(L), to_slv(R));
|
|
end function std_match;
|
|
|
|
function find_lsb (arg : float; y : STD_ULOGIC) return INTEGER is
|
|
begin
|
|
for_loop : for i in arg'low to arg'high loop
|
|
if arg(i) = y then
|
|
return i;
|
|
end if;
|
|
end loop;
|
|
return arg'high+1; -- return out of bounds 'high
|
|
end function find_lsb;
|
|
|
|
function find_msb (arg : float; y : STD_ULOGIC) return INTEGER is
|
|
begin
|
|
for_loop : for i in arg'high downto arg'low loop
|
|
if arg(i) = y then
|
|
return i;
|
|
end if;
|
|
end loop;
|
|
return arg'low-1; -- return out of bounds 'low
|
|
end function find_msb;
|
|
|
|
-- These override the defaults for the compare operators.
|
|
function "=" (l, r : float) return BOOLEAN is
|
|
begin
|
|
return eq(l, r);
|
|
end function "=";
|
|
function "/=" (l, r : float) return BOOLEAN is
|
|
begin
|
|
return ne(l, r);
|
|
end function "/=";
|
|
function ">=" (l, r : float) return BOOLEAN is
|
|
begin
|
|
return ge(l, r);
|
|
end function ">=";
|
|
function "<=" (l, r : float) return BOOLEAN is
|
|
begin
|
|
return le(l, r);
|
|
end function "<=";
|
|
function ">" (l, r : float) return BOOLEAN is
|
|
begin
|
|
return gt(l, r);
|
|
end function ">";
|
|
function "<" (l, r : float) return BOOLEAN is
|
|
begin
|
|
return lt(l, r);
|
|
end function "<";
|
|
-- purpose: maximum of two numbers (overrides default)
|
|
function maximum (
|
|
L, R : float)
|
|
return float is
|
|
begin
|
|
if l > r then return l;
|
|
else return r;
|
|
end if;
|
|
end function maximum;
|
|
|
|
function minimum (
|
|
L, R : float)
|
|
return float is
|
|
begin
|
|
if l > r then return r;
|
|
else return l;
|
|
end if;
|
|
end function minimum;
|
|
|
|
-----------------------------------------------------------------------------
|
|
-- conversion functions
|
|
-----------------------------------------------------------------------------
|
|
|
|
-- Converts a floating point number of one format into another format
|
|
-- Synthesizable
|
|
function resize (
|
|
arg : 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 float is
|
|
constant in_fraction_width : NATURAL := -arg'low; -- length of FP output fraction
|
|
constant in_exponent_width : NATURAL := arg'high; -- length of FP output exponent
|
|
variable result : float (exponent_width downto -fraction_width);
|
|
-- result value
|
|
variable fptype : valid_fpstate;
|
|
variable expon_in : SIGNED (in_exponent_width-1 downto 0);
|
|
variable fract_in : UNSIGNED (in_fraction_width downto 0);
|
|
variable round : BOOLEAN;
|
|
variable expon_out : SIGNED (exponent_width-1 downto 0); -- output fract
|
|
variable fract_out : UNSIGNED (fraction_width downto 0); -- output fract
|
|
variable passguard : NATURAL;
|
|
begin
|
|
fptype := class(arg, check_error);
|
|
if ((fptype = pos_denormal or fptype = neg_denormal) and denormalize_in
|
|
and (in_exponent_width < exponent_width
|
|
or in_fraction_width < fraction_width))
|
|
or in_exponent_width > exponent_width
|
|
or in_fraction_width > fraction_width then
|
|
-- size reduction
|
|
classcase : case fptype is
|
|
when isx =>
|
|
result := (others => 'X');
|
|
when nan | quiet_nan =>
|
|
result := qnanfp (fraction_width => fraction_width,
|
|
exponent_width => exponent_width);
|
|
when pos_inf =>
|
|
result := pos_inffp (fraction_width => fraction_width,
|
|
exponent_width => exponent_width);
|
|
when neg_inf =>
|
|
result := neg_inffp (fraction_width => fraction_width,
|
|
exponent_width => exponent_width);
|
|
when pos_zero | neg_zero =>
|
|
result := zerofp (fraction_width => fraction_width, -- hate -0
|
|
exponent_width => exponent_width);
|
|
when others =>
|
|
break_number (
|
|
arg => arg,
|
|
fptyp => fptype,
|
|
denormalize => denormalize_in,
|
|
fract => fract_in,
|
|
expon => expon_in);
|
|
if fraction_width > in_fraction_width and denormalize_in then
|
|
-- You only get here if you have a denormal input
|
|
fract_out := (others => '0'); -- pad with zeros
|
|
fract_out (fraction_width downto
|
|
fraction_width - in_fraction_width) := fract_in;
|
|
result := normalize (
|
|
fract => fract_out,
|
|
expon => expon_in,
|
|
sign => arg(arg'high),
|
|
fraction_width => fraction_width,
|
|
exponent_width => exponent_width,
|
|
round_style => round_style,
|
|
denormalize => denormalize,
|
|
nguard => 0);
|
|
else
|
|
result := normalize (
|
|
fract => fract_in,
|
|
expon => expon_in,
|
|
sign => arg(arg'high),
|
|
fraction_width => fraction_width,
|
|
exponent_width => exponent_width,
|
|
round_style => round_style,
|
|
denormalize => denormalize,
|
|
nguard => in_fraction_width - fraction_width);
|
|
end if;
|
|
end case classcase;
|
|
else -- size increase or the same size
|
|
if exponent_width > in_exponent_width then
|
|
expon_in := signed(arg (in_exponent_width-1 downto 0));
|
|
if fptype = pos_zero or fptype = neg_zero then
|
|
result (exponent_width-1 downto 0) := (others => '0');
|
|
elsif expon_in = -1 then -- inf or nan (shorts out check_error)
|
|
result (exponent_width-1 downto 0) := (others => '1');
|
|
else
|
|
-- invert top BIT
|
|
expon_in(expon_in'high) := not expon_in(expon_in'high);
|
|
expon_out := resize (expon_in, expon_out'length); -- signed expand
|
|
-- Flip it back.
|
|
expon_out(expon_out'high) := not expon_out(expon_out'high);
|
|
result (exponent_width-1 downto 0) := float(expon_out);
|
|
end if;
|
|
result (exponent_width) := arg (in_exponent_width); -- sign
|
|
else -- exponent_width = in_exponent_width
|
|
result (exponent_width downto 0) := arg (in_exponent_width downto 0);
|
|
end if;
|
|
if fraction_width > in_fraction_width then
|
|
result (-1 downto -fraction_width) := (others => '0'); -- zeros
|
|
result (-1 downto -in_fraction_width) :=
|
|
arg (-1 downto -in_fraction_width);
|
|
else -- fraction_width = in_fraciton_width
|
|
result (-1 downto -fraction_width) :=
|
|
arg (-1 downto -in_fraction_width);
|
|
end if;
|
|
end if;
|
|
return result;
|
|
end function resize;
|
|
|
|
function resize (
|
|
arg : float; -- Floating point input
|
|
size_res : 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 float is
|
|
variable result : float (size_res'left downto size_res'right);
|
|
begin
|
|
if (result'length < 1) then
|
|
return result;
|
|
else
|
|
result := resize (arg => arg,
|
|
fraction_width => -size_res'low,
|
|
exponent_width => size_res'high,
|
|
round_style => round_style,
|
|
check_error => check_error,
|
|
denormalize_in => denormalize_in,
|
|
denormalize => denormalize);
|
|
return result;
|
|
end if;
|
|
end function resize;
|
|
|
|
function to_float32 (
|
|
arg : 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 float is
|
|
begin
|
|
return resize (arg => arg,
|
|
exponent_width => float32'high,
|
|
fraction_width => -float32'low,
|
|
round_style => round_style,
|
|
check_error => check_error,
|
|
denormalize_in => denormalize_in,
|
|
denormalize => denormalize);
|
|
end function to_float32;
|
|
|
|
function to_float64 (
|
|
arg : 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 float is
|
|
begin
|
|
return resize (arg => arg,
|
|
exponent_width => float64'high,
|
|
fraction_width => -float64'low,
|
|
round_style => round_style,
|
|
check_error => check_error,
|
|
denormalize_in => denormalize_in,
|
|
denormalize => denormalize);
|
|
end function to_float64;
|
|
|
|
function to_float128 (
|
|
arg : 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 float is
|
|
begin
|
|
return resize (arg => arg,
|
|
exponent_width => float128'high,
|
|
fraction_width => -float128'low,
|
|
round_style => round_style,
|
|
check_error => check_error,
|
|
denormalize_in => denormalize_in,
|
|
denormalize => denormalize);
|
|
end function to_float128;
|
|
|
|
-- to_float (Real)
|
|
-- Not Synthisable (unless the input is a constant)
|
|
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 float is
|
|
variable result : float (exponent_width downto -fraction_width);
|
|
variable arg_real : REAL; -- Real version of argument
|
|
variable validfp : boundary_type; -- Check for valid results
|
|
variable exp : INTEGER; -- Integer version of exponent
|
|
variable exp_real : REAL; -- real version of exponent
|
|
variable expon : UNSIGNED (exponent_width - 1 downto 0);
|
|
-- Unsigned version of exp.
|
|
constant expon_base : SIGNED (exponent_width-1 downto 0) :=
|
|
gen_expon_base(exponent_width); -- exponent offset
|
|
variable fract : UNSIGNED (fraction_width-1 downto 0);
|
|
variable frac : REAL; -- Real version of fraction
|
|
constant roundfrac : REAL := 2.0 ** (-2 - fract'high); -- used for rounding
|
|
variable round : BOOLEAN; -- to round or not to round
|
|
begin
|
|
result := (others => '0');
|
|
arg_real := arg;
|
|
if arg_real < 0.0 then
|
|
result (exponent_width) := '1';
|
|
arg_real := 0.0 - arg_real; -- Make it positive.
|
|
else
|
|
result (exponent_width) := '0';
|
|
end if;
|
|
validfp := test_boundary (arg => arg_real,
|
|
fraction_width => fraction_width,
|
|
exponent_width => exponent_width,
|
|
denormalize => denormalize);
|
|
if validfp = zero then
|
|
return result; -- Result initialized to "0".
|
|
elsif validfp = infinity then
|
|
result (exponent_width - 1 downto 0) := (others => '1'); -- Exponent all "1"
|
|
-- return infinity.
|
|
return result;
|
|
else
|
|
if validfp = denormal then -- Exponent will default to "0".
|
|
expon := (others => '0');
|
|
frac := arg_real * (2.0 ** (to_integer(expon_base)-1));
|
|
else -- Number less than 1. "normal" number
|
|
-- exp_real := log (arg_real)/ log (2.0);
|
|
exp_real := log2 (arg_real);
|
|
exp := INTEGER (floor(exp_real)); -- positive fraction.
|
|
expon := UNSIGNED (to_signed (exp-1, exponent_width));
|
|
expon(exponent_width-1) := not expon(exponent_width-1);
|
|
frac := (arg_real / 2.0 ** exp) - 1.0; -- Number less than 1.
|
|
end if;
|
|
for i in 0 to fract'high loop
|
|
if frac >= 2.0 ** (-1 - i) then
|
|
fract (fract'high - i) := '1';
|
|
frac := frac - 2.0 ** (-1 - i);
|
|
else
|
|
fract (fract'high - i) := '0';
|
|
end if;
|
|
end loop;
|
|
round := false;
|
|
case round_style is
|
|
when round_nearest =>
|
|
if frac > roundfrac or ((frac = roundfrac) and fract(0) = '1') then
|
|
round := true;
|
|
end if;
|
|
when round_inf =>
|
|
if frac /= 0.0 and result(exponent_width) = '0' then
|
|
round := true;
|
|
end if;
|
|
when round_neginf =>
|
|
if frac /= 0.0 and result(exponent_width) = '1' then
|
|
round := true;
|
|
end if;
|
|
when round_zero =>
|
|
null; -- don't round
|
|
end case;
|
|
if (round) then
|
|
if and_reducex(fract) = '1' then -- fraction is all "1"
|
|
expon := expon + 1;
|
|
fract := (others => '0');
|
|
else
|
|
fract := fract + 1;
|
|
end if;
|
|
end if;
|
|
result (exponent_width-1 downto 0) := float(expon);
|
|
result (-1 downto -fraction_width) := float(fract);
|
|
return result;
|
|
end if;
|
|
end function to_float;
|
|
|
|
-- to_float (Integer)
|
|
-- Synthisable
|
|
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 float is
|
|
variable result : float (exponent_width downto -fraction_width);
|
|
variable arg_int : INTEGER; -- Real version of argument
|
|
variable rexp : SIGNED (exponent_width - 1 downto 0);
|
|
variable exp : SIGNED (exponent_width - 1 downto 0);
|
|
-- signed version of exp.
|
|
variable expon : UNSIGNED (exponent_width - 1 downto 0);
|
|
-- Unsigned version of exp.
|
|
variable rfract : UNSIGNED (fraction_width-1 downto 0);
|
|
variable fract : UNSIGNED (fraction_width-1 downto 0);
|
|
variable round : BOOLEAN;
|
|
constant frac_base : INTEGER := 30; -- Base to multiply fraction by
|
|
variable fract_shift : UNSIGNED (frac_base downto 0);
|
|
-- unshifted fract
|
|
variable validfp : boundary_type; -- used to check integer
|
|
begin
|
|
if arg < 0 then
|
|
result (exponent_width) := '1';
|
|
arg_int := -arg; -- Make it positive.
|
|
else
|
|
result (exponent_width) := '0';
|
|
arg_int := arg;
|
|
end if;
|
|
validfp := fp_input_type (arg => arg_int,
|
|
exponent_width => exponent_width,
|
|
fraction_width => fraction_width);
|
|
if validfp = zero then
|
|
result := zerofp (fraction_width => fraction_width,
|
|
exponent_width => exponent_width);
|
|
elsif validfp = infinity then
|
|
if result (exponent_width) = '0' then
|
|
result := pos_inffp (fraction_width => fraction_width,
|
|
exponent_width => exponent_width);
|
|
else
|
|
-- return infinity.
|
|
result := neg_inffp (fraction_width => fraction_width,
|
|
exponent_width => exponent_width);
|
|
end if;
|
|
else -- Normal number (can't be denormal)
|
|
-- Compute Exponent
|
|
exp := to_signed (log2(arg_int), exp'length); -- positive fraction.
|
|
-- Compute Fraction
|
|
fract_shift := to_unsigned (arg_int, frac_base+1);
|
|
fract_shift := shift_left (fract_shift, (frac_base-to_integer(exp)));
|
|
-- pull out the fraction
|
|
fract := (others => '0'); -- zero out fraction first.
|
|
fract (fract'high downto maximum(0, fract'high-(frac_base-1))) :=
|
|
fract_shift (frac_base-1 downto maximum(0, frac_base-1-fract'high));
|
|
-- Round
|
|
if frac_base-1-fract'high > 0 then
|
|
round := check_round (
|
|
fract_in => fract (0),
|
|
sign => result (exponent_width),
|
|
remainder => fract_shift (frac_base-2-fract'high
|
|
downto 0),
|
|
round_style => round_style);
|
|
if round then
|
|
fp_round(fract_in => fract,
|
|
expon_in => exp,
|
|
fract_out => rfract,
|
|
expon_out => rexp);
|
|
else
|
|
rfract := fract;
|
|
rexp := exp;
|
|
end if;
|
|
else
|
|
rexp := exp;
|
|
rfract := fract;
|
|
end if;
|
|
expon := UNSIGNED (rexp-1);
|
|
expon(exponent_width-1) := not expon(exponent_width-1);
|
|
result (exponent_width-1 downto 0) := float(expon);
|
|
result (-1 downto -fraction_width) := float(rfract);
|
|
end if;
|
|
return result;
|
|
end function to_float;
|
|
|
|
-- to_float (unsigned)
|
|
-- Synthesizable
|
|
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 float is
|
|
variable result : float (exponent_width downto -fraction_width);
|
|
constant ARG_LEFT : INTEGER := ARG'length-1;
|
|
alias XARG : UNSIGNED(ARG_LEFT downto 0) is ARG;
|
|
variable arg_int : UNSIGNED(xarg'range); -- Real version of argument
|
|
variable argb2 : UNSIGNED(xarg'high/2 downto 0); -- log2 of input
|
|
variable rexp : SIGNED (exponent_width - 1 downto 0);
|
|
variable exp : SIGNED (exponent_width - 1 downto 0);
|
|
-- signed version of exp.
|
|
variable expon : UNSIGNED (exponent_width - 1 downto 0);
|
|
-- Unsigned version of exp.
|
|
constant expon_base : SIGNED (exponent_width-1 downto 0) :=
|
|
gen_expon_base(exponent_width); -- exponent offset
|
|
variable round : BOOLEAN;
|
|
variable fract : UNSIGNED (fraction_width-1 downto 0);
|
|
variable rfract : UNSIGNED (fraction_width-1 downto 0);
|
|
begin
|
|
arg_int := UNSIGNED(to_x01(STD_LOGIC_VECTOR (xarg)));
|
|
if (or_reducex (arg_int) = 'X') then
|
|
result := (others => 'X');
|
|
elsif (arg_int = 0) then
|
|
result := zerofp (fraction_width => fraction_width,
|
|
exponent_width => exponent_width);
|
|
else -- Normal number (can't be denormal)
|
|
result (exponent_width) := '0'; -- positive sign
|
|
-- Compute Exponent
|
|
argb2 := to_unsigned(find_msb(arg_int, '1'), argb2'length); -- Log2
|
|
if argb2 > UNSIGNED(expon_base) then
|
|
result := pos_inffp (fraction_width => fraction_width,
|
|
exponent_width => exponent_width);
|
|
else
|
|
exp := SIGNED(resize(argb2, exp'length));
|
|
arg_int := shift_left (arg_int, arg_int'high-to_integer(exp));
|
|
if (arg_int'high > fraction_width) then
|
|
fract := arg_int (arg_int'high-1 downto (arg_int'high-fraction_width));
|
|
round := check_round (
|
|
fract_in => fract (0),
|
|
sign => result (exponent_width),
|
|
remainder => arg_int((arg_int'high-fraction_width-1)
|
|
downto 0),
|
|
round_style => round_style);
|
|
if round then
|
|
fp_round(fract_in => fract,
|
|
expon_in => exp,
|
|
fract_out => rfract,
|
|
expon_out => rexp);
|
|
else
|
|
rfract := fract;
|
|
rexp := exp;
|
|
end if;
|
|
else
|
|
rexp := exp;
|
|
rfract := (others => '0');
|
|
rfract (fraction_width-1 downto fraction_width-1-(arg_int'high-1)) :=
|
|
arg_int (arg_int'high-1 downto 0);
|
|
end if;
|
|
expon := UNSIGNED (rexp-1);
|
|
expon(exponent_width-1) := not expon(exponent_width-1);
|
|
result (exponent_width-1 downto 0) := float(expon);
|
|
result (-1 downto -fraction_width) := float(rfract);
|
|
end if;
|
|
end if;
|
|
return result;
|
|
end function to_float;
|
|
|
|
-- to_float (signed)
|
|
-- Synthesizable
|
|
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 float is
|
|
constant ARG_LEFT : INTEGER := ARG'length-1;
|
|
alias XARG : SIGNED(ARG_LEFT downto 0) is ARG;
|
|
variable result : float (exponent_width downto -fraction_width);
|
|
variable argabs : SIGNED (xarg'range);
|
|
variable arg_int : UNSIGNED(xarg'range); -- unsigned version of argument
|
|
variable sign : STD_ULOGIC; -- sign of the signed number
|
|
begin
|
|
sign := to_x01 (xarg(xarg'high));
|
|
argabs := abs (xarg);
|
|
arg_int := UNSIGNED (argabs);
|
|
result := to_float (
|
|
arg => arg_int,
|
|
fraction_width => fraction_width,
|
|
exponent_width => exponent_width,
|
|
round_style => round_style);
|
|
if sign = '1' then
|
|
result (exponent_width) := '1';
|
|
end if;
|
|
return result;
|
|
end function to_float;
|
|
|
|
-- std_logic_vector to float
|
|
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 float is
|
|
variable fpvar : float (exponent_width downto -fraction_width);
|
|
alias argslv : STD_LOGIC_VECTOR (fpvar'length-1 downto 0) is arg;
|
|
begin
|
|
fpvar := float(argslv);
|
|
-- floop : for i in fpvar'range loop
|
|
-- fpvar(i) := to_X01 (argslv(i-fpvar'low)); -- fpvar(8) := arg (8+23)
|
|
-- end loop floop;
|
|
return fpvar;
|
|
end function to_float;
|
|
|
|
-- 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 float is
|
|
begin
|
|
return to_float (arg => to_stdlogicvector(arg),
|
|
exponent_width => exponent_width,
|
|
fraction_width => fraction_width);
|
|
end function to_float;
|
|
|
|
-- purpose: converts a ufixed to a floating point
|
|
function to_float (
|
|
arg : 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 extentions
|
|
return float is
|
|
constant integer_width : INTEGER := arg'high;
|
|
constant in_fraction_width : INTEGER := arg'low;
|
|
variable xresult : ufixed (integer_width downto in_fraction_width);
|
|
variable result : float (exponent_width downto -fraction_width);
|
|
variable arg_int : UNSIGNED(integer_width - in_fraction_width
|
|
downto 0); -- Real version of argument
|
|
variable exp, exptmp : SIGNED (exponent_width downto 0);
|
|
variable expon : UNSIGNED (exponent_width - 1 downto 0); -- Unsigned version of exp.
|
|
constant expon_base : SIGNED (exponent_width-1 downto 0) :=
|
|
gen_expon_base(exponent_width); -- exponent offset
|
|
variable fract, fracttmp : UNSIGNED (fraction_width-1 downto 0) :=
|
|
(others => '0');
|
|
variable round : BOOLEAN := false;
|
|
begin -- function to_float
|
|
xresult := to_01(arg, 'X');
|
|
arg_int := UNSIGNED(to_slv(xresult));
|
|
if (or_reducex (arg_int) = 'X') then
|
|
result := (others => 'X');
|
|
elsif (arg_int = 0) then
|
|
result := (others => '0'); -- return zero
|
|
else
|
|
result := (others => '0'); -- positive sign
|
|
-- Compute Exponent
|
|
exp := to_signed(find_msb(arg_int, '1'), exp'length); -- Log2
|
|
if exp + in_fraction_width > expon_base then -- return infinity
|
|
result := pos_inffp (fraction_width => fraction_width,
|
|
exponent_width => exponent_width);
|
|
return result;
|
|
elsif (denormalize and
|
|
(exp + in_fraction_width <= -resize(expon_base, exp'length))) then
|
|
-- denormal number
|
|
exp := -resize(expon_base, exp'length);
|
|
-- shift by a constant
|
|
arg_int := shift_left (arg_int,
|
|
(arg_int'high + to_integer(expon_base)
|
|
+ in_fraction_width - 1));
|
|
if (arg_int'high > fraction_width) then
|
|
fract := arg_int (arg_int'high-1 downto (arg_int'high-fraction_width));
|
|
round := check_round (
|
|
fract_in => arg_int(arg_int'high-fraction_width),
|
|
sign => '0',
|
|
remainder => arg_int((arg_int'high-fraction_width-1)
|
|
downto 0),
|
|
round_style => round_style);
|
|
if (round) then
|
|
fp_round (fract_in => arg_int (arg_int'high-1 downto
|
|
(arg_int'high-fraction_width)),
|
|
expon_in => exp,
|
|
fract_out => fract,
|
|
expon_out => exptmp);
|
|
exp := exptmp;
|
|
end if;
|
|
else
|
|
fract (fraction_width-1 downto fraction_width-1-(arg_int'high-1)) :=
|
|
arg_int (arg_int'high-1 downto 0);
|
|
end if;
|
|
else
|
|
arg_int := shift_left (arg_int, arg_int'high-to_integer(exp));
|
|
exp := exp + in_fraction_width;
|
|
if (arg_int'high > fraction_width) then
|
|
fract := arg_int (arg_int'high-1 downto (arg_int'high-fraction_width));
|
|
round := check_round (
|
|
fract_in => fract(0),
|
|
sign => '0',
|
|
remainder => arg_int((arg_int'high-fraction_width-1)
|
|
downto 0),
|
|
round_style => round_style);
|
|
if (round) then
|
|
fp_round (fract_in => fract,
|
|
expon_in => exp,
|
|
fract_out => fracttmp,
|
|
expon_out => exptmp);
|
|
fract := fracttmp;
|
|
exp := exptmp;
|
|
end if;
|
|
else
|
|
fract (fraction_width-1 downto fraction_width-1-(arg_int'high-1)) :=
|
|
arg_int (arg_int'high-1 downto 0);
|
|
end if;
|
|
end if;
|
|
expon := UNSIGNED (resize (exp-1, exponent_width));
|
|
expon(exponent_width-1) := not expon(exponent_width-1);
|
|
result (exponent_width-1 downto 0) := float(expon);
|
|
result (-1 downto -fraction_width) := float(fract);
|
|
end if;
|
|
return result;
|
|
end function to_float;
|
|
|
|
function to_float (
|
|
arg : 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 float is
|
|
constant integer_width : INTEGER := arg'high;
|
|
constant in_fraction_width : INTEGER := arg'low;
|
|
variable xresult : sfixed (integer_width downto in_fraction_width);
|
|
variable result : float (exponent_width downto -fraction_width);
|
|
variable arg_int : UNSIGNED(integer_width - in_fraction_width - 1
|
|
downto 0); -- signed version of argument
|
|
variable argx : SIGNED (integer_width - in_fraction_width downto 0);
|
|
variable exp, exptmp : SIGNED (exponent_width downto 0);
|
|
variable expon : UNSIGNED (exponent_width - 1 downto 0);
|
|
-- Unsigned version of exp.
|
|
constant expon_base : SIGNED (exponent_width-1 downto 0) :=
|
|
gen_expon_base(exponent_width); -- exponent offset
|
|
variable fract, fracttmp : UNSIGNED (fraction_width-1 downto 0) :=
|
|
(others => '0');
|
|
variable round : BOOLEAN := false;
|
|
begin
|
|
xresult := to_01(arg, 'X');
|
|
argx := SIGNED(to_slv(xresult));
|
|
if (or_reducex (UNSIGNED(argx)) = 'X') then
|
|
result := (others => 'X');
|
|
elsif (argx = 0) then
|
|
result := (others => '0');
|
|
else
|
|
result := (others => '0'); -- zero out the result
|
|
if argx(argx'left) = '1' then -- toss the sign bit
|
|
result (exponent_width) := '1'; -- Negative number
|
|
argx := -argx; -- Make it positive.
|
|
else
|
|
result (exponent_width) := '0';
|
|
end if;
|
|
arg_int := UNSIGNED(to_x01(STD_LOGIC_VECTOR (argx(arg_int'range))));
|
|
-- Compute Exponent
|
|
exp := to_signed(find_msb(arg_int, '1'), exp'length); -- Log2
|
|
if exp + in_fraction_width > expon_base then -- return infinity
|
|
result (-1 downto -fraction_width) := (others => '0');
|
|
result (exponent_width -1 downto 0) := (others => '1');
|
|
return result;
|
|
elsif (denormalize and
|
|
(exp + in_fraction_width <= -resize(expon_base, exp'length))) then
|
|
exp := -resize(expon_base, exp'length);
|
|
-- shift by a constant
|
|
arg_int := shift_left (arg_int,
|
|
(arg_int'high + to_integer(expon_base)
|
|
+ in_fraction_width - 1));
|
|
if (arg_int'high > fraction_width) then
|
|
fract := arg_int (arg_int'high-1 downto (arg_int'high-fraction_width));
|
|
round := check_round (
|
|
fract_in => arg_int(arg_int'high-fraction_width),
|
|
sign => result(result'high),
|
|
remainder => arg_int((arg_int'high-fraction_width-1)
|
|
downto 0),
|
|
round_style => round_style);
|
|
if (round) then
|
|
fp_round (fract_in => arg_int (arg_int'high-1 downto
|
|
(arg_int'high-fraction_width)),
|
|
expon_in => exp,
|
|
fract_out => fract,
|
|
expon_out => exptmp);
|
|
exp := exptmp;
|
|
end if;
|
|
else
|
|
fract (fraction_width-1 downto fraction_width-1-(arg_int'high-1)) :=
|
|
arg_int (arg_int'high-1 downto 0);
|
|
end if;
|
|
else
|
|
arg_int := shift_left (arg_int, arg_int'high-to_integer(exp));
|
|
exp := exp + in_fraction_width;
|
|
if (arg_int'high > fraction_width) then
|
|
fract := arg_int (arg_int'high-1 downto (arg_int'high-fraction_width));
|
|
round := check_round (
|
|
fract_in => fract(0),
|
|
sign => result(result'high),
|
|
remainder => arg_int((arg_int'high-fraction_width-1)
|
|
downto 0),
|
|
round_style => round_style);
|
|
if (round) then
|
|
fp_round (fract_in => fract,
|
|
expon_in => exp,
|
|
fract_out => fracttmp,
|
|
expon_out => exptmp);
|
|
fract := fracttmp;
|
|
exp := exptmp;
|
|
end if;
|
|
else
|
|
fract (fraction_width-1 downto fraction_width-1-(arg_int'high-1)) :=
|
|
arg_int (arg_int'high-1 downto 0);
|
|
end if;
|
|
end if;
|
|
expon := UNSIGNED (resize(exp-1, exponent_width));
|
|
expon(exponent_width-1) := not expon(exponent_width-1);
|
|
result (exponent_width-1 downto 0) := float(expon);
|
|
result (-1 downto -fraction_width) := float(fract);
|
|
end if;
|
|
return result;
|
|
end function to_float;
|
|
|
|
-- size_res functions
|
|
-- Integer to float
|
|
function to_float (
|
|
arg : INTEGER;
|
|
size_res : float;
|
|
constant round_style : round_type := float_round_style) -- rounding option
|
|
return float is
|
|
variable result : float (size_res'left downto size_res'right);
|
|
begin
|
|
if (result'length < 1) then
|
|
return result;
|
|
else
|
|
result := to_float (arg => arg,
|
|
exponent_width => size_res'high,
|
|
fraction_width => -size_res'low,
|
|
round_style => round_style);
|
|
return result;
|
|
end if;
|
|
end function to_float;
|
|
|
|
-- real to float
|
|
function to_float (
|
|
arg : REAL;
|
|
size_res : float;
|
|
constant round_style : round_type := float_round_style; -- rounding option
|
|
constant denormalize : BOOLEAN := float_denormalize) -- Use IEEE extended FP
|
|
return float is
|
|
variable result : float (size_res'left downto size_res'right);
|
|
begin
|
|
if (result'length < 1) then
|
|
return result;
|
|
else
|
|
result := to_float (arg => arg,
|
|
exponent_width => size_res'high,
|
|
fraction_width => -size_res'low,
|
|
round_style => round_style,
|
|
denormalize => denormalize);
|
|
return result;
|
|
end if;
|
|
end function to_float;
|
|
|
|
-- unsigned to float
|
|
function to_float (
|
|
arg : UNSIGNED;
|
|
size_res : float;
|
|
constant round_style : round_type := float_round_style) -- rounding option
|
|
return float is
|
|
variable result : float (size_res'left downto size_res'right);
|
|
begin
|
|
if (result'length < 1) then
|
|
return result;
|
|
else
|
|
result := to_float (arg => arg,
|
|
exponent_width => size_res'high,
|
|
fraction_width => -size_res'low,
|
|
round_style => round_style);
|
|
return result;
|
|
end if;
|
|
end function to_float;
|
|
|
|
-- signed to float
|
|
function to_float (
|
|
arg : SIGNED;
|
|
size_res : float;
|
|
constant round_style : round_type := float_round_style) -- rounding
|
|
return float is
|
|
variable result : float (size_res'left downto size_res'right);
|
|
begin
|
|
if (result'length < 1) then
|
|
return result;
|
|
else
|
|
result := to_float (arg => arg,
|
|
exponent_width => size_res'high,
|
|
fraction_width => -size_res'low,
|
|
round_style => round_style);
|
|
return result;
|
|
end if;
|
|
end function to_float;
|
|
|
|
-- std_logic_vector to float
|
|
function to_float (
|
|
arg : STD_LOGIC_VECTOR;
|
|
size_res : float)
|
|
return float is
|
|
variable result : float (size_res'left downto size_res'right);
|
|
begin
|
|
if (result'length < 1) then
|
|
return result;
|
|
else
|
|
result := to_float (arg => arg,
|
|
exponent_width => size_res'high,
|
|
fraction_width => -size_res'low);
|
|
return result;
|
|
end if;
|
|
end function to_float;
|
|
|
|
-- std_ulogic_vector to float
|
|
function to_float (
|
|
arg : STD_ULOGIC_VECTOR;
|
|
size_res : float)
|
|
return float is
|
|
variable result : float (size_res'left downto size_res'right);
|
|
begin
|
|
if (result'length < 1) then
|
|
return result;
|
|
else
|
|
result := to_float (arg => to_stdlogicvector(arg),
|
|
exponent_width => size_res'high,
|
|
fraction_width => -size_res'low);
|
|
return result;
|
|
end if;
|
|
end function to_float;
|
|
|
|
-- unsigned fixed point to float
|
|
function to_float (
|
|
arg : ufixed; -- unsigned fixed point input
|
|
size_res : float;
|
|
constant round_style : round_type := float_round_style; -- rounding
|
|
constant denormalize : BOOLEAN := float_denormalize) -- use ieee extentions
|
|
return float is
|
|
variable result : float (size_res'left downto size_res'right);
|
|
begin
|
|
if (result'length < 1) then
|
|
return result;
|
|
else
|
|
result := to_float (arg => arg,
|
|
exponent_width => size_res'high,
|
|
fraction_width => -size_res'low,
|
|
round_style => round_style,
|
|
denormalize => denormalize);
|
|
return result;
|
|
end if;
|
|
end function to_float;
|
|
|
|
-- signed fixed point to float
|
|
function to_float (
|
|
arg : sfixed;
|
|
size_res : float;
|
|
constant round_style : round_type := float_round_style; -- rounding
|
|
constant denormalize : BOOLEAN := float_denormalize) -- rounding option
|
|
return float is
|
|
variable result : float (size_res'left downto size_res'right);
|
|
begin
|
|
if (result'length < 1) then
|
|
return result;
|
|
else
|
|
result := to_float (arg => arg,
|
|
exponent_width => size_res'high,
|
|
fraction_width => -size_res'low,
|
|
round_style => round_style,
|
|
denormalize => denormalize);
|
|
return result;
|
|
end if;
|
|
end function to_float;
|
|
|
|
-- fp_to_integer - Floating point to integer
|
|
-- Note, to do an "int" function, call this routine with the
|
|
-- round_style set to "round_zero".
|
|
-- Synthesizable
|
|
function to_integer (
|
|
arg : 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 is
|
|
variable validfp : valid_fpstate; -- Valid FP state
|
|
variable frac : UNSIGNED (30 downto 0); -- Fraction
|
|
variable result : INTEGER;
|
|
variable sign : STD_ULOGIC; -- true if negative
|
|
begin
|
|
validfp := class (arg, check_error);
|
|
classcase : case validfp is
|
|
when isx | nan | quiet_nan | pos_zero | neg_zero | pos_denormal | neg_denormal =>
|
|
result := 0; -- return 0
|
|
when pos_inf =>
|
|
result := INTEGER'high;
|
|
when neg_inf =>
|
|
result := INTEGER'low;
|
|
when others =>
|
|
float_to_unsigned (
|
|
arg => arg,
|
|
frac => frac,
|
|
sign => sign,
|
|
denormalize => false,
|
|
bias => 0,
|
|
round_style => round_style);
|
|
-- Add the sign bit back in.
|
|
if sign = '1' then
|
|
-- Because the most negative signed number is 1 less than the most
|
|
-- positive signed number, we need this code.
|
|
if and_reducex(frac) = '1' then -- return most negative number
|
|
result := INTEGER'low;
|
|
else
|
|
result := -to_integer(frac);
|
|
end if;
|
|
else
|
|
result := to_integer(frac);
|
|
end if;
|
|
end case classcase;
|
|
return result;
|
|
end function to_integer;
|
|
|
|
-- fp_to_unsigned - floating point to unsigned number
|
|
-- Synthesizable
|
|
function to_unsigned (
|
|
arg : 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 is
|
|
variable validfp : valid_fpstate; -- Valid FP state
|
|
variable frac : UNSIGNED (size-1 downto 0); -- Fraction
|
|
variable sign : STD_ULOGIC; -- not used
|
|
begin
|
|
validfp := class (arg, check_error);
|
|
classcase : case validfp is
|
|
when isx | nan | quiet_nan =>
|
|
frac := (others => 'X');
|
|
when pos_zero | neg_inf | neg_zero | neg_normal | pos_denormal | neg_denormal =>
|
|
frac := (others => '0'); -- return 0
|
|
when pos_inf =>
|
|
frac := (others => '1');
|
|
when others =>
|
|
float_to_unsigned (
|
|
arg => arg,
|
|
frac => frac,
|
|
sign => sign,
|
|
denormalize => false,
|
|
bias => 0,
|
|
round_style => round_style);
|
|
end case classcase;
|
|
return (frac);
|
|
end function to_unsigned;
|
|
|
|
-- fp_to_signed - floating point to signed number
|
|
-- Synthesizable
|
|
function to_signed (
|
|
arg : 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 is
|
|
variable sign : STD_ULOGIC; -- true if negative
|
|
variable validfp : valid_fpstate; -- Valid FP state
|
|
variable frac : UNSIGNED (size-1 downto 0); -- Fraction
|
|
variable result : SIGNED (size-1 downto 0);
|
|
begin
|
|
validfp := class (arg, check_error);
|
|
classcase : case validfp is
|
|
when isx | nan | quiet_nan =>
|
|
result := (others => 'X');
|
|
when pos_zero | neg_zero | pos_denormal | neg_denormal =>
|
|
result := (others => '0'); -- return 0
|
|
when pos_inf =>
|
|
result := (others => '1');
|
|
result (result'high) := '0';
|
|
when neg_inf =>
|
|
result := (others => '0');
|
|
result (result'high) := '1';
|
|
when others =>
|
|
float_to_unsigned (
|
|
arg => arg,
|
|
sign => sign,
|
|
frac => frac,
|
|
denormalize => false,
|
|
bias => 0,
|
|
round_style => round_style);
|
|
result (size-1) := '0';
|
|
result (size-2 downto 0) := SIGNED(frac (size-2 downto 0));
|
|
if sign = '1' then
|
|
-- Because the most negative signed number is 1 less than the most
|
|
-- positive signed number, we need this code.
|
|
if frac(frac'high) = '1' then -- return most negative number
|
|
result := (others => '0');
|
|
result (result'high) := '1';
|
|
else
|
|
result := -result;
|
|
end if;
|
|
else
|
|
if frac(frac'high) = '1' then -- return most positive number
|
|
result := (others => '1');
|
|
result (result'high) := '0';
|
|
end if;
|
|
end if;
|
|
end case classcase;
|
|
return result;
|
|
end function to_signed;
|
|
|
|
-- purpose: Converts a float to ufixed
|
|
function to_ufixed (
|
|
arg : float; -- fp input
|
|
constant left_index : INTEGER; -- integer part
|
|
constant right_index : INTEGER; -- fraction part
|
|
constant round_style : BOOLEAN := fixed_round_style; -- rounding
|
|
constant overflow_style : BOOLEAN := fixed_overflow_style; -- saturate
|
|
constant check_error : BOOLEAN := float_check_error; -- check for errors
|
|
constant denormalize : BOOLEAN := float_denormalize)
|
|
return ufixed is
|
|
constant fraction_width : INTEGER := -minx(arg'low, arg'low); -- length of FP output fraction
|
|
constant exponent_width : INTEGER := arg'high; -- length of FP output exponent
|
|
constant size : INTEGER := left_index - right_index + 4; -- unsigned size
|
|
variable expon_base : INTEGER; -- exponent offset
|
|
variable validfp : valid_fpstate; -- Valid FP state
|
|
variable exp : INTEGER; -- Exponent
|
|
variable expon : UNSIGNED (exponent_width-1 downto 0); -- Vectorized exponent
|
|
-- Base to divide fraction by
|
|
variable frac : UNSIGNED (size-1 downto 0) := (others => '0'); -- Fraction
|
|
variable frac_shift : UNSIGNED (size-1 downto 0); -- Fraction shifted
|
|
variable shift : INTEGER;
|
|
variable result_big : ufixed (left_index downto right_index-3);
|
|
variable result : ufixed (left_index downto right_index); -- result
|
|
begin -- function to_ufixed
|
|
validfp := class (arg, check_error);
|
|
classcase : case validfp is
|
|
when isx | nan | quiet_nan =>
|
|
frac := (others => 'X');
|
|
when pos_zero | neg_inf | neg_zero | neg_normal | neg_denormal =>
|
|
frac := (others => '0'); -- return 0
|
|
when pos_inf =>
|
|
frac := (others => '1'); -- always saturate
|
|
when others =>
|
|
expon_base := 2**(exponent_width-1) -1; -- exponent offset
|
|
-- Figure out the fraction
|
|
if (validfp = pos_denormal) and denormalize then
|
|
exp := -expon_base +1;
|
|
frac (frac'high) := '0'; -- Add the "1.0".
|
|
else
|
|
-- exponent /= '0', normal floating point
|
|
expon := UNSIGNED(arg (exponent_width-1 downto 0));
|
|
expon(exponent_width-1) := not expon(exponent_width-1);
|
|
exp := to_integer (SIGNED(expon)) +1;
|
|
frac (frac'high) := '1'; -- Add the "1.0".
|
|
end if;
|
|
shift := (frac'high - 3 + right_index) - exp;
|
|
if fraction_width > frac'high then -- Can only use size-2 bits
|
|
frac (frac'high-1 downto 0) := UNSIGNED (to_slv (arg(-1 downto
|
|
-frac'high)));
|
|
else -- can use all bits
|
|
frac (frac'high-1 downto frac'high-fraction_width) :=
|
|
UNSIGNED (to_slv (arg(-1 downto -fraction_width)));
|
|
end if;
|
|
frac_shift := frac srl shift;
|
|
if shift < 0 then -- Overflow
|
|
frac := (others => '1');
|
|
else
|
|
frac := frac_shift;
|
|
end if;
|
|
end case classcase;
|
|
result_big := to_ufixed (arg => STD_LOGIC_VECTOR(frac),
|
|
left_index => left_index,
|
|
right_index => (right_index-3));
|
|
result := resize (arg => result_big,
|
|
left_index => left_index,
|
|
right_index => right_index,
|
|
round_style => round_style,
|
|
overflow_style => overflow_style);
|
|
return result;
|
|
end function to_ufixed;
|
|
|
|
-- purpose: Converts a float to sfixed
|
|
function to_sfixed (
|
|
arg : float; -- fp input
|
|
constant left_index : INTEGER; -- integer part
|
|
constant right_index : INTEGER; -- fraction part
|
|
constant round_style : BOOLEAN := fixed_round_style; -- rounding
|
|
constant overflow_style : BOOLEAN := fixed_overflow_style; -- saturate
|
|
constant check_error : BOOLEAN := float_check_error; -- check for errors
|
|
constant denormalize : BOOLEAN := float_denormalize)
|
|
return sfixed is
|
|
constant fraction_width : INTEGER := -minx(arg'low, arg'low); -- length of FP output fraction
|
|
constant exponent_width : INTEGER := arg'high; -- length of FP output exponent
|
|
constant size : INTEGER := left_index - right_index + 4; -- unsigned size
|
|
variable expon_base : INTEGER; -- exponent offset
|
|
variable validfp : valid_fpstate; -- Valid FP state
|
|
variable exp : INTEGER; -- Exponent
|
|
variable sign : BOOLEAN; -- true if negative
|
|
variable expon : UNSIGNED (exponent_width-1 downto 0); -- Vectorized exponent
|
|
-- Base to divide fraction by
|
|
variable frac : UNSIGNED (size-2 downto 0) := (others => '0'); -- Fraction
|
|
variable frac_shift : UNSIGNED (size-2 downto 0); -- Fraction shifted
|
|
variable shift : INTEGER;
|
|
variable rsigned : SIGNED (size-1 downto 0); -- signed version of result
|
|
variable result_big : sfixed (left_index downto right_index-3);
|
|
variable result : sfixed (left_index downto right_index) := (others => '0'); -- result
|
|
begin -- function to_ufixed
|
|
validfp := class (arg, check_error);
|
|
classcase : case validfp is
|
|
when isx | nan | quiet_nan =>
|
|
result := (others => 'X');
|
|
when pos_zero | neg_zero =>
|
|
result := (others => '0'); -- return 0
|
|
when neg_inf =>
|
|
result (left_index) := '1'; -- return smallest negative number
|
|
when pos_inf =>
|
|
result := (others => '1'); -- return largest number
|
|
result (left_index) := '0';
|
|
when others =>
|
|
expon_base := 2**(exponent_width-1) -1; -- exponent offset
|
|
if arg(exponent_width) = '0' then
|
|
sign := false;
|
|
else
|
|
sign := true;
|
|
end if;
|
|
-- Figure out the fraction
|
|
if (validfp = pos_denormal or validfp = neg_denormal)
|
|
and denormalize then
|
|
exp := -expon_base +1;
|
|
frac (frac'high) := '0'; -- Add the "1.0".
|
|
else
|
|
-- exponent /= '0', normal floating point
|
|
expon := UNSIGNED(arg (exponent_width-1 downto 0));
|
|
expon(exponent_width-1) := not expon(exponent_width-1);
|
|
exp := to_integer (SIGNED(expon)) +1;
|
|
frac (frac'high) := '1'; -- Add the "1.0".
|
|
end if;
|
|
shift := (frac'high - 3 + right_index) - exp;
|
|
if fraction_width > frac'high then -- Can only use size-2 bits
|
|
frac (frac'high-1 downto 0) := UNSIGNED (to_slv (arg(-1 downto
|
|
-frac'high)));
|
|
else -- can use all bits
|
|
frac (frac'high-1 downto frac'high-fraction_width) :=
|
|
UNSIGNED (to_slv (arg(-1 downto -fraction_width)));
|
|
end if;
|
|
frac_shift := frac srl shift;
|
|
if shift < 0 then -- Overflow
|
|
frac := (others => '1');
|
|
else
|
|
frac := frac_shift;
|
|
end if;
|
|
if not sign then
|
|
rsigned := SIGNED("0" & frac);
|
|
else
|
|
rsigned := -(SIGNED("0" & frac));
|
|
end if;
|
|
result_big := to_sfixed (arg => STD_LOGIC_VECTOR(rsigned),
|
|
left_index => left_index,
|
|
right_index => (right_index-3));
|
|
result := resize (arg => result_big,
|
|
left_index => left_index,
|
|
right_index => right_index,
|
|
round_style => round_style,
|
|
overflow_style => overflow_style);
|
|
end case classcase;
|
|
return result;
|
|
end function to_sfixed;
|
|
|
|
-- size_res versions
|
|
-- float to unsigned
|
|
function to_unsigned (
|
|
arg : 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 is
|
|
variable result : UNSIGNED (size_res'range);
|
|
begin
|
|
if (SIZE_RES'length = 0) then
|
|
return result;
|
|
else
|
|
result := to_unsigned (arg => arg,
|
|
size => size_res'length,
|
|
check_error => check_error,
|
|
round_style => round_style);
|
|
return result;
|
|
end if;
|
|
end function to_unsigned;
|
|
|
|
-- float to signed
|
|
function to_signed (
|
|
arg : 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 is
|
|
variable result : SIGNED (size_res'range);
|
|
begin
|
|
if (SIZE_RES'length = 0) then
|
|
return result;
|
|
else
|
|
result := to_signed (arg => arg,
|
|
size => size_res'length,
|
|
check_error => check_error,
|
|
round_style => round_style);
|
|
return result;
|
|
end if;
|
|
end function to_signed;
|
|
|
|
-- purpose: Converts a float to unsigned fixed point
|
|
function to_ufixed (
|
|
arg : float; -- fp input
|
|
size_res : ufixed;
|
|
constant round_style : BOOLEAN := fixed_round_style; -- rounding
|
|
constant overflow_style : BOOLEAN := fixed_overflow_style; -- saturate
|
|
constant check_error : BOOLEAN := float_check_error; -- check for errors
|
|
constant denormalize : BOOLEAN := float_denormalize)
|
|
return ufixed is
|
|
variable result : ufixed (size_res'left downto size_res'right);
|
|
begin
|
|
if (result'length < 1) then
|
|
return result;
|
|
else
|
|
result := to_ufixed (arg => arg,
|
|
left_index => size_res'high,
|
|
right_index => size_res'low,
|
|
round_style => round_style,
|
|
overflow_style => overflow_style,
|
|
check_error => check_error,
|
|
denormalize => denormalize);
|
|
return result;
|
|
end if;
|
|
end function to_ufixed;
|
|
|
|
-- float to signed fixed point
|
|
function to_sfixed (
|
|
arg : float; -- fp input
|
|
size_res : sfixed;
|
|
constant round_style : BOOLEAN := fixed_round_style; -- rounding
|
|
constant overflow_style : BOOLEAN := fixed_overflow_style; -- saturate
|
|
constant check_error : BOOLEAN := float_check_error; -- check for errors
|
|
constant denormalize : BOOLEAN := float_denormalize)
|
|
return sfixed is
|
|
variable result : sfixed (size_res'left downto size_res'right);
|
|
begin
|
|
if (result'length < 1) then
|
|
return result;
|
|
else
|
|
result := to_sfixed (arg => arg,
|
|
left_index => size_res'high,
|
|
right_index => size_res'low,
|
|
round_style => round_style,
|
|
overflow_style => overflow_style,
|
|
check_error => check_error,
|
|
denormalize => denormalize);
|
|
return result;
|
|
end if;
|
|
end function to_sfixed;
|
|
|
|
-- Floating point to Real number conversion
|
|
-- Not Synthesizable
|
|
function to_real (
|
|
arg : 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 is
|
|
constant fraction_width : INTEGER := -minx(arg'low, arg'low); -- length of FP output fraction
|
|
constant exponent_width : INTEGER := arg'high; -- length of FP output exponent
|
|
variable sign : REAL; -- Sign, + or - 1
|
|
variable exp : INTEGER; -- Exponent
|
|
variable expon_base : INTEGER; -- exponent offset
|
|
variable frac : REAL := 0.0; -- Fraction
|
|
variable validfp : valid_fpstate; -- Valid FP state
|
|
variable expon : UNSIGNED (exponent_width - 1 downto 0)
|
|
:= (others => '1'); -- Vectorized exponent
|
|
begin
|
|
validfp := class (arg, check_error);
|
|
classcase : case validfp is
|
|
when isx | pos_zero | neg_zero | nan | quiet_nan =>
|
|
return 0.0;
|
|
when neg_inf =>
|
|
return REAL'low; -- Negative infinity.
|
|
when pos_inf =>
|
|
return REAL'high; -- Positive infinity
|
|
when others =>
|
|
expon_base := 2**(exponent_width-1) -1;
|
|
if to_X01(arg(exponent_width)) = '0' then
|
|
sign := 1.0;
|
|
else
|
|
sign := -1.0;
|
|
end if;
|
|
-- Figure out the fraction
|
|
for i in 0 to fraction_width-1 loop
|
|
if to_X01(arg (-1 - i)) = '1' then
|
|
frac := frac + (2.0 **(-1 - i));
|
|
end if;
|
|
end loop; -- i
|
|
if validfp = pos_normal or validfp = neg_normal or not denormalize then
|
|
-- exponent /= '0', normal floating point
|
|
expon := UNSIGNED(arg (exponent_width-1 downto 0));
|
|
expon(exponent_width-1) := not expon(exponent_width-1);
|
|
exp := to_integer (SIGNED(expon)) +1;
|
|
sign := sign * (2.0 ** exp) * (1.0 + frac);
|
|
else -- exponent = '0', IEEE extended floating point
|
|
exp := 1 - expon_base;
|
|
sign := sign * (2.0 ** exp) * frac;
|
|
end if;
|
|
return sign;
|
|
end case classcase;
|
|
end function to_real;
|
|
|
|
-- purpose: Removes meta-logical values from FP string
|
|
function to_01 (
|
|
arg : float; -- floating point input
|
|
XMAP : STD_LOGIC := '0')
|
|
return float is
|
|
variable BAD_ELEMENT : BOOLEAN := false;
|
|
variable RESULT : float (arg'range);
|
|
begin -- function to_01
|
|
if (arg'length < 1) then
|
|
assert NO_WARNING
|
|
report "FLOAT_GENERIC_PKG.TO_01: null detected, returning NAFP"
|
|
severity warning;
|
|
return NAFP;
|
|
end if;
|
|
for I in RESULT'range loop
|
|
case arg(I) is
|
|
when '0' | 'L' => RESULT(I) := '0';
|
|
when '1' | 'H' => RESULT(I) := '1';
|
|
when others => BAD_ELEMENT := true;
|
|
end case;
|
|
end loop;
|
|
if BAD_ELEMENT then
|
|
RESULT := (others => XMAP);
|
|
end if;
|
|
return RESULT;
|
|
end function to_01;
|
|
|
|
function Is_X
|
|
(arg : float)
|
|
return BOOLEAN is
|
|
begin
|
|
return Is_X (to_slv(arg));
|
|
end function Is_X;
|
|
|
|
function to_X01 (arg : float) return float is
|
|
begin
|
|
if (arg'length < 1) then
|
|
assert NO_WARNING
|
|
report "FLOAT_GENERIC_PKG.TO_X01: null detected, returning NAFP"
|
|
severity warning;
|
|
return NAFP;
|
|
else
|
|
return to_float (to_X01(to_slv(arg)), arg'high, -arg'low);
|
|
end if;
|
|
end function to_X01;
|
|
|
|
function to_X01Z (arg : float) return float is
|
|
begin
|
|
if (arg'length < 1) then
|
|
assert NO_WARNING
|
|
report "FLOAT_GENERIC_PKG.TO_X01Z: null detected, returning NAFP"
|
|
severity warning;
|
|
return NAFP;
|
|
else
|
|
return to_float (to_X01Z(to_slv(arg)), arg'high, -arg'low);
|
|
end if;
|
|
end function to_X01Z;
|
|
|
|
function to_UX01 (arg : float) return float is
|
|
begin
|
|
if (arg'length < 1) then
|
|
assert NO_WARNING
|
|
report "FLOAT_GENERIC_PKG.TO_UX01: null detected, returning NAFP"
|
|
severity warning;
|
|
return NAFP;
|
|
else
|
|
return to_float (to_UX01(to_slv(arg)), arg'high, -arg'low);
|
|
end if;
|
|
end function to_UX01;
|
|
|
|
-- These allows the base math functions to use the default values
|
|
-- of their parameters. Thus they do full IEEE floating point.
|
|
function "+" (l, r : float) return float is
|
|
begin
|
|
return add (l, r);
|
|
end function "+";
|
|
function "-" (l, r : float) return float is
|
|
begin
|
|
return subtract (l, r);
|
|
end function "-";
|
|
function "*" (l, r : float) return float is
|
|
begin
|
|
return multiply (l, r);
|
|
end function "*";
|
|
function "/" (l, r : float) return float is
|
|
begin
|
|
return divide (l, r);
|
|
end function "/";
|
|
function "rem" (l, r : float) return float is
|
|
begin
|
|
return remainder (l, r);
|
|
end function "rem";
|
|
function "mod" (l, r : float) return float is
|
|
begin
|
|
return modulo (l, r);
|
|
end function "mod";
|
|
-- overloaded versions
|
|
function "+" (l : float; r : REAL) return float is
|
|
variable r_float : float (l'range);
|
|
begin
|
|
r_float := to_float (r, l); -- use size_res function
|
|
return add (l, r_float);
|
|
end function "+";
|
|
|
|
function "+" (l : REAL; r : float) return float is
|
|
variable l_float : float (r'range);
|
|
begin
|
|
l_float := to_float(l, r);
|
|
return add (l_float, r);
|
|
end function "+";
|
|
|
|
function "+" (l : float; r : INTEGER) return float is
|
|
variable r_float : float (l'range);
|
|
begin
|
|
r_float := to_float (r, l); -- use size_res function
|
|
return add (l, r_float);
|
|
end function "+";
|
|
|
|
function "+" (l : INTEGER; r : float) return float is
|
|
variable l_float : float (r'range);
|
|
begin
|
|
l_float := to_float(l, r);
|
|
return add (l_float, r);
|
|
end function "+";
|
|
|
|
function "-" (l : float; r : REAL) return float is
|
|
variable r_float : float (l'range);
|
|
begin
|
|
r_float := to_float (r, l); -- use size_res function
|
|
return subtract (l, r_float);
|
|
end function "-";
|
|
|
|
function "-" (l : REAL; r : float) return float is
|
|
variable l_float : float (r'range);
|
|
begin
|
|
l_float := to_float(l, r);
|
|
return subtract (l_float, r);
|
|
end function "-";
|
|
|
|
function "-" (l : float; r : INTEGER) return float is
|
|
variable r_float : float (l'range);
|
|
begin
|
|
r_float := to_float (r, l); -- use size_res function
|
|
return subtract (l, r_float);
|
|
end function "-";
|
|
|
|
function "-" (l : INTEGER; r : float) return float is
|
|
variable l_float : float (r'range);
|
|
begin
|
|
l_float := to_float(l, r);
|
|
return subtract (l_float, r);
|
|
end function "-";
|
|
|
|
function "*" (l : float; r : REAL) return float is
|
|
variable r_float : float (l'range);
|
|
begin
|
|
r_float := to_float (r, l); -- use size_res function
|
|
return multiply (l, r_float);
|
|
end function "*";
|
|
|
|
function "*" (l : REAL; r : float) return float is
|
|
variable l_float : float (r'range);
|
|
begin
|
|
l_float := to_float(l, r);
|
|
return multiply (l_float, r);
|
|
end function "*";
|
|
|
|
function "*" (l : float; r : INTEGER) return float is
|
|
variable r_float : float (l'range);
|
|
begin
|
|
r_float := to_float (r, l); -- use size_res function
|
|
return multiply (l, r_float);
|
|
end function "*";
|
|
|
|
function "*" (l : INTEGER; r : float) return float is
|
|
variable l_float : float (r'range);
|
|
begin
|
|
l_float := to_float(l, r);
|
|
return multiply (l_float, r);
|
|
end function "*";
|
|
|
|
function "/" (l : float; r : REAL) return float is
|
|
variable r_float : float (l'range);
|
|
begin
|
|
r_float := to_float (r, l); -- use size_res function
|
|
return divide (l, r_float);
|
|
end function "/";
|
|
|
|
function "/" (l : REAL; r : float) return float is
|
|
variable l_float : float (r'range);
|
|
begin
|
|
l_float := to_float(l, r);
|
|
return divide (l_float, r);
|
|
end function "/";
|
|
|
|
function "/" (l : float; r : INTEGER) return float is
|
|
variable r_float : float (l'range);
|
|
begin
|
|
r_float := to_float (r, l); -- use size_res function
|
|
return divide (l, r_float);
|
|
end function "/";
|
|
|
|
function "/" (l : INTEGER; r : float) return float is
|
|
variable l_float : float (r'range);
|
|
begin
|
|
l_float := to_float(l, r);
|
|
return divide (l_float, r);
|
|
end function "/";
|
|
|
|
function "rem" (l : float; r : REAL) return float is
|
|
variable r_float : float (l'range);
|
|
begin
|
|
r_float := to_float (r, l); -- use size_res function
|
|
return remainder (l, r_float);
|
|
end function "rem";
|
|
|
|
function "rem" (l : REAL; r : float) return float is
|
|
variable l_float : float (r'range);
|
|
begin
|
|
l_float := to_float(l, r);
|
|
return remainder (l_float, r);
|
|
end function "rem";
|
|
|
|
function "rem" (l : float; r : INTEGER) return float is
|
|
variable r_float : float (l'range);
|
|
begin
|
|
r_float := to_float (r, l); -- use size_res function
|
|
return remainder (l, r_float);
|
|
end function "rem";
|
|
|
|
function "rem" (l : INTEGER; r : float) return float is
|
|
variable l_float : float (r'range);
|
|
begin
|
|
l_float := to_float(l, r);
|
|
return remainder (l_float, r);
|
|
end function "rem";
|
|
|
|
function "mod" (l : float; r : REAL) return float is
|
|
variable r_float : float (l'range);
|
|
begin
|
|
r_float := to_float (r, l); -- use size_res function
|
|
return modulo (l, r_float);
|
|
end function "mod";
|
|
|
|
function "mod" (l : REAL; r : float) return float is
|
|
variable l_float : float (r'range);
|
|
begin
|
|
l_float := to_float(l, r);
|
|
return modulo (l_float, r);
|
|
end function "mod";
|
|
|
|
function "mod" (l : float; r : INTEGER) return float is
|
|
variable r_float : float (l'range);
|
|
begin
|
|
r_float := to_float (r, l); -- use size_res function
|
|
return modulo (l, r_float);
|
|
end function "mod";
|
|
|
|
function "mod" (l : INTEGER; r : float) return float is
|
|
variable l_float : float (r'range);
|
|
begin
|
|
l_float := to_float(l, r);
|
|
return modulo (l_float, r);
|
|
end function "mod";
|
|
|
|
function "=" (l : float; r : REAL) return BOOLEAN is
|
|
variable r_float : float (l'range);
|
|
begin
|
|
r_float := to_float (r, l); -- use size_res function
|
|
return eq (l, r_float);
|
|
end function "=";
|
|
|
|
function "/=" (l : float; r : REAL) return BOOLEAN is
|
|
variable r_float : float (l'range);
|
|
begin
|
|
r_float := to_float (r, l); -- use size_res function
|
|
return ne (l, r_float);
|
|
end function "/=";
|
|
|
|
function ">=" (l : float; r : REAL) return BOOLEAN is
|
|
variable r_float : float (l'range);
|
|
begin
|
|
r_float := to_float (r, l); -- use size_res function
|
|
return ge (l, r_float);
|
|
end function ">=";
|
|
|
|
function "<=" (l : float; r : REAL) return BOOLEAN is
|
|
variable r_float : float (l'range);
|
|
begin
|
|
r_float := to_float (r, l); -- use size_res function
|
|
return le (l, r_float);
|
|
end function "<=";
|
|
|
|
function ">" (l : float; r : REAL) return BOOLEAN is
|
|
variable r_float : float (l'range);
|
|
begin
|
|
r_float := to_float (r, l); -- use size_res function
|
|
return gt (l, r_float);
|
|
end function ">";
|
|
|
|
function "<" (l : float; r : REAL) return BOOLEAN is
|
|
variable r_float : float (l'range);
|
|
begin
|
|
r_float := to_float (r, l); -- use size_res function
|
|
return lt (l, r_float);
|
|
end function "<";
|
|
|
|
function "=" (l : REAL; r : float) return BOOLEAN is
|
|
variable l_float : float (r'range);
|
|
begin
|
|
l_float := to_float(l, r);
|
|
return eq (l_float, r);
|
|
end function "=";
|
|
|
|
function "/=" (l : REAL; r : float) return BOOLEAN is
|
|
variable l_float : float (r'range);
|
|
begin
|
|
l_float := to_float(l, r);
|
|
return ne (l_float, r);
|
|
end function "/=";
|
|
|
|
function ">=" (l : REAL; r : float) return BOOLEAN is
|
|
variable l_float : float (r'range);
|
|
begin
|
|
l_float := to_float(l, r);
|
|
return ge (l_float, r);
|
|
end function ">=";
|
|
|
|
function "<=" (l : REAL; r : float) return BOOLEAN is
|
|
variable l_float : float (r'range);
|
|
begin
|
|
l_float := to_float(l, r);
|
|
return le (l_float, r);
|
|
end function "<=";
|
|
|
|
function ">" (l : REAL; r : float) return BOOLEAN is
|
|
variable l_float : float (r'range);
|
|
begin
|
|
l_float := to_float(l, r);
|
|
return gt (l_float, r);
|
|
end function ">";
|
|
|
|
function "<" (l : REAL; r : float) return BOOLEAN is
|
|
variable l_float : float (r'range);
|
|
begin
|
|
l_float := to_float(l, r);
|
|
return lt (l_float, r);
|
|
end function "<";
|
|
|
|
function "=" (l : float; r : INTEGER) return BOOLEAN is
|
|
variable r_float : float (l'range);
|
|
begin
|
|
r_float := to_float (r, l); -- use size_res function
|
|
return eq (l, r_float);
|
|
end function "=";
|
|
|
|
function "/=" (l : float; r : INTEGER) return BOOLEAN is
|
|
variable r_float : float (l'range);
|
|
begin
|
|
r_float := to_float (r, l); -- use size_res function
|
|
return ne (l, r_float);
|
|
end function "/=";
|
|
|
|
function ">=" (l : float; r : INTEGER) return BOOLEAN is
|
|
variable r_float : float (l'range);
|
|
begin
|
|
r_float := to_float (r, l); -- use size_res function
|
|
return ge (l, r_float);
|
|
end function ">=";
|
|
|
|
function "<=" (l : float; r : INTEGER) return BOOLEAN is
|
|
variable r_float : float (l'range);
|
|
begin
|
|
r_float := to_float (r, l); -- use size_res function
|
|
return le (l, r_float);
|
|
end function "<=";
|
|
|
|
function ">" (l : float; r : INTEGER) return BOOLEAN is
|
|
variable r_float : float (l'range);
|
|
begin
|
|
r_float := to_float (r, l); -- use size_res function
|
|
return gt (l, r_float);
|
|
end function ">";
|
|
|
|
function "<" (l : float; r : INTEGER) return BOOLEAN is
|
|
variable r_float : float (l'range);
|
|
begin
|
|
r_float := to_float (r, l); -- use size_res function
|
|
return lt (l, r_float);
|
|
end function "<";
|
|
|
|
function "=" (l : INTEGER; r : float) return BOOLEAN is
|
|
variable l_float : float (r'range);
|
|
begin
|
|
l_float := to_float(l, r);
|
|
return eq (l_float, r);
|
|
end function "=";
|
|
|
|
function "/=" (l : INTEGER; r : float) return BOOLEAN is
|
|
variable l_float : float (r'range);
|
|
begin
|
|
l_float := to_float(l, r);
|
|
return ne (l_float, r);
|
|
end function "/=";
|
|
|
|
function ">=" (l : INTEGER; r : float) return BOOLEAN is
|
|
variable l_float : float (r'range);
|
|
begin
|
|
l_float := to_float(l, r);
|
|
return ge (l_float, r);
|
|
end function ">=";
|
|
|
|
function "<=" (l : INTEGER; r : float) return BOOLEAN is
|
|
variable l_float : float (r'range);
|
|
begin
|
|
l_float := to_float(l, r);
|
|
return le (l_float, r);
|
|
end function "<=";
|
|
|
|
function ">" (l : INTEGER; r : float) return BOOLEAN is
|
|
variable l_float : float (r'range);
|
|
begin
|
|
l_float := to_float(l, r);
|
|
return gt (l_float, r);
|
|
end function ">";
|
|
|
|
function "<" (l : INTEGER; r : float) return BOOLEAN is
|
|
variable l_float : float (r'range);
|
|
begin
|
|
l_float := to_float(l, r);
|
|
return lt (l_float, r);
|
|
end function "<";
|
|
|
|
----------------------------------------------------------------------------
|
|
-- logical functions
|
|
----------------------------------------------------------------------------
|
|
function "not" (L : float) return float is
|
|
variable RESULT : STD_LOGIC_VECTOR(L'length-1 downto 0); -- force downto
|
|
variable resfp : float (L'range); -- back to float
|
|
begin
|
|
RESULT := not to_slv(L);
|
|
resfp := float (RESULT);
|
|
return resfp;
|
|
end function "not";
|
|
|
|
function "and" (L, R : float) return float is
|
|
variable RESULT : STD_LOGIC_VECTOR(L'length-1 downto 0); -- force downto
|
|
variable resfp : float (L'range); -- back to float
|
|
begin
|
|
RESULT := to_slv(L) and to_slv(R);
|
|
resfp := float (RESULT);
|
|
return resfp;
|
|
end function "and";
|
|
|
|
function "or" (L, R : float) return float is
|
|
variable RESULT : STD_LOGIC_VECTOR(L'length-1 downto 0); -- force downto
|
|
variable resfp : float (L'range); -- back to float
|
|
begin
|
|
RESULT := to_slv(L) or to_slv(R);
|
|
resfp := float (RESULT);
|
|
return resfp;
|
|
end function "or";
|
|
|
|
function "nand" (L, R : float) return float is
|
|
variable RESULT : STD_LOGIC_VECTOR(L'length-1 downto 0); -- force downto
|
|
variable resfp : float (L'range); -- back to float
|
|
begin
|
|
RESULT := to_slv(L) nand to_slv(R);
|
|
resfp := float (RESULT);
|
|
return resfp;
|
|
end function "nand";
|
|
|
|
function "nor" (L, R : float) return float is
|
|
variable RESULT : STD_LOGIC_VECTOR(L'length-1 downto 0); -- force downto
|
|
variable resfp : float (L'range); -- back to float
|
|
begin
|
|
RESULT := to_slv(L) nor to_slv(R);
|
|
resfp := float (RESULT);
|
|
return resfp;
|
|
end function "nor";
|
|
|
|
function "xor" (L, R : float) return float is
|
|
variable RESULT : STD_LOGIC_VECTOR(L'length-1 downto 0); -- force downto
|
|
variable resfp : float (L'range); -- back to float
|
|
begin
|
|
RESULT := to_slv(L) xor to_slv(R);
|
|
resfp := float (RESULT);
|
|
return resfp;
|
|
end function "xor";
|
|
|
|
function "xnor" (L, R : float) return float is
|
|
variable RESULT : STD_LOGIC_VECTOR(L'length-1 downto 0); -- force downto
|
|
variable resfp : float (L'range); -- back to float
|
|
begin
|
|
RESULT := to_slv(L) xnor to_slv(R);
|
|
resfp := float (RESULT);
|
|
return resfp;
|
|
end function "xnor";
|
|
|
|
-- Vector and std_ulogic functions, same as functions in numeric_std
|
|
function "and" (L : STD_ULOGIC; R : float) return float is
|
|
variable result : float (R'range);
|
|
begin
|
|
for i in result'range loop
|
|
result(i) := L and R(i);
|
|
end loop;
|
|
return result;
|
|
end function "and";
|
|
|
|
function "and" (L : float; R : STD_ULOGIC) return float is
|
|
variable result : float (L'range);
|
|
begin
|
|
for i in result'range loop
|
|
result(i) := L(i) and R;
|
|
end loop;
|
|
return result;
|
|
end function "and";
|
|
|
|
function "or" (L : STD_ULOGIC; R : float) return float is
|
|
variable result : float (R'range);
|
|
begin
|
|
for i in result'range loop
|
|
result(i) := L or R(i);
|
|
end loop;
|
|
return result;
|
|
end function "or";
|
|
|
|
function "or" (L : float; R : STD_ULOGIC) return float is
|
|
variable result : float (L'range);
|
|
begin
|
|
for i in result'range loop
|
|
result(i) := L(i) or R;
|
|
end loop;
|
|
return result;
|
|
end function "or";
|
|
|
|
function "nand" (L : STD_ULOGIC; R : float) return float is
|
|
variable result : float (R'range);
|
|
begin
|
|
for i in result'range loop
|
|
result(i) := L nand R(i);
|
|
end loop;
|
|
return result;
|
|
end function "nand";
|
|
|
|
function "nand" (L : float; R : STD_ULOGIC) return float is
|
|
variable result : float (L'range);
|
|
begin
|
|
for i in result'range loop
|
|
result(i) := L(i) nand R;
|
|
end loop;
|
|
return result;
|
|
end function "nand";
|
|
|
|
function "nor" (L : STD_ULOGIC; R : float) return float is
|
|
variable result : float (R'range);
|
|
begin
|
|
for i in result'range loop
|
|
result(i) := L nor R(i);
|
|
end loop;
|
|
return result;
|
|
end function "nor";
|
|
|
|
function "nor" (L : float; R : STD_ULOGIC) return float is
|
|
variable result : float (L'range);
|
|
begin
|
|
for i in result'range loop
|
|
result(i) := L(i) nor R;
|
|
end loop;
|
|
return result;
|
|
end function "nor";
|
|
|
|
function "xor" (L : STD_ULOGIC; R : float) return float is
|
|
variable result : float (R'range);
|
|
begin
|
|
for i in result'range loop
|
|
result(i) := L xor R(i);
|
|
end loop;
|
|
return result;
|
|
end function "xor";
|
|
|
|
function "xor" (L : float; R : STD_ULOGIC) return float is
|
|
variable result : float (L'range);
|
|
begin
|
|
for i in result'range loop
|
|
result(i) := L(i) xor R;
|
|
end loop;
|
|
return result;
|
|
end function "xor";
|
|
|
|
function "xnor" (L : STD_ULOGIC; R : float) return float is
|
|
variable result : float (R'range);
|
|
begin
|
|
for i in result'range loop
|
|
result(i) := L xnor R(i);
|
|
end loop;
|
|
return result;
|
|
end function "xnor";
|
|
|
|
function "xnor" (L : float; R : STD_ULOGIC) return float is
|
|
variable result : float (L'range);
|
|
begin
|
|
for i in result'range loop
|
|
result(i) := L(i) xnor R;
|
|
end loop;
|
|
return result;
|
|
end function "xnor";
|
|
|
|
-- Reduction operators, same as numeric_std functions
|
|
-- %%% remove 6 functions (old syntax)
|
|
function and_reduce(arg : float) return STD_ULOGIC is
|
|
begin
|
|
return and_reducex (to_slv(arg));
|
|
end function and_reduce;
|
|
|
|
function nand_reduce(arg : float) return STD_ULOGIC is
|
|
begin
|
|
return not and_reducex (to_slv(arg));
|
|
end function nand_reduce;
|
|
|
|
function or_reduce(arg : float) return STD_ULOGIC is
|
|
begin
|
|
return or_reducex (to_slv(arg));
|
|
end function or_reduce;
|
|
|
|
function nor_reduce(arg : float) return STD_ULOGIC is
|
|
begin
|
|
return not or_reducex (to_slv(arg));
|
|
end function nor_reduce;
|
|
|
|
function xor_reduce(arg : float) return STD_ULOGIC is
|
|
begin
|
|
return xor_reducex (to_slv(arg));
|
|
end function xor_reduce;
|
|
|
|
function xnor_reduce(arg : float) return STD_ULOGIC is
|
|
begin
|
|
return not xor_reducex (to_slv(arg));
|
|
end function xnor_reduce;
|
|
|
|
-- %%% Uncomment the following 6 functions (new syntax)
|
|
-- function "and" ( arg : float ) RETURN std_ulogic is
|
|
-- begin
|
|
-- return and to_slv(arg);
|
|
-- end function "and";
|
|
-- function "nand" ( arg : float ) RETURN std_ulogic is
|
|
-- begin
|
|
-- return nand to_slv(arg);
|
|
-- end function "nand";;
|
|
-- function "or" ( arg : float ) RETURN std_ulogic is
|
|
-- begin
|
|
-- return or to_slv(arg);
|
|
-- end function "or";
|
|
-- function "nor" ( arg : float ) RETURN std_ulogic is
|
|
-- begin
|
|
-- return nor to_slv(arg);
|
|
-- end function "nor";
|
|
-- function "xor" ( arg : float ) RETURN std_ulogic is
|
|
-- begin
|
|
-- return xor to_slv(arg);
|
|
-- end function "xor";
|
|
-- function "xnor" ( arg : float ) RETURN std_ulogic is
|
|
-- begin
|
|
-- return xnor to_slv(arg);
|
|
-- end function "xnor";
|
|
-----------------------------------------------------------------------------
|
|
-- Recommended Functions from the IEEE 754 Appendix
|
|
-----------------------------------------------------------------------------
|
|
-- returns x with the sign of y.
|
|
function Copysign (
|
|
x, y : float) -- floating point input
|
|
return float is
|
|
begin
|
|
return y(y'high) & x (x'high-1 downto x'low);
|
|
end function Copysign;
|
|
|
|
-- Returns y * 2**n for integral values of N without computing 2**n
|
|
function Scalb (
|
|
y : 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 float is
|
|
constant fraction_width : NATURAL := -minx(y'low, y'low); -- length of FP output fraction
|
|
constant exponent_width : NATURAL := y'high; -- length of FP output exponent
|
|
variable arg, result : float (exponent_width downto -fraction_width); -- internal argument
|
|
variable expon : SIGNED (exponent_width-1 downto 0); -- Vectorized exp
|
|
variable exp : SIGNED (exponent_width downto 0);
|
|
variable ufract : UNSIGNED (fraction_width downto 0);
|
|
constant expon_base : SIGNED (exponent_width-1 downto 0)
|
|
:= gen_expon_base(exponent_width); -- exponent offset
|
|
variable fptype : valid_fpstate;
|
|
begin
|
|
-- This can be done by simply adding N to the exponent.
|
|
arg := to_01 (y, 'X');
|
|
fptype := class(arg, check_error);
|
|
classcase : case fptype is
|
|
when isx =>
|
|
result := (others => 'X');
|
|
when nan | quiet_nan =>
|
|
-- Return quiet NAN, IEEE754-1985-7.1,1
|
|
result := qnanfp (fraction_width => fraction_width,
|
|
exponent_width => exponent_width);
|
|
when others =>
|
|
break_number (
|
|
arg => arg,
|
|
fptyp => fptype,
|
|
denormalize => denormalize,
|
|
fract => ufract,
|
|
expon => expon);
|
|
exp := resize (expon, exp'length) + N;
|
|
result := normalize (
|
|
fract => ufract,
|
|
expon => exp,
|
|
sign => to_x01 (arg (arg'high)),
|
|
fraction_width => fraction_width,
|
|
exponent_width => exponent_width,
|
|
round_style => round_style,
|
|
denormalize => denormalize,
|
|
nguard => 0);
|
|
end case classcase;
|
|
return result;
|
|
end function Scalb;
|
|
|
|
-- Returns y * 2**n for integral values of N without computing 2**n
|
|
function Scalb (
|
|
y : 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 float is
|
|
variable n_int : INTEGER;
|
|
begin
|
|
n_int := to_integer(N);
|
|
return Scalb (y => y,
|
|
N => n_int,
|
|
round_style => round_style,
|
|
check_error => check_error,
|
|
denormalize => denormalize);
|
|
end function Scalb;
|
|
|
|
-- returns the unbiased exponent of x
|
|
function Logb (
|
|
x : float) -- floating point input
|
|
return INTEGER is
|
|
constant fraction_width : NATURAL := -minx (x'low, x'low); -- length of FP output fraction
|
|
constant exponent_width : NATURAL := x'high; -- length of FP output exponent
|
|
variable result : INTEGER; -- result
|
|
variable arg : float (exponent_width downto -fraction_width); -- internal argument
|
|
variable expon : SIGNED (exponent_width - 1 downto 0);
|
|
variable fract : UNSIGNED (fraction_width downto 0);
|
|
constant expon_base : INTEGER := 2**(exponent_width-1) -1; -- exponent
|
|
-- offset +1
|
|
variable fptype : valid_fpstate;
|
|
begin
|
|
-- Just return the exponent.
|
|
arg := to_01 (x, 'X');
|
|
fptype := class(arg);
|
|
classcase : case fptype is
|
|
when isx | nan | quiet_nan =>
|
|
-- Return quiet NAN, IEEE754-1985-7.1,1
|
|
result := 0;
|
|
when pos_denormal | neg_denormal =>
|
|
fract (fraction_width) := '0';
|
|
fract (fraction_width-1 downto 0) :=
|
|
UNSIGNED (to_slv(arg(-1 downto -fraction_width)));
|
|
result := find_msb (fract, '1') -- Find the first "1"
|
|
- fraction_width; -- subtract the length we want
|
|
result := -expon_base + 1 + result;
|
|
when others =>
|
|
expon := SIGNED(arg (exponent_width - 1 downto 0));
|
|
expon(exponent_width-1) := not expon(exponent_width-1);
|
|
expon := expon + 1;
|
|
result := to_integer (expon);
|
|
end case classcase;
|
|
return result;
|
|
end function Logb;
|
|
|
|
-- returns the unbiased exponent of x
|
|
function Logb (
|
|
x : float) -- floating point input
|
|
return SIGNED is
|
|
constant exponent_width : NATURAL := x'high; -- length of FP output exponent
|
|
variable result : SIGNED (exponent_width - 1 downto 0); -- result
|
|
begin
|
|
-- Just return the exponent.
|
|
result := to_signed (Logb (x), exponent_width);
|
|
return result;
|
|
end function Logb;
|
|
|
|
-- returns the next representable neighbor of x in the direction toward y
|
|
function Nextafter (
|
|
x, y : float; -- floating point input
|
|
constant check_error : BOOLEAN := float_check_error; -- check for errors
|
|
constant denormalize : BOOLEAN := float_denormalize)
|
|
return float is
|
|
constant fraction_width : NATURAL := -minx(x'low, x'low); -- length of FP output fraction
|
|
constant exponent_width : NATURAL := x'high; -- length of FP output exponent
|
|
function "=" (
|
|
l, r : float) -- inputs
|
|
return BOOLEAN is
|
|
begin -- function "="
|
|
return eq (l => l,
|
|
r => r,
|
|
check_error => false);
|
|
end function "=";
|
|
function ">" (
|
|
l, r : float) -- inputs
|
|
return BOOLEAN is
|
|
begin -- function ">"
|
|
return gt (l => l,
|
|
r => r,
|
|
check_error => false);
|
|
end function ">";
|
|
variable fract : UNSIGNED (fraction_width-1 downto 0);
|
|
variable expon : UNSIGNED (exponent_width-1 downto 0);
|
|
variable sign : STD_ULOGIC;
|
|
variable result : float (exponent_width downto -fraction_width);
|
|
variable validfpx, validfpy : valid_fpstate; -- Valid FP state
|
|
begin -- fp_Nextafter
|
|
-- If Y > X, add one to the fraction, otherwise subtract.
|
|
validfpx := class (x, check_error);
|
|
validfpy := class (y, check_error);
|
|
if validfpx = isx or validfpy = isx then
|
|
result := (others => 'X');
|
|
return result;
|
|
elsif (validfpx = nan or validfpy = nan) then
|
|
return nanfp (fraction_width => fraction_width,
|
|
exponent_width => exponent_width);
|
|
elsif (validfpx = quiet_nan or validfpy = quiet_nan) then
|
|
return qnanfp (fraction_width => fraction_width,
|
|
exponent_width => exponent_width);
|
|
elsif x = y then -- Return X
|
|
return x;
|
|
else
|
|
fract := UNSIGNED (to_slv (x (-1 downto -fraction_width))); -- Fraction
|
|
expon := UNSIGNED (x (exponent_width - 1 downto 0)); -- exponent
|
|
sign := x(exponent_width); -- sign bit
|
|
if (y > x) then
|
|
-- Increase the number given
|
|
if validfpx = neg_inf then
|
|
-- return most negative number
|
|
expon := (others => '1');
|
|
expon (0) := '0';
|
|
fract := (others => '1');
|
|
elsif validfpx = pos_zero or validfpx = neg_zero then
|
|
-- return smallest denormal number
|
|
sign := '0';
|
|
expon := (others => '0');
|
|
fract := (others => '0');
|
|
fract(0) := '1';
|
|
elsif validfpx = pos_normal then
|
|
if and_reducex (fract) = '1' then -- fraction is all "1".
|
|
if and_reducex (expon (exponent_width-1 downto 1)) = '1'
|
|
and expon (0) = '0' then
|
|
-- Exponent is one away from infinity.
|
|
assert NO_WARNING
|
|
report "FLOAT_GENERIC_PKG.FP_NEXTAFTER: NextAfter overflow"
|
|
severity warning;
|
|
return pos_inffp (fraction_width => fraction_width,
|
|
exponent_width => exponent_width);
|
|
else
|
|
expon := expon + 1;
|
|
fract := (others => '0');
|
|
end if;
|
|
else
|
|
fract := fract + 1;
|
|
end if;
|
|
elsif validfpx = pos_denormal then
|
|
if and_reducex (fract) = '1' then -- fraction is all "1".
|
|
-- return smallest possible normal number
|
|
expon := (others => '0');
|
|
expon(0) := '1';
|
|
fract := (others => '0');
|
|
else
|
|
fract := fract + 1;
|
|
end if;
|
|
elsif validfpx = neg_normal then
|
|
if or_reducex (fract) = '0' then -- fraction is all "0".
|
|
if or_reducex (expon (exponent_width-1 downto 1)) = '0' and
|
|
expon (0) = '1' then -- Smallest exponent
|
|
-- return the largest negative denormal number
|
|
expon := (others => '0');
|
|
fract := (others => '1');
|
|
else
|
|
expon := expon - 1;
|
|
fract := (others => '1');
|
|
end if;
|
|
else
|
|
fract := fract - 1;
|
|
end if;
|
|
elsif validfpx = neg_denormal then
|
|
if or_reducex (fract(fract'high downto 1)) = '0'
|
|
and fract (0) = '1' then -- Smallest possible fraction
|
|
return zerofp (fraction_width => fraction_width,
|
|
exponent_width => exponent_width);
|
|
else
|
|
fract := fract - 1;
|
|
end if;
|
|
end if;
|
|
else
|
|
-- Decrease the number
|
|
if validfpx = pos_inf then
|
|
-- return most positive number
|
|
expon := (others => '1');
|
|
expon (0) := '0';
|
|
fract := (others => '1');
|
|
elsif validfpx = pos_zero
|
|
or class (x) = neg_zero then
|
|
-- return smallest negative denormal number
|
|
sign := '1';
|
|
expon := (others => '0');
|
|
fract := (others => '0');
|
|
fract(0) := '1';
|
|
elsif validfpx = neg_normal then
|
|
if and_reducex (fract) = '1' then -- fraction is all "1".
|
|
if and_reducex (expon (exponent_width-1 downto 1)) = '1'
|
|
and expon (0) = '0' then
|
|
-- Exponent is one away from infinity.
|
|
assert NO_WARNING
|
|
report "FLOAT_GENERIC_PKG.FP_NEXTAFTER: NextAfter overflow"
|
|
severity warning;
|
|
return neg_inffp (fraction_width => fraction_width,
|
|
exponent_width => exponent_width);
|
|
else
|
|
expon := expon + 1; -- Fraction overflow
|
|
fract := (others => '0');
|
|
end if;
|
|
else
|
|
fract := fract + 1;
|
|
end if;
|
|
elsif validfpx = neg_denormal then
|
|
if and_reducex (fract) = '1' then -- fraction is all "1".
|
|
-- return smallest possible normal number
|
|
expon := (others => '0');
|
|
expon(0) := '1';
|
|
fract := (others => '0');
|
|
else
|
|
fract := fract + 1;
|
|
end if;
|
|
elsif validfpx = pos_normal then
|
|
if or_reducex (fract) = '0' then -- fraction is all "0".
|
|
if or_reducex (expon (exponent_width-1 downto 1)) = '0' and
|
|
expon (0) = '1' then -- Smallest exponent
|
|
-- return the largest positive denormal number
|
|
expon := (others => '0');
|
|
fract := (others => '1');
|
|
else
|
|
expon := expon - 1;
|
|
fract := (others => '1');
|
|
end if;
|
|
else
|
|
fract := fract - 1;
|
|
end if;
|
|
elsif validfpx = pos_denormal then
|
|
if or_reducex (fract(fract'high downto 1)) = '0'
|
|
and fract (0) = '1' then -- Smallest possible fraction
|
|
return zerofp (fraction_width => fraction_width,
|
|
exponent_width => exponent_width);
|
|
else
|
|
fract := fract - 1;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
result (-1 downto -fraction_width) := float(fract);
|
|
result (exponent_width -1 downto 0) := float(expon);
|
|
result (exponent_width) := sign;
|
|
return result;
|
|
end if;
|
|
end function Nextafter;
|
|
|
|
-- Returns True if X is unordered with Y.
|
|
function Unordered (
|
|
x, y : float) -- floating point input
|
|
return BOOLEAN is
|
|
variable lfptype, rfptype : valid_fpstate;
|
|
begin
|
|
lfptype := class (x);
|
|
rfptype := class (y);
|
|
if (lfptype = nan or lfptype = quiet_nan or
|
|
rfptype = nan or rfptype = quiet_nan or
|
|
lfptype = isx or rfptype = isx) then
|
|
return true;
|
|
else
|
|
return false;
|
|
end if;
|
|
end function Unordered;
|
|
|
|
function Finite (
|
|
x : float)
|
|
return BOOLEAN is
|
|
variable fp_state : valid_fpstate; -- fp state
|
|
begin
|
|
fp_state := Class (x);
|
|
if (fp_state = pos_inf) or (fp_state = neg_inf) then
|
|
return true;
|
|
else
|
|
return false;
|
|
end if;
|
|
end function Finite;
|
|
|
|
function Isnan (
|
|
x : float)
|
|
return BOOLEAN is
|
|
variable fp_state : valid_fpstate; -- fp state
|
|
begin
|
|
fp_state := Class (x);
|
|
if (fp_state = nan) or (fp_state = quiet_nan) then
|
|
return true;
|
|
else
|
|
return false;
|
|
end if;
|
|
end function Isnan;
|
|
|
|
-- Function to return constants.
|
|
function zerofp (
|
|
constant exponent_width : NATURAL := float_exponent_width; -- exponent
|
|
constant fraction_width : NATURAL := float_fraction_width) -- fraction
|
|
return float is
|
|
constant result : float (exponent_width downto -fraction_width) :=
|
|
(others => '0'); -- zero
|
|
begin
|
|
return result;
|
|
end function zerofp;
|
|
function nanfp (
|
|
constant exponent_width : NATURAL := float_exponent_width; -- exponent
|
|
constant fraction_width : NATURAL := float_fraction_width) -- fraction
|
|
return float is
|
|
variable result : float (exponent_width downto -fraction_width) :=
|
|
(others => '0'); -- zero
|
|
begin
|
|
result (exponent_width-1 downto 0) := (others => '1');
|
|
-- Exponent all "1"
|
|
result (-1) := '1'; -- MSB of Fraction "1"
|
|
-- Note: From W. Khan "IEEE Standard 754 for Binary Floating Point"
|
|
-- The difference between a signaling NAN and a quiet NAN is that
|
|
-- the MSB of the Fraction is a "1" in a Signaling NAN, and is a
|
|
-- "0" in a quiet NAN.
|
|
return result;
|
|
end function nanfp;
|
|
function qnanfp (
|
|
constant exponent_width : NATURAL := float_exponent_width; -- exponent
|
|
constant fraction_width : NATURAL := float_fraction_width) -- fraction
|
|
return float is
|
|
variable result : float (exponent_width downto -fraction_width) :=
|
|
(others => '0'); -- zero
|
|
begin
|
|
result (exponent_width-1 downto 0) := (others => '1');
|
|
-- Exponent all "1"
|
|
result (-fraction_width) := '1'; -- LSB of Fraction "1"
|
|
-- (Could have been any bit)
|
|
return result;
|
|
end function qnanfp;
|
|
function pos_inffp (
|
|
constant exponent_width : NATURAL := float_exponent_width; -- exponent
|
|
constant fraction_width : NATURAL := float_fraction_width) -- fraction
|
|
return float is
|
|
variable result : float (exponent_width downto -fraction_width) :=
|
|
(others => '0'); -- zero
|
|
begin
|
|
result (exponent_width-1 downto 0) := (others => '1'); -- Exponent all "1"
|
|
return result;
|
|
end function pos_inffp;
|
|
function neg_inffp (
|
|
constant exponent_width : NATURAL := float_exponent_width; -- exponent
|
|
constant fraction_width : NATURAL := float_fraction_width) -- fraction
|
|
return float is
|
|
variable result : float (exponent_width downto -fraction_width) :=
|
|
(others => '0'); -- zero
|
|
begin
|
|
result (exponent_width downto 0) := (others => '1'); -- top bits all "1"
|
|
return result;
|
|
end function neg_inffp;
|
|
function neg_zerofp (
|
|
constant exponent_width : NATURAL := float_exponent_width; -- exponent
|
|
constant fraction_width : NATURAL := float_fraction_width) -- fraction
|
|
return float is
|
|
variable result : float (exponent_width downto -fraction_width) :=
|
|
(others => '0'); -- zero
|
|
begin
|
|
result (exponent_width) := '1';
|
|
return result;
|
|
end function neg_zerofp;
|
|
-- size_res versions
|
|
function zerofp (
|
|
size_res : float) -- variable is only use for sizing
|
|
return float is
|
|
begin
|
|
return zerofp (
|
|
exponent_width => size_res'high,
|
|
fraction_width => -size_res'low);
|
|
end function zerofp;
|
|
function nanfp (
|
|
size_res : float) -- variable is only use for sizing
|
|
return float is
|
|
begin
|
|
return nanfp (
|
|
exponent_width => size_res'high,
|
|
fraction_width => -size_res'low);
|
|
end function nanfp;
|
|
function qnanfp (
|
|
size_res : float) -- variable is only use for sizing
|
|
return float is
|
|
begin
|
|
return qnanfp (
|
|
exponent_width => size_res'high,
|
|
fraction_width => -size_res'low);
|
|
end function qnanfp;
|
|
function pos_inffp (
|
|
size_res : float) -- variable is only use for sizing
|
|
return float is
|
|
begin
|
|
return pos_inffp (
|
|
exponent_width => size_res'high,
|
|
fraction_width => -size_res'low);
|
|
end function pos_inffp;
|
|
function neg_inffp (
|
|
size_res : float) -- variable is only use for sizing
|
|
return float is
|
|
begin
|
|
return neg_inffp (
|
|
exponent_width => size_res'high,
|
|
fraction_width => -size_res'low);
|
|
end function neg_inffp;
|
|
function neg_zerofp (
|
|
size_res : float) -- variable is only use for sizing
|
|
return float is
|
|
begin
|
|
return neg_zerofp (
|
|
exponent_width => size_res'high,
|
|
fraction_width => -size_res'low);
|
|
end function neg_zerofp;
|
|
|
|
-- rtl_synthesis off
|
|
-- synthesis translate_off
|
|
-- purpose: writes float into a line (NOTE changed basetype)
|
|
type MVL9plus is ('U', 'X', '0', '1', 'Z', 'W', 'L', 'H', '-', error);
|
|
type char_indexed_by_MVL9 is array (STD_ULOGIC) of CHARACTER;
|
|
type MVL9_indexed_by_char is array (CHARACTER) of STD_ULOGIC;
|
|
type MVL9plus_indexed_by_char is array (CHARACTER) of MVL9plus;
|
|
|
|
constant MVL9_to_char : char_indexed_by_MVL9 := "UX01ZWLH-";
|
|
constant char_to_MVL9 : MVL9_indexed_by_char :=
|
|
('U' => 'U', 'X' => 'X', '0' => '0', '1' => '1', 'Z' => 'Z',
|
|
'W' => 'W', 'L' => 'L', 'H' => 'H', '-' => '-', others => 'U');
|
|
constant char_to_MVL9plus : MVL9plus_indexed_by_char :=
|
|
('U' => 'U', 'X' => 'X', '0' => '0', '1' => '1', 'Z' => 'Z',
|
|
'W' => 'W', 'L' => 'L', 'H' => 'H', '-' => '-', others => error);
|
|
|
|
-- %%% Remove the following lines for inclution in VHDL-200x-ft
|
|
constant NUS : STRING(2 to 1) := (others => ' '); -- NULL array
|
|
function justify (
|
|
value : STRING;
|
|
justified : SIDE := right;
|
|
field : width := 0)
|
|
return STRING is
|
|
constant VAL_LEN : INTEGER := value'length;
|
|
variable result : STRING (1 to field) := (others => ' ');
|
|
begin -- function justify
|
|
-- return value if field is too small
|
|
if VAL_LEN >= field then
|
|
return value;
|
|
end if;
|
|
if justified = left then
|
|
result(1 to VAL_LEN) := value;
|
|
elsif justified = right then
|
|
result(field - VAL_LEN + 1 to field) := value;
|
|
end if;
|
|
return result;
|
|
end function justify;
|
|
-------------------------------------------------------------------
|
|
-- TO_HSTRING
|
|
-------------------------------------------------------------------
|
|
function to_hstring (
|
|
value : STD_LOGIC_VECTOR;
|
|
justified : SIDE := right;
|
|
field : width := 0
|
|
) return STRING is
|
|
constant ne : INTEGER := (value'length+3)/4;
|
|
variable pad : STD_LOGIC_VECTOR(0 to (ne*4 - value'length) - 1);
|
|
variable ivalue : STD_LOGIC_VECTOR(0 to ne*4 - 1);
|
|
variable result : STRING(1 to ne);
|
|
variable quad : STD_LOGIC_VECTOR(0 to 3);
|
|
begin
|
|
if value'length < 1 then
|
|
return NUS;
|
|
else
|
|
if value (value'left) = 'Z' then
|
|
pad := (others => 'Z');
|
|
else
|
|
pad := (others => '0');
|
|
end if;
|
|
ivalue := pad & value;
|
|
for i in 0 to ne-1 loop
|
|
quad := To_X01Z(ivalue(4*i to 4*i+3));
|
|
case quad is
|
|
when x"0" => result(i+1) := '0';
|
|
when x"1" => result(i+1) := '1';
|
|
when x"2" => result(i+1) := '2';
|
|
when x"3" => result(i+1) := '3';
|
|
when x"4" => result(i+1) := '4';
|
|
when x"5" => result(i+1) := '5';
|
|
when x"6" => result(i+1) := '6';
|
|
when x"7" => result(i+1) := '7';
|
|
when x"8" => result(i+1) := '8';
|
|
when x"9" => result(i+1) := '9';
|
|
when x"A" => result(i+1) := 'A';
|
|
when x"B" => result(i+1) := 'B';
|
|
when x"C" => result(i+1) := 'C';
|
|
when x"D" => result(i+1) := 'D';
|
|
when x"E" => result(i+1) := 'E';
|
|
when x"F" => result(i+1) := 'F';
|
|
when "ZZZZ" => result(i+1) := 'Z';
|
|
when others => result(i+1) := 'X';
|
|
end case;
|
|
end loop;
|
|
return justify(result, justified, field);
|
|
end if;
|
|
end function to_hstring;
|
|
|
|
-------------------------------------------------------------------
|
|
-- TO_OSTRING
|
|
-------------------------------------------------------------------
|
|
function to_ostring (
|
|
value : STD_LOGIC_VECTOR;
|
|
justified : SIDE := right;
|
|
field : width := 0
|
|
) return STRING is
|
|
constant ne : INTEGER := (value'length+2)/3;
|
|
variable pad : STD_LOGIC_VECTOR(0 to (ne*3 - value'length) - 1);
|
|
variable ivalue : STD_LOGIC_VECTOR(0 to ne*3 - 1);
|
|
variable result : STRING(1 to ne);
|
|
variable tri : STD_LOGIC_VECTOR(0 to 2);
|
|
begin
|
|
if value'length < 1 then
|
|
return NUS;
|
|
else
|
|
if value (value'left) = 'Z' then
|
|
pad := (others => 'Z');
|
|
else
|
|
pad := (others => '0');
|
|
end if;
|
|
ivalue := pad & value;
|
|
for i in 0 to ne-1 loop
|
|
tri := To_X01Z(ivalue(3*i to 3*i+2));
|
|
case tri is
|
|
when o"0" => result(i+1) := '0';
|
|
when o"1" => result(i+1) := '1';
|
|
when o"2" => result(i+1) := '2';
|
|
when o"3" => result(i+1) := '3';
|
|
when o"4" => result(i+1) := '4';
|
|
when o"5" => result(i+1) := '5';
|
|
when o"6" => result(i+1) := '6';
|
|
when o"7" => result(i+1) := '7';
|
|
when "ZZZ" => result(i+1) := 'Z';
|
|
when others => result(i+1) := 'X';
|
|
end case;
|
|
end loop;
|
|
return justify(result, justified, field);
|
|
end if;
|
|
end function to_ostring;
|
|
-- %%% end remove lines
|
|
|
|
procedure write (
|
|
L : inout LINE; -- input line
|
|
VALUE : in float; -- floating point input
|
|
JUSTIFIED : in SIDE := right;
|
|
FIELD : in WIDTH := 0) is
|
|
variable s : STRING(1 to value'high - value'low +3);
|
|
variable sindx : INTEGER;
|
|
begin -- function write
|
|
s(1) := MVL9_to_char(STD_ULOGIC(VALUE(VALUE'high)));
|
|
s(2) := ':';
|
|
sindx := 3;
|
|
for i in VALUE'high-1 downto 0 loop
|
|
s(sindx) := MVL9_to_char(STD_ULOGIC(VALUE(i)));
|
|
sindx := sindx + 1;
|
|
end loop;
|
|
s(sindx) := ':';
|
|
sindx := sindx + 1;
|
|
for i in -1 downto VALUE'low loop
|
|
s(sindx) := MVL9_to_char(STD_ULOGIC(VALUE(i)));
|
|
sindx := sindx + 1;
|
|
end loop;
|
|
write(L, s, JUSTIFIED, FIELD);
|
|
end procedure write;
|
|
|
|
procedure READ(L : inout LINE; VALUE : out float) is
|
|
-- Possible data: 0:0000:0000000
|
|
-- 000000000000
|
|
variable c : CHARACTER;
|
|
variable readOk : BOOLEAN;
|
|
variable i : INTEGER; -- index variable
|
|
begin -- READ
|
|
loop -- skip white space
|
|
read(l, c, readOk);
|
|
exit when ((readOk = false) or ((c /= ' ') and (c /= CR) and (c /= HT)));
|
|
end loop;
|
|
for i in value'high downto value'low loop
|
|
value(i) := 'X';
|
|
end loop;
|
|
i := value'high;
|
|
readloop : loop
|
|
if readOk = false then -- Bail out if there was a bad read
|
|
report "FLOAT_GENERIC_PKG.READ(float): "
|
|
& "Error end of file encountered.";
|
|
return;
|
|
elsif c = ' ' or c = CR or c = HT then -- reading done.
|
|
if (i /= value'low) then
|
|
report "FLOAT_GENERIC_PKG.READ(float): "
|
|
& "Warning: Value truncated.";
|
|
return;
|
|
end if;
|
|
elsif c = ':' or c = '.' then -- seperator, ignore
|
|
if not (i = -1 or i = value'high-1) then
|
|
report "FLOAT_GENERIC_PKG.READ(float): "
|
|
& "Warning: Seperator point does not match number format: '"
|
|
& c & "' ecountered at location " & INTEGER'image(i) & ".";
|
|
end if;
|
|
elsif (char_to_MVL9plus(c) = error) then
|
|
report "FLOAT_GENERIC_PKG.READ(float): "
|
|
& "Error: Character '" & c & "' read, expected STD_ULOGIC literal.";
|
|
return;
|
|
else
|
|
value (i) := char_to_MVL9(c);
|
|
i := i - 1;
|
|
if i < value'low then
|
|
return;
|
|
end if;
|
|
end if;
|
|
read(l, c, readOk);
|
|
end loop readloop;
|
|
end procedure READ;
|
|
|
|
procedure READ(L : inout LINE; VALUE : out float; GOOD : out BOOLEAN) is
|
|
-- Possible data: 0:0000:0000000
|
|
-- 000000000000
|
|
variable c : CHARACTER;
|
|
variable i : INTEGER; -- index variable
|
|
variable readOk : BOOLEAN;
|
|
begin -- READ
|
|
loop -- skip white space
|
|
read(l, c, readOk);
|
|
exit when ((readOk = false) or ((c /= ' ') and (c /= CR) and (c /= HT)));
|
|
end loop;
|
|
for i in value'high downto value'low loop
|
|
value(i) := 'X';
|
|
end loop;
|
|
i := value'high;
|
|
good := true;
|
|
readloop : loop
|
|
if readOk = false then -- Bail out if there was a bad read
|
|
good := false;
|
|
return;
|
|
elsif c = ' ' or c = CR or c = HT then -- reading done
|
|
good := false;
|
|
return;
|
|
elsif c = ':' or c = '.' then -- seperator, ignore
|
|
good := (i = -1 or i = value'high-1);
|
|
elsif (char_to_MVL9plus(c) = error) then
|
|
good := false;
|
|
return;
|
|
else
|
|
value (i) := char_to_MVL9(c);
|
|
i := i - 1;
|
|
if i < value'low then
|
|
return;
|
|
end if;
|
|
end if;
|
|
read(l, c, readOk);
|
|
end loop readloop;
|
|
end procedure READ;
|
|
|
|
procedure owrite (
|
|
L : inout LINE; -- access type (pointer)
|
|
VALUE : in float; -- value to write
|
|
JUSTIFIED : in SIDE := right; -- which side to justify text
|
|
FIELD : in WIDTH := 0) is -- width of field
|
|
begin
|
|
write (L => L,
|
|
VALUE => to_ostring(VALUE),
|
|
JUSTIFIED => JUSTIFIED,
|
|
FIELD => FIELD);
|
|
end procedure owrite;
|
|
|
|
procedure OREAD(L : inout LINE; VALUE : out float) is
|
|
constant ne : INTEGER := ((value'length+2)/3) * 3; -- pad
|
|
variable slv : STD_LOGIC_VECTOR (ne-1 downto 0); -- slv
|
|
variable dummy : CHARACTER; -- to read the "."
|
|
variable igood : BOOLEAN;
|
|
variable nybble : STD_LOGIC_VECTOR (2 downto 0); -- 3 bits
|
|
variable i : INTEGER;
|
|
begin
|
|
OREAD (L => L,
|
|
VALUE => nybble,
|
|
good => igood);
|
|
assert (igood)
|
|
report "FLOAT_GENERIC_PKG.OREAD: Failed to skip white space " & L.all
|
|
severity error;
|
|
i := ne-1 - 3; -- Top - 3
|
|
slv (ne-1 downto i+1) := nybble;
|
|
while (i /= -1) and igood and L.all'length /= 0 loop
|
|
if (L.all(1) = '.') or (L.all(1) = ':') then
|
|
read (L, dummy);
|
|
else
|
|
OREAD (L => L,
|
|
VALUE => nybble,
|
|
good => igood);
|
|
assert (igood)
|
|
report "FLOAT_GENERIC_PKG.OREAD: Failed to read the string " & L.all
|
|
severity error;
|
|
slv (i downto i-2) := nybble;
|
|
i := i - 3;
|
|
end if;
|
|
end loop;
|
|
assert igood and -- We did not get another error
|
|
(i = -1) and -- We read everything, and high bits 0
|
|
(or_reducex(slv(ne-1 downto VALUE'high-VALUE'low+1)) = '0')
|
|
report "FLOAT_GENERIC_PKG.OREAD: Vector truncated."
|
|
severity error;
|
|
value := to_float (slv(VALUE'high-VALUE'low downto 0),
|
|
value'high, -value'low);
|
|
end procedure OREAD;
|
|
|
|
procedure OREAD(L : inout LINE; VALUE : out float; GOOD : out BOOLEAN) is
|
|
constant ne : INTEGER := ((value'length+2)/3) * 3; -- pad
|
|
variable slv : STD_LOGIC_VECTOR (ne-1 downto 0); -- slv
|
|
variable dummy : CHARACTER; -- to read the "."
|
|
variable igood : BOOLEAN;
|
|
variable nybble : STD_LOGIC_VECTOR (2 downto 0); -- 3 bits
|
|
variable i : INTEGER;
|
|
begin
|
|
OREAD (L => L,
|
|
VALUE => nybble,
|
|
good => igood);
|
|
i := ne-1 - 3; -- Top - 3
|
|
slv (ne-1 downto i+1) := nybble;
|
|
while (i /= -1) and igood and L.all'length /= 0 loop
|
|
if (L.all(1) = '.') or (L.all(1) = ':') then
|
|
read (L, dummy, igood);
|
|
else
|
|
OREAD (L => L,
|
|
VALUE => nybble,
|
|
good => igood);
|
|
slv (i downto i-2) := nybble;
|
|
i := i - 3;
|
|
end if;
|
|
end loop;
|
|
good := igood and -- We did not get another error
|
|
(i = -1) and -- We read everything, and high bits 0
|
|
(or_reducex(slv(ne-1 downto VALUE'high-VALUE'low+1)) = '0');
|
|
value := to_float (slv(VALUE'high-VALUE'low downto 0),
|
|
value'high, -value'low);
|
|
end procedure OREAD;
|
|
|
|
procedure hwrite (
|
|
L : inout LINE; -- access type (pointer)
|
|
VALUE : in float; -- value to write
|
|
JUSTIFIED : in SIDE := right; -- which side to justify text
|
|
FIELD : in WIDTH := 0) is -- width of field
|
|
begin
|
|
write (L => L,
|
|
VALUE => to_hstring(VALUE),
|
|
JUSTIFIED => JUSTIFIED,
|
|
FIELD => FIELD);
|
|
end procedure hwrite;
|
|
|
|
procedure HREAD(L : inout LINE; VALUE : out float) is
|
|
constant ne : INTEGER := ((value'length+3)/4) * 4; -- pad
|
|
variable slv : STD_LOGIC_VECTOR (ne-1 downto 0); -- slv
|
|
variable dummy : CHARACTER; -- to read the "."
|
|
variable igood : BOOLEAN;
|
|
variable nybble : STD_LOGIC_VECTOR (3 downto 0); -- 4 bits
|
|
variable i : INTEGER;
|
|
begin
|
|
HREAD (L => L,
|
|
VALUE => nybble,
|
|
good => igood);
|
|
assert (igood)
|
|
report "FLOAT_GENERIC_PKG.HREAD: Failed to skip white space " & L.all
|
|
severity error;
|
|
i := ne - 1 - 4; -- Top - 4
|
|
slv (ne -1 downto i+1) := nybble;
|
|
while (i /= -1) and igood and L.all'length /= 0 loop
|
|
if (L.all(1) = '.') or (L.all(1) = ':') then
|
|
read (L, dummy);
|
|
else
|
|
HREAD (L => L,
|
|
VALUE => nybble,
|
|
good => igood);
|
|
assert (igood)
|
|
report "FLOAT_GENERIC_PKG.HREAD: Failed to read the string " & L.all
|
|
severity error;
|
|
slv (i downto i-3) := nybble;
|
|
i := i - 4;
|
|
end if;
|
|
end loop;
|
|
assert igood and -- We did not get another error
|
|
(i = -1) and -- We read everything
|
|
(or_reducex(slv(ne-1 downto VALUE'high-VALUE'low+1)) = '0')
|
|
report "FLOAT_GENERIC_PKG.HREAD: Vector truncated."
|
|
severity error;
|
|
value := to_float (slv(VALUE'high-VALUE'low downto 0),
|
|
value'high, -value'low);
|
|
end procedure HREAD;
|
|
|
|
procedure HREAD(L : inout LINE; VALUE : out float; GOOD : out BOOLEAN) is
|
|
constant ne : INTEGER := ((value'length+3)/4) * 4; -- pad
|
|
variable slv : STD_LOGIC_VECTOR (ne-1 downto 0); -- slv
|
|
variable dummy : CHARACTER; -- to read the "."
|
|
variable igood : BOOLEAN;
|
|
variable nybble : STD_LOGIC_VECTOR (3 downto 0); -- 4 bits
|
|
variable i : INTEGER;
|
|
begin
|
|
HREAD (L => L,
|
|
VALUE => nybble,
|
|
good => igood);
|
|
i := ne - 1 - 4; -- Top - 4
|
|
slv (ne-1 downto i+1) := nybble;
|
|
while (i /= -1) and igood and L.all'length /= 0 loop
|
|
if (L.all(1) = '.') or (L.all(1) = ':') then
|
|
read (L, dummy, igood);
|
|
else
|
|
HREAD (L => L,
|
|
VALUE => nybble,
|
|
good => igood);
|
|
slv (i downto i-3) := nybble;
|
|
i := i - 4;
|
|
end if;
|
|
end loop;
|
|
good := igood and -- We did not get another error
|
|
(i = -1) and -- We read everything, and high bits 0
|
|
(or_reducex(slv(ne-1 downto VALUE'high-VALUE'low+1)) = '0');
|
|
value := to_float (slv(VALUE'high-VALUE'low downto 0),
|
|
value'high, -value'low);
|
|
end procedure HREAD;
|
|
|
|
function to_string (
|
|
value : float;
|
|
justified : SIDE := right;
|
|
field : width := 0
|
|
) return STRING is
|
|
variable s : STRING(1 to value'high - value'low +3);
|
|
variable sindx : INTEGER;
|
|
begin -- function write
|
|
s(1) := MVL9_to_char(STD_ULOGIC(VALUE(VALUE'high)));
|
|
s(2) := ':';
|
|
sindx := 3;
|
|
for i in VALUE'high-1 downto 0 loop
|
|
s(sindx) := MVL9_to_char(STD_ULOGIC(VALUE(i)));
|
|
sindx := sindx + 1;
|
|
end loop;
|
|
s(sindx) := ':';
|
|
sindx := sindx + 1;
|
|
for i in -1 downto VALUE'low loop
|
|
s(sindx) := MVL9_to_char(STD_ULOGIC(VALUE(i)));
|
|
sindx := sindx + 1;
|
|
end loop;
|
|
return justify (s, JUSTIFIED, FIELD);
|
|
end function to_string;
|
|
|
|
function to_hstring (
|
|
value : float;
|
|
justified : SIDE := right;
|
|
field : width := 0
|
|
) return STRING is
|
|
variable slv : STD_LOGIC_VECTOR (value'length-1 downto 0);
|
|
begin
|
|
floop : for i in slv'range loop
|
|
slv(i) := to_X01Z (value(i + value'low));
|
|
end loop floop;
|
|
return to_hstring (slv, justified, field);
|
|
end function to_hstring;
|
|
|
|
function to_ostring (
|
|
value : float;
|
|
justified : SIDE := right;
|
|
field : width := 0
|
|
) return STRING is
|
|
variable slv : STD_LOGIC_VECTOR (value'length-1 downto 0);
|
|
begin
|
|
floop : for i in slv'range loop
|
|
slv(i) := to_X01Z (value(i + value'low));
|
|
end loop floop;
|
|
return to_ostring (slv, justified, field);
|
|
end function to_ostring;
|
|
|
|
function from_string (
|
|
bstring : STRING; -- binary string
|
|
constant exponent_width : NATURAL := float_exponent_width;
|
|
constant fraction_width : NATURAL := float_fraction_width)
|
|
return float is
|
|
variable result : float (exponent_width downto -fraction_width);
|
|
variable L : LINE;
|
|
variable good : BOOLEAN;
|
|
begin
|
|
L := new STRING'(bstring);
|
|
read (L, result, good);
|
|
deallocate (L);
|
|
assert (good)
|
|
report "FLOAT_GENERIC_PKG.from_string: Bad string " & bstring
|
|
severity error;
|
|
return result;
|
|
end function from_string;
|
|
|
|
function from_ostring (
|
|
ostring : STRING; -- Octal string
|
|
constant exponent_width : NATURAL := float_exponent_width;
|
|
constant fraction_width : NATURAL := float_fraction_width)
|
|
return float is
|
|
variable result : float (exponent_width downto -fraction_width);
|
|
variable L : LINE;
|
|
variable good : BOOLEAN;
|
|
begin
|
|
L := new STRING'(ostring);
|
|
oread (L, result, good);
|
|
deallocate (L);
|
|
assert (good)
|
|
report "FLOAT_GENERIC_PKG.from_ostring: Bad string " & ostring
|
|
severity error;
|
|
return result;
|
|
end function from_ostring;
|
|
|
|
function from_hstring (
|
|
hstring : STRING; -- hex string
|
|
constant exponent_width : NATURAL := float_exponent_width;
|
|
constant fraction_width : NATURAL := float_fraction_width)
|
|
return float is
|
|
variable result : float (exponent_width downto -fraction_width);
|
|
variable L : LINE;
|
|
variable good : BOOLEAN;
|
|
begin
|
|
L := new STRING'(hstring);
|
|
hread (L, result, good);
|
|
deallocate (L);
|
|
assert (good)
|
|
report "FLOAT_GENERIC_PKG.from_hstring: Bad string " & hstring
|
|
severity error;
|
|
return result;
|
|
end function from_hstring;
|
|
|
|
function from_string (
|
|
bstring : STRING; -- binary string
|
|
size_res : float) -- used for sizing only
|
|
return float is
|
|
begin
|
|
return from_string (bstring => bstring,
|
|
exponent_width => size_res'high,
|
|
fraction_width => -size_res'low);
|
|
end function from_string;
|
|
|
|
function from_ostring (
|
|
ostring : STRING; -- Octal string
|
|
size_res : float) -- used for sizing only
|
|
return float is
|
|
begin
|
|
return from_ostring (ostring => ostring,
|
|
exponent_width => size_res'high,
|
|
fraction_width => -size_res'low);
|
|
end function from_ostring;
|
|
|
|
function from_hstring (
|
|
hstring : STRING; -- hex string
|
|
size_res : float) -- used for sizing only
|
|
return float is
|
|
begin
|
|
return from_hstring (hstring => hstring,
|
|
exponent_width => size_res'high,
|
|
fraction_width => -size_res'low);
|
|
end function from_hstring;
|
|
-- synthesis translate_on
|
|
-- rtl_synthesis on
|
|
function to_StdLogicVector (arg : float) return STD_LOGIC_VECTOR is
|
|
begin
|
|
return to_slv (arg);
|
|
end function to_StdLogicVector;
|
|
|
|
function to_Std_Logic_Vector (arg : float) return std_logic_vector is
|
|
begin
|
|
return to_slv (arg);
|
|
end function to_Std_Logic_Vector;
|
|
|
|
function to_StdULogicVector (arg : float) return STD_ULOGIC_VECTOR is
|
|
begin
|
|
return to_sulv (arg);
|
|
end function to_StdULogicVector;
|
|
|
|
function to_Std_ULogic_Vector (arg : float) return std_ulogic_vector is
|
|
begin
|
|
return to_sulv (arg);
|
|
end function to_Std_ULogic_Vector;
|
|
end package body float_pkg;
|