From 28572366235082478e491258a838ae3099147beb Mon Sep 17 00:00:00 2001 From: Jens Ahrensfeld Date: Mon, 22 Mar 2021 12:42:32 +0000 Subject: [PATCH] - added git-svn-id: http://moon:8086/svn/vhdl/trunk@1446 cc03376c-175c-47c8-b038-4cd826a8556b --- lib/fixed/ieee_proposed/189_lewis_p.pdf | Bin 0 -> 198534 bytes lib/fixed/ieee_proposed/Makefile.lib | 9 + .../ieee_proposed/fixed_float_types_c.vhdl | 34 + lib/fixed/ieee_proposed/fixed_pkg_c.vhdl | 8378 +++++++++++++++++ 4 files changed, 8421 insertions(+) create mode 100644 lib/fixed/ieee_proposed/189_lewis_p.pdf create mode 100644 lib/fixed/ieee_proposed/Makefile.lib create mode 100644 lib/fixed/ieee_proposed/fixed_float_types_c.vhdl create mode 100644 lib/fixed/ieee_proposed/fixed_pkg_c.vhdl diff --git a/lib/fixed/ieee_proposed/189_lewis_p.pdf b/lib/fixed/ieee_proposed/189_lewis_p.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d09d11a3575076cb0a4b3fa80eebe32ae55ac9bb GIT binary patch literal 198534 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

-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 z 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 z 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

N+saYO!IokVFBvPC{lB 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 literal 0 HcmV?d00001 diff --git a/lib/fixed/ieee_proposed/Makefile.lib b/lib/fixed/ieee_proposed/Makefile.lib new file mode 100644 index 0000000..3009937 --- /dev/null +++ b/lib/fixed/ieee_proposed/Makefile.lib @@ -0,0 +1,9 @@ +SRCS += fixed_float_types_c.vhdl +SRCS += fixed_pkg_c.vhdl + +# Compile +TARGET := fixed_pkg +WORK_LIB := ieee_proposed + +include ../../../Common/make/ghdl.mk + diff --git a/lib/fixed/ieee_proposed/fixed_float_types_c.vhdl b/lib/fixed/ieee_proposed/fixed_float_types_c.vhdl new file mode 100644 index 0000000..315b628 --- /dev/null +++ b/lib/fixed/ieee_proposed/fixed_float_types_c.vhdl @@ -0,0 +1,34 @@ +-- -------------------------------------------------------------------- +-- "fixed_float_types" package contains types used in the fixed and floating +-- point packages.. +-- Please see the documentation for the floating point package. +-- This package should be compiled into "ieee_proposed" and used as follows: +-- +-- This verison is designed to work with the VHDL-93 compilers. Please +-- note the "%%%" comments. These are where we diverge from the +-- VHDL-200X LRM. +-- +-- -------------------------------------------------------------------- +-- Version : $Revision: 1.21 $ +-- Date : $Date: 2007-09-11 14:52:13-04 $ +-- -------------------------------------------------------------------- + +package fixed_float_types is + + -- Types used for generics of fixed_generic_pkg + + type fixed_round_style_type is (fixed_round, fixed_truncate); + + type fixed_overflow_style_type is (fixed_saturate, fixed_wrap); + + -- Type used for generics of float_generic_pkg + + -- These are the same as the C FE_TONEAREST, FE_UPWARD, FE_DOWNWARD, + -- and FE_TOWARDZERO floating point rounding macros. + + type round_type is (round_nearest, -- Default, nearest LSB '0' + round_inf, -- Round toward positive infinity + round_neginf, -- Round toward negative infinity + round_zero); -- Round toward zero (truncate) + +end package fixed_float_types; diff --git a/lib/fixed/ieee_proposed/fixed_pkg_c.vhdl b/lib/fixed/ieee_proposed/fixed_pkg_c.vhdl new file mode 100644 index 0000000..f362323 --- /dev/null +++ b/lib/fixed/ieee_proposed/fixed_pkg_c.vhdl @@ -0,0 +1,8378 @@ +-- -------------------------------------------------------------------- +-- "fixed_pkg_c.vhdl" package contains functions for fixed point math. +-- Please see the documentation for the fixed point package. +-- This package should be compiled into "ieee_proposed" and used as follows: +-- use ieee.std_logic_1164.all; +-- use ieee.numeric_std.all; +-- use ieee_proposed.fixed_float_types.all; +-- use ieee_proposed.fixed_pkg.all; +-- +-- This verison is designed to work with the VHDL-93 compilers +-- synthesis tools. Please note the "%%%" comments. These are where we +-- diverge from the VHDL-200X LRM. +-- -------------------------------------------------------------------- +-- Version : $Revision: 2.0 $ +-- Date : $Date: 2011/01/26 15:55:27 $ +-- -------------------------------------------------------------------- + +use STD.TEXTIO.all; +library IEEE; +use IEEE.STD_LOGIC_1164.all; +use IEEE.NUMERIC_STD.all; +library IEEE_PROPOSED; +use IEEE_PROPOSED.fixed_float_types.all; + +package fixed_pkg is +-- generic ( + -- Rounding routine to use in fixed point, fixed_round or fixed_truncate + constant fixed_round_style : fixed_round_style_type := fixed_round; + -- Overflow routine to use in fixed point, fixed_saturate or fixed_wrap + constant fixed_overflow_style : fixed_overflow_style_type := fixed_saturate; + -- Extra bits used in divide routines + constant fixed_guard_bits : NATURAL := 3; + -- If TRUE, then turn off warnings on "X" propagation + constant no_warning : BOOLEAN := (false + ); + + -- Author David Bishop (dbishop@vhdl.org) + + -- base Unsigned fixed point type, downto direction assumed + type UNRESOLVED_ufixed is array (INTEGER range <>) of STD_ULOGIC; + -- base Signed fixed point type, downto direction assumed + type UNRESOLVED_sfixed is array (INTEGER range <>) of STD_ULOGIC; + + subtype U_ufixed is UNRESOLVED_ufixed; + subtype U_sfixed is UNRESOLVED_sfixed; + + subtype ufixed is UNRESOLVED_ufixed; + subtype sfixed is UNRESOLVED_sfixed; + + --=========================================================================== + -- Arithmetic Operators: + --=========================================================================== + + -- Absolute value, 2's complement + -- abs sfixed(a downto b) = sfixed(a+1 downto b) + function "abs" (arg : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + + -- Negation, 2's complement + -- - sfixed(a downto b) = sfixed(a+1 downto b) + function "-" (arg : UNRESOLVED_sfixed)return UNRESOLVED_sfixed; + + -- Addition + -- ufixed(a downto b) + ufixed(c downto d) + -- = ufixed(maximum(a,c)+1 downto minimum(b,d)) + function "+" (l, r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + + -- sfixed(a downto b) + sfixed(c downto d) + -- = sfixed(maximum(a,c)+1 downto minimum(b,d)) + function "+" (l, r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + + -- Subtraction + -- ufixed(a downto b) - ufixed(c downto d) + -- = ufixed(maximum(a,c)+1 downto minimum(b,d)) + function "-" (l, r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + + -- sfixed(a downto b) - sfixed(c downto d) + -- = sfixed(maximum(a,c)+1 downto minimum(b,d)) + function "-" (l, r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + + -- Multiplication + -- ufixed(a downto b) * ufixed(c downto d) = ufixed(a+c+1 downto b+d) + function "*" (l, r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + + -- sfixed(a downto b) * sfixed(c downto d) = sfixed(a+c+1 downto b+d) + function "*" (l, r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + + -- Division + -- ufixed(a downto b) / ufixed(c downto d) = ufixed(a-d downto b-c-1) + function "/" (l, r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + + -- sfixed(a downto b) / sfixed(c downto d) = sfixed(a-d+1 downto b-c) + function "/" (l, r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + + -- Remainder + -- ufixed (a downto b) rem ufixed (c downto d) + -- = ufixed (minimum(a,c) downto minimum(b,d)) + function "rem" (l, r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + + -- sfixed (a downto b) rem sfixed (c downto d) + -- = sfixed (minimum(a,c) downto minimum(b,d)) + function "rem" (l, r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + + -- Modulo + -- ufixed (a downto b) mod ufixed (c downto d) + -- = ufixed (minimum(a,c) downto minimum(b, d)) + function "mod" (l, r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + + -- sfixed (a downto b) mod sfixed (c downto d) + -- = sfixed (c downto minimum(b, d)) + function "mod" (l, r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + + ---------------------------------------------------------------------------- + -- In these routines the "real" or "natural" (integer) + -- are converted into a fixed point number and then the operation is + -- performed. It is assumed that the array will be large enough. + -- If the input is "real" then the real number is converted into a fixed of + -- the same size as the fixed point input. If the number is an "integer" + -- then it is converted into fixed with the range (l'high downto 0). + ---------------------------------------------------------------------------- + + -- ufixed(a downto b) + ufixed(a downto b) = ufixed(a+1 downto b) + function "+" (l : UNRESOLVED_ufixed; r : REAL) return UNRESOLVED_ufixed; + + -- ufixed(c downto d) + ufixed(c downto d) = ufixed(c+1 downto d) + function "+" (l : REAL; r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + + -- ufixed(a downto b) + ufixed(a downto 0) = ufixed(a+1 downto minimum(0,b)) + function "+" (l : UNRESOLVED_ufixed; r : NATURAL) return UNRESOLVED_ufixed; + + -- ufixed(a downto 0) + ufixed(c downto d) = ufixed(c+1 downto minimum(0,d)) + function "+" (l : NATURAL; r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + + -- ufixed(a downto b) - ufixed(a downto b) = ufixed(a+1 downto b) + function "-" (l : UNRESOLVED_ufixed; r : REAL) return UNRESOLVED_ufixed; + + -- ufixed(c downto d) - ufixed(c downto d) = ufixed(c+1 downto d) + function "-" (l : REAL; r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + + -- ufixed(a downto b) - ufixed(a downto 0) = ufixed(a+1 downto minimum(0,b)) + function "-" (l : UNRESOLVED_ufixed; r : NATURAL) return UNRESOLVED_ufixed; + + -- ufixed(a downto 0) + ufixed(c downto d) = ufixed(c+1 downto minimum(0,d)) + function "-" (l : NATURAL; r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + + -- ufixed(a downto b) * ufixed(a downto b) = ufixed(2a+1 downto 2b) + function "*" (l : UNRESOLVED_ufixed; r : REAL) return UNRESOLVED_ufixed; + + -- ufixed(c downto d) * ufixed(c downto d) = ufixed(2c+1 downto 2d) + function "*" (l : REAL; r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + + -- ufixed (a downto b) * ufixed (a downto 0) = ufixed (2a+1 downto b) + function "*" (l : UNRESOLVED_ufixed; r : NATURAL) return UNRESOLVED_ufixed; + + -- ufixed (a downto b) * ufixed (a downto 0) = ufixed (2a+1 downto b) + function "*" (l : NATURAL; r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + + -- ufixed(a downto b) / ufixed(a downto b) = ufixed(a-b downto b-a-1) + function "/" (l : UNRESOLVED_ufixed; r : REAL) return UNRESOLVED_ufixed; + + -- ufixed(a downto b) / ufixed(a downto b) = ufixed(a-b downto b-a-1) + function "/" (l : REAL; r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + + -- ufixed(a downto b) / ufixed(a downto 0) = ufixed(a downto b-a-1) + function "/" (l : UNRESOLVED_ufixed; r : NATURAL) return UNRESOLVED_ufixed; + + -- ufixed(c downto 0) / ufixed(c downto d) = ufixed(c-d downto -c-1) + function "/" (l : NATURAL; r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + + -- ufixed (a downto b) rem ufixed (a downto b) = ufixed (a downto b) + function "rem" (l : UNRESOLVED_ufixed; r : REAL) return UNRESOLVED_ufixed; + + -- ufixed (c downto d) rem ufixed (c downto d) = ufixed (c downto d) + function "rem" (l : REAL; r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + + -- ufixed (a downto b) rem ufixed (a downto 0) = ufixed (a downto minimum(b,0)) + function "rem" (l : UNRESOLVED_ufixed; r : NATURAL) return UNRESOLVED_ufixed; + + -- ufixed (c downto 0) rem ufixed (c downto d) = ufixed (c downto minimum(d,0)) + function "rem" (l : NATURAL; r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + + -- ufixed (a downto b) mod ufixed (a downto b) = ufixed (a downto b) + function "mod" (l : UNRESOLVED_ufixed; r : REAL) return UNRESOLVED_ufixed; + + -- ufixed (c downto d) mod ufixed (c downto d) = ufixed (c downto d) + function "mod" (l : REAL; r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + + -- ufixed (a downto b) mod ufixed (a downto 0) = ufixed (a downto minimum(b,0)) + function "mod" (l : UNRESOLVED_ufixed; r : NATURAL) return UNRESOLVED_ufixed; + + -- ufixed (c downto 0) mod ufixed (c downto d) = ufixed (c downto minimum(d,0)) + function "mod" (l : NATURAL; r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + + -- sfixed(a downto b) + sfixed(a downto b) = sfixed(a+1 downto b) + function "+" (l : UNRESOLVED_sfixed; r : REAL) return UNRESOLVED_sfixed; + + -- sfixed(c downto d) + sfixed(c downto d) = sfixed(c+1 downto d) + function "+" (l : REAL; r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + + -- sfixed(a downto b) + sfixed(a downto 0) = sfixed(a+1 downto minimum(0,b)) + function "+" (l : UNRESOLVED_sfixed; r : INTEGER) return UNRESOLVED_sfixed; + + -- sfixed(c downto 0) + sfixed(c downto d) = sfixed(c+1 downto minimum(0,d)) + function "+" (l : INTEGER; r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + + -- sfixed(a downto b) - sfixed(a downto b) = sfixed(a+1 downto b) + function "-" (l : UNRESOLVED_sfixed; r : REAL) return UNRESOLVED_sfixed; + + -- sfixed(c downto d) - sfixed(c downto d) = sfixed(c+1 downto d) + function "-" (l : REAL; r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + + -- sfixed(a downto b) - sfixed(a downto 0) = sfixed(a+1 downto minimum(0,b)) + function "-" (l : UNRESOLVED_sfixed; r : INTEGER) return UNRESOLVED_sfixed; + + -- sfixed(c downto 0) - sfixed(c downto d) = sfixed(c+1 downto minimum(0,d)) + function "-" (l : INTEGER; r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + + -- sfixed(a downto b) * sfixed(a downto b) = sfixed(2a+1 downto 2b) + function "*" (l : UNRESOLVED_sfixed; r : REAL) return UNRESOLVED_sfixed; + + -- sfixed(c downto d) * sfixed(c downto d) = sfixed(2c+1 downto 2d) + function "*" (l : REAL; r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + + -- sfixed(a downto b) * sfixed(a downto 0) = sfixed(2a+1 downto b) + function "*" (l : UNRESOLVED_sfixed; r : INTEGER) return UNRESOLVED_sfixed; + + -- sfixed(c downto 0) * sfixed(c downto d) = sfixed(2c+1 downto d) + function "*" (l : INTEGER; r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + + -- sfixed(a downto b) / sfixed(a downto b) = sfixed(a-b+1 downto b-a) + function "/" (l : UNRESOLVED_sfixed; r : REAL) return UNRESOLVED_sfixed; + + -- sfixed(c downto d) / sfixed(c downto d) = sfixed(c-d+1 downto d-c) + function "/" (l : REAL; r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + + -- sfixed(a downto b) / sfixed(a downto 0) = sfixed(a+1 downto b-a) + function "/" (l : UNRESOLVED_sfixed; r : INTEGER) return UNRESOLVED_sfixed; + + -- sfixed(c downto 0) / sfixed(c downto d) = sfixed(c-d+1 downto -c) + function "/" (l : INTEGER; r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + + -- sfixed (a downto b) rem sfixed (a downto b) = sfixed (a downto b) + function "rem" (l : UNRESOLVED_sfixed; r : REAL) return UNRESOLVED_sfixed; + + -- sfixed (c downto d) rem sfixed (c downto d) = sfixed (c downto d) + function "rem" (l : REAL; r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + + -- sfixed (a downto b) rem sfixed (a downto 0) = sfixed (a downto minimum(b,0)) + function "rem" (l : UNRESOLVED_sfixed; r : INTEGER) return UNRESOLVED_sfixed; + + -- sfixed (c downto 0) rem sfixed (c downto d) = sfixed (c downto minimum(d,0)) + function "rem" (l : INTEGER; r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + + -- sfixed (a downto b) mod sfixed (a downto b) = sfixed (a downto b) + function "mod" (l : UNRESOLVED_sfixed; r : REAL) return UNRESOLVED_sfixed; + + -- sfixed (c downto d) mod sfixed (c downto d) = sfixed (c downto d) + function "mod" (l : REAL; r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + + -- sfixed (a downto b) mod sfixed (a downto 0) = sfixed (a downto minimum(b,0)) + function "mod" (l : UNRESOLVED_sfixed; r : INTEGER) return UNRESOLVED_sfixed; + + -- sfixed (c downto 0) mod sfixed (c downto d) = sfixed (c downto minimum(d,0)) + function "mod" (l : INTEGER; r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + + -- This version of divide gives the user more control + -- ufixed(a downto b) / ufixed(c downto d) = ufixed(a-d downto b-c-1) + function divide ( + l, r : UNRESOLVED_ufixed; + constant round_style : fixed_round_style_type := fixed_round_style; + constant guard_bits : NATURAL := fixed_guard_bits) + return UNRESOLVED_ufixed; + + -- This version of divide gives the user more control + -- sfixed(a downto b) / sfixed(c downto d) = sfixed(a-d+1 downto b-c) + function divide ( + l, r : UNRESOLVED_sfixed; + constant round_style : fixed_round_style_type := fixed_round_style; + constant guard_bits : NATURAL := fixed_guard_bits) + return UNRESOLVED_sfixed; + + -- These functions return 1/X + -- 1 / ufixed(a downto b) = ufixed(-b downto -a-1) + function reciprocal ( + arg : UNRESOLVED_ufixed; -- fixed point input + constant round_style : fixed_round_style_type := fixed_round_style; + constant guard_bits : NATURAL := fixed_guard_bits) + return UNRESOLVED_ufixed; + + -- 1 / sfixed(a downto b) = sfixed(-b+1 downto -a) + function reciprocal ( + arg : UNRESOLVED_sfixed; -- fixed point input + constant round_style : fixed_round_style_type := fixed_round_style; + constant guard_bits : NATURAL := fixed_guard_bits) + return UNRESOLVED_sfixed; + + -- REM function + -- ufixed (a downto b) rem ufixed (c downto d) + -- = ufixed (minimum(a,c) downto minimum(b,d)) + function remainder ( + l, r : UNRESOLVED_ufixed; + constant round_style : fixed_round_style_type := fixed_round_style; + constant guard_bits : NATURAL := fixed_guard_bits) + return UNRESOLVED_ufixed; + + -- sfixed (a downto b) rem sfixed (c downto d) + -- = sfixed (minimum(a,c) downto minimum(b,d)) + function remainder ( + l, r : UNRESOLVED_sfixed; + constant round_style : fixed_round_style_type := fixed_round_style; + constant guard_bits : NATURAL := fixed_guard_bits) + return UNRESOLVED_sfixed; + + -- mod function + -- ufixed (a downto b) mod ufixed (c downto d) + -- = ufixed (minimum(a,c) downto minimum(b, d)) + function modulo ( + l, r : UNRESOLVED_ufixed; + constant round_style : fixed_round_style_type := fixed_round_style; + constant guard_bits : NATURAL := fixed_guard_bits) + return UNRESOLVED_ufixed; + + -- sfixed (a downto b) mod sfixed (c downto d) + -- = sfixed (c downto minimum(b, d)) + function modulo ( + l, r : UNRESOLVED_sfixed; + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style; + constant guard_bits : NATURAL := fixed_guard_bits) + return UNRESOLVED_sfixed; + + -- Procedure for those who need an "accumulator" function. + -- add_carry (ufixed(a downto b), ufixed (c downto d)) + -- = ufixed (maximum(a,c) downto minimum(b,d)) + procedure add_carry ( + L, R : in UNRESOLVED_ufixed; + c_in : in STD_ULOGIC; + result : out UNRESOLVED_ufixed; + c_out : out STD_ULOGIC); + + -- add_carry (sfixed(a downto b), sfixed (c downto d)) + -- = sfixed (maximum(a,c) downto minimum(b,d)) + procedure add_carry ( + L, R : in UNRESOLVED_sfixed; + c_in : in STD_ULOGIC; + result : out UNRESOLVED_sfixed; + c_out : out STD_ULOGIC); + + -- Scales the result by a power of 2. Width of input = width of output with + -- the binary point moved. + function scalb (y : UNRESOLVED_ufixed; N : INTEGER) return UNRESOLVED_ufixed; + function scalb (y : UNRESOLVED_ufixed; N : SIGNED) return UNRESOLVED_ufixed; + function scalb (y : UNRESOLVED_sfixed; N : INTEGER) return UNRESOLVED_sfixed; + function scalb (y : UNRESOLVED_sfixed; N : SIGNED) return UNRESOLVED_sfixed; + + function Is_Negative (arg : UNRESOLVED_sfixed) return BOOLEAN; + + --=========================================================================== + -- Comparison Operators + --=========================================================================== + + function ">" (l, r : UNRESOLVED_ufixed) return BOOLEAN; + function ">" (l, r : UNRESOLVED_sfixed) return BOOLEAN; + function "<" (l, r : UNRESOLVED_ufixed) return BOOLEAN; + function "<" (l, r : UNRESOLVED_sfixed) return BOOLEAN; + function "<=" (l, r : UNRESOLVED_ufixed) return BOOLEAN; + function "<=" (l, r : UNRESOLVED_sfixed) return BOOLEAN; + function ">=" (l, r : UNRESOLVED_ufixed) return BOOLEAN; + function ">=" (l, r : UNRESOLVED_sfixed) return BOOLEAN; + function "=" (l, r : UNRESOLVED_ufixed) return BOOLEAN; + function "=" (l, r : UNRESOLVED_sfixed) return BOOLEAN; + function "/=" (l, r : UNRESOLVED_ufixed) return BOOLEAN; + function "/=" (l, r : UNRESOLVED_sfixed) return BOOLEAN; + + function \?=\ (l, r : UNRESOLVED_ufixed) return STD_ULOGIC; + function \?/=\ (l, r : UNRESOLVED_ufixed) return STD_ULOGIC; + function \?>\ (l, r : UNRESOLVED_ufixed) return STD_ULOGIC; + function \?>=\ (l, r : UNRESOLVED_ufixed) return STD_ULOGIC; + function \?<\ (l, r : UNRESOLVED_ufixed) return STD_ULOGIC; + function \?<=\ (l, r : UNRESOLVED_ufixed) return STD_ULOGIC; + function \?=\ (l, r : UNRESOLVED_sfixed) return STD_ULOGIC; + function \?/=\ (l, r : UNRESOLVED_sfixed) return STD_ULOGIC; + function \?>\ (l, r : UNRESOLVED_sfixed) return STD_ULOGIC; + function \?>=\ (l, r : UNRESOLVED_sfixed) return STD_ULOGIC; + function \?<\ (l, r : UNRESOLVED_sfixed) return STD_ULOGIC; + function \?<=\ (l, r : UNRESOLVED_sfixed) return STD_ULOGIC; + + function std_match (l, r : UNRESOLVED_ufixed) return BOOLEAN; + function std_match (l, r : UNRESOLVED_sfixed) return BOOLEAN; + + -- Overloads the default "maximum" and "minimum" function + + function maximum (l, r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + function minimum (l, r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + function maximum (l, r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + function minimum (l, r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + + ---------------------------------------------------------------------------- + -- In these compare functions a natural is converted into a + -- fixed point number of the bounds "maximum(l'high,0) downto 0" + ---------------------------------------------------------------------------- + + function "=" (l : UNRESOLVED_ufixed; r : NATURAL) return BOOLEAN; + function "/=" (l : UNRESOLVED_ufixed; r : NATURAL) return BOOLEAN; + function ">=" (l : UNRESOLVED_ufixed; r : NATURAL) return BOOLEAN; + function "<=" (l : UNRESOLVED_ufixed; r : NATURAL) return BOOLEAN; + function ">" (l : UNRESOLVED_ufixed; r : NATURAL) return BOOLEAN; + function "<" (l : UNRESOLVED_ufixed; r : NATURAL) return BOOLEAN; + + function "=" (l : NATURAL; r : UNRESOLVED_ufixed) return BOOLEAN; + function "/=" (l : NATURAL; r : UNRESOLVED_ufixed) return BOOLEAN; + function ">=" (l : NATURAL; r : UNRESOLVED_ufixed) return BOOLEAN; + function "<=" (l : NATURAL; r : UNRESOLVED_ufixed) return BOOLEAN; + function ">" (l : NATURAL; r : UNRESOLVED_ufixed) return BOOLEAN; + function "<" (l : NATURAL; r : UNRESOLVED_ufixed) return BOOLEAN; + + function \?=\ (l : UNRESOLVED_ufixed; r : NATURAL) return STD_ULOGIC; + function \?/=\ (l : UNRESOLVED_ufixed; r : NATURAL) return STD_ULOGIC; + function \?>=\ (l : UNRESOLVED_ufixed; r : NATURAL) return STD_ULOGIC; + function \?<=\ (l : UNRESOLVED_ufixed; r : NATURAL) return STD_ULOGIC; + function \?>\ (l : UNRESOLVED_ufixed; r : NATURAL) return STD_ULOGIC; + function \?<\ (l : UNRESOLVED_ufixed; r : NATURAL) return STD_ULOGIC; + + function \?=\ (l : NATURAL; r : UNRESOLVED_ufixed) return STD_ULOGIC; + function \?/=\ (l : NATURAL; r : UNRESOLVED_ufixed) return STD_ULOGIC; + function \?>=\ (l : NATURAL; r : UNRESOLVED_ufixed) return STD_ULOGIC; + function \?<=\ (l : NATURAL; r : UNRESOLVED_ufixed) return STD_ULOGIC; + function \?>\ (l : NATURAL; r : UNRESOLVED_ufixed) return STD_ULOGIC; + function \?<\ (l : NATURAL; r : UNRESOLVED_ufixed) return STD_ULOGIC; + + function maximum (l : UNRESOLVED_ufixed; r : NATURAL) + return UNRESOLVED_ufixed; + function minimum (l : UNRESOLVED_ufixed; r : NATURAL) + return UNRESOLVED_ufixed; + function maximum (l : NATURAL; r : UNRESOLVED_ufixed) + return UNRESOLVED_ufixed; + function minimum (l : NATURAL; r : UNRESOLVED_ufixed) + return UNRESOLVED_ufixed; + ---------------------------------------------------------------------------- + -- In these compare functions a real is converted into a + -- fixed point number of the bounds "l'high+1 downto l'low" + ---------------------------------------------------------------------------- + + function "=" (l : UNRESOLVED_ufixed; r : REAL) return BOOLEAN; + function "/=" (l : UNRESOLVED_ufixed; r : REAL) return BOOLEAN; + function ">=" (l : UNRESOLVED_ufixed; r : REAL) return BOOLEAN; + function "<=" (l : UNRESOLVED_ufixed; r : REAL) return BOOLEAN; + function ">" (l : UNRESOLVED_ufixed; r : REAL) return BOOLEAN; + function "<" (l : UNRESOLVED_ufixed; r : REAL) return BOOLEAN; + + function "=" (l : REAL; r : UNRESOLVED_ufixed) return BOOLEAN; + function "/=" (l : REAL; r : UNRESOLVED_ufixed) return BOOLEAN; + function ">=" (l : REAL; r : UNRESOLVED_ufixed) return BOOLEAN; + function "<=" (l : REAL; r : UNRESOLVED_ufixed) return BOOLEAN; + function ">" (l : REAL; r : UNRESOLVED_ufixed) return BOOLEAN; + function "<" (l : REAL; r : UNRESOLVED_ufixed) return BOOLEAN; + + function \?=\ (l : UNRESOLVED_ufixed; r : REAL) return STD_ULOGIC; + function \?/=\ (l : UNRESOLVED_ufixed; r : REAL) return STD_ULOGIC; + function \?>=\ (l : UNRESOLVED_ufixed; r : REAL) return STD_ULOGIC; + function \?<=\ (l : UNRESOLVED_ufixed; r : REAL) return STD_ULOGIC; + function \?>\ (l : UNRESOLVED_ufixed; r : REAL) return STD_ULOGIC; + function \?<\ (l : UNRESOLVED_ufixed; r : REAL) return STD_ULOGIC; + + function \?=\ (l : REAL; r : UNRESOLVED_ufixed) return STD_ULOGIC; + function \?/=\ (l : REAL; r : UNRESOLVED_ufixed) return STD_ULOGIC; + function \?>=\ (l : REAL; r : UNRESOLVED_ufixed) return STD_ULOGIC; + function \?<=\ (l : REAL; r : UNRESOLVED_ufixed) return STD_ULOGIC; + function \?>\ (l : REAL; r : UNRESOLVED_ufixed) return STD_ULOGIC; + function \?<\ (l : REAL; r : UNRESOLVED_ufixed) return STD_ULOGIC; + + function maximum (l : UNRESOLVED_ufixed; r : REAL) return UNRESOLVED_ufixed; + function maximum (l : REAL; r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + function minimum (l : UNRESOLVED_ufixed; r : REAL) return UNRESOLVED_ufixed; + function minimum (l : REAL; r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + ---------------------------------------------------------------------------- + -- In these compare functions an integer is converted into a + -- fixed point number of the bounds "maximum(l'high,1) downto 0" + ---------------------------------------------------------------------------- + + function "=" (l : UNRESOLVED_sfixed; r : INTEGER) return BOOLEAN; + function "/=" (l : UNRESOLVED_sfixed; r : INTEGER) return BOOLEAN; + function ">=" (l : UNRESOLVED_sfixed; r : INTEGER) return BOOLEAN; + function "<=" (l : UNRESOLVED_sfixed; r : INTEGER) return BOOLEAN; + function ">" (l : UNRESOLVED_sfixed; r : INTEGER) return BOOLEAN; + function "<" (l : UNRESOLVED_sfixed; r : INTEGER) return BOOLEAN; + + function "=" (l : INTEGER; r : UNRESOLVED_sfixed) return BOOLEAN; + function "/=" (l : INTEGER; r : UNRESOLVED_sfixed) return BOOLEAN; + function ">=" (l : INTEGER; r : UNRESOLVED_sfixed) return BOOLEAN; + function "<=" (l : INTEGER; r : UNRESOLVED_sfixed) return BOOLEAN; + function ">" (l : INTEGER; r : UNRESOLVED_sfixed) return BOOLEAN; + function "<" (l : INTEGER; r : UNRESOLVED_sfixed) return BOOLEAN; + + function \?=\ (l : UNRESOLVED_sfixed; r : INTEGER) return STD_ULOGIC; + function \?/=\ (l : UNRESOLVED_sfixed; r : INTEGER) return STD_ULOGIC; + function \?>=\ (l : UNRESOLVED_sfixed; r : INTEGER) return STD_ULOGIC; + function \?<=\ (l : UNRESOLVED_sfixed; r : INTEGER) return STD_ULOGIC; + function \?>\ (l : UNRESOLVED_sfixed; r : INTEGER) return STD_ULOGIC; + function \?<\ (l : UNRESOLVED_sfixed; r : INTEGER) return STD_ULOGIC; + + function \?=\ (l : INTEGER; r : UNRESOLVED_sfixed) return STD_ULOGIC; + function \?/=\ (l : INTEGER; r : UNRESOLVED_sfixed) return STD_ULOGIC; + function \?>=\ (l : INTEGER; r : UNRESOLVED_sfixed) return STD_ULOGIC; + function \?<=\ (l : INTEGER; r : UNRESOLVED_sfixed) return STD_ULOGIC; + function \?>\ (l : INTEGER; r : UNRESOLVED_sfixed) return STD_ULOGIC; + function \?<\ (l : INTEGER; r : UNRESOLVED_sfixed) return STD_ULOGIC; + + function maximum (l : UNRESOLVED_sfixed; r : INTEGER) + return UNRESOLVED_sfixed; + function maximum (l : INTEGER; r : UNRESOLVED_sfixed) + return UNRESOLVED_sfixed; + function minimum (l : UNRESOLVED_sfixed; r : INTEGER) + return UNRESOLVED_sfixed; + function minimum (l : INTEGER; r : UNRESOLVED_sfixed) + return UNRESOLVED_sfixed; + ---------------------------------------------------------------------------- + -- In these compare functions a real is converted into a + -- fixed point number of the bounds "l'high+1 downto l'low" + ---------------------------------------------------------------------------- + + function "=" (l : UNRESOLVED_sfixed; r : REAL) return BOOLEAN; + function "/=" (l : UNRESOLVED_sfixed; r : REAL) return BOOLEAN; + function ">=" (l : UNRESOLVED_sfixed; r : REAL) return BOOLEAN; + function "<=" (l : UNRESOLVED_sfixed; r : REAL) return BOOLEAN; + function ">" (l : UNRESOLVED_sfixed; r : REAL) return BOOLEAN; + function "<" (l : UNRESOLVED_sfixed; r : REAL) return BOOLEAN; + + function "=" (l : REAL; r : UNRESOLVED_sfixed) return BOOLEAN; + function "/=" (l : REAL; r : UNRESOLVED_sfixed) return BOOLEAN; + function ">=" (l : REAL; r : UNRESOLVED_sfixed) return BOOLEAN; + function "<=" (l : REAL; r : UNRESOLVED_sfixed) return BOOLEAN; + function ">" (l : REAL; r : UNRESOLVED_sfixed) return BOOLEAN; + function "<" (l : REAL; r : UNRESOLVED_sfixed) return BOOLEAN; + + function \?=\ (l : UNRESOLVED_sfixed; r : REAL) return STD_ULOGIC; + function \?/=\ (l : UNRESOLVED_sfixed; r : REAL) return STD_ULOGIC; + function \?>=\ (l : UNRESOLVED_sfixed; r : REAL) return STD_ULOGIC; + function \?<=\ (l : UNRESOLVED_sfixed; r : REAL) return STD_ULOGIC; + function \?>\ (l : UNRESOLVED_sfixed; r : REAL) return STD_ULOGIC; + function \?<\ (l : UNRESOLVED_sfixed; r : REAL) return STD_ULOGIC; + + function \?=\ (l : REAL; r : UNRESOLVED_sfixed) return STD_ULOGIC; + function \?/=\ (l : REAL; r : UNRESOLVED_sfixed) return STD_ULOGIC; + function \?>=\ (l : REAL; r : UNRESOLVED_sfixed) return STD_ULOGIC; + function \?<=\ (l : REAL; r : UNRESOLVED_sfixed) return STD_ULOGIC; + function \?>\ (l : REAL; r : UNRESOLVED_sfixed) return STD_ULOGIC; + function \?<\ (l : REAL; r : UNRESOLVED_sfixed) return STD_ULOGIC; + + function maximum (l : UNRESOLVED_sfixed; r : REAL) return UNRESOLVED_sfixed; + function maximum (l : REAL; r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + function minimum (l : UNRESOLVED_sfixed; r : REAL) return UNRESOLVED_sfixed; + function minimum (l : REAL; r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + --=========================================================================== + -- Shift and Rotate Functions. + -- Note that sra and sla are not the same as the BIT_VECTOR version + --=========================================================================== + + function "sll" (ARG : UNRESOLVED_ufixed; COUNT : INTEGER) + return UNRESOLVED_ufixed; + function "srl" (ARG : UNRESOLVED_ufixed; COUNT : INTEGER) + return UNRESOLVED_ufixed; + function "rol" (ARG : UNRESOLVED_ufixed; COUNT : INTEGER) + return UNRESOLVED_ufixed; + function "ror" (ARG : UNRESOLVED_ufixed; COUNT : INTEGER) + return UNRESOLVED_ufixed; + function "sla" (ARG : UNRESOLVED_ufixed; COUNT : INTEGER) + return UNRESOLVED_ufixed; + function "sra" (ARG : UNRESOLVED_ufixed; COUNT : INTEGER) + return UNRESOLVED_ufixed; + function "sll" (ARG : UNRESOLVED_sfixed; COUNT : INTEGER) + return UNRESOLVED_sfixed; + function "srl" (ARG : UNRESOLVED_sfixed; COUNT : INTEGER) + return UNRESOLVED_sfixed; + function "rol" (ARG : UNRESOLVED_sfixed; COUNT : INTEGER) + return UNRESOLVED_sfixed; + function "ror" (ARG : UNRESOLVED_sfixed; COUNT : INTEGER) + return UNRESOLVED_sfixed; + function "sla" (ARG : UNRESOLVED_sfixed; COUNT : INTEGER) + return UNRESOLVED_sfixed; + function "sra" (ARG : UNRESOLVED_sfixed; COUNT : INTEGER) + return UNRESOLVED_sfixed; + function SHIFT_LEFT (ARG : UNRESOLVED_ufixed; COUNT : NATURAL) + return UNRESOLVED_ufixed; + function SHIFT_RIGHT (ARG : UNRESOLVED_ufixed; COUNT : NATURAL) + return UNRESOLVED_ufixed; + function SHIFT_LEFT (ARG : UNRESOLVED_sfixed; COUNT : NATURAL) + return UNRESOLVED_sfixed; + function SHIFT_RIGHT (ARG : UNRESOLVED_sfixed; COUNT : NATURAL) + return UNRESOLVED_sfixed; + + ---------------------------------------------------------------------------- + -- logical functions + ---------------------------------------------------------------------------- + + function "not" (l : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + function "and" (l, r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + function "or" (l, r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + function "nand" (l, r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + function "nor" (l, r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + function "xor" (l, r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + function "xnor" (l, r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + function "not" (l : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + function "and" (l, r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + function "or" (l, r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + function "nand" (l, r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + function "nor" (l, r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + function "xor" (l, r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + function "xnor" (l, r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + + -- Vector and std_ulogic functions, same as functions in numeric_std + function "and" (l : STD_ULOGIC; r : UNRESOLVED_ufixed) + return UNRESOLVED_ufixed; + function "and" (l : UNRESOLVED_ufixed; r : STD_ULOGIC) + return UNRESOLVED_ufixed; + function "or" (l : STD_ULOGIC; r : UNRESOLVED_ufixed) + return UNRESOLVED_ufixed; + function "or" (l : UNRESOLVED_ufixed; r : STD_ULOGIC) + return UNRESOLVED_ufixed; + function "nand" (l : STD_ULOGIC; r : UNRESOLVED_ufixed) + return UNRESOLVED_ufixed; + function "nand" (l : UNRESOLVED_ufixed; r : STD_ULOGIC) + return UNRESOLVED_ufixed; + function "nor" (l : STD_ULOGIC; r : UNRESOLVED_ufixed) + return UNRESOLVED_ufixed; + function "nor" (l : UNRESOLVED_ufixed; r : STD_ULOGIC) + return UNRESOLVED_ufixed; + function "xor" (l : STD_ULOGIC; r : UNRESOLVED_ufixed) + return UNRESOLVED_ufixed; + function "xor" (l : UNRESOLVED_ufixed; r : STD_ULOGIC) + return UNRESOLVED_ufixed; + function "xnor" (l : STD_ULOGIC; r : UNRESOLVED_ufixed) + return UNRESOLVED_ufixed; + function "xnor" (l : UNRESOLVED_ufixed; r : STD_ULOGIC) + return UNRESOLVED_ufixed; + function "and" (l : STD_ULOGIC; r : UNRESOLVED_sfixed) + return UNRESOLVED_sfixed; + function "and" (l : UNRESOLVED_sfixed; r : STD_ULOGIC) + return UNRESOLVED_sfixed; + function "or" (l : STD_ULOGIC; r : UNRESOLVED_sfixed) + return UNRESOLVED_sfixed; + function "or" (l : UNRESOLVED_sfixed; r : STD_ULOGIC) + return UNRESOLVED_sfixed; + function "nand" (l : STD_ULOGIC; r : UNRESOLVED_sfixed) + return UNRESOLVED_sfixed; + function "nand" (l : UNRESOLVED_sfixed; r : STD_ULOGIC) + return UNRESOLVED_sfixed; + function "nor" (l : STD_ULOGIC; r : UNRESOLVED_sfixed) + return UNRESOLVED_sfixed; + function "nor" (l : UNRESOLVED_sfixed; r : STD_ULOGIC) + return UNRESOLVED_sfixed; + function "xor" (l : STD_ULOGIC; r : UNRESOLVED_sfixed) + return UNRESOLVED_sfixed; + function "xor" (l : UNRESOLVED_sfixed; r : STD_ULOGIC) + return UNRESOLVED_sfixed; + function "xnor" (l : STD_ULOGIC; r : UNRESOLVED_sfixed) + return UNRESOLVED_sfixed; + function "xnor" (l : UNRESOLVED_sfixed; r : STD_ULOGIC) + return UNRESOLVED_sfixed; + + -- Reduction operators, same as numeric_std functions + function and_reduce (l : UNRESOLVED_ufixed) return STD_ULOGIC; + function nand_reduce (l : UNRESOLVED_ufixed) return STD_ULOGIC; + function or_reduce (l : UNRESOLVED_ufixed) return STD_ULOGIC; + function nor_reduce (l : UNRESOLVED_ufixed) return STD_ULOGIC; + function xor_reduce (l : UNRESOLVED_ufixed) return STD_ULOGIC; + function xnor_reduce (l : UNRESOLVED_ufixed) return STD_ULOGIC; + function and_reduce (l : UNRESOLVED_sfixed) return STD_ULOGIC; + function nand_reduce (l : UNRESOLVED_sfixed) return STD_ULOGIC; + function or_reduce (l : UNRESOLVED_sfixed) return STD_ULOGIC; + function nor_reduce (l : UNRESOLVED_sfixed) return STD_ULOGIC; + function xor_reduce (l : UNRESOLVED_sfixed) return STD_ULOGIC; + function xnor_reduce (l : UNRESOLVED_sfixed) return STD_ULOGIC; + + -- returns arg'low-1 if not found + function find_leftmost (arg : UNRESOLVED_ufixed; y : STD_ULOGIC) + return INTEGER; + function find_leftmost (arg : UNRESOLVED_sfixed; y : STD_ULOGIC) + return INTEGER; + + -- returns arg'high+1 if not found + function find_rightmost (arg : UNRESOLVED_ufixed; y : STD_ULOGIC) + return INTEGER; + function find_rightmost (arg : UNRESOLVED_sfixed; y : STD_ULOGIC) + return INTEGER; + + --=========================================================================== + -- RESIZE Functions + --=========================================================================== + -- resizes the number (larger or smaller) + -- The returned result will be ufixed (left_index downto right_index) + -- If "round_style" is fixed_round, then the result will be rounded. + -- If the MSB of the remainder is a "1" AND the LSB of the unrounded result + -- is a '1' or the lower bits of the remainder include a '1' then the result + -- will be increased by the smallest representable number for that type. + -- "overflow_style" can be fixed_saturate or fixed_wrap. + -- In saturate mode, if the number overflows then the largest possible + -- representable number is returned. If wrap mode, then the upper bits + -- of the number are truncated. + + function resize ( + arg : UNRESOLVED_ufixed; -- input + constant left_index : INTEGER; -- integer portion + constant right_index : INTEGER; -- size of fraction + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNRESOLVED_ufixed; + + -- "size_res" functions create the size of the output from the indices + -- of the "size_res" input. The actual value of "size_res" is not used. + function resize ( + arg : UNRESOLVED_ufixed; -- input + size_res : UNRESOLVED_ufixed; -- for size only + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNRESOLVED_ufixed; + + -- Note that in "wrap" mode the sign bit is not replicated. Thus the + -- resize of a negative number can have a positive result in wrap mode. + function resize ( + arg : UNRESOLVED_sfixed; -- input + constant left_index : INTEGER; -- integer portion + constant right_index : INTEGER; -- size of fraction + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNRESOLVED_sfixed; + + function resize ( + arg : UNRESOLVED_sfixed; -- input + size_res : UNRESOLVED_sfixed; -- for size only + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNRESOLVED_sfixed; + + --=========================================================================== + -- Conversion Functions + --=========================================================================== + + -- integer (natural) to unsigned fixed point. + -- arguments are the upper and lower bounds of the number, thus + -- ufixed (7 downto -3) <= to_ufixed (int, 7, -3); + function to_ufixed ( + arg : NATURAL; -- integer + constant left_index : INTEGER; -- left index (high index) + constant right_index : INTEGER := 0; -- right index + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNRESOLVED_ufixed; + + function to_ufixed ( + arg : NATURAL; -- integer + size_res : UNRESOLVED_ufixed; -- for size only + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNRESOLVED_ufixed; + + -- real to unsigned fixed point + function to_ufixed ( + arg : REAL; -- real + constant left_index : INTEGER; -- left index (high index) + constant right_index : INTEGER; -- right index + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style; + constant guard_bits : NATURAL := fixed_guard_bits) + return UNRESOLVED_ufixed; + + function to_ufixed ( + arg : REAL; -- real + size_res : UNRESOLVED_ufixed; -- for size only + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style; + constant guard_bits : NATURAL := fixed_guard_bits) + return UNRESOLVED_ufixed; + + -- unsigned to unsigned fixed point + function to_ufixed ( + arg : UNSIGNED; -- unsigned + constant left_index : INTEGER; -- left index (high index) + constant right_index : INTEGER := 0; -- right index + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNRESOLVED_ufixed; + + function to_ufixed ( + arg : UNSIGNED; -- unsigned + size_res : UNRESOLVED_ufixed; -- for size only + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNRESOLVED_ufixed; + + -- Performs a conversion. ufixed (arg'range) is returned + function to_ufixed ( + arg : UNSIGNED) -- unsigned + return UNRESOLVED_ufixed; + + -- unsigned fixed point to unsigned + function to_unsigned ( + arg : UNRESOLVED_ufixed; -- fixed point input + constant size : NATURAL; -- length of output + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNSIGNED; + + -- unsigned fixed point to unsigned + function to_unsigned ( + arg : UNRESOLVED_ufixed; -- fixed point input + size_res : UNSIGNED; -- used for length of output + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNSIGNED; + + -- unsigned fixed point to real + function to_real ( + arg : UNRESOLVED_ufixed) -- fixed point input + return REAL; + + -- unsigned fixed point to integer + function to_integer ( + arg : UNRESOLVED_ufixed; -- fixed point input + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return NATURAL; + + -- Integer to UNRESOLVED_sfixed + function to_sfixed ( + arg : INTEGER; -- integer + constant left_index : INTEGER; -- left index (high index) + constant right_index : INTEGER := 0; -- right index + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNRESOLVED_sfixed; + + function to_sfixed ( + arg : INTEGER; -- integer + size_res : UNRESOLVED_sfixed; -- for size only + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNRESOLVED_sfixed; + + -- Real to sfixed + function to_sfixed ( + arg : REAL; -- real + constant left_index : INTEGER; -- left index (high index) + constant right_index : INTEGER; -- right index + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style; + constant guard_bits : NATURAL := fixed_guard_bits) + return UNRESOLVED_sfixed; + + function to_sfixed ( + arg : REAL; -- real + size_res : UNRESOLVED_sfixed; -- for size only + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style; + constant guard_bits : NATURAL := fixed_guard_bits) + return UNRESOLVED_sfixed; + + -- signed to sfixed + function to_sfixed ( + arg : SIGNED; -- signed + constant left_index : INTEGER; -- left index (high index) + constant right_index : INTEGER := 0; -- right index + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNRESOLVED_sfixed; + + function to_sfixed ( + arg : SIGNED; -- signed + size_res : UNRESOLVED_sfixed; -- for size only + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNRESOLVED_sfixed; + + -- signed to sfixed (output assumed to be size of signed input) + function to_sfixed ( + arg : SIGNED) -- signed + return UNRESOLVED_sfixed; + + -- Conversion from ufixed to sfixed + function to_sfixed ( + arg : UNRESOLVED_ufixed) + return UNRESOLVED_sfixed; + + -- signed fixed point to signed + function to_signed ( + arg : UNRESOLVED_sfixed; -- fixed point input + constant size : NATURAL; -- length of output + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return SIGNED; + + -- signed fixed point to signed + function to_signed ( + arg : UNRESOLVED_sfixed; -- fixed point input + size_res : SIGNED; -- used for length of output + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return SIGNED; + + -- signed fixed point to real + function to_real ( + arg : UNRESOLVED_sfixed) -- fixed point input + return REAL; + + -- signed fixed point to integer + function to_integer ( + arg : UNRESOLVED_sfixed; -- fixed point input + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return INTEGER; + + -- Because of the fairly complicated sizing rules in the fixed point + -- packages these functions are provided to compute the result ranges + -- Example: + -- signal uf1 : ufixed (3 downto -3); + -- signal uf2 : ufixed (4 downto -2); + -- signal uf1multuf2 : ufixed (ufixed_high (3, -3, '*', 4, -2) downto + -- ufixed_low (3, -3, '*', 4, -2)); + -- uf1multuf2 <= uf1 * uf2; + -- Valid characters: '+', '-', '*', '/', 'r' or 'R' (rem), 'm' or 'M' (mod), + -- '1' (reciprocal), 'a' or 'A' (abs), 'n' or 'N' (unary -) + function ufixed_high (left_index, right_index : INTEGER; + operation : CHARACTER := 'X'; + left_index2, right_index2 : INTEGER := 0) + return INTEGER; + + function ufixed_low (left_index, right_index : INTEGER; + operation : CHARACTER := 'X'; + left_index2, right_index2 : INTEGER := 0) + return INTEGER; + + function sfixed_high (left_index, right_index : INTEGER; + operation : CHARACTER := 'X'; + left_index2, right_index2 : INTEGER := 0) + return INTEGER; + + function sfixed_low (left_index, right_index : INTEGER; + operation : CHARACTER := 'X'; + left_index2, right_index2 : INTEGER := 0) + return INTEGER; + + -- Same as above, but using the "size_res" input only for their ranges: + -- signal uf1multuf2 : ufixed (ufixed_high (uf1, '*', uf2) downto + -- ufixed_low (uf1, '*', uf2)); + -- uf1multuf2 <= uf1 * uf2; + -- + function ufixed_high (size_res : UNRESOLVED_ufixed; + operation : CHARACTER := 'X'; + size_res2 : UNRESOLVED_ufixed) + return INTEGER; + + function ufixed_low (size_res : UNRESOLVED_ufixed; + operation : CHARACTER := 'X'; + size_res2 : UNRESOLVED_ufixed) + return INTEGER; + + function sfixed_high (size_res : UNRESOLVED_sfixed; + operation : CHARACTER := 'X'; + size_res2 : UNRESOLVED_sfixed) + return INTEGER; + + function sfixed_low (size_res : UNRESOLVED_sfixed; + operation : CHARACTER := 'X'; + size_res2 : UNRESOLVED_sfixed) + return INTEGER; + + -- purpose: returns a saturated number + function saturate ( + constant left_index : INTEGER; + constant right_index : INTEGER) + return UNRESOLVED_ufixed; + + -- purpose: returns a saturated number + function saturate ( + constant left_index : INTEGER; + constant right_index : INTEGER) + return UNRESOLVED_sfixed; + + function saturate ( + size_res : UNRESOLVED_ufixed) -- only the size of this is used + return UNRESOLVED_ufixed; + + function saturate ( + size_res : UNRESOLVED_sfixed) -- only the size of this is used + return UNRESOLVED_sfixed; + + --=========================================================================== + -- Translation Functions + --=========================================================================== + + -- maps meta-logical values + function to_01 ( + s : UNRESOLVED_ufixed; -- fixed point input + constant XMAP : STD_ULOGIC := '0') -- Map x to + return UNRESOLVED_ufixed; + + -- maps meta-logical values + function to_01 ( + s : UNRESOLVED_sfixed; -- fixed point input + constant XMAP : STD_ULOGIC := '0') -- Map x to + return UNRESOLVED_sfixed; + + function Is_X (arg : UNRESOLVED_ufixed) return BOOLEAN; + function Is_X (arg : UNRESOLVED_sfixed) return BOOLEAN; + function to_X01 (arg : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + function to_X01 (arg : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + function to_X01Z (arg : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + function to_X01Z (arg : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + function to_UX01 (arg : UNRESOLVED_ufixed) return UNRESOLVED_ufixed; + function to_UX01 (arg : UNRESOLVED_sfixed) return UNRESOLVED_sfixed; + + -- straight vector conversion routines, needed for synthesis. + -- These functions are here so that a std_logic_vector can be + -- converted to and from sfixed and ufixed. Note that you can + -- not convert these vectors because of their negative index. + + function to_slv ( + arg : UNRESOLVED_ufixed) -- fixed point vector + return STD_LOGIC_VECTOR; + alias to_StdLogicVector is to_slv [UNRESOLVED_ufixed + return STD_LOGIC_VECTOR]; + alias to_Std_Logic_Vector is to_slv [UNRESOLVED_ufixed + return STD_LOGIC_VECTOR]; + + function to_slv ( + arg : UNRESOLVED_sfixed) -- fixed point vector + return STD_LOGIC_VECTOR; + alias to_StdLogicVector is to_slv [UNRESOLVED_sfixed + return STD_LOGIC_VECTOR]; + alias to_Std_Logic_Vector is to_slv [UNRESOLVED_sfixed + return STD_LOGIC_VECTOR]; + + function to_sulv ( + arg : UNRESOLVED_ufixed) -- fixed point vector + return STD_ULOGIC_VECTOR; + alias to_StdULogicVector is to_sulv [UNRESOLVED_ufixed + return STD_ULOGIC_VECTOR]; + alias to_Std_ULogic_Vector is to_sulv [UNRESOLVED_ufixed + return STD_ULOGIC_VECTOR]; + + function to_sulv ( + arg : UNRESOLVED_sfixed) -- fixed point vector + return STD_ULOGIC_VECTOR; + alias to_StdULogicVector is to_sulv [UNRESOLVED_sfixed + return STD_ULOGIC_VECTOR]; + alias to_Std_ULogic_Vector is to_sulv [UNRESOLVED_sfixed + return STD_ULOGIC_VECTOR]; + + function to_ufixed ( + arg : STD_ULOGIC_VECTOR; -- shifted vector + constant left_index : INTEGER; + constant right_index : INTEGER) + return UNRESOLVED_ufixed; + + function to_ufixed ( + arg : STD_ULOGIC_VECTOR; -- shifted vector + size_res : UNRESOLVED_ufixed) -- for size only + return UNRESOLVED_ufixed; + + function to_sfixed ( + arg : STD_ULOGIC_VECTOR; -- shifted vector + constant left_index : INTEGER; + constant right_index : INTEGER) + return UNRESOLVED_sfixed; + + function to_sfixed ( + arg : STD_ULOGIC_VECTOR; -- shifted vector + size_res : UNRESOLVED_sfixed) -- for size only + return UNRESOLVED_sfixed; + + -- As a concession to those who use a graphical DSP environment, + -- these functions take parameters in those tools format and create + -- fixed point numbers. These functions are designed to convert from + -- a std_logic_vector to the VHDL fixed point format using the conventions + -- of these packages. In a pure VHDL environment you should use the + -- "to_ufixed" and "to_sfixed" routines. + + -- unsigned fixed point + function to_UFix ( + arg : STD_ULOGIC_VECTOR; + width : NATURAL; -- width of vector + fraction : NATURAL) -- width of fraction + return UNRESOLVED_ufixed; + + -- signed fixed point + function to_SFix ( + arg : STD_ULOGIC_VECTOR; + width : NATURAL; -- width of vector + fraction : NATURAL) -- width of fraction + return UNRESOLVED_sfixed; + + -- finding the bounds of a number. These functions can be used like this: + -- signal xxx : ufixed (7 downto -3); + -- -- Which is the same as "ufixed (UFix_high (11,3) downto UFix_low(11,3))" + -- signal yyy : ufixed (UFix_high (11, 3, "+", 11, 3) + -- downto UFix_low(11, 3, "+", 11, 3)); + -- Where "11" is the width of xxx (xxx'length), + -- and 3 is the lower bound (abs (xxx'low)) + -- In a pure VHDL environment use "ufixed_high" and "ufixed_low" + + function UFix_high (width, fraction : NATURAL; + operation : CHARACTER := 'X'; + width2, fraction2 : NATURAL := 0) + return INTEGER; + + function UFix_low (width, fraction : NATURAL; + operation : CHARACTER := 'X'; + width2, fraction2 : NATURAL := 0) + return INTEGER; + + -- Same as above but for signed fixed point. Note that the width + -- of a signed fixed point number ignores the sign bit, thus + -- width = sxxx'length-1 + + function SFix_high (width, fraction : NATURAL; + operation : CHARACTER := 'X'; + width2, fraction2 : NATURAL := 0) + return INTEGER; + + function SFix_low (width, fraction : NATURAL; + operation : CHARACTER := 'X'; + width2, fraction2 : NATURAL := 0) + return INTEGER; +-- rtl_synthesis off +-- pragma synthesis_off + --=========================================================================== + -- string and textio Functions + --=========================================================================== + + -- purpose: writes fixed point into a line + procedure WRITE ( + L : inout LINE; -- input line + VALUE : in UNRESOLVED_ufixed; -- fixed point input + JUSTIFIED : in SIDE := right; + FIELD : in WIDTH := 0); + + -- purpose: writes fixed point into a line + procedure WRITE ( + L : inout LINE; -- input line + VALUE : in UNRESOLVED_sfixed; -- fixed point input + JUSTIFIED : in SIDE := right; + FIELD : in WIDTH := 0); + + procedure READ(L : inout LINE; + VALUE : out UNRESOLVED_ufixed); + + procedure READ(L : inout LINE; + VALUE : out UNRESOLVED_ufixed; + GOOD : out BOOLEAN); + + procedure READ(L : inout LINE; + VALUE : out UNRESOLVED_sfixed); + + procedure READ(L : inout LINE; + VALUE : out UNRESOLVED_sfixed; + GOOD : out BOOLEAN); + + alias bwrite is WRITE [LINE, UNRESOLVED_ufixed, SIDE, width]; + alias bwrite is WRITE [LINE, UNRESOLVED_sfixed, SIDE, width]; + alias bread is READ [LINE, UNRESOLVED_ufixed]; + alias bread is READ [LINE, UNRESOLVED_ufixed, BOOLEAN]; + alias bread is READ [LINE, UNRESOLVED_sfixed]; + alias bread is READ [LINE, UNRESOLVED_sfixed, BOOLEAN]; + alias BINARY_WRITE is WRITE [LINE, UNRESOLVED_ufixed, SIDE, width]; + alias BINARY_WRITE is WRITE [LINE, UNRESOLVED_sfixed, SIDE, width]; + alias BINARY_READ is READ [LINE, UNRESOLVED_ufixed, BOOLEAN]; + alias BINARY_READ is READ [LINE, UNRESOLVED_ufixed]; + alias BINARY_READ is READ [LINE, UNRESOLVED_sfixed, BOOLEAN]; + alias BINARY_READ is READ [LINE, UNRESOLVED_sfixed]; + + -- octal read and write + procedure OWRITE ( + L : inout LINE; -- input line + VALUE : in UNRESOLVED_ufixed; -- fixed point input + JUSTIFIED : in SIDE := right; + FIELD : in WIDTH := 0); + + procedure OWRITE ( + L : inout LINE; -- input line + VALUE : in UNRESOLVED_sfixed; -- fixed point input + JUSTIFIED : in SIDE := right; + FIELD : in WIDTH := 0); + + procedure OREAD(L : inout LINE; + VALUE : out UNRESOLVED_ufixed); + + procedure OREAD(L : inout LINE; + VALUE : out UNRESOLVED_ufixed; + GOOD : out BOOLEAN); + + procedure OREAD(L : inout LINE; + VALUE : out UNRESOLVED_sfixed); + + procedure OREAD(L : inout LINE; + VALUE : out UNRESOLVED_sfixed; + GOOD : out BOOLEAN); + alias OCTAL_READ is OREAD [LINE, UNRESOLVED_ufixed, BOOLEAN]; + alias OCTAL_READ is OREAD [LINE, UNRESOLVED_ufixed]; + alias OCTAL_READ is OREAD [LINE, UNRESOLVED_sfixed, BOOLEAN]; + alias OCTAL_READ is OREAD [LINE, UNRESOLVED_sfixed]; + alias OCTAL_WRITE is OWRITE [LINE, UNRESOLVED_ufixed, SIDE, WIDTH]; + alias OCTAL_WRITE is OWRITE [LINE, UNRESOLVED_sfixed, SIDE, WIDTH]; + + -- hex read and write + procedure HWRITE ( + L : inout LINE; -- input line + VALUE : in UNRESOLVED_ufixed; -- fixed point input + JUSTIFIED : in SIDE := right; + FIELD : in WIDTH := 0); + + -- purpose: writes fixed point into a line + procedure HWRITE ( + L : inout LINE; -- input line + VALUE : in UNRESOLVED_sfixed; -- fixed point input + JUSTIFIED : in SIDE := right; + FIELD : in WIDTH := 0); + + procedure HREAD(L : inout LINE; + VALUE : out UNRESOLVED_ufixed); + + procedure HREAD(L : inout LINE; + VALUE : out UNRESOLVED_ufixed; + GOOD : out BOOLEAN); + + procedure HREAD(L : inout LINE; + VALUE : out UNRESOLVED_sfixed); + + procedure HREAD(L : inout LINE; + VALUE : out UNRESOLVED_sfixed; + GOOD : out BOOLEAN); + alias HEX_READ is HREAD [LINE, UNRESOLVED_ufixed, BOOLEAN]; + alias HEX_READ is HREAD [LINE, UNRESOLVED_sfixed, BOOLEAN]; + alias HEX_READ is HREAD [LINE, UNRESOLVED_ufixed]; + alias HEX_READ is HREAD [LINE, UNRESOLVED_sfixed]; + alias HEX_WRITE is HWRITE [LINE, UNRESOLVED_ufixed, SIDE, WIDTH]; + alias HEX_WRITE is HWRITE [LINE, UNRESOLVED_sfixed, SIDE, WIDTH]; + + -- returns a string, useful for: + -- assert (x = y) report "error found " & to_string(x) severity error; + function to_string (value : UNRESOLVED_ufixed) return STRING; + alias to_bstring is to_string [UNRESOLVED_ufixed return STRING]; + alias TO_BINARY_STRING is TO_STRING [UNRESOLVED_ufixed return STRING]; + + function to_ostring (value : UNRESOLVED_ufixed) return STRING; + alias TO_OCTAL_STRING is TO_OSTRING [UNRESOLVED_ufixed return STRING]; + + function to_hstring (value : UNRESOLVED_ufixed) return STRING; + alias TO_HEX_STRING is TO_HSTRING [UNRESOLVED_ufixed return STRING]; + + function to_string (value : UNRESOLVED_sfixed) return STRING; + alias to_bstring is to_string [UNRESOLVED_sfixed return STRING]; + alias TO_BINARY_STRING is TO_STRING [UNRESOLVED_sfixed return STRING]; + + function to_ostring (value : UNRESOLVED_sfixed) return STRING; + alias TO_OCTAL_STRING is TO_OSTRING [UNRESOLVED_sfixed return STRING]; + + function to_hstring (value : UNRESOLVED_sfixed) return STRING; + alias TO_HEX_STRING is TO_HSTRING [UNRESOLVED_sfixed return STRING]; + + -- From string functions allow you to convert a string into a fixed + -- point number. Example: + -- signal uf1 : ufixed (3 downto -3); + -- uf1 <= from_string ("0110.100", uf1'high, uf1'low); -- 6.5 + -- The "." is optional in this syntax, however it exist and is + -- in the wrong location an error is produced. Overflow will + -- result in saturation. + + function from_string ( + bstring : STRING; -- binary string + constant left_index : INTEGER; + constant right_index : INTEGER) + return UNRESOLVED_ufixed; + alias from_bstring is from_string [STRING, INTEGER, INTEGER + return UNRESOLVED_ufixed]; + alias from_binary_string is from_string [STRING, INTEGER, INTEGER + return UNRESOLVED_ufixed]; + + -- Octal and hex conversions work as follows: + -- uf1 <= from_hstring ("6.8", 3, -3); -- 6.5 (bottom zeros dropped) + -- uf1 <= from_ostring ("06.4", 3, -3); -- 6.5 (top zeros dropped) + + function from_ostring ( + ostring : STRING; -- Octal string + constant left_index : INTEGER; + constant right_index : INTEGER) + return UNRESOLVED_ufixed; + alias from_octal_string is from_ostring [STRING, INTEGER, INTEGER + return UNRESOLVED_ufixed]; + + function from_hstring ( + hstring : STRING; -- hex string + constant left_index : INTEGER; + constant right_index : INTEGER) + return UNRESOLVED_ufixed; + alias from_hex_string is from_hstring [STRING, INTEGER, INTEGER + return UNRESOLVED_ufixed]; + + function from_string ( + bstring : STRING; -- binary string + constant left_index : INTEGER; + constant right_index : INTEGER) + return UNRESOLVED_sfixed; + alias from_bstring is from_string [STRING, INTEGER, INTEGER + return UNRESOLVED_sfixed]; + alias from_binary_string is from_string [STRING, INTEGER, INTEGER + return UNRESOLVED_sfixed]; + + function from_ostring ( + ostring : STRING; -- Octal string + constant left_index : INTEGER; + constant right_index : INTEGER) + return UNRESOLVED_sfixed; + alias from_octal_string is from_ostring [STRING, INTEGER, INTEGER + return UNRESOLVED_sfixed]; + + function from_hstring ( + hstring : STRING; -- hex string + constant left_index : INTEGER; + constant right_index : INTEGER) + return UNRESOLVED_sfixed; + alias from_hex_string is from_hstring [STRING, INTEGER, INTEGER + return UNRESOLVED_sfixed]; + + -- Same as above, "size_res" is used for it's range only. + function from_string ( + bstring : STRING; -- binary string + size_res : UNRESOLVED_ufixed) + return UNRESOLVED_ufixed; + alias from_bstring is from_string [STRING, UNRESOLVED_ufixed + return UNRESOLVED_ufixed]; + alias from_binary_string is from_string [STRING, UNRESOLVED_ufixed + return UNRESOLVED_ufixed]; + + function from_ostring ( + ostring : STRING; -- Octal string + size_res : UNRESOLVED_ufixed) + return UNRESOLVED_ufixed; + alias from_octal_string is from_ostring [STRING, UNRESOLVED_ufixed + return UNRESOLVED_ufixed]; + + function from_hstring ( + hstring : STRING; -- hex string + size_res : UNRESOLVED_ufixed) + return UNRESOLVED_ufixed; + alias from_hex_string is from_hstring [STRING, UNRESOLVED_ufixed + return UNRESOLVED_ufixed]; + + function from_string ( + bstring : STRING; -- binary string + size_res : UNRESOLVED_sfixed) + return UNRESOLVED_sfixed; + alias from_bstring is from_string [STRING, UNRESOLVED_sfixed + return UNRESOLVED_sfixed]; + alias from_binary_string is from_string [STRING, UNRESOLVED_sfixed + return UNRESOLVED_sfixed]; + + function from_ostring ( + ostring : STRING; -- Octal string + size_res : UNRESOLVED_sfixed) + return UNRESOLVED_sfixed; + alias from_octal_string is from_ostring [STRING, UNRESOLVED_sfixed + return UNRESOLVED_sfixed]; + + function from_hstring ( + hstring : STRING; -- hex string + size_res : UNRESOLVED_sfixed) + return UNRESOLVED_sfixed; + alias from_hex_string is from_hstring [STRING, UNRESOLVED_sfixed + return UNRESOLVED_sfixed]; + + -- Direct conversion functions. Example: + -- signal uf1 : ufixed (3 downto -3); + -- uf1 <= from_string ("0110.100"); -- 6.5 + -- In this case the "." is not optional, and the size of + -- the output must match exactly. + + function from_string ( + bstring : STRING) -- binary string + return UNRESOLVED_ufixed; + alias from_bstring is from_string [STRING return UNRESOLVED_ufixed]; + alias from_binary_string is from_string [STRING return UNRESOLVED_ufixed]; + + -- Direct octal and hex conversion functions. In this case + -- the string lengths must match. Example: + -- signal sf1 := sfixed (5 downto -3); + -- sf1 <= from_ostring ("71.4") -- -6.5 + + function from_ostring ( + ostring : STRING) -- Octal string + return UNRESOLVED_ufixed; + alias from_octal_string is from_ostring [STRING return UNRESOLVED_ufixed]; + + function from_hstring ( + hstring : STRING) -- hex string + return UNRESOLVED_ufixed; + alias from_hex_string is from_hstring [STRING return UNRESOLVED_ufixed]; + + function from_string ( + bstring : STRING) -- binary string + return UNRESOLVED_sfixed; + alias from_bstring is from_string [STRING return UNRESOLVED_sfixed]; + alias from_binary_string is from_string [STRING return UNRESOLVED_sfixed]; + + function from_ostring ( + ostring : STRING) -- Octal string + return UNRESOLVED_sfixed; + alias from_octal_string is from_ostring [STRING return UNRESOLVED_sfixed]; + + function from_hstring ( + hstring : STRING) -- hex string + return UNRESOLVED_sfixed; + alias from_hex_string is from_hstring [STRING return UNRESOLVED_sfixed]; +-- rtl_synthesis on +-- pragma synthesis_on + + -- IN VHDL-2006 std_logic_vector is a subtype of std_ulogic_vector, so these + -- extra functions are needed for compatability. + function to_ufixed ( + arg : STD_LOGIC_VECTOR; -- shifted vector + constant left_index : INTEGER; + constant right_index : INTEGER) + return UNRESOLVED_ufixed; + + function to_ufixed ( + arg : STD_LOGIC_VECTOR; -- shifted vector + size_res : UNRESOLVED_ufixed) -- for size only + return UNRESOLVED_ufixed; + + function to_sfixed ( + arg : STD_LOGIC_VECTOR; -- shifted vector + constant left_index : INTEGER; + constant right_index : INTEGER) + return UNRESOLVED_sfixed; + + function to_sfixed ( + arg : STD_LOGIC_VECTOR; -- shifted vector + size_res : UNRESOLVED_sfixed) -- for size only + return UNRESOLVED_sfixed; + + -- unsigned fixed point + function to_UFix ( + arg : STD_LOGIC_VECTOR; + width : NATURAL; -- width of vector + fraction : NATURAL) -- width of fraction + return UNRESOLVED_ufixed; + + -- signed fixed point + function to_SFix ( + arg : STD_LOGIC_VECTOR; + width : NATURAL; -- width of vector + fraction : NATURAL) -- width of fraction + return UNRESOLVED_sfixed; + +end package fixed_pkg; +------------------------------------------------------------------------------- +-- Proposed package body for the VHDL-200x-FT fixed_pkg package +-- (Fixed point math package) +-- This package body supplies a recommended implementation of these functions +-- Version : $Revision: 2.0 $ +-- Date : $Date: 2011/01/26 15:55:27 $ +-- +-- Created for VHDL-200X-ft, David Bishop (dbishop@vhdl.org) +------------------------------------------------------------------------------- +library IEEE; +use IEEE.MATH_REAL.all; + +package body fixed_pkg is + -- Author David Bishop (dbishop@vhdl.org) + -- Other contributers: Jim Lewis, Yannick Grugni, Ryan W. Hilton + -- null array constants + constant NAUF : UNRESOLVED_ufixed (0 downto 1) := (others => '0'); + constant NASF : UNRESOLVED_sfixed (0 downto 1) := (others => '0'); + constant NSLV : STD_ULOGIC_VECTOR (0 downto 1) := (others => '0'); + + -- This differed constant will tell you if the package body is synthesizable + -- or implemented as real numbers, set to "true" if synthesizable. + constant fixedsynth_or_real : BOOLEAN := true; + + -- %%% Replicated functions + function maximum ( + l, r : integer) -- inputs + return integer is + begin -- function max + if l > r then return l; + else return r; + end if; + end function maximum; + + function minimum ( + l, r : integer) -- inputs + return integer is + begin -- function min + if l > r then return r; + else return l; + end if; + end function minimum; + + function "sra" (arg : SIGNED; count : INTEGER) + return SIGNED is + begin + if (COUNT >= 0) then + return SHIFT_RIGHT(arg, count); + else + return SHIFT_LEFT(arg, -count); + end if; + end function "sra"; + + function or_reduce (arg : STD_ULOGIC_VECTOR) + return STD_LOGIC is + variable Upper, Lower : STD_ULOGIC; + variable Half : INTEGER; + variable BUS_int : STD_ULOGIC_VECTOR (arg'length - 1 downto 0); + variable Result : STD_ULOGIC; + begin + if (arg'length < 1) then -- In the case of a NULL range + Result := '0'; + else + BUS_int := to_ux01 (arg); + if (BUS_int'length = 1) then + Result := BUS_int (BUS_int'left); + elsif (BUS_int'length = 2) then + Result := BUS_int (BUS_int'right) or BUS_int (BUS_int'left); + else + Half := (BUS_int'length + 1) / 2 + BUS_int'right; + Upper := or_reduce (BUS_int (BUS_int'left downto Half)); + Lower := or_reduce (BUS_int (Half - 1 downto BUS_int'right)); + Result := Upper or Lower; + end if; + end if; + return Result; + end function or_reduce; + + -- purpose: AND all of the bits in a vector together + -- This is a copy of the proposed "and_reduce" from 1076.3 + function and_reduce (arg : STD_ULOGIC_VECTOR) + return STD_LOGIC is + variable Upper, Lower : STD_ULOGIC; + variable Half : INTEGER; + variable BUS_int : STD_ULOGIC_VECTOR (arg'length - 1 downto 0); + variable Result : STD_ULOGIC; + begin + if (arg'length < 1) then -- In the case of a NULL range + Result := '1'; + else + BUS_int := to_ux01 (arg); + if (BUS_int'length = 1) then + Result := BUS_int (BUS_int'left); + elsif (BUS_int'length = 2) then + Result := BUS_int (BUS_int'right) and BUS_int (BUS_int'left); + else + Half := (BUS_int'length + 1) / 2 + BUS_int'right; + Upper := and_reduce (BUS_int (BUS_int'left downto Half)); + Lower := and_reduce (BUS_int (Half - 1 downto BUS_int'right)); + Result := Upper and Lower; + end if; + end if; + return Result; + end function and_reduce; + + function xor_reduce (arg : STD_ULOGIC_VECTOR) return STD_ULOGIC is + variable Upper, Lower : STD_ULOGIC; + variable Half : INTEGER; + variable BUS_int : STD_ULOGIC_VECTOR (arg'length - 1 downto 0); + variable Result : STD_ULOGIC := '0'; -- In the case of a NULL range + begin + if (arg'length >= 1) then + BUS_int := to_ux01 (arg); + if (BUS_int'length = 1) then + Result := BUS_int (BUS_int'left); + elsif (BUS_int'length = 2) then + Result := BUS_int(BUS_int'right) xor BUS_int(BUS_int'left); + else + Half := (BUS_int'length + 1) / 2 + BUS_int'right; + Upper := xor_reduce (BUS_int (BUS_int'left downto Half)); + Lower := xor_reduce (BUS_int (Half - 1 downto BUS_int'right)); + Result := Upper xor Lower; + end if; + end if; + return Result; + end function xor_reduce; + + function nand_reduce(arg : std_ulogic_vector) return STD_ULOGIC is + begin + return not and_reduce (arg); + end function nand_reduce; + function nor_reduce(arg : std_ulogic_vector) return STD_ULOGIC is + begin + return not or_reduce (arg); + end function nor_reduce; + function xnor_reduce(arg : std_ulogic_vector) return STD_ULOGIC is + begin + return not xor_reduce (arg); + end function xnor_reduce; + -- Match table, copied form new std_logic_1164 + type stdlogic_table is array(STD_ULOGIC, STD_ULOGIC) of STD_ULOGIC; + constant match_logic_table : stdlogic_table := ( + ----------------------------------------------------- + -- U X 0 1 Z W L H - | | + ----------------------------------------------------- + ('U', 'U', 'U', 'U', 'U', 'U', 'U', 'U', '1'), -- | U | + ('U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', '1'), -- | X | + ('U', 'X', '1', '0', 'X', 'X', '1', '0', '1'), -- | 0 | + ('U', 'X', '0', '1', 'X', 'X', '0', '1', '1'), -- | 1 | + ('U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', '1'), -- | Z | + ('U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', '1'), -- | W | + ('U', 'X', '1', '0', 'X', 'X', '1', '0', '1'), -- | L | + ('U', 'X', '0', '1', 'X', 'X', '0', '1', '1'), -- | H | + ('1', '1', '1', '1', '1', '1', '1', '1', '1') -- | - | + ); + + constant no_match_logic_table : stdlogic_table := ( + ----------------------------------------------------- + -- U X 0 1 Z W L H - | | + ----------------------------------------------------- + ('U', 'U', 'U', 'U', 'U', 'U', 'U', 'U', '0'), -- | U | + ('U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', '0'), -- | X | + ('U', 'X', '0', '1', 'X', 'X', '0', '1', '0'), -- | 0 | + ('U', 'X', '1', '0', 'X', 'X', '1', '0', '0'), -- | 1 | + ('U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', '0'), -- | Z | + ('U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', '0'), -- | W | + ('U', 'X', '0', '1', 'X', 'X', '0', '1', '0'), -- | L | + ('U', 'X', '1', '0', 'X', 'X', '1', '0', '0'), -- | H | + ('0', '0', '0', '0', '0', '0', '0', '0', '0') -- | - | + ); + + ------------------------------------------------------------------- + -- ?= functions, Similar to "std_match", but returns "std_ulogic". + ------------------------------------------------------------------- + function \?=\ (l, r : STD_ULOGIC) return STD_ULOGIC is + begin + return match_logic_table (l, r); + end function \?=\; + function \?/=\ (l, r : STD_ULOGIC) return STD_ULOGIC is + begin + return no_match_logic_table (l, r); + end function \?/=\; + -- "?=" operator is similar to "std_match", but returns a std_ulogic.. + -- Id: M.2B + function \?=\ (L, R: UNSIGNED) return STD_ULOGIC is + constant L_LEFT : INTEGER := L'LENGTH-1; + constant R_LEFT : INTEGER := R'LENGTH-1; + alias XL : UNSIGNED(L_LEFT downto 0) is L; + alias XR : UNSIGNED(R_LEFT downto 0) is R; + constant SIZE : NATURAL := MAXIMUM(L'LENGTH, R'LENGTH); + variable LX : UNSIGNED(SIZE-1 downto 0); + variable RX : UNSIGNED(SIZE-1 downto 0); + variable result, result1 : STD_ULOGIC; -- result + begin + -- Logically identical to an "=" operator. + if ((L'LENGTH < 1) or (R'LENGTH < 1)) then + assert NO_WARNING + report "NUMERIC_STD.""?="": null detected, returning X" + severity warning; + return 'X'; + else + LX := RESIZE(XL, SIZE); + RX := RESIZE(XR, SIZE); + result := '1'; + for i in LX'low to LX'high loop + result1 := \?=\(LX(i), RX(i)); + if result1 = 'U' then + return 'U'; + elsif result1 = 'X' or result = 'X' then + result := 'X'; + else + result := result and result1; + end if; + end loop; + return result; + end if; + end function \?=\; + + -- Id: M.3B + function \?=\ (L, R: SIGNED) return std_ulogic is + constant L_LEFT : INTEGER := L'LENGTH-1; + constant R_LEFT : INTEGER := R'LENGTH-1; + alias XL : SIGNED(L_LEFT downto 0) is L; + alias XR : SIGNED(R_LEFT downto 0) is R; + constant SIZE : NATURAL := MAXIMUM(L'LENGTH, R'LENGTH); + variable LX : SIGNED(SIZE-1 downto 0); + variable RX : SIGNED(SIZE-1 downto 0); + variable result, result1 : STD_ULOGIC; -- result + begin -- ?= + if ((L'LENGTH < 1) or (R'LENGTH < 1)) then + assert NO_WARNING + report "NUMERIC_STD.""?="": null detected, returning X" + severity warning; + return 'X'; + else + LX := RESIZE(XL, SIZE); + RX := RESIZE(XR, SIZE); + result := '1'; + for i in LX'low to LX'high loop + result1 := \?=\ (LX(i), RX(i)); + if result1 = 'U' then + return 'U'; + elsif result1 = 'X' or result = 'X' then + result := 'X'; + else + result := result and result1; + end if; + end loop; + return result; + end if; + end function \?=\; + + function \?/=\ (L, R : UNSIGNED) return std_ulogic is + constant L_LEFT : INTEGER := L'LENGTH-1; + constant R_LEFT : INTEGER := R'LENGTH-1; + alias XL : UNSIGNED(L_LEFT downto 0) is L; + alias XR : UNSIGNED(R_LEFT downto 0) is R; + constant SIZE : NATURAL := MAXIMUM(L'LENGTH, R'LENGTH); + variable LX : UNSIGNED(SIZE-1 downto 0); + variable RX : UNSIGNED(SIZE-1 downto 0); + variable result, result1 : STD_ULOGIC; -- result + begin -- ?= + if ((L'LENGTH < 1) or (R'LENGTH < 1)) then + assert NO_WARNING + report "NUMERIC_STD.""?/="": null detected, returning X" + severity warning; + return 'X'; + else + LX := RESIZE(XL, SIZE); + RX := RESIZE(XR, SIZE); + result := '0'; + for i in LX'low to LX'high loop + result1 := \?/=\ (LX(i), RX(i)); + if result1 = 'U' then + result := 'U'; + elsif result1 = 'X' or result = 'X' then + result := 'X'; + else + result := result or result1; + end if; + end loop; + return result; + end if; + end function \?/=\; + + function \?/=\ (L, R : SIGNED) return std_ulogic is + constant L_LEFT : INTEGER := L'LENGTH-1; + constant R_LEFT : INTEGER := R'LENGTH-1; + alias XL : SIGNED(L_LEFT downto 0) is L; + alias XR : SIGNED(R_LEFT downto 0) is R; + constant SIZE : NATURAL := MAXIMUM(L'LENGTH, R'LENGTH); + variable LX : SIGNED(SIZE-1 downto 0); + variable RX : SIGNED(SIZE-1 downto 0); + variable result, result1 : STD_ULOGIC; -- result + begin -- ?= + if ((L'LENGTH < 1) or (R'LENGTH < 1)) then + assert NO_WARNING + report "NUMERIC_STD.""?/="": null detected, returning X" + severity warning; + return 'X'; + else + LX := RESIZE(XL, SIZE); + RX := RESIZE(XR, SIZE); + result := '0'; + for i in LX'low to LX'high loop + result1 := \?/=\ (LX(i), RX(i)); + if result1 = 'U' then + return 'U'; + elsif result1 = 'X' or result = 'X' then + result := 'X'; + else + result := result or result1; + end if; + end loop; + return result; + end if; + end function \?/=\; + function Is_X ( s : UNSIGNED ) return BOOLEAN is + begin + return Is_X (STD_LOGIC_VECTOR (s)); + end function Is_X; + + function Is_X ( s : SIGNED ) return BOOLEAN is + begin + return Is_X (STD_LOGIC_VECTOR (s)); + end function Is_X; + function \?>\ (L, R : UNSIGNED) return STD_ULOGIC is + begin + if ((l'length < 1) or (r'length < 1)) then + assert NO_WARNING + report "NUMERIC_STD.""?>"": null detected, returning X" + severity warning; + return 'X'; + else + for i in L'range loop + if L(i) = '-' then + report "NUMERIC_STD.""?>"": '-' found in compare string" + severity error; + return 'X'; + end if; + end loop; + for i in R'range loop + if R(i) = '-' then + report "NUMERIC_STD.""?>"": '-' found in compare string" + severity error; + return 'X'; + end if; + end loop; + 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 \?>\; + -- %%% function "?>" (L, R : UNSIGNED) return std_ulogic is + -- %%% end function "?>"\; + function \?>\ (L, R : SIGNED) return STD_ULOGIC is + begin + if ((l'length < 1) or (r'length < 1)) then + assert NO_WARNING + report "NUMERIC_STD.""?>"": null detected, returning X" + severity warning; + return 'X'; + else + for i in L'range loop + if L(i) = '-' then + report "NUMERIC_STD.""?>"": '-' found in compare string" + severity error; + return 'X'; + end if; + end loop; + for i in R'range loop + if R(i) = '-' then + report "NUMERIC_STD.""?>"": '-' found in compare string" + severity error; + return 'X'; + end if; + end loop; + 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 \?>\; + function \?>=\ (L, R : UNSIGNED) return STD_ULOGIC is + begin + if ((l'length < 1) or (r'length < 1)) then + assert NO_WARNING + report "NUMERIC_STD.""?>="": null detected, returning X" + severity warning; + return 'X'; + else + for i in L'range loop + if L(i) = '-' then + report "NUMERIC_STD.""?>="": '-' found in compare string" + severity error; + return 'X'; + end if; + end loop; + for i in R'range loop + if R(i) = '-' then + report "NUMERIC_STD.""?>="": '-' found in compare string" + severity error; + return 'X'; + end if; + end loop; + 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 \?>=\; + -- %%% function "?>=" (L, R : UNSIGNED) return std_ulogic is + -- %%% end function "?>="; + function \?>=\ (L, R : SIGNED) return STD_ULOGIC is + begin + if ((l'length < 1) or (r'length < 1)) then + assert NO_WARNING + report "NUMERIC_STD.""?>="": null detected, returning X" + severity warning; + return 'X'; + else + for i in L'range loop + if L(i) = '-' then + report "NUMERIC_STD.""?>="": '-' found in compare string" + severity error; + return 'X'; + end if; + end loop; + for i in R'range loop + if R(i) = '-' then + report "NUMERIC_STD.""?>="": '-' found in compare string" + severity error; + return 'X'; + end if; + end loop; + 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 \?>=\; + function \?<\ (L, R : UNSIGNED) return STD_ULOGIC is + begin + if ((l'length < 1) or (r'length < 1)) then + assert NO_WARNING + report "NUMERIC_STD.""?<"": null detected, returning X" + severity warning; + return 'X'; + else + for i in L'range loop + if L(i) = '-' then + report "NUMERIC_STD.""?<"": '-' found in compare string" + severity error; + return 'X'; + end if; + end loop; + for i in R'range loop + if R(i) = '-' then + report "NUMERIC_STD.""?<"": '-' found in compare string" + severity error; + return 'X'; + end if; + end loop; + 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 \?<\; + -- %%% function "?<" (L, R : UNSIGNED) return std_ulogic is + -- %%% end function "?<"; + function \?<\ (L, R : SIGNED) return STD_ULOGIC is + begin + if ((l'length < 1) or (r'length < 1)) then + assert NO_WARNING + report "NUMERIC_STD.""?<"": null detected, returning X" + severity warning; + return 'X'; + else + for i in L'range loop + if L(i) = '-' then + report "NUMERIC_STD.""?<"": '-' found in compare string" + severity error; + return 'X'; + end if; + end loop; + for i in R'range loop + if R(i) = '-' then + report "NUMERIC_STD.""?<"": '-' found in compare string" + severity error; + return 'X'; + end if; + end loop; + 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 \?<\; + function \?<=\ (L, R : UNSIGNED) return STD_ULOGIC is + begin + if ((l'length < 1) or (r'length < 1)) then + assert NO_WARNING + report "NUMERIC_STD.""?<="": null detected, returning X" + severity warning; + return 'X'; + else + for i in L'range loop + if L(i) = '-' then + report "NUMERIC_STD.""?<="": '-' found in compare string" + severity error; + return 'X'; + end if; + end loop; + for i in R'range loop + if R(i) = '-' then + report "NUMERIC_STD.""?<="": '-' found in compare string" + severity error; + return 'X'; + end if; + end loop; + 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 \?<=\; + -- %%% function "?<=" (L, R : UNSIGNED) return std_ulogic is + -- %%% end function "?<="; + function \?<=\ (L, R : SIGNED) return STD_ULOGIC is + begin + if ((l'length < 1) or (r'length < 1)) then + assert NO_WARNING + report "NUMERIC_STD.""?<="": null detected, returning X" + severity warning; + return 'X'; + else + for i in L'range loop + if L(i) = '-' then + report "NUMERIC_STD.""?<="": '-' found in compare string" + severity error; + return 'X'; + end if; + end loop; + for i in R'range loop + if R(i) = '-' then + report "NUMERIC_STD.""?<="": '-' found in compare string" + severity error; + return 'X'; + end if; + end loop; + 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 replicated functions + -- Special version of "minimum" to do some boundary checking without errors + function mins (l, r : INTEGER) + return INTEGER is + begin -- function mins + if (L = INTEGER'low or R = INTEGER'low) then + return 0; -- error condition, silent + end if; + return minimum (L, R); + end function mins; + + -- Special version of "minimum" to do some boundary checking with errors + function mine (l, r : INTEGER) + return INTEGER is + begin -- function mine + if (L = INTEGER'low or R = INTEGER'low) then + report fixed_pkg'instance_name + & " Unbounded number passed, was a literal used?" + severity error; + return 0; + end if; + return minimum (L, R); + end function mine; + + -- The following functions are used only internally. Every function + -- calls "cleanvec" either directly or indirectly. + -- purpose: Fixes "downto" problem and resolves meta states + function cleanvec ( + arg : UNRESOLVED_sfixed) -- input + return UNRESOLVED_sfixed is + constant left_index : INTEGER := maximum(arg'left, arg'right); + constant right_index : INTEGER := mins(arg'left, arg'right); + variable result : UNRESOLVED_sfixed (arg'range); + begin -- function cleanvec + assert not (arg'ascending and (arg'low /= INTEGER'low)) + report fixed_pkg'instance_name + & " Vector passed using a ""to"" range, expected is ""downto""" + severity error; + return arg; + end function cleanvec; + + -- purpose: Fixes "downto" problem and resolves meta states + function cleanvec ( + arg : UNRESOLVED_ufixed) -- input + return UNRESOLVED_ufixed is + constant left_index : INTEGER := maximum(arg'left, arg'right); + constant right_index : INTEGER := mins(arg'left, arg'right); + variable result : UNRESOLVED_ufixed (arg'range); + begin -- function cleanvec + assert not (arg'ascending and (arg'low /= INTEGER'low)) + report fixed_pkg'instance_name + & " Vector passed using a ""to"" range, expected is ""downto""" + severity error; + return arg; + end function cleanvec; + + -- Type convert a "unsigned" into a "ufixed", used internally + function to_fixed ( + arg : UNSIGNED; -- shifted vector + constant left_index : INTEGER; + constant right_index : INTEGER) + return UNRESOLVED_ufixed is + variable result : UNRESOLVED_ufixed (left_index downto right_index); + begin -- function to_fixed + result := UNRESOLVED_ufixed(arg); + return result; + end function to_fixed; + + -- Type convert a "signed" into an "sfixed", used internally + function to_fixed ( + arg : SIGNED; -- shifted vector + constant left_index : INTEGER; + constant right_index : INTEGER) + return UNRESOLVED_sfixed is + variable result : UNRESOLVED_sfixed (left_index downto right_index); + begin -- function to_fixed + result := UNRESOLVED_sfixed(arg); + return result; + end function to_fixed; + + -- Type convert a "ufixed" into an "unsigned", used internally + function to_uns ( + arg : UNRESOLVED_ufixed) -- fp vector + return UNSIGNED is + subtype t is UNSIGNED(arg'high - arg'low downto 0); + variable slv : t; + begin -- function to_uns + slv := t(arg); + return slv; + end function to_uns; + + -- Type convert an "sfixed" into a "signed", used internally + function to_s ( + arg : UNRESOLVED_sfixed) -- fp vector + return SIGNED is + subtype t is SIGNED(arg'high - arg'low downto 0); + variable slv : t; + begin -- function to_s + slv := t(arg); + return slv; + end function to_s; + + -- adds 1 to the LSB of the number + procedure round_up (arg : in UNRESOLVED_ufixed; + result : out UNRESOLVED_ufixed; + overflowx : out BOOLEAN) is + variable arguns, resuns : UNSIGNED (arg'high-arg'low+1 downto 0) + := (others => '0'); + begin -- round_up + arguns (arguns'high-1 downto 0) := to_uns (arg); + resuns := arguns + 1; + result := to_fixed(resuns(arg'high-arg'low + downto 0), arg'high, arg'low); + overflowx := (resuns(resuns'high) = '1'); + end procedure round_up; + + -- adds 1 to the LSB of the number + procedure round_up (arg : in UNRESOLVED_sfixed; + result : out UNRESOLVED_sfixed; + overflowx : out BOOLEAN) is + variable args, ress : SIGNED (arg'high-arg'low+1 downto 0); + begin -- round_up + args (args'high-1 downto 0) := to_s (arg); + args(args'high) := arg(arg'high); -- sign extend + ress := args + 1; + result := to_fixed(ress (ress'high-1 + downto 0), arg'high, arg'low); + overflowx := ((arg(arg'high) /= ress(ress'high-1)) + and (or_reduce (STD_ULOGIC_VECTOR(ress)) /= '0')); + end procedure round_up; + + -- Rounding - Performs a "round_nearest" (IEEE 754) which rounds up + -- when the remainder is > 0.5. If the remainder IS 0.5 then if the + -- bottom bit is a "1" it is rounded, otherwise it remains the same. + function round_fixed (arg : UNRESOLVED_ufixed; + remainder : UNRESOLVED_ufixed; + overflow_style : fixed_overflow_style_type := fixed_overflow_style) + return UNRESOLVED_ufixed is + variable rounds : BOOLEAN; + variable round_overflow : BOOLEAN; + variable result : UNRESOLVED_ufixed (arg'range); + begin + rounds := false; + if (remainder'length > 1) then + if (remainder (remainder'high) = '1') then + rounds := (arg(arg'low) = '1') + or (or_reduce (to_sulv(remainder(remainder'high-1 downto + remainder'low))) = '1'); + end if; + else + rounds := (arg(arg'low) = '1') and (remainder (remainder'high) = '1'); + end if; + if rounds then + round_up(arg => arg, + result => result, + overflowx => round_overflow); + else + result := arg; + end if; + if (overflow_style = fixed_saturate) and round_overflow then + result := saturate (result'high, result'low); + end if; + return result; + end function round_fixed; + + -- Rounding case statement + function round_fixed (arg : UNRESOLVED_sfixed; + remainder : UNRESOLVED_sfixed; + overflow_style : fixed_overflow_style_type := fixed_overflow_style) + return UNRESOLVED_sfixed is + variable rounds : BOOLEAN; + variable round_overflow : BOOLEAN; + variable result : UNRESOLVED_sfixed (arg'range); + begin + rounds := false; + if (remainder'length > 1) then + if (remainder (remainder'high) = '1') then + rounds := (arg(arg'low) = '1') + or (or_reduce (to_sulv(remainder(remainder'high-1 downto + remainder'low))) = '1'); + end if; + else + rounds := (arg(arg'low) = '1') and (remainder (remainder'high) = '1'); + end if; + if rounds then + round_up(arg => arg, + result => result, + overflowx => round_overflow); + else + result := arg; + end if; + if round_overflow then + if (overflow_style = fixed_saturate) then + if arg(arg'high) = '0' then + result := saturate (result'high, result'low); + else + result := not saturate (result'high, result'low); + end if; + -- Sign bit not fixed when wrapping + end if; + end if; + return result; + end function round_fixed; + + -- converts an sfixed into a ufixed. The output is the same length as the + -- input, because abs("1000") = "1000" = 8. + function to_ufixed ( + arg : UNRESOLVED_sfixed) + return UNRESOLVED_ufixed + is + constant left_index : INTEGER := arg'high; + constant right_index : INTEGER := mine(arg'low, arg'low); + variable xarg : UNRESOLVED_sfixed(left_index+1 downto right_index); + variable result : UNRESOLVED_ufixed(left_index downto right_index); + begin + if arg'length < 1 then + return NAUF; + end if; + xarg := abs(arg); + result := UNRESOLVED_ufixed (xarg (left_index downto right_index)); + return result; + end function to_ufixed; + +----------------------------------------------------------------------------- +-- Visible functions +----------------------------------------------------------------------------- + + -- Conversion functions. These are needed for synthesis where typically + -- the only input and output type is a std_logic_vector. + function to_sulv ( + arg : UNRESOLVED_ufixed) -- fixed point vector + return STD_ULOGIC_VECTOR is + variable result : STD_ULOGIC_VECTOR (arg'length-1 downto 0); + begin + if arg'length < 1 then + return NSLV; + end if; + result := STD_ULOGIC_VECTOR (arg); + return result; + end function to_sulv; + + function to_sulv ( + arg : UNRESOLVED_sfixed) -- fixed point vector + return STD_ULOGIC_VECTOR is + variable result : STD_ULOGIC_VECTOR (arg'length-1 downto 0); + begin + if arg'length < 1 then + return NSLV; + end if; + result := STD_ULOGIC_VECTOR (arg); + return result; + end function to_sulv; + + function to_slv ( + arg : UNRESOLVED_ufixed) -- fixed point vector + return STD_LOGIC_VECTOR is + begin + return to_stdlogicvector(to_sulv(arg)); + end function to_slv; + + function to_slv ( + arg : UNRESOLVED_sfixed) -- fixed point vector + return STD_LOGIC_VECTOR is + begin + return to_stdlogicvector(to_sulv(arg)); + end function to_slv; + + function to_ufixed ( + arg : STD_ULOGIC_VECTOR; -- shifted vector + constant left_index : INTEGER; + constant right_index : INTEGER) + return unresolved_ufixed is + variable result : UNRESOLVED_ufixed (left_index downto right_index); + begin + if (arg'length < 1 or right_index > left_index) then + return NAUF; + end if; + if (arg'length /= result'length) then + report fixed_pkg'instance_name & "TO_UFIXED(SLV) " + & "Vector lengths do not match. Input length is " + & INTEGER'image(arg'length) & " and output will be " + & INTEGER'image(result'length) & " wide." + severity error; + return NAUF; + else + result := to_fixed (arg => UNSIGNED(arg), + left_index => left_index, + right_index => right_index); + return result; + end if; + end function to_ufixed; + + function to_sfixed ( + arg : STD_ULOGIC_VECTOR; -- shifted vector + constant left_index : INTEGER; + constant right_index : INTEGER) + return unresolved_sfixed is + variable result : UNRESOLVED_sfixed (left_index downto right_index); + begin + if (arg'length < 1 or right_index > left_index) then + return NASF; + end if; + if (arg'length /= result'length) then + report fixed_pkg'instance_name & "TO_SFIXED(SLV) " + & "Vector lengths do not match. Input length is " + & INTEGER'image(arg'length) & " and output will be " + & INTEGER'image(result'length) & " wide." + severity error; + return NASF; + else + result := to_fixed (arg => SIGNED(arg), + left_index => left_index, + right_index => right_index); + return result; + end if; + end function to_sfixed; + + -- Two's complement number, Grows the vector by 1 bit. + -- because "abs (1000.000) = 01000.000" or abs(-16) = 16. + function "abs" ( + arg : UNRESOLVED_sfixed) -- fixed point input + return UNRESOLVED_sfixed is + constant left_index : INTEGER := arg'high; + constant right_index : INTEGER := mine(arg'low, arg'low); + variable ressns : SIGNED (arg'length downto 0); + variable result : UNRESOLVED_sfixed (left_index+1 downto right_index); + begin + if (arg'length < 1 or result'length < 1) then + return NASF; + end if; + ressns (arg'length-1 downto 0) := to_s (cleanvec (arg)); + ressns (arg'length) := ressns (arg'length-1); -- expand sign bit + result := to_fixed (abs(ressns), left_index+1, right_index); + return result; + end function "abs"; + + -- also grows the vector by 1 bit. + function "-" ( + arg : UNRESOLVED_sfixed) -- fixed point input + return UNRESOLVED_sfixed is + constant left_index : INTEGER := arg'high+1; + constant right_index : INTEGER := mine(arg'low, arg'low); + variable ressns : SIGNED (arg'length downto 0); + variable result : UNRESOLVED_sfixed (left_index downto right_index); + begin + if (arg'length < 1 or result'length < 1) then + return NASF; + end if; + ressns (arg'length-1 downto 0) := to_s (cleanvec(arg)); + ressns (arg'length) := ressns (arg'length-1); -- expand sign bit + result := to_fixed (-ressns, left_index, right_index); + return result; + end function "-"; + + -- Addition + function "+" ( + l, r : UNRESOLVED_ufixed) -- ufixed(a downto b) + ufixed(c downto d) = + return UNRESOLVED_ufixed is -- ufixed(max(a,c)+1 downto min(b,d)) + constant left_index : INTEGER := maximum(l'high, r'high)+1; + constant right_index : INTEGER := mine(l'low, r'low); + variable lresize, rresize : UNRESOLVED_ufixed (left_index downto right_index); + variable result : UNRESOLVED_ufixed (left_index downto right_index); + variable lslv, rslv : UNSIGNED (left_index-right_index + downto 0); + variable result_slv : UNSIGNED (left_index-right_index + downto 0); + begin + if (l'length < 1 or r'length < 1 or result'length < 1) then + return NAUF; + end if; + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_uns (lresize); + rslv := to_uns (rresize); + result_slv := lslv + rslv; + result := to_fixed(result_slv, left_index, right_index); + return result; + end function "+"; + + function "+" ( + l, r : UNRESOLVED_sfixed) -- sfixed(a downto b) + sfixed(c downto d) = + return UNRESOLVED_sfixed is -- sfixed(max(a,c)+1 downto min(b,d)) + constant left_index : INTEGER := maximum(l'high, r'high)+1; + constant right_index : INTEGER := mine(l'low, r'low); + variable lresize, rresize : UNRESOLVED_sfixed (left_index downto right_index); + variable result : UNRESOLVED_sfixed (left_index downto right_index); + variable lslv, rslv : SIGNED (left_index-right_index downto 0); + variable result_slv : SIGNED (left_index-right_index downto 0); + begin + if (l'length < 1 or r'length < 1 or result'length < 1) then + return NASF; + end if; + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_s (lresize); + rslv := to_s (rresize); + result_slv := lslv + rslv; + result := to_fixed(result_slv, left_index, right_index); + return result; + end function "+"; + + -- Subtraction + function "-" ( + l, r : UNRESOLVED_ufixed) -- ufixed(a downto b) - ufixed(c downto d) = + return UNRESOLVED_ufixed is -- ufixed(max(a,c)+1 downto min(b,d)) + constant left_index : INTEGER := maximum(l'high, r'high)+1; + constant right_index : INTEGER := mine(l'low, r'low); + variable lresize, rresize : UNRESOLVED_ufixed (left_index downto right_index); + variable result : UNRESOLVED_ufixed (left_index downto right_index); + variable lslv, rslv : UNSIGNED (left_index-right_index + downto 0); + variable result_slv : UNSIGNED (left_index-right_index + downto 0); + begin + if (l'length < 1 or r'length < 1 or result'length < 1) then + return NAUF; + end if; + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_uns (lresize); + rslv := to_uns (rresize); + result_slv := lslv - rslv; + result := to_fixed(result_slv, left_index, right_index); + return result; + end function "-"; + + function "-" ( + l, r : UNRESOLVED_sfixed) -- sfixed(a downto b) - sfixed(c downto d) = + return UNRESOLVED_sfixed is -- sfixed(max(a,c)+1 downto min(b,d)) + constant left_index : INTEGER := maximum(l'high, r'high)+1; + constant right_index : INTEGER := mine(l'low, r'low); + variable lresize, rresize : UNRESOLVED_sfixed (left_index downto right_index); + variable result : UNRESOLVED_sfixed (left_index downto right_index); + variable lslv, rslv : SIGNED (left_index-right_index downto 0); + variable result_slv : SIGNED (left_index-right_index downto 0); + begin + if (l'length < 1 or r'length < 1 or result'length < 1) then + return NASF; + end if; + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_s (lresize); + rslv := to_s (rresize); + result_slv := lslv - rslv; + result := to_fixed(result_slv, left_index, right_index); + return result; + end function "-"; + + function "*" ( + l, r : UNRESOLVED_ufixed) -- ufixed(a downto b) * ufixed(c downto d) = + return UNRESOLVED_ufixed is -- ufixed(a+c+1 downto b+d) + variable lslv : UNSIGNED (l'length-1 downto 0); + variable rslv : UNSIGNED (r'length-1 downto 0); + variable result_slv : UNSIGNED (r'length+l'length-1 downto 0); + variable result : UNRESOLVED_ufixed (l'high + r'high+1 downto + mine(l'low, l'low) + mine(r'low, r'low)); + begin + if (l'length < 1 or r'length < 1 or + result'length /= result_slv'length) then + return NAUF; + end if; + lslv := to_uns (cleanvec(l)); + rslv := to_uns (cleanvec(r)); + result_slv := lslv * rslv; + result := to_fixed (result_slv, result'high, result'low); + return result; + end function "*"; + + function "*" ( + l, r : UNRESOLVED_sfixed) -- sfixed(a downto b) * sfixed(c downto d) = + return UNRESOLVED_sfixed is -- sfixed(a+c+1 downto b+d) + variable lslv : SIGNED (l'length-1 downto 0); + variable rslv : SIGNED (r'length-1 downto 0); + variable result_slv : SIGNED (r'length+l'length-1 downto 0); + variable result : UNRESOLVED_sfixed (l'high + r'high+1 downto + mine(l'low, l'low) + mine(r'low, r'low)); + begin + if (l'length < 1 or r'length < 1 or + result'length /= result_slv'length) then + return NASF; + end if; + lslv := to_s (cleanvec(l)); + rslv := to_s (cleanvec(r)); + result_slv := lslv * rslv; + result := to_fixed (result_slv, result'high, result'low); + return result; + end function "*"; + + function "/" ( + l, r : UNRESOLVED_ufixed) -- ufixed(a downto b) / ufixed(c downto d) = + return UNRESOLVED_ufixed is -- ufixed(a-d downto b-c-1) + begin + return divide (l, r); + end function "/"; + + function "/" ( + l, r : UNRESOLVED_sfixed) -- sfixed(a downto b) / sfixed(c downto d) = + return UNRESOLVED_sfixed is -- sfixed(a-d+1 downto b-c) + begin + return divide (l, r); + end function "/"; + + -- This version of divide gives the user more control + -- ufixed(a downto b) / ufixed(c downto d) = ufixed(a-d downto b-c-1) + function divide ( + l, r : UNRESOLVED_ufixed; + constant round_style : fixed_round_style_type := fixed_round_style; + constant guard_bits : NATURAL := fixed_guard_bits) + return UNRESOLVED_ufixed is + variable result : UNRESOLVED_ufixed (l'high - mine(r'low, r'low) downto + mine (l'low, l'low) - r'high -1); + variable dresult : UNRESOLVED_ufixed (result'high downto result'low -guard_bits); + variable lresize : UNRESOLVED_ufixed (l'high downto l'high - dresult'length+1); + variable lslv : UNSIGNED (lresize'length-1 downto 0); + variable rslv : UNSIGNED (r'length-1 downto 0); + variable result_slv : UNSIGNED (lresize'length-1 downto 0); + begin + if (l'length < 1 or r'length < 1 or + mins(r'low, r'low) /= r'low or mins(l'low, l'low) /= l'low) then + return NAUF; + end if; + lresize := resize (arg => l, + left_index => lresize'high, + right_index => lresize'low, + overflow_style => fixed_wrap, -- vector only grows + round_style => fixed_truncate); + lslv := to_uns (cleanvec (lresize)); + rslv := to_uns (cleanvec (r)); + if (rslv = 0) then + report fixed_pkg'instance_name + & "DIVIDE(ufixed) Division by zero" severity error; + result := saturate (result'high, result'low); -- saturate + else + result_slv := lslv / rslv; + dresult := to_fixed (result_slv, dresult'high, dresult'low); + result := resize (arg => dresult, + left_index => result'high, + right_index => result'low, + overflow_style => fixed_wrap, -- overflow impossible + round_style => round_style); + end if; + return result; + end function divide; + + -- sfixed(a downto b) / sfixed(c downto d) = sfixed(a-d+1 downto b-c) + function divide ( + l, r : UNRESOLVED_sfixed; + constant round_style : fixed_round_style_type := fixed_round_style; + constant guard_bits : NATURAL := fixed_guard_bits) + return UNRESOLVED_sfixed is + variable result : UNRESOLVED_sfixed (l'high - mine(r'low, r'low) + 1 downto + mine (l'low, l'low) - r'high); + variable dresult : UNRESOLVED_sfixed (result'high downto result'low-guard_bits); + variable lresize : UNRESOLVED_sfixed (l'high+1 downto l'high+1 -dresult'length+1); + variable lslv : SIGNED (lresize'length-1 downto 0); + variable rslv : SIGNED (r'length-1 downto 0); + variable result_slv : SIGNED (lresize'length-1 downto 0); + begin + if (l'length < 1 or r'length < 1 or + mins(r'low, r'low) /= r'low or mins(l'low, l'low) /= l'low) then + return NASF; + end if; + lresize := resize (arg => l, + left_index => lresize'high, + right_index => lresize'low, + overflow_style => fixed_wrap, -- vector only grows + round_style => fixed_truncate); + lslv := to_s (cleanvec (lresize)); + rslv := to_s (cleanvec (r)); + if (rslv = 0) then + report fixed_pkg'instance_name + & "DIVIDE(sfixed) Division by zero" severity error; + result := saturate (result'high, result'low); + else + result_slv := lslv / rslv; + dresult := to_fixed (result_slv, dresult'high, dresult'low); + result := resize (arg => dresult, + left_index => result'high, + right_index => result'low, + overflow_style => fixed_wrap, -- overflow impossible + round_style => round_style); + end if; + return result; + end function divide; + + -- 1 / ufixed(a downto b) = ufixed(-b downto -a-1) + function reciprocal ( + arg : UNRESOLVED_ufixed; -- fixed point input + constant round_style : fixed_round_style_type := fixed_round_style; + constant guard_bits : NATURAL := fixed_guard_bits) + return UNRESOLVED_ufixed is + constant one : UNRESOLVED_ufixed (0 downto 0) := "1"; + begin + return divide (l => one, + r => arg, + round_style => round_style, + guard_bits => guard_bits); + end function reciprocal; + + -- 1 / sfixed(a downto b) = sfixed(-b+1 downto -a) + function reciprocal ( + arg : UNRESOLVED_sfixed; -- fixed point input + constant round_style : fixed_round_style_type := fixed_round_style; + constant guard_bits : NATURAL := fixed_guard_bits) + return UNRESOLVED_sfixed is + constant one : UNRESOLVED_sfixed (1 downto 0) := "01"; -- extra bit. + variable resultx : UNRESOLVED_sfixed (-mine(arg'low, arg'low)+2 downto -arg'high); + begin + if (arg'length < 1 or resultx'length < 1) then + return NASF; + else + resultx := divide (l => one, + r => arg, + round_style => round_style, + guard_bits => guard_bits); + return resultx (resultx'high-1 downto resultx'low); -- remove extra bit + end if; + end function reciprocal; + + -- ufixed (a downto b) rem ufixed (c downto d) + -- = ufixed (min(a,c) downto min(b,d)) + function "rem" ( + l, r : UNRESOLVED_ufixed) -- fixed point input + return UNRESOLVED_ufixed is + begin + return remainder (l, r); + end function "rem"; + + -- remainder + -- sfixed (a downto b) rem sfixed (c downto d) + -- = sfixed (min(a,c) downto min(b,d)) + function "rem" ( + l, r : UNRESOLVED_sfixed) -- fixed point input + return UNRESOLVED_sfixed is + begin + return remainder (l, r); + end function "rem"; + + -- ufixed (a downto b) rem ufixed (c downto d) + -- = ufixed (min(a,c) downto min(b,d)) + function remainder ( + l, r : UNRESOLVED_ufixed; -- fixed point input + constant round_style : fixed_round_style_type := fixed_round_style; + constant guard_bits : NATURAL := fixed_guard_bits) + return UNRESOLVED_ufixed is + variable result : UNRESOLVED_ufixed (minimum(l'high, r'high) downto + mine(l'low, r'low)); + variable lresize : UNRESOLVED_ufixed (maximum(l'high, r'low) downto + mins(r'low, r'low)-guard_bits); + variable rresize : UNRESOLVED_ufixed (r'high downto r'low-guard_bits); + variable dresult : UNRESOLVED_ufixed (rresize'range); + variable lslv : UNSIGNED (lresize'length-1 downto 0); + variable rslv : UNSIGNED (rresize'length-1 downto 0); + variable result_slv : UNSIGNED (rslv'range); + begin + if (l'length < 1 or r'length < 1 or + mins(r'low, r'low) /= r'low or mins(l'low, l'low) /= l'low) then + return NAUF; + end if; + lresize := resize (arg => l, + left_index => lresize'high, + right_index => lresize'low, + overflow_style => fixed_wrap, -- vector only grows + round_style => fixed_truncate); + lslv := to_uns (lresize); + rresize := resize (arg => r, + left_index => rresize'high, + right_index => rresize'low, + overflow_style => fixed_wrap, -- vector only grows + round_style => fixed_truncate); + rslv := to_uns (rresize); + if (rslv = 0) then + report fixed_pkg'instance_name + & "remainder(ufixed) Division by zero" severity error; + result := saturate (result'high, result'low); -- saturate + else + if (r'low <= l'high) then + result_slv := lslv rem rslv; + dresult := to_fixed (result_slv, dresult'high, dresult'low); + result := resize (arg => dresult, + left_index => result'high, + right_index => result'low, + overflow_style => fixed_wrap, -- can't overflow + round_style => round_style); + end if; + if l'low < r'low then + result(mins(r'low-1, l'high) downto l'low) := + cleanvec(l(mins(r'low-1, l'high) downto l'low)); + end if; + end if; + return result; + end function remainder; + + -- remainder + -- sfixed (a downto b) rem sfixed (c downto d) + -- = sfixed (min(a,c) downto min(b,d)) + function remainder ( + l, r : UNRESOLVED_sfixed; -- fixed point input + constant round_style : fixed_round_style_type := fixed_round_style; + constant guard_bits : NATURAL := fixed_guard_bits) + return UNRESOLVED_sfixed is + variable l_abs : UNRESOLVED_ufixed (l'range); + variable r_abs : UNRESOLVED_ufixed (r'range); + variable result : UNRESOLVED_sfixed (minimum(r'high, l'high) downto + mine(r'low, l'low)); + variable neg_result : UNRESOLVED_sfixed (minimum(r'high, l'high)+1 downto + mins(r'low, l'low)); + begin + if (l'length < 1 or r'length < 1 or + mins(r'low, r'low) /= r'low or mins(l'low, l'low) /= l'low) then + return NASF; + end if; + l_abs := to_ufixed (l); + r_abs := to_ufixed (r); + result := UNRESOLVED_sfixed (remainder ( + l => l_abs, + r => r_abs, + round_style => round_style)); + neg_result := -result; + if l(l'high) = '1' then + result := neg_result(result'range); + end if; + return result; + end function remainder; + + -- modulo + -- ufixed (a downto b) mod ufixed (c downto d) + -- = ufixed (min(a,c) downto min(b, d)) + function "mod" ( + l, r : UNRESOLVED_ufixed) -- fixed point input + return UNRESOLVED_ufixed is + begin + return modulo (l, r); + end function "mod"; + + -- sfixed (a downto b) mod sfixed (c downto d) + -- = sfixed (c downto min(b, d)) + function "mod" ( + l, r : UNRESOLVED_sfixed) -- fixed point input + return UNRESOLVED_sfixed is + begin + return modulo(l, r); + end function "mod"; + + -- modulo + -- ufixed (a downto b) mod ufixed (c downto d) + -- = ufixed (min(a,c) downto min(b, d)) + function modulo ( + l, r : UNRESOLVED_ufixed; -- fixed point input + constant round_style : fixed_round_style_type := fixed_round_style; + constant guard_bits : NATURAL := fixed_guard_bits) + return UNRESOLVED_ufixed is + begin + return remainder(l => l, + r => r, + round_style => round_style, + guard_bits => guard_bits); + end function modulo; + + -- sfixed (a downto b) mod sfixed (c downto d) + -- = sfixed (c downto min(b, d)) + function modulo ( + l, r : UNRESOLVED_sfixed; -- fixed point input + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style; + constant guard_bits : NATURAL := fixed_guard_bits) + return UNRESOLVED_sfixed is + variable l_abs : UNRESOLVED_ufixed (l'range); + variable r_abs : UNRESOLVED_ufixed (r'range); + variable result : UNRESOLVED_sfixed (r'high downto + mine(r'low, l'low)); + variable dresult : UNRESOLVED_sfixed (minimum(r'high, l'high)+1 downto + mins(r'low, l'low)); + variable dresult_not_zero : BOOLEAN; + begin + if (l'length < 1 or r'length < 1 or + mins(r'low, r'low) /= r'low or mins(l'low, l'low) /= l'low) then + return NASF; + end if; + l_abs := to_ufixed (l); + r_abs := to_ufixed (r); + dresult := "0" & UNRESOLVED_sfixed(remainder (l => l_abs, + r => r_abs, + round_style => round_style)); + if (to_s(dresult) = 0) then + dresult_not_zero := false; + else + dresult_not_zero := true; + end if; + if to_x01(l(l'high)) = '1' and to_x01(r(r'high)) = '0' + and dresult_not_zero then + result := resize (arg => r - dresult, + left_index => result'high, + right_index => result'low, + overflow_style => overflow_style, + round_style => round_style); + elsif to_x01(l(l'high)) = '1' and to_x01(r(r'high)) = '1' then + result := resize (arg => -dresult, + left_index => result'high, + right_index => result'low, + overflow_style => overflow_style, + round_style => round_style); + elsif to_x01(l(l'high)) = '0' and to_x01(r(r'high)) = '1' + and dresult_not_zero then + result := resize (arg => dresult + r, + left_index => result'high, + right_index => result'low, + overflow_style => overflow_style, + round_style => round_style); + else + result := resize (arg => dresult, + left_index => result'high, + right_index => result'low, + overflow_style => overflow_style, + round_style => round_style); + end if; + return result; + end function modulo; + + -- Procedure for those who need an "accumulator" function + procedure add_carry ( + L, R : in UNRESOLVED_ufixed; + c_in : in STD_ULOGIC; + result : out UNRESOLVED_ufixed; + c_out : out STD_ULOGIC) is + constant left_index : INTEGER := maximum(l'high, r'high)+1; + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_ufixed (left_index downto right_index); + variable lslv, rslv : UNSIGNED (left_index-right_index + downto 0); + variable result_slv : UNSIGNED (left_index-right_index + downto 0); + variable cx : UNSIGNED (0 downto 0); -- Carry in + begin + if (l'length < 1 or r'length < 1) then + result := NAUF; + c_out := '0'; + else + cx (0) := c_in; + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_uns (lresize); + rslv := to_uns (rresize); + result_slv := lslv + rslv + cx; + c_out := result_slv(left_index-right_index); + result := to_fixed(result_slv (left_index-right_index-1 downto 0), + left_index-1, right_index); + end if; + end procedure add_carry; + + procedure add_carry ( + L, R : in UNRESOLVED_sfixed; + c_in : in STD_ULOGIC; + result : out UNRESOLVED_sfixed; + c_out : out STD_ULOGIC) is + constant left_index : INTEGER := maximum(l'high, r'high)+1; + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_sfixed (left_index downto right_index); + variable lslv, rslv : SIGNED (left_index-right_index + downto 0); + variable result_slv : SIGNED (left_index-right_index + downto 0); + variable cx : SIGNED (1 downto 0); -- Carry in + begin + if (l'length < 1 or r'length < 1) then + result := NASF; + c_out := '0'; + else + cx (1) := '0'; + cx (0) := c_in; + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_s (lresize); + rslv := to_s (rresize); + result_slv := lslv + rslv + cx; + c_out := result_slv(left_index-right_index); + result := to_fixed(result_slv (left_index-right_index-1 downto 0), + left_index-1, right_index); + end if; + end procedure add_carry; + + -- Scales the result by a power of 2. Width of input = width of output with + -- the decimal point moved. + function scalb (y : UNRESOLVED_ufixed; N : INTEGER) + return UNRESOLVED_ufixed is + variable result : UNRESOLVED_ufixed (y'high+N downto y'low+N); + begin + if y'length < 1 then + return NAUF; + else + result := y; + return result; + end if; + end function scalb; + + function scalb (y : UNRESOLVED_ufixed; N : SIGNED) + return UNRESOLVED_ufixed is + begin + return scalb (y => y, + N => to_integer(N)); + end function scalb; + + function scalb (y : UNRESOLVED_sfixed; N : INTEGER) + return UNRESOLVED_sfixed is + variable result : UNRESOLVED_sfixed (y'high+N downto y'low+N); + begin + if y'length < 1 then + return NASF; + else + result := y; + return result; + end if; + end function scalb; + + function scalb (y : UNRESOLVED_sfixed; N : SIGNED) + return UNRESOLVED_sfixed is + begin + return scalb (y => y, + N => to_integer(N)); + end function scalb; + + function Is_Negative (arg : UNRESOLVED_sfixed) return BOOLEAN is + begin + if to_X01(arg(arg'high)) = '1' then + return true; + else + return false; + end if; + end function Is_Negative; + + function find_rightmost (arg : UNRESOLVED_ufixed; y : STD_ULOGIC) + return INTEGER is + begin + for_loop : for i in arg'reverse_range loop + if \?=\ (arg(i), y) = '1' then + return i; + end if; + end loop; + return arg'high+1; -- return out of bounds 'high + end function find_rightmost; + + function find_leftmost (arg : UNRESOLVED_ufixed; y : STD_ULOGIC) + return INTEGER is + begin + for_loop : for i in arg'range loop + if \?=\ (arg(i), y) = '1' then + return i; + end if; + end loop; + return arg'low-1; -- return out of bounds 'low + end function find_leftmost; + + function find_rightmost (arg : UNRESOLVED_sfixed; y : STD_ULOGIC) + return INTEGER is + begin + for_loop : for i in arg'reverse_range loop + if \?=\ (arg(i), y) = '1' then + return i; + end if; + end loop; + return arg'high+1; -- return out of bounds 'high + end function find_rightmost; + + function find_leftmost (arg : UNRESOLVED_sfixed; y : STD_ULOGIC) + return INTEGER is + begin + for_loop : for i in arg'range loop + if \?=\ (arg(i), y) = '1' then + return i; + end if; + end loop; + return arg'low-1; -- return out of bounds 'low + end function find_leftmost; + + function "sll" (ARG : UNRESOLVED_ufixed; COUNT : INTEGER) + return UNRESOLVED_ufixed is + variable argslv : UNSIGNED (arg'length-1 downto 0); + variable result : UNRESOLVED_ufixed (arg'range); + begin + argslv := to_uns (arg); + argslv := argslv sll COUNT; + result := to_fixed (argslv, result'high, result'low); + return result; + end function "sll"; + + function "srl" (ARG : UNRESOLVED_ufixed; COUNT : INTEGER) + return UNRESOLVED_ufixed is + variable argslv : UNSIGNED (arg'length-1 downto 0); + variable result : UNRESOLVED_ufixed (arg'range); + begin + argslv := to_uns (arg); + argslv := argslv srl COUNT; + result := to_fixed (argslv, result'high, result'low); + return result; + end function "srl"; + + function "rol" (ARG : UNRESOLVED_ufixed; COUNT : INTEGER) + return UNRESOLVED_ufixed is + variable argslv : UNSIGNED (arg'length-1 downto 0); + variable result : UNRESOLVED_ufixed (arg'range); + begin + argslv := to_uns (arg); + argslv := argslv rol COUNT; + result := to_fixed (argslv, result'high, result'low); + return result; + end function "rol"; + + function "ror" (ARG : UNRESOLVED_ufixed; COUNT : INTEGER) + return UNRESOLVED_ufixed is + variable argslv : UNSIGNED (arg'length-1 downto 0); + variable result : UNRESOLVED_ufixed (arg'range); + begin + argslv := to_uns (arg); + argslv := argslv ror COUNT; + result := to_fixed (argslv, result'high, result'low); + return result; + end function "ror"; + + function "sla" (ARG : UNRESOLVED_ufixed; COUNT : INTEGER) + return UNRESOLVED_ufixed is + variable argslv : UNSIGNED (arg'length-1 downto 0); + variable result : UNRESOLVED_ufixed (arg'range); + begin + argslv := to_uns (arg); + -- Arithmetic shift on an unsigned is a logical shift + argslv := argslv sll COUNT; + result := to_fixed (argslv, result'high, result'low); + return result; + end function "sla"; + + function "sra" (ARG : UNRESOLVED_ufixed; COUNT : INTEGER) + return UNRESOLVED_ufixed is + variable argslv : UNSIGNED (arg'length-1 downto 0); + variable result : UNRESOLVED_ufixed (arg'range); + begin + argslv := to_uns (arg); + -- Arithmetic shift on an unsigned is a logical shift + argslv := argslv srl COUNT; + result := to_fixed (argslv, result'high, result'low); + return result; + end function "sra"; + + function "sll" (ARG : UNRESOLVED_sfixed; COUNT : INTEGER) + return UNRESOLVED_sfixed is + variable argslv : SIGNED (arg'length-1 downto 0); + variable result : UNRESOLVED_sfixed (arg'range); + begin + argslv := to_s (arg); + argslv := argslv sll COUNT; + result := to_fixed (argslv, result'high, result'low); + return result; + end function "sll"; + + function "srl" (ARG : UNRESOLVED_sfixed; COUNT : INTEGER) + return UNRESOLVED_sfixed is + variable argslv : SIGNED (arg'length-1 downto 0); + variable result : UNRESOLVED_sfixed (arg'range); + begin + argslv := to_s (arg); + argslv := argslv srl COUNT; + result := to_fixed (argslv, result'high, result'low); + return result; + end function "srl"; + + function "rol" (ARG : UNRESOLVED_sfixed; COUNT : INTEGER) + return UNRESOLVED_sfixed is + variable argslv : SIGNED (arg'length-1 downto 0); + variable result : UNRESOLVED_sfixed (arg'range); + begin + argslv := to_s (arg); + argslv := argslv rol COUNT; + result := to_fixed (argslv, result'high, result'low); + return result; + end function "rol"; + + function "ror" (ARG : UNRESOLVED_sfixed; COUNT : INTEGER) + return UNRESOLVED_sfixed is + variable argslv : SIGNED (arg'length-1 downto 0); + variable result : UNRESOLVED_sfixed (arg'range); + begin + argslv := to_s (arg); + argslv := argslv ror COUNT; + result := to_fixed (argslv, result'high, result'low); + return result; + end function "ror"; + + function "sla" (ARG : UNRESOLVED_sfixed; COUNT : INTEGER) + return UNRESOLVED_sfixed is + variable argslv : SIGNED (arg'length-1 downto 0); + variable result : UNRESOLVED_sfixed (arg'range); + begin + argslv := to_s (arg); + if COUNT > 0 then + -- Arithmetic shift left on a 2's complement number is a logic shift + argslv := argslv sll COUNT; + else + argslv := argslv sra -COUNT; + end if; + result := to_fixed (argslv, result'high, result'low); + return result; + end function "sla"; + + function "sra" (ARG : UNRESOLVED_sfixed; COUNT : INTEGER) + return UNRESOLVED_sfixed is + variable argslv : SIGNED (arg'length-1 downto 0); + variable result : UNRESOLVED_sfixed (arg'range); + begin + argslv := to_s (arg); + if COUNT > 0 then + argslv := argslv sra COUNT; + else + -- Arithmetic shift left on a 2's complement number is a logic shift + argslv := argslv sll -COUNT; + end if; + result := to_fixed (argslv, result'high, result'low); + return result; + end function "sra"; + + -- Because some people want the older functions. + function SHIFT_LEFT (ARG : UNRESOLVED_ufixed; COUNT : NATURAL) + return UNRESOLVED_ufixed is + begin + if (ARG'length < 1) then + return NAUF; + end if; + return ARG sla COUNT; + end function SHIFT_LEFT; + + function SHIFT_RIGHT (ARG : UNRESOLVED_ufixed; COUNT : NATURAL) + return UNRESOLVED_ufixed is + begin + if (ARG'length < 1) then + return NAUF; + end if; + return ARG sra COUNT; + end function SHIFT_RIGHT; + + function SHIFT_LEFT (ARG : UNRESOLVED_sfixed; COUNT : NATURAL) + return UNRESOLVED_sfixed is + begin + if (ARG'length < 1) then + return NASF; + end if; + return ARG sla COUNT; + end function SHIFT_LEFT; + + function SHIFT_RIGHT (ARG : UNRESOLVED_sfixed; COUNT : NATURAL) + return UNRESOLVED_sfixed is + begin + if (ARG'length < 1) then + return NASF; + end if; + return ARG sra COUNT; + end function SHIFT_RIGHT; + + ---------------------------------------------------------------------------- + -- logical functions + ---------------------------------------------------------------------------- + function "not" (L : UNRESOLVED_ufixed) return UNRESOLVED_ufixed is + variable RESULT : STD_ULOGIC_VECTOR(L'length-1 downto 0); -- force downto + begin + RESULT := not to_sulv(L); + return to_ufixed(RESULT, L'high, L'low); + end function "not"; + + function "and" (L, R : UNRESOLVED_ufixed) return UNRESOLVED_ufixed is + variable RESULT : STD_ULOGIC_VECTOR(L'length-1 downto 0); -- force downto + begin + if (L'high = R'high and L'low = R'low) then + RESULT := to_sulv(L) and to_sulv(R); + else + assert NO_WARNING + report fixed_pkg'instance_name + & """and"": Range error L'RANGE /= R'RANGE" + severity warning; + RESULT := (others => 'X'); + end if; + return to_ufixed(RESULT, L'high, L'low); + end function "and"; + + function "or" (L, R : UNRESOLVED_ufixed) return UNRESOLVED_ufixed is + variable RESULT : STD_ULOGIC_VECTOR(L'length-1 downto 0); -- force downto + begin + if (L'high = R'high and L'low = R'low) then + RESULT := to_sulv(L) or to_sulv(R); + else + assert NO_WARNING + report fixed_pkg'instance_name + & """or"": Range error L'RANGE /= R'RANGE" + severity warning; + RESULT := (others => 'X'); + end if; + return to_ufixed(RESULT, L'high, L'low); + end function "or"; + + function "nand" (L, R : UNRESOLVED_ufixed) return UNRESOLVED_ufixed is + variable RESULT : STD_ULOGIC_VECTOR(L'length-1 downto 0); -- force downto + begin + if (L'high = R'high and L'low = R'low) then + RESULT := to_sulv(L) nand to_sulv(R); + else + assert NO_WARNING + report fixed_pkg'instance_name + & """nand"": Range error L'RANGE /= R'RANGE" + severity warning; + RESULT := (others => 'X'); + end if; + return to_ufixed(RESULT, L'high, L'low); + end function "nand"; + + function "nor" (L, R : UNRESOLVED_ufixed) return UNRESOLVED_ufixed is + variable RESULT : STD_ULOGIC_VECTOR(L'length-1 downto 0); -- force downto + begin + if (L'high = R'high and L'low = R'low) then + RESULT := to_sulv(L) nor to_sulv(R); + else + assert NO_WARNING + report fixed_pkg'instance_name + & """nor"": Range error L'RANGE /= R'RANGE" + severity warning; + RESULT := (others => 'X'); + end if; + return to_ufixed(RESULT, L'high, L'low); + end function "nor"; + + function "xor" (L, R : UNRESOLVED_ufixed) return UNRESOLVED_ufixed is + variable RESULT : STD_ULOGIC_VECTOR(L'length-1 downto 0); -- force downto + begin + if (L'high = R'high and L'low = R'low) then + RESULT := to_sulv(L) xor to_sulv(R); + else + assert NO_WARNING + report fixed_pkg'instance_name + & """xor"": Range error L'RANGE /= R'RANGE" + severity warning; + RESULT := (others => 'X'); + end if; + return to_ufixed(RESULT, L'high, L'low); + end function "xor"; + + function "xnor" (L, R : UNRESOLVED_ufixed) return UNRESOLVED_ufixed is + variable RESULT : STD_ULOGIC_VECTOR(L'length-1 downto 0); -- force downto + begin + if (L'high = R'high and L'low = R'low) then + RESULT := to_sulv(L) xnor to_sulv(R); + else + assert NO_WARNING + report fixed_pkg'instance_name + & """xnor"": Range error L'RANGE /= R'RANGE" + severity warning; + RESULT := (others => 'X'); + end if; + return to_ufixed(RESULT, L'high, L'low); + end function "xnor"; + + function "not" (L : UNRESOLVED_sfixed) return UNRESOLVED_sfixed is + variable RESULT : STD_ULOGIC_VECTOR(L'length-1 downto 0); -- force downto + begin + RESULT := not to_sulv(L); + return to_sfixed(RESULT, L'high, L'low); + end function "not"; + + function "and" (L, R : UNRESOLVED_sfixed) return UNRESOLVED_sfixed is + variable RESULT : STD_ULOGIC_VECTOR(L'length-1 downto 0); -- force downto + begin + if (L'high = R'high and L'low = R'low) then + RESULT := to_sulv(L) and to_sulv(R); + else + assert NO_WARNING + report fixed_pkg'instance_name + & """and"": Range error L'RANGE /= R'RANGE" + severity warning; + RESULT := (others => 'X'); + end if; + return to_sfixed(RESULT, L'high, L'low); + end function "and"; + + function "or" (L, R : UNRESOLVED_sfixed) return UNRESOLVED_sfixed is + variable RESULT : STD_ULOGIC_VECTOR(L'length-1 downto 0); -- force downto + begin + if (L'high = R'high and L'low = R'low) then + RESULT := to_sulv(L) or to_sulv(R); + else + assert NO_WARNING + report fixed_pkg'instance_name + & """or"": Range error L'RANGE /= R'RANGE" + severity warning; + RESULT := (others => 'X'); + end if; + return to_sfixed(RESULT, L'high, L'low); + end function "or"; + + function "nand" (L, R : UNRESOLVED_sfixed) return UNRESOLVED_sfixed is + variable RESULT : STD_ULOGIC_VECTOR(L'length-1 downto 0); -- force downto + begin + if (L'high = R'high and L'low = R'low) then + RESULT := to_sulv(L) nand to_sulv(R); + else + assert NO_WARNING + report fixed_pkg'instance_name + & """nand"": Range error L'RANGE /= R'RANGE" + severity warning; + RESULT := (others => 'X'); + end if; + return to_sfixed(RESULT, L'high, L'low); + end function "nand"; + + function "nor" (L, R : UNRESOLVED_sfixed) return UNRESOLVED_sfixed is + variable RESULT : STD_ULOGIC_VECTOR(L'length-1 downto 0); -- force downto + begin + if (L'high = R'high and L'low = R'low) then + RESULT := to_sulv(L) nor to_sulv(R); + else + assert NO_WARNING + report fixed_pkg'instance_name + & """nor"": Range error L'RANGE /= R'RANGE" + severity warning; + RESULT := (others => 'X'); + end if; + return to_sfixed(RESULT, L'high, L'low); + end function "nor"; + + function "xor" (L, R : UNRESOLVED_sfixed) return UNRESOLVED_sfixed is + variable RESULT : STD_ULOGIC_VECTOR(L'length-1 downto 0); -- force downto + begin + if (L'high = R'high and L'low = R'low) then + RESULT := to_sulv(L) xor to_sulv(R); + else + assert NO_WARNING + report fixed_pkg'instance_name + & """xor"": Range error L'RANGE /= R'RANGE" + severity warning; + RESULT := (others => 'X'); + end if; + return to_sfixed(RESULT, L'high, L'low); + end function "xor"; + + function "xnor" (L, R : UNRESOLVED_sfixed) return UNRESOLVED_sfixed is + variable RESULT : STD_ULOGIC_VECTOR(L'length-1 downto 0); -- force downto + begin + if (L'high = R'high and L'low = R'low) then + RESULT := to_sulv(L) xnor to_sulv(R); + else + assert NO_WARNING + report fixed_pkg'instance_name + & """xnor"": Range error L'RANGE /= R'RANGE" + severity warning; + RESULT := (others => 'X'); + end if; + return to_sfixed(RESULT, L'high, L'low); + end function "xnor"; + + -- Vector and std_ulogic functions, same as functions in numeric_std + function "and" (L : STD_ULOGIC; R : UNRESOLVED_ufixed) + return UNRESOLVED_ufixed is + variable result : UNRESOLVED_ufixed (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 : UNRESOLVED_ufixed; R : STD_ULOGIC) + return UNRESOLVED_ufixed is + variable result : UNRESOLVED_ufixed (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 : UNRESOLVED_ufixed) + return UNRESOLVED_ufixed is + variable result : UNRESOLVED_ufixed (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 : UNRESOLVED_ufixed; R : STD_ULOGIC) + return UNRESOLVED_ufixed is + variable result : UNRESOLVED_ufixed (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 : UNRESOLVED_ufixed) + return UNRESOLVED_ufixed is + variable result : UNRESOLVED_ufixed (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 : UNRESOLVED_ufixed; R : STD_ULOGIC) + return UNRESOLVED_ufixed is + variable result : UNRESOLVED_ufixed (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 : UNRESOLVED_ufixed) + return UNRESOLVED_ufixed is + variable result : UNRESOLVED_ufixed (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 : UNRESOLVED_ufixed; R : STD_ULOGIC) + return UNRESOLVED_ufixed is + variable result : UNRESOLVED_ufixed (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 : UNRESOLVED_ufixed) + return UNRESOLVED_ufixed is + variable result : UNRESOLVED_ufixed (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 : UNRESOLVED_ufixed; R : STD_ULOGIC) + return UNRESOLVED_ufixed is + variable result : UNRESOLVED_ufixed (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 : UNRESOLVED_ufixed) + return UNRESOLVED_ufixed is + variable result : UNRESOLVED_ufixed (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 : UNRESOLVED_ufixed; R : STD_ULOGIC) + return UNRESOLVED_ufixed is + variable result : UNRESOLVED_ufixed (L'range); + begin + for i in result'range loop + result(i) := L(i) xnor R; + end loop; + return result; + end function "xnor"; + + function "and" (L : STD_ULOGIC; R : UNRESOLVED_sfixed) + return UNRESOLVED_sfixed is + variable result : UNRESOLVED_sfixed (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 : UNRESOLVED_sfixed; R : STD_ULOGIC) + return UNRESOLVED_sfixed is + variable result : UNRESOLVED_sfixed (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 : UNRESOLVED_sfixed) + return UNRESOLVED_sfixed is + variable result : UNRESOLVED_sfixed (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 : UNRESOLVED_sfixed; R : STD_ULOGIC) + return UNRESOLVED_sfixed is + variable result : UNRESOLVED_sfixed (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 : UNRESOLVED_sfixed) + return UNRESOLVED_sfixed is + variable result : UNRESOLVED_sfixed (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 : UNRESOLVED_sfixed; R : STD_ULOGIC) + return UNRESOLVED_sfixed is + variable result : UNRESOLVED_sfixed (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 : UNRESOLVED_sfixed) + return UNRESOLVED_sfixed is + variable result : UNRESOLVED_sfixed (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 : UNRESOLVED_sfixed; R : STD_ULOGIC) + return UNRESOLVED_sfixed is + variable result : UNRESOLVED_sfixed (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 : UNRESOLVED_sfixed) + return UNRESOLVED_sfixed is + variable result : UNRESOLVED_sfixed (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 : UNRESOLVED_sfixed; R : STD_ULOGIC) + return UNRESOLVED_sfixed is + variable result : UNRESOLVED_sfixed (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 : UNRESOLVED_sfixed) + return UNRESOLVED_sfixed is + variable result : UNRESOLVED_sfixed (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 : UNRESOLVED_sfixed; R : STD_ULOGIC) + return UNRESOLVED_sfixed is + variable result : UNRESOLVED_sfixed (L'range); + begin + for i in result'range loop + result(i) := L(i) xnor R; + end loop; + return result; + end function "xnor"; + + -- Reduction operator_reduces + function and_reduce (l : UNRESOLVED_ufixed) return STD_ULOGIC is + begin + return and_reduce (to_sulv(l)); + end function and_reduce; + + function nand_reduce (l : UNRESOLVED_ufixed) return STD_ULOGIC is + begin + return nand_reduce (to_sulv(l)); + end function nand_reduce; + + function or_reduce (l : UNRESOLVED_ufixed) return STD_ULOGIC is + begin + return or_reduce (to_sulv(l)); + end function or_reduce; + + function nor_reduce (l : UNRESOLVED_ufixed) return STD_ULOGIC is + begin + return nor_reduce (to_sulv(l)); + end function nor_reduce; + + function xor_reduce (l : UNRESOLVED_ufixed) return STD_ULOGIC is + begin + return xor_reduce (to_sulv(l)); + end function xor_reduce; + + function xnor_reduce (l : UNRESOLVED_ufixed) return STD_ULOGIC is + begin + return xnor_reduce (to_sulv(l)); + end function xnor_reduce; + + function and_reduce (l : UNRESOLVED_sfixed) return STD_ULOGIC is + begin + return and_reduce (to_sulv(l)); + end function and_reduce; + + function nand_reduce (l : UNRESOLVED_sfixed) return STD_ULOGIC is + begin + return nand_reduce (to_sulv(l)); + end function nand_reduce; + + function or_reduce (l : UNRESOLVED_sfixed) return STD_ULOGIC is + begin + return or_reduce (to_sulv(l)); + end function or_reduce; + + function nor_reduce (l : UNRESOLVED_sfixed) return STD_ULOGIC is + begin + return nor_reduce (to_sulv(l)); + end function nor_reduce; + + function xor_reduce (l : UNRESOLVED_sfixed) return STD_ULOGIC is + begin + return xor_reduce (to_sulv(l)); + end function xor_reduce; + + function xnor_reduce (l : UNRESOLVED_sfixed) return STD_ULOGIC is + begin + return xnor_reduce (to_sulv(l)); + end function xnor_reduce; + -- End reduction operator_reduces + + function \?=\ (L, R : UNRESOLVED_ufixed) return STD_ULOGIC is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_ufixed (left_index downto right_index); + variable lslv, rslv : UNSIGNED (lresize'length-1 downto 0); + begin -- ?= + if ((L'length < 1) or (R'length < 1)) then + assert NO_WARNING + report fixed_pkg'instance_name + & """?="": null detected, returning X" + severity warning; + return 'X'; + else + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_uns (lresize); + rslv := to_uns (rresize); + return \?=\ (lslv, rslv); + end if; + end function \?=\; + + function \?/=\ (L, R : UNRESOLVED_ufixed) return STD_ULOGIC is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_ufixed (left_index downto right_index); + variable lslv, rslv : UNSIGNED (lresize'length-1 downto 0); + begin -- ?/= + if ((L'length < 1) or (R'length < 1)) then + assert NO_WARNING + report fixed_pkg'instance_name + & """?/="": null detected, returning X" + severity warning; + return 'X'; + else + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_uns (lresize); + rslv := to_uns (rresize); + return \?/=\ (lslv, rslv); + end if; + end function \?/=\; + + function \?>\ (L, R : UNRESOLVED_ufixed) return STD_ULOGIC is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_ufixed (left_index downto right_index); + variable lslv, rslv : UNSIGNED (lresize'length-1 downto 0); + begin -- ?> + if ((l'length < 1) or (r'length < 1)) then + assert NO_WARNING + report fixed_pkg'instance_name + & """?>"": null detected, returning X" + severity warning; + return 'X'; + else + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_uns (lresize); + rslv := to_uns (rresize); + return \?>\ (lslv, rslv); + end if; + end function \?>\; + + function \?>=\ (L, R : UNRESOLVED_ufixed) return STD_ULOGIC is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_ufixed (left_index downto right_index); + variable lslv, rslv : UNSIGNED (lresize'length-1 downto 0); + begin -- ?>= + if ((l'length < 1) or (r'length < 1)) then + assert NO_WARNING + report fixed_pkg'instance_name + & """?>="": null detected, returning X" + severity warning; + return 'X'; + else + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_uns (lresize); + rslv := to_uns (rresize); + return \?>=\ (lslv, rslv); + end if; + end function \?>=\; + + function \?<\ (L, R : UNRESOLVED_ufixed) return STD_ULOGIC is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_ufixed (left_index downto right_index); + variable lslv, rslv : UNSIGNED (lresize'length-1 downto 0); + begin -- ?< + if ((l'length < 1) or (r'length < 1)) then + assert NO_WARNING + report fixed_pkg'instance_name + & """?<"": null detected, returning X" + severity warning; + return 'X'; + else + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_uns (lresize); + rslv := to_uns (rresize); + return \?<\ (lslv, rslv); + end if; + end function \?<\; + + function \?<=\ (L, R : UNRESOLVED_ufixed) return STD_ULOGIC is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_ufixed (left_index downto right_index); + variable lslv, rslv : UNSIGNED (lresize'length-1 downto 0); + begin -- ?<= + if ((l'length < 1) or (r'length < 1)) then + assert NO_WARNING + report fixed_pkg'instance_name + & """?<="": null detected, returning X" + severity warning; + return 'X'; + else + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_uns (lresize); + rslv := to_uns (rresize); + return \?<=\ (lslv, rslv); + end if; + end function \?<=\; + + function \?=\ (L, R : UNRESOLVED_sfixed) return STD_ULOGIC is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_sfixed (left_index downto right_index); + variable lslv, rslv : SIGNED (lresize'length-1 downto 0); + begin -- ?= + if ((L'length < 1) or (R'length < 1)) then + assert NO_WARNING + report fixed_pkg'instance_name + & """?="": null detected, returning X" + severity warning; + return 'X'; + else + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_s (lresize); + rslv := to_s (rresize); + return \?=\ (lslv, rslv); + end if; + end function \?=\; + + function \?/=\ (L, R : UNRESOLVED_sfixed) return STD_ULOGIC is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_sfixed (left_index downto right_index); + variable lslv, rslv : SIGNED (lresize'length-1 downto 0); + begin -- ?/= + if ((L'length < 1) or (R'length < 1)) then + assert NO_WARNING + report fixed_pkg'instance_name + & """?/="": null detected, returning X" + severity warning; + return 'X'; + else + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_s (lresize); + rslv := to_s (rresize); + return \?/=\ (lslv, rslv); + end if; + end function \?/=\; + + function \?>\ (L, R : UNRESOLVED_sfixed) return STD_ULOGIC is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_sfixed (left_index downto right_index); + variable lslv, rslv : SIGNED (lresize'length-1 downto 0); + begin -- ?> + if ((l'length < 1) or (r'length < 1)) then + assert NO_WARNING + report fixed_pkg'instance_name + & """?>"": null detected, returning X" + severity warning; + return 'X'; + else + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_s (lresize); + rslv := to_s (rresize); + return \?>\ (lslv, rslv); + end if; + end function \?>\; + + function \?>=\ (L, R : UNRESOLVED_sfixed) return STD_ULOGIC is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_sfixed (left_index downto right_index); + variable lslv, rslv : SIGNED (lresize'length-1 downto 0); + begin -- ?>= + if ((l'length < 1) or (r'length < 1)) then + assert NO_WARNING + report fixed_pkg'instance_name + & """?>="": null detected, returning X" + severity warning; + return 'X'; + else + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_s (lresize); + rslv := to_s (rresize); + return \?>=\ (lslv, rslv); + end if; + end function \?>=\; + + function \?<\ (L, R : UNRESOLVED_sfixed) return STD_ULOGIC is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_sfixed (left_index downto right_index); + variable lslv, rslv : SIGNED (lresize'length-1 downto 0); + begin -- ?< + if ((l'length < 1) or (r'length < 1)) then + assert NO_WARNING + report fixed_pkg'instance_name + & """?<"": null detected, returning X" + severity warning; + return 'X'; + else + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_s (lresize); + rslv := to_s (rresize); + return \?<\ (lslv, rslv); + end if; + end function \?<\; + + function \?<=\ (L, R : UNRESOLVED_sfixed) return STD_ULOGIC is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_sfixed (left_index downto right_index); + variable lslv, rslv : SIGNED (lresize'length-1 downto 0); + begin -- ?<= + if ((l'length < 1) or (r'length < 1)) then + assert NO_WARNING + report fixed_pkg'instance_name + & """?<="": null detected, returning X" + severity warning; + return 'X'; + else + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_s (lresize); + rslv := to_s (rresize); + return \?<=\ (lslv, rslv); + end if; + end function \?<=\; + + -- Match function, similar to "std_match" from numeric_std + function std_match (L, R : UNRESOLVED_ufixed) return BOOLEAN is + begin + if (L'high = R'high and L'low = R'low) then + return std_match(to_sulv(L), to_sulv(R)); + else + assert NO_WARNING + report fixed_pkg'instance_name + & "STD_MATCH: L'RANGE /= R'RANGE, returning FALSE" + severity warning; + return false; + end if; + end function std_match; + + function std_match (L, R : UNRESOLVED_sfixed) return BOOLEAN is + begin + if (L'high = R'high and L'low = R'low) then + return std_match(to_sulv(L), to_sulv(R)); + else + assert NO_WARNING + report fixed_pkg'instance_name + & "STD_MATCH: L'RANGE /= R'RANGE, returning FALSE" + severity warning; + return false; + end if; + end function std_match; + + -- compare functions + function "=" ( + l, r : UNRESOLVED_ufixed) -- fixed point input + return BOOLEAN is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_ufixed (left_index downto right_index); + variable lslv, rslv : UNSIGNED (lresize'length-1 downto 0); + begin + if (l'length < 1 or r'length < 1) then + assert NO_WARNING + report fixed_pkg'instance_name + & """="": null argument detected, returning FALSE" + severity warning; + return false; + elsif (Is_X(l) or Is_X(r)) then + assert NO_WARNING + report fixed_pkg'instance_name + & """="": metavalue detected, returning FALSE" + severity warning; + return false; + end if; + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_uns (lresize); + rslv := to_uns (rresize); + return lslv = rslv; + end function "="; + + function "=" ( + l, r : UNRESOLVED_sfixed) -- fixed point input + return BOOLEAN is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_sfixed (left_index downto right_index); + variable lslv, rslv : SIGNED (lresize'length-1 downto 0); + begin + if (l'length < 1 or r'length < 1) then + assert NO_WARNING + report fixed_pkg'instance_name + & """="": null argument detected, returning FALSE" + severity warning; + return false; + elsif (Is_X(l) or Is_X(r)) then + assert NO_WARNING + report fixed_pkg'instance_name + & """="": metavalue detected, returning FALSE" + severity warning; + return false; + end if; + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_s (lresize); + rslv := to_s (rresize); + return lslv = rslv; + end function "="; + + function "/=" ( + l, r : UNRESOLVED_ufixed) -- fixed point input + return BOOLEAN is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_ufixed (left_index downto right_index); + variable lslv, rslv : UNSIGNED (lresize'length-1 downto 0); + begin + if (l'length < 1 or r'length < 1) then + assert NO_WARNING + report fixed_pkg'instance_name + & """/="": null argument detected, returning TRUE" + severity warning; + return true; + elsif (Is_X(l) or Is_X(r)) then + assert NO_WARNING + report fixed_pkg'instance_name + & """/="": metavalue detected, returning TRUE" + severity warning; + return true; + end if; + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_uns (lresize); + rslv := to_uns (rresize); + return lslv /= rslv; + end function "/="; + + function "/=" ( + l, r : UNRESOLVED_sfixed) -- fixed point input + return BOOLEAN is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_sfixed (left_index downto right_index); + variable lslv, rslv : SIGNED (lresize'length-1 downto 0); + begin + if (l'length < 1 or r'length < 1) then + assert NO_WARNING + report fixed_pkg'instance_name + & """/="": null argument detected, returning TRUE" + severity warning; + return true; + elsif (Is_X(l) or Is_X(r)) then + assert NO_WARNING + report fixed_pkg'instance_name + & """/="": metavalue detected, returning TRUE" + severity warning; + return true; + end if; + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_s (lresize); + rslv := to_s (rresize); + return lslv /= rslv; + end function "/="; + + function ">" ( + l, r : UNRESOLVED_ufixed) -- fixed point input + return BOOLEAN is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_ufixed (left_index downto right_index); + variable lslv, rslv : UNSIGNED (lresize'length-1 downto 0); + begin + if (l'length < 1 or r'length < 1) then + assert NO_WARNING + report fixed_pkg'instance_name + & """>"": null argument detected, returning FALSE" + severity warning; + return false; + elsif (Is_X(l) or Is_X(r)) then + assert NO_WARNING + report fixed_pkg'instance_name + & """>"": metavalue detected, returning FALSE" + severity warning; + return false; + end if; + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_uns (lresize); + rslv := to_uns (rresize); + return lslv > rslv; + end function ">"; + + function ">" ( + l, r : UNRESOLVED_sfixed) -- fixed point input + return BOOLEAN is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_sfixed (left_index downto right_index); + variable lslv, rslv : SIGNED (lresize'length-1 downto 0); + begin + if (l'length < 1 or r'length < 1) then + assert NO_WARNING + report fixed_pkg'instance_name + & """>"": null argument detected, returning FALSE" + severity warning; + return false; + elsif (Is_X(l) or Is_X(r)) then + assert NO_WARNING + report fixed_pkg'instance_name + & """>"": metavalue detected, returning FALSE" + severity warning; + return false; + end if; + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_s (lresize); + rslv := to_s (rresize); + return lslv > rslv; + end function ">"; + + function "<" ( + l, r : UNRESOLVED_ufixed) -- fixed point input + return BOOLEAN is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_ufixed (left_index downto right_index); + variable lslv, rslv : UNSIGNED (lresize'length-1 downto 0); + begin + if (l'length < 1 or r'length < 1) then + assert NO_WARNING + report fixed_pkg'instance_name + & """<"": null argument detected, returning FALSE" + severity warning; + return false; + elsif (Is_X(l) or Is_X(r)) then + assert NO_WARNING + report fixed_pkg'instance_name + & """<"": metavalue detected, returning FALSE" + severity warning; + return false; + end if; + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_uns (lresize); + rslv := to_uns (rresize); + return lslv < rslv; + end function "<"; + + function "<" ( + l, r : UNRESOLVED_sfixed) -- fixed point input + return BOOLEAN is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_sfixed (left_index downto right_index); + variable lslv, rslv : SIGNED (lresize'length-1 downto 0); + begin + if (l'length < 1 or r'length < 1) then + assert NO_WARNING + report fixed_pkg'instance_name + & """<"": null argument detected, returning FALSE" + severity warning; + return false; + elsif (Is_X(l) or Is_X(r)) then + assert NO_WARNING + report fixed_pkg'instance_name + & """<"": metavalue detected, returning FALSE" + severity warning; + return false; + end if; + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_s (lresize); + rslv := to_s (rresize); + return lslv < rslv; + end function "<"; + + function ">=" ( + l, r : UNRESOLVED_ufixed) -- fixed point input + return BOOLEAN is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_ufixed (left_index downto right_index); + variable lslv, rslv : UNSIGNED (lresize'length-1 downto 0); + begin + if (l'length < 1 or r'length < 1) then + assert NO_WARNING + report fixed_pkg'instance_name + & """>="": null argument detected, returning FALSE" + severity warning; + return false; + elsif (Is_X(l) or Is_X(r)) then + assert NO_WARNING + report fixed_pkg'instance_name + & """>="": metavalue detected, returning FALSE" + severity warning; + return false; + end if; + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_uns (lresize); + rslv := to_uns (rresize); + return lslv >= rslv; + end function ">="; + + function ">=" ( + l, r : UNRESOLVED_sfixed) -- fixed point input + return BOOLEAN is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_sfixed (left_index downto right_index); + variable lslv, rslv : SIGNED (lresize'length-1 downto 0); + begin + if (l'length < 1 or r'length < 1) then + assert NO_WARNING + report fixed_pkg'instance_name + & """>="": null argument detected, returning FALSE" + severity warning; + return false; + elsif (Is_X(l) or Is_X(r)) then + assert NO_WARNING + report fixed_pkg'instance_name + & """>="": metavalue detected, returning FALSE" + severity warning; + return false; + end if; + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_s (lresize); + rslv := to_s (rresize); + return lslv >= rslv; + end function ">="; + + function "<=" ( + l, r : UNRESOLVED_ufixed) -- fixed point input + return BOOLEAN is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_ufixed (left_index downto right_index); + variable lslv, rslv : UNSIGNED (lresize'length-1 downto 0); + begin + if (l'length < 1 or r'length < 1) then + assert NO_WARNING + report fixed_pkg'instance_name + & """<="": null argument detected, returning FALSE" + severity warning; + return false; + elsif (Is_X(l) or Is_X(r)) then + assert NO_WARNING + report fixed_pkg'instance_name + & """<="": metavalue detected, returning FALSE" + severity warning; + return false; + end if; + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_uns (lresize); + rslv := to_uns (rresize); + return lslv <= rslv; + end function "<="; + + function "<=" ( + l, r : UNRESOLVED_sfixed) -- fixed point input + return BOOLEAN is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_sfixed (left_index downto right_index); + variable lslv, rslv : SIGNED (lresize'length-1 downto 0); + begin + if (l'length < 1 or r'length < 1) then + assert NO_WARNING + report fixed_pkg'instance_name + & """<="": null argument detected, returning FALSE" + severity warning; + return false; + elsif (Is_X(l) or Is_X(r)) then + assert NO_WARNING + report fixed_pkg'instance_name + & """<="": metavalue detected, returning FALSE" + severity warning; + return false; + end if; + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + lslv := to_s (lresize); + rslv := to_s (rresize); + return lslv <= rslv; + end function "<="; + + -- overloads of the default maximum and minimum functions + function maximum (l, r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_ufixed (left_index downto right_index); + begin + if (l'length < 1 or r'length < 1) then + return NAUF; + end if; + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + if lresize > rresize then return lresize; + else return rresize; + end if; + end function maximum; + + function maximum (l, r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_sfixed (left_index downto right_index); + begin + if (l'length < 1 or r'length < 1) then + return NASF; + end if; + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + if lresize > rresize then return lresize; + else return rresize; + end if; + end function maximum; + + function minimum (l, r : UNRESOLVED_ufixed) return UNRESOLVED_ufixed is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_ufixed (left_index downto right_index); + begin + if (l'length < 1 or r'length < 1) then + return NAUF; + end if; + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + if lresize > rresize then return rresize; + else return lresize; + end if; + end function minimum; + + function minimum (l, r : UNRESOLVED_sfixed) return UNRESOLVED_sfixed is + constant left_index : INTEGER := maximum(l'high, r'high); + constant right_index : INTEGER := mins(l'low, r'low); + variable lresize, rresize : UNRESOLVED_sfixed (left_index downto right_index); + begin + if (l'length < 1 or r'length < 1) then + return NASF; + end if; + lresize := resize (l, left_index, right_index); + rresize := resize (r, left_index, right_index); + if lresize > rresize then return rresize; + else return lresize; + end if; + end function minimum; + + function to_ufixed ( + arg : NATURAL; -- integer + constant left_index : INTEGER; -- left index (high index) + constant right_index : INTEGER := 0; -- right index + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNRESOLVED_ufixed is + constant fw : INTEGER := mins (right_index, right_index); -- catch literals + variable result : UNRESOLVED_ufixed (left_index downto fw); + variable sresult : UNRESOLVED_ufixed (left_index downto 0) := + (others => '0'); -- integer portion + variable argx : NATURAL; -- internal version of arg + begin + if (result'length < 1) then + return NAUF; + end if; + if arg /= 0 then + argx := arg; + for I in 0 to sresult'left loop + if (argx mod 2) = 0 then + sresult(I) := '0'; + else + sresult(I) := '1'; + end if; + argx := argx/2; + end loop; + if argx /= 0 then + assert NO_WARNING + report fixed_pkg'instance_name + & "TO_UFIXED(NATURAL): vector truncated" + severity warning; + if overflow_style = fixed_saturate then + return saturate (left_index, right_index); + end if; + end if; + result := resize (arg => sresult, + left_index => left_index, + right_index => right_index, + round_style => round_style, + overflow_style => overflow_style); + else + result := (others => '0'); + end if; + return result; + end function to_ufixed; + + function to_sfixed ( + arg : INTEGER; -- integer + constant left_index : INTEGER; -- left index (high index) + constant right_index : INTEGER := 0; -- right index + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNRESOLVED_sfixed is + constant fw : INTEGER := mins (right_index, right_index); -- catch literals + variable result : UNRESOLVED_sfixed (left_index downto fw); + variable sresult : UNRESOLVED_sfixed (left_index downto 0) := + (others => '0'); -- integer portion + variable argx : INTEGER; -- internal version of arg + variable sign : STD_ULOGIC; -- sign of input + begin + if (result'length < 1) then -- null range + return NASF; + end if; + if arg /= 0 then + if (arg < 0) then + sign := '1'; + argx := -(arg + 1); + else + sign := '0'; + argx := arg; + end if; + for I in 0 to sresult'left loop + if (argx mod 2) = 0 then + sresult(I) := sign; + else + sresult(I) := not sign; + end if; + argx := argx/2; + end loop; + if argx /= 0 or left_index < 0 or sign /= sresult(sresult'left) then + assert NO_WARNING + report fixed_pkg'instance_name + & "TO_SFIXED(INTEGER): vector truncated" + severity warning; + if overflow_style = fixed_saturate then -- saturate + if arg < 0 then + result := not saturate (result'high, result'low); -- underflow + else + result := saturate (result'high, result'low); -- overflow + end if; + return result; + end if; + end if; + result := resize (arg => sresult, + left_index => left_index, + right_index => right_index, + round_style => round_style, + overflow_style => overflow_style); + else + result := (others => '0'); + end if; + return result; + end function to_sfixed; + + function to_ufixed ( + arg : REAL; -- real + constant left_index : INTEGER; -- left index (high index) + constant right_index : INTEGER; -- right index + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style; + constant guard_bits : NATURAL := fixed_guard_bits) -- # of guard bits + return UNRESOLVED_ufixed is + constant fw : INTEGER := mins (right_index, right_index); -- catch literals + variable result : UNRESOLVED_ufixed (left_index downto fw) := + (others => '0'); + variable Xresult : UNRESOLVED_ufixed (left_index downto + fw-guard_bits) := + (others => '0'); + variable presult : REAL; +-- variable overflow_needed : BOOLEAN; + begin + -- If negative or null range, return. + if (left_index < fw) then + return NAUF; + end if; + if (arg < 0.0) then + report fixed_pkg'instance_name + & "TO_UFIXED: Negative argument passed " + & REAL'image(arg) severity error; + return result; + end if; + presult := arg; + if presult >= (2.0**(left_index+1)) then + assert NO_WARNING report fixed_pkg'instance_name + & "TO_UFIXED(REAL): vector truncated" + severity warning; + if overflow_style = fixed_wrap then + presult := presult mod (2.0**(left_index+1)); -- wrap + else + return saturate (result'high, result'low); + end if; + end if; + for i in Xresult'range loop + if presult >= 2.0**i then + Xresult(i) := '1'; + presult := presult - 2.0**i; + else + Xresult(i) := '0'; + end if; + end loop; + if guard_bits > 0 and round_style = fixed_round then + result := round_fixed (arg => Xresult (left_index + downto right_index), + remainder => Xresult (right_index-1 downto + right_index-guard_bits), + overflow_style => overflow_style); + else + result := Xresult (result'range); + end if; + return result; + end function to_ufixed; + + function to_sfixed ( + arg : REAL; -- real + constant left_index : INTEGER; -- left index (high index) + constant right_index : INTEGER; -- right index + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style; + constant guard_bits : NATURAL := fixed_guard_bits) -- # of guard bits + return UNRESOLVED_sfixed is + constant fw : INTEGER := mins (right_index, right_index); -- catch literals + variable result : UNRESOLVED_sfixed (left_index downto fw) := + (others => '0'); + variable Xresult : UNRESOLVED_sfixed (left_index+1 downto fw-guard_bits) := + (others => '0'); + variable presult : REAL; + begin + if (left_index < fw) then -- null range + return NASF; + end if; + if (arg >= (2.0**left_index) or arg < -(2.0**left_index)) then + assert NO_WARNING report fixed_pkg'instance_name + & "TO_SFIXED(REAL): vector truncated" + severity warning; + if overflow_style = fixed_saturate then + if arg < 0.0 then -- saturate + result := not saturate (result'high, result'low); -- underflow + else + result := saturate (result'high, result'low); -- overflow + end if; + return result; + else + presult := abs(arg) mod (2.0**(left_index+1)); -- wrap + end if; + else + presult := abs(arg); + end if; + for i in Xresult'range loop + if presult >= 2.0**i then + Xresult(i) := '1'; + presult := presult - 2.0**i; + else + Xresult(i) := '0'; + end if; + end loop; + if arg < 0.0 then + Xresult := to_fixed(-to_s(Xresult), Xresult'high, Xresult'low); + end if; + if guard_bits > 0 and round_style = fixed_round then + result := round_fixed (arg => Xresult (left_index + downto right_index), + remainder => Xresult (right_index-1 downto + right_index-guard_bits), + overflow_style => overflow_style); + else + result := Xresult (result'range); + end if; + return result; + end function to_sfixed; + + function to_ufixed ( + arg : UNSIGNED; -- unsigned + constant left_index : INTEGER; -- left index (high index) + constant right_index : INTEGER := 0; -- right index + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNRESOLVED_ufixed is + constant ARG_LEFT : INTEGER := ARG'length-1; + alias XARG : UNSIGNED(ARG_LEFT downto 0) is ARG; + variable result : UNRESOLVED_ufixed (left_index downto right_index); + begin + if arg'length < 1 or (left_index < right_index) then + return NAUF; + end if; + result := resize (arg => UNRESOLVED_ufixed (XARG), + left_index => left_index, + right_index => right_index, + round_style => round_style, + overflow_style => overflow_style); + return result; + end function to_ufixed; + + -- converted version + function to_ufixed ( + arg : UNSIGNED) -- unsigned + return UNRESOLVED_ufixed is + constant ARG_LEFT : INTEGER := ARG'length-1; + alias XARG : UNSIGNED(ARG_LEFT downto 0) is ARG; + begin + if arg'length < 1 then + return NAUF; + end if; + return UNRESOLVED_ufixed(xarg); + end function to_ufixed; + + function to_sfixed ( + arg : SIGNED; -- signed + constant left_index : INTEGER; -- left index (high index) + constant right_index : INTEGER := 0; -- right index + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNRESOLVED_sfixed is + constant ARG_LEFT : INTEGER := ARG'length-1; + alias XARG : SIGNED(ARG_LEFT downto 0) is ARG; + variable result : UNRESOLVED_sfixed (left_index downto right_index); + begin + if arg'length < 1 or (left_index < right_index) then + return NASF; + end if; + result := resize (arg => UNRESOLVED_sfixed (XARG), + left_index => left_index, + right_index => right_index, + round_style => round_style, + overflow_style => overflow_style); + return result; + end function to_sfixed; + + -- converted version + function to_sfixed ( + arg : SIGNED) -- signed + return UNRESOLVED_sfixed is + constant ARG_LEFT : INTEGER := ARG'length-1; + alias XARG : SIGNED(ARG_LEFT downto 0) is ARG; + begin + if arg'length < 1 then + return NASF; + end if; + return UNRESOLVED_sfixed(xarg); + end function to_sfixed; + + function to_sfixed (arg : UNRESOLVED_ufixed) return UNRESOLVED_sfixed is + variable result : UNRESOLVED_sfixed (arg'high+1 downto arg'low); + begin + if arg'length < 1 then + return NASF; + end if; + result (arg'high downto arg'low) := UNRESOLVED_sfixed(cleanvec(arg)); + result (arg'high+1) := '0'; + return result; + end function to_sfixed; + + -- Because of the fairly complicated sizing rules in the fixed point + -- packages these functions are provided to compute the result ranges + -- Example: + -- signal uf1 : ufixed (3 downto -3); + -- signal uf2 : ufixed (4 downto -2); + -- signal uf1multuf2 : ufixed (ufixed_high (3, -3, '*', 4, -2) downto + -- ufixed_low (3, -3, '*', 4, -2)); + -- uf1multuf2 <= uf1 * uf2; + -- Valid characters: '+', '-', '*', '/', 'r' or 'R' (rem), 'm' or 'M' (mod), + -- '1' (reciprocal), 'A', 'a' (abs), 'N', 'n' (-sfixed) + function ufixed_high (left_index, right_index : INTEGER; + operation : CHARACTER := 'X'; + left_index2, right_index2 : INTEGER := 0) + return INTEGER is + begin + case operation is + when '+'| '-' => return maximum (left_index, left_index2) + 1; + when '*' => return left_index + left_index2 + 1; + when '/' => return left_index - right_index2; + when '1' => return -right_index; -- reciprocal + when 'R'|'r' => return mins (left_index, left_index2); -- "rem" + when 'M'|'m' => return mins (left_index, left_index2); -- "mod" + when others => return left_index; -- For abs and default + end case; + end function ufixed_high; + + function ufixed_low (left_index, right_index : INTEGER; + operation : CHARACTER := 'X'; + left_index2, right_index2 : INTEGER := 0) + return INTEGER is + begin + case operation is + when '+'| '-' => return mins (right_index, right_index2); + when '*' => return right_index + right_index2; + when '/' => return right_index - left_index2 - 1; + when '1' => return -left_index - 1; -- reciprocal + when 'R'|'r' => return mins (right_index, right_index2); -- "rem" + when 'M'|'m' => return mins (right_index, right_index2); -- "mod" + when others => return right_index; -- for abs and default + end case; + end function ufixed_low; + + function sfixed_high (left_index, right_index : INTEGER; + operation : CHARACTER := 'X'; + left_index2, right_index2 : INTEGER := 0) + return INTEGER is + begin + case operation is + when '+'| '-' => return maximum (left_index, left_index2) + 1; + when '*' => return left_index + left_index2 + 1; + when '/' => return left_index - right_index2 + 1; + when '1' => return -right_index + 1; -- reciprocal + when 'R'|'r' => return mins (left_index, left_index2); -- "rem" + when 'M'|'m' => return left_index2; -- "mod" + when 'A'|'a' => return left_index + 1; -- "abs" + when 'N'|'n' => return left_index + 1; -- -sfixed + when others => return left_index; + end case; + end function sfixed_high; + + function sfixed_low (left_index, right_index : INTEGER; + operation : CHARACTER := 'X'; + left_index2, right_index2 : INTEGER := 0) + return INTEGER is + begin + case operation is + when '+'| '-' => return mins (right_index, right_index2); + when '*' => return right_index + right_index2; + when '/' => return right_index - left_index2; + when '1' => return -left_index; -- reciprocal + when 'R'|'r' => return mins (right_index, right_index2); -- "rem" + when 'M'|'m' => return mins (right_index, right_index2); -- "mod" + when others => return right_index; -- default for abs, neg and default + end case; + end function sfixed_low; + + -- Same as above, but using the "size_res" input only for their ranges: + -- signal uf1multuf2 : ufixed (ufixed_high (uf1, '*', uf2) downto + -- ufixed_low (uf1, '*', uf2)); + -- uf1multuf2 <= uf1 * uf2; + function ufixed_high (size_res : UNRESOLVED_ufixed; + operation : CHARACTER := 'X'; + size_res2 : UNRESOLVED_ufixed) + return INTEGER is + begin + return ufixed_high (left_index => size_res'high, + right_index => size_res'low, + operation => operation, + left_index2 => size_res2'high, + right_index2 => size_res2'low); + end function ufixed_high; + + function ufixed_low (size_res : UNRESOLVED_ufixed; + operation : CHARACTER := 'X'; + size_res2 : UNRESOLVED_ufixed) + return INTEGER is + begin + return ufixed_low (left_index => size_res'high, + right_index => size_res'low, + operation => operation, + left_index2 => size_res2'high, + right_index2 => size_res2'low); + end function ufixed_low; + + function sfixed_high (size_res : UNRESOLVED_sfixed; + operation : CHARACTER := 'X'; + size_res2 : UNRESOLVED_sfixed) + return INTEGER is + begin + return sfixed_high (left_index => size_res'high, + right_index => size_res'low, + operation => operation, + left_index2 => size_res2'high, + right_index2 => size_res2'low); + end function sfixed_high; + + function sfixed_low (size_res : UNRESOLVED_sfixed; + operation : CHARACTER := 'X'; + size_res2 : UNRESOLVED_sfixed) + return INTEGER is + begin + return sfixed_low (left_index => size_res'high, + right_index => size_res'low, + operation => operation, + left_index2 => size_res2'high, + right_index2 => size_res2'low); + end function sfixed_low; + + -- purpose: returns a saturated number + function saturate ( + constant left_index : INTEGER; + constant right_index : INTEGER) + return UNRESOLVED_ufixed is + constant sat : UNRESOLVED_ufixed (left_index downto right_index) := + (others => '1'); + begin + return sat; + end function saturate; + + -- purpose: returns a saturated number + function saturate ( + constant left_index : INTEGER; + constant right_index : INTEGER) + return UNRESOLVED_sfixed is + variable sat : UNRESOLVED_sfixed (left_index downto right_index) := + (others => '1'); + begin + -- saturate positive, to saturate negative, just do "not saturate()" + sat (left_index) := '0'; + return sat; + end function saturate; + + function saturate ( + size_res : UNRESOLVED_ufixed) -- only the size of this is used + return UNRESOLVED_ufixed is + begin + return saturate (size_res'high, size_res'low); + end function saturate; + + function saturate ( + size_res : UNRESOLVED_sfixed) -- only the size of this is used + return UNRESOLVED_sfixed is + begin + return saturate (size_res'high, size_res'low); + end function saturate; + + -- As a concession to those who use a graphical DSP environment, + -- these functions take parameters in those tools format and create + -- fixed point numbers. These functions are designed to convert from + -- a std_logic_vector to the VHDL fixed point format using the conventions + -- of these packages. In a pure VHDL environment you should use the + -- "to_ufixed" and "to_sfixed" routines. + -- Unsigned fixed point + function to_UFix ( + arg : STD_ULOGIC_VECTOR; + width : NATURAL; -- width of vector + fraction : NATURAL) -- width of fraction + return UNRESOLVED_ufixed is + variable result : UNRESOLVED_ufixed (width-fraction-1 downto -fraction); + begin + if (arg'length /= result'length) then + report fixed_pkg'instance_name + & "TO_UFIX (STD_ULOGIC_VECTOR) " + & "Vector lengths do not match. Input length is " + & INTEGER'image(arg'length) & " and output will be " + & INTEGER'image(result'length) & " wide." + severity error; + return NAUF; + else + result := to_ufixed (arg, result'high, result'low); + return result; + end if; + end function to_UFix; + + -- signed fixed point + function to_SFix ( + arg : STD_ULOGIC_VECTOR; + width : NATURAL; -- width of vector + fraction : NATURAL) -- width of fraction + return UNRESOLVED_sfixed is + variable result : UNRESOLVED_sfixed (width-fraction-1 downto -fraction); + begin + if (arg'length /= result'length) then + report fixed_pkg'instance_name + & "TO_SFIX (STD_ULOGIC_VECTOR) " + & "Vector lengths do not match. Input length is " + & INTEGER'image(arg'length) & " and output will be " + & INTEGER'image(result'length) & " wide." + severity error; + return NASF; + else + result := to_sfixed (arg, result'high, result'low); + return result; + end if; + end function to_SFix; + + -- finding the bounds of a number. These functions can be used like this: + -- signal xxx : ufixed (7 downto -3); + -- -- Which is the same as "ufixed (UFix_high (11,3) downto UFix_low(11,3))" + -- signal yyy : ufixed (UFix_high (11, 3, "+", 11, 3) + -- downto UFix_low(11, 3, "+", 11, 3)); + -- Where "11" is the width of xxx (xxx'length), + -- and 3 is the lower bound (abs (xxx'low)) + -- In a pure VHDL environment use "ufixed_high" and "ufixed_low" + function ufix_high ( + width, fraction : NATURAL; + operation : CHARACTER := 'X'; + width2, fraction2 : NATURAL := 0) + return INTEGER is + begin + return ufixed_high (left_index => width - 1 - fraction, + right_index => -fraction, + operation => operation, + left_index2 => width2 - 1 - fraction2, + right_index2 => -fraction2); + end function ufix_high; + + function ufix_low ( + width, fraction : NATURAL; + operation : CHARACTER := 'X'; + width2, fraction2 : NATURAL := 0) + return INTEGER is + begin + return ufixed_low (left_index => width - 1 - fraction, + right_index => -fraction, + operation => operation, + left_index2 => width2 - 1 - fraction2, + right_index2 => -fraction2); + end function ufix_low; + + function sfix_high ( + width, fraction : NATURAL; + operation : CHARACTER := 'X'; + width2, fraction2 : NATURAL := 0) + return INTEGER is + begin + return sfixed_high (left_index => width - fraction, + right_index => -fraction, + operation => operation, + left_index2 => width2 - fraction2, + right_index2 => -fraction2); + end function sfix_high; + + function sfix_low ( + width, fraction : NATURAL; + operation : CHARACTER := 'X'; + width2, fraction2 : NATURAL := 0) + return INTEGER is + begin + return sfixed_low (left_index => width - fraction, + right_index => -fraction, + operation => operation, + left_index2 => width2 - fraction2, + right_index2 => -fraction2); + end function sfix_low; + + function to_unsigned ( + arg : UNRESOLVED_ufixed; -- ufixed point input + constant size : NATURAL; -- length of output + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNSIGNED is + begin + return to_uns(resize (arg => arg, + left_index => size-1, + right_index => 0, + round_style => round_style, + overflow_style => overflow_style)); + end function to_unsigned; + + function to_unsigned ( + arg : UNRESOLVED_ufixed; -- ufixed point input + size_res : UNSIGNED; -- length of output + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNSIGNED is + begin + return to_unsigned (arg => arg, + size => size_res'length, + round_style => round_style, + overflow_style => overflow_style); + end function to_unsigned; + + function to_signed ( + arg : UNRESOLVED_sfixed; -- sfixed point input + constant size : NATURAL; -- length of output + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return SIGNED is + begin + return to_s(resize (arg => arg, + left_index => size-1, + right_index => 0, + round_style => round_style, + overflow_style => overflow_style)); + end function to_signed; + + function to_signed ( + arg : UNRESOLVED_sfixed; -- sfixed point input + size_res : SIGNED; -- used for length of output + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return SIGNED is + begin + return to_signed (arg => arg, + size => size_res'length, + round_style => round_style, + overflow_style => overflow_style); + end function to_signed; + + function to_real ( + arg : UNRESOLVED_ufixed) -- ufixed point input + return REAL is + constant left_index : INTEGER := arg'high; + constant right_index : INTEGER := arg'low; + variable result : REAL; -- result + variable arg_int : UNRESOLVED_ufixed (left_index downto right_index); + begin + if (arg'length < 1) then + return 0.0; + end if; + arg_int := to_x01(cleanvec(arg)); + if (Is_X(arg_int)) then + assert NO_WARNING + report fixed_pkg'instance_name + & "TO_REAL (ufixed): metavalue detected, returning 0.0" + severity warning; + return 0.0; + end if; + result := 0.0; + for i in arg_int'range loop + if (arg_int(i) = '1') then + result := result + (2.0**i); + end if; + end loop; + return result; + end function to_real; + + function to_real ( + arg : UNRESOLVED_sfixed) -- ufixed point input + return REAL is + constant left_index : INTEGER := arg'high; + constant right_index : INTEGER := arg'low; + variable result : REAL; -- result + variable arg_int : UNRESOLVED_sfixed (left_index downto right_index); + -- unsigned version of argument + variable arg_uns : UNRESOLVED_ufixed (left_index downto right_index); + -- absolute of argument + begin + if (arg'length < 1) then + return 0.0; + end if; + arg_int := to_x01(cleanvec(arg)); + if (Is_X(arg_int)) then + assert NO_WARNING + report fixed_pkg'instance_name + & "TO_REAL (sfixed): metavalue detected, returning 0.0" + severity warning; + return 0.0; + end if; + arg_uns := to_ufixed (arg_int); + result := to_real (arg_uns); + if (arg_int(arg_int'high) = '1') then + result := -result; + end if; + return result; + end function to_real; + + function to_integer ( + arg : UNRESOLVED_ufixed; -- fixed point input + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return NATURAL is + constant left_index : INTEGER := arg'high; + variable arg_uns : UNSIGNED (left_index+1 downto 0) + := (others => '0'); + begin + if (arg'length < 1) then + return 0; + end if; + if (Is_X (arg)) then + assert NO_WARNING + report fixed_pkg'instance_name + & "TO_INTEGER (ufixed): metavalue detected, returning 0" + severity warning; + return 0; + end if; + if (left_index < -1) then + return 0; + end if; + arg_uns := to_uns(resize (arg => arg, + left_index => arg_uns'high, + right_index => 0, + round_style => round_style, + overflow_style => overflow_style)); + return to_integer (arg_uns); + end function to_integer; + + function to_integer ( + arg : UNRESOLVED_sfixed; -- fixed point input + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return INTEGER is + constant left_index : INTEGER := arg'high; + constant right_index : INTEGER := arg'low; + variable arg_s : SIGNED (left_index+1 downto 0); + begin + if (arg'length < 1) then + return 0; + end if; + if (Is_X (arg)) then + assert NO_WARNING + report fixed_pkg'instance_name + & "TO_INTEGER (sfixed): metavalue detected, returning 0" + severity warning; + return 0; + end if; + if (left_index < -1) then + return 0; + end if; + arg_s := to_s(resize (arg => arg, + left_index => arg_s'high, + right_index => 0, + round_style => round_style, + overflow_style => overflow_style)); + return to_integer (arg_s); + end function to_integer; + + function to_01 ( + s : UNRESOLVED_ufixed; -- ufixed point input + constant XMAP : STD_ULOGIC := '0') -- Map x to + return UNRESOLVED_ufixed is + variable result : UNRESOLVED_ufixed (s'range); -- result + begin + if (s'length < 1) then + assert NO_WARNING + report fixed_pkg'instance_name + & "TO_01(ufixed): null detected, returning NULL" + severity warning; + return NAUF; + end if; + return to_fixed (to_01(to_uns(s), XMAP), s'high, s'low); + end function to_01; + + function to_01 ( + s : UNRESOLVED_sfixed; -- sfixed point input + constant XMAP : STD_ULOGIC := '0') -- Map x to + return UNRESOLVED_sfixed is + variable result : UNRESOLVED_sfixed (s'range); + begin + if (s'length < 1) then + assert NO_WARNING + report fixed_pkg'instance_name + & "TO_01(sfixed): null detected, returning NULL" + severity warning; + return NASF; + end if; + return to_fixed (to_01(to_s(s), XMAP), s'high, s'low); + end function to_01; + + function Is_X ( + arg : UNRESOLVED_ufixed) + return BOOLEAN is + variable argslv : STD_ULOGIC_VECTOR (arg'length-1 downto 0); -- slv + begin + argslv := to_sulv(arg); + return Is_X (argslv); + end function Is_X; + + function Is_X ( + arg : UNRESOLVED_sfixed) + return BOOLEAN is + variable argslv : STD_ULOGIC_VECTOR (arg'length-1 downto 0); -- slv + begin + argslv := to_sulv(arg); + return Is_X (argslv); + end function Is_X; + + function To_X01 ( + arg : UNRESOLVED_ufixed) + return UNRESOLVED_ufixed is + begin + return to_ufixed (To_X01(to_sulv(arg)), arg'high, arg'low); + end function To_X01; + + function to_X01 ( + arg : UNRESOLVED_sfixed) + return UNRESOLVED_sfixed is + begin + return to_sfixed (To_X01(to_sulv(arg)), arg'high, arg'low); + end function To_X01; + + function To_X01Z ( + arg : UNRESOLVED_ufixed) + return UNRESOLVED_ufixed is + begin + return to_ufixed (To_X01Z(to_sulv(arg)), arg'high, arg'low); + end function To_X01Z; + + function to_X01Z ( + arg : UNRESOLVED_sfixed) + return UNRESOLVED_sfixed is + begin + return to_sfixed (To_X01Z(to_sulv(arg)), arg'high, arg'low); + end function To_X01Z; + + function To_UX01 ( + arg : UNRESOLVED_ufixed) + return UNRESOLVED_ufixed is + begin + return to_ufixed (To_UX01(to_sulv(arg)), arg'high, arg'low); + end function To_UX01; + + function to_UX01 ( + arg : UNRESOLVED_sfixed) + return UNRESOLVED_sfixed is + begin + return to_sfixed (To_UX01(to_sulv(arg)), arg'high, arg'low); + end function To_UX01; + + function resize ( + arg : UNRESOLVED_ufixed; -- input + constant left_index : INTEGER; -- integer portion + constant right_index : INTEGER; -- size of fraction + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNRESOLVED_ufixed is + constant arghigh : INTEGER := maximum (arg'high, arg'low); + constant arglow : INTEGER := mine (arg'high, arg'low); + variable invec : UNRESOLVED_ufixed (arghigh downto arglow); + variable result : UNRESOLVED_ufixed(left_index downto right_index) := + (others => '0'); + variable needs_rounding : BOOLEAN := false; + begin -- resize + if (arg'length < 1) or (result'length < 1) then + return NAUF; + elsif (invec'length < 1) then + return result; -- string literal value + else + invec := cleanvec(arg); + if (right_index > arghigh) then -- return top zeros + needs_rounding := (round_style = fixed_round) and + (right_index = arghigh+1); + elsif (left_index < arglow) then -- return overflow + if (overflow_style = fixed_saturate) and + (or_reduce(to_sulv(invec)) = '1') then + result := saturate (result'high, result'low); -- saturate + end if; + elsif (arghigh > left_index) then + -- wrap or saturate? + if (overflow_style = fixed_saturate and + or_reduce (to_sulv(invec(arghigh downto left_index+1))) = '1') + then + result := saturate (result'high, result'low); -- saturate + else + if (arglow >= right_index) then + result (left_index downto arglow) := + invec(left_index downto arglow); + else + result (left_index downto right_index) := + invec (left_index downto right_index); + needs_rounding := (round_style = fixed_round); -- round + end if; + end if; + else -- arghigh <= integer width + if (arglow >= right_index) then + result (arghigh downto arglow) := invec; + else + result (arghigh downto right_index) := + invec (arghigh downto right_index); + needs_rounding := (round_style = fixed_round); -- round + end if; + end if; + -- Round result + if needs_rounding then + result := round_fixed (arg => result, + remainder => invec (right_index-1 + downto arglow), + overflow_style => overflow_style); + end if; + return result; + end if; + end function resize; + + function resize ( + arg : UNRESOLVED_sfixed; -- input + constant left_index : INTEGER; -- integer portion + constant right_index : INTEGER; -- size of fraction + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNRESOLVED_sfixed is + constant arghigh : INTEGER := maximum (arg'high, arg'low); + constant arglow : INTEGER := mine (arg'high, arg'low); + variable invec : UNRESOLVED_sfixed (arghigh downto arglow); + variable result : UNRESOLVED_sfixed(left_index downto right_index) := + (others => '0'); + variable reduced : STD_ULOGIC; + variable needs_rounding : BOOLEAN := false; -- rounding + begin -- resize + if (arg'length < 1) or (result'length < 1) then + return NASF; + elsif (invec'length < 1) then + return result; -- string literal value + else + invec := cleanvec(arg); + if (right_index > arghigh) then -- return top zeros + if (arg'low /= INTEGER'low) then -- check for a literal + result := (others => arg(arghigh)); -- sign extend + end if; + needs_rounding := (round_style = fixed_round) and + (right_index = arghigh+1); + elsif (left_index < arglow) then -- return overflow + if (overflow_style = fixed_saturate) then + reduced := or_reduce (to_sulv(invec)); + if (reduced = '1') then + if (invec(arghigh) = '0') then + -- saturate POSITIVE + result := saturate (result'high, result'low); + else + -- saturate negative + result := not saturate (result'high, result'low); + end if; + -- else return 0 (input was 0) + end if; + -- else return 0 (wrap) + end if; + elsif (arghigh > left_index) then + if (invec(arghigh) = '0') then + reduced := or_reduce (to_sulv(invec(arghigh-1 downto + left_index))); + if overflow_style = fixed_saturate and reduced = '1' then + -- saturate positive + result := saturate (result'high, result'low); + else + if (right_index > arglow) then + result := invec (left_index downto right_index); + needs_rounding := (round_style = fixed_round); + else + result (left_index downto arglow) := + invec (left_index downto arglow); + end if; + end if; + else + reduced := and_reduce (to_sulv(invec(arghigh-1 downto + left_index))); + if overflow_style = fixed_saturate and reduced = '0' then + result := not saturate (result'high, result'low); + else + if (right_index > arglow) then + result := invec (left_index downto right_index); + needs_rounding := (round_style = fixed_round); + else + result (left_index downto arglow) := + invec (left_index downto arglow); + end if; + end if; + end if; + else -- arghigh <= integer width + if (arglow >= right_index) then + result (arghigh downto arglow) := invec; + else + result (arghigh downto right_index) := + invec (arghigh downto right_index); + needs_rounding := (round_style = fixed_round); -- round + end if; + if (left_index > arghigh) then -- sign extend + result(left_index downto arghigh+1) := (others => invec(arghigh)); + end if; + end if; + -- Round result + if (needs_rounding) then + result := round_fixed (arg => result, + remainder => invec (right_index-1 + downto arglow), + overflow_style => overflow_style); + end if; + return result; + end if; + end function resize; + + -- size_res functions + -- These functions compute the size from a passed variable named "size_res" + -- The only part of this variable used it it's size, it is never passed + -- to a lower level routine. + function to_ufixed ( + arg : STD_ULOGIC_VECTOR; -- shifted vector + size_res : UNRESOLVED_ufixed) -- for size only + return UNRESOLVED_ufixed is + constant fw : INTEGER := mine (size_res'low, size_res'low); -- catch literals + variable result : UNRESOLVED_ufixed (size_res'left downto fw); + begin + if (result'length < 1 or arg'length < 1) then + return NAUF; + else + result := to_ufixed (arg => arg, + left_index => size_res'high, + right_index => size_res'low); + return result; + end if; + end function to_ufixed; + + function to_sfixed ( + arg : STD_ULOGIC_VECTOR; -- shifted vector + size_res : UNRESOLVED_sfixed) -- for size only + return UNRESOLVED_sfixed is + constant fw : INTEGER := mine (size_res'low, size_res'low); -- catch literals + variable result : UNRESOLVED_sfixed (size_res'left downto fw); + begin + if (result'length < 1 or arg'length < 1) then + return NASF; + else + result := to_sfixed (arg => arg, + left_index => size_res'high, + right_index => size_res'low); + return result; + end if; + end function to_sfixed; + + function to_ufixed ( + arg : NATURAL; -- integer + size_res : UNRESOLVED_ufixed; -- for size only + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNRESOLVED_ufixed is + constant fw : INTEGER := mine (size_res'low, size_res'low); -- catch literals + variable result : UNRESOLVED_ufixed (size_res'left downto fw); + begin + if (result'length < 1) then + return NAUF; + else + result := to_ufixed (arg => arg, + left_index => size_res'high, + right_index => size_res'low, + round_style => round_style, + overflow_style => overflow_style); + return result; + end if; + end function to_ufixed; + + function to_sfixed ( + arg : INTEGER; -- integer + size_res : UNRESOLVED_sfixed; -- for size only + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNRESOLVED_sfixed is + constant fw : INTEGER := mine (size_res'low, size_res'low); -- catch literals + variable result : UNRESOLVED_sfixed (size_res'left downto fw); + begin + if (result'length < 1) then + return NASF; + else + result := to_sfixed (arg => arg, + left_index => size_res'high, + right_index => size_res'low, + round_style => round_style, + overflow_style => overflow_style); + return result; + end if; + end function to_sfixed; + + function to_ufixed ( + arg : REAL; -- real + size_res : UNRESOLVED_ufixed; -- for size only + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style; + constant guard_bits : NATURAL := fixed_guard_bits) -- # of guard bits + return UNRESOLVED_ufixed is + constant fw : INTEGER := mine (size_res'low, size_res'low); -- catch literals + variable result : UNRESOLVED_ufixed (size_res'left downto fw); + begin + if (result'length < 1) then + return NAUF; + else + result := to_ufixed (arg => arg, + left_index => size_res'high, + right_index => size_res'low, + guard_bits => guard_bits, + round_style => round_style, + overflow_style => overflow_style); + return result; + end if; + end function to_ufixed; + + function to_sfixed ( + arg : REAL; -- real + size_res : UNRESOLVED_sfixed; -- for size only + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style; + constant guard_bits : NATURAL := fixed_guard_bits) -- # of guard bits + return UNRESOLVED_sfixed is + constant fw : INTEGER := mine (size_res'low, size_res'low); -- catch literals + variable result : UNRESOLVED_sfixed (size_res'left downto fw); + begin + if (result'length < 1) then + return NASF; + else + result := to_sfixed (arg => arg, + left_index => size_res'high, + right_index => size_res'low, + guard_bits => guard_bits, + round_style => round_style, + overflow_style => overflow_style); + return result; + end if; + end function to_sfixed; + + function to_ufixed ( + arg : UNSIGNED; -- unsigned + size_res : UNRESOLVED_ufixed; -- for size only + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNRESOLVED_ufixed is + constant fw : INTEGER := mine (size_res'low, size_res'low); -- catch literals + variable result : UNRESOLVED_ufixed (size_res'left downto fw); + begin + if (result'length < 1 or arg'length < 1) then + return NAUF; + else + result := to_ufixed (arg => arg, + left_index => size_res'high, + right_index => size_res'low, + round_style => round_style, + overflow_style => overflow_style); + return result; + end if; + end function to_ufixed; + + function to_sfixed ( + arg : SIGNED; -- signed + size_res : UNRESOLVED_sfixed; -- for size only + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNRESOLVED_sfixed is + constant fw : INTEGER := mine (size_res'low, size_res'low); -- catch literals + variable result : UNRESOLVED_sfixed (size_res'left downto fw); + begin + if (result'length < 1 or arg'length < 1) then + return NASF; + else + result := to_sfixed (arg => arg, + left_index => size_res'high, + right_index => size_res'low, + round_style => round_style, + overflow_style => overflow_style); + return result; + end if; + end function to_sfixed; + + function resize ( + arg : UNRESOLVED_ufixed; -- input + size_res : UNRESOLVED_ufixed; -- for size only + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNRESOLVED_ufixed is + constant fw : INTEGER := mine (size_res'low, size_res'low); -- catch literals + variable result : UNRESOLVED_ufixed (size_res'high downto fw); + begin + if (result'length < 1 or arg'length < 1) then + return NAUF; + else + result := resize (arg => arg, + left_index => size_res'high, + right_index => size_res'low, + round_style => round_style, + overflow_style => overflow_style); + return result; + end if; + end function resize; + + function resize ( + arg : UNRESOLVED_sfixed; -- input + size_res : UNRESOLVED_sfixed; -- for size only + constant overflow_style : fixed_overflow_style_type := fixed_overflow_style; + constant round_style : fixed_round_style_type := fixed_round_style) + return UNRESOLVED_sfixed is + constant fw : INTEGER := mine (size_res'low, size_res'low); -- catch literals + variable result : UNRESOLVED_sfixed (size_res'high downto fw); + begin + if (result'length < 1 or arg'length < 1) then + return NASF; + else + result := resize (arg => arg, + left_index => size_res'high, + right_index => size_res'low, + round_style => round_style, + overflow_style => overflow_style); + return result; + end if; + end function resize; + + -- Overloaded math functions for real + function "+" ( + l : UNRESOLVED_ufixed; -- fixed point input + r : REAL) + return UNRESOLVED_ufixed is + begin + return (l + to_ufixed (r, l'high, l'low)); + end function "+"; + + function "+" ( + l : REAL; + r : UNRESOLVED_ufixed) -- fixed point input + return UNRESOLVED_ufixed is + begin + return (to_ufixed (l, r'high, r'low) + r); + end function "+"; + + function "+" ( + l : UNRESOLVED_sfixed; -- fixed point input + r : REAL) + return UNRESOLVED_sfixed is + begin + return (l + to_sfixed (r, l'high, l'low)); + end function "+"; + + function "+" ( + l : REAL; + r : UNRESOLVED_sfixed) -- fixed point input + return UNRESOLVED_sfixed is + begin + return (to_sfixed (l, r'high, r'low) + r); + end function "+"; + + function "-" ( + l : UNRESOLVED_ufixed; -- fixed point input + r : REAL) + return UNRESOLVED_ufixed is + begin + return (l - to_ufixed (r, l'high, l'low)); + end function "-"; + + function "-" ( + l : REAL; + r : UNRESOLVED_ufixed) -- fixed point input + return UNRESOLVED_ufixed is + begin + return (to_ufixed (l, r'high, r'low) - r); + end function "-"; + + function "-" ( + l : UNRESOLVED_sfixed; -- fixed point input + r : REAL) + return UNRESOLVED_sfixed is + begin + return (l - to_sfixed (r, l'high, l'low)); + end function "-"; + + function "-" ( + l : REAL; + r : UNRESOLVED_sfixed) -- fixed point input + return UNRESOLVED_sfixed is + begin + return (to_sfixed (l, r'high, r'low) - r); + end function "-"; + + function "*" ( + l : UNRESOLVED_ufixed; -- fixed point input + r : REAL) + return UNRESOLVED_ufixed is + begin + return (l * to_ufixed (r, l'high, l'low)); + end function "*"; + + function "*" ( + l : REAL; + r : UNRESOLVED_ufixed) -- fixed point input + return UNRESOLVED_ufixed is + begin + return (to_ufixed (l, r'high, r'low) * r); + end function "*"; + + function "*" ( + l : UNRESOLVED_sfixed; -- fixed point input + r : REAL) + return UNRESOLVED_sfixed is + begin + return (l * to_sfixed (r, l'high, l'low)); + end function "*"; + + function "*" ( + l : REAL; + r : UNRESOLVED_sfixed) -- fixed point input + return UNRESOLVED_sfixed is + begin + return (to_sfixed (l, r'high, r'low) * r); + end function "*"; + + function "/" ( + l : UNRESOLVED_ufixed; -- fixed point input + r : REAL) + return UNRESOLVED_ufixed is + begin + return (l / to_ufixed (r, l'high, l'low)); + end function "/"; + + function "/" ( + l : REAL; + r : UNRESOLVED_ufixed) -- fixed point input + return UNRESOLVED_ufixed is + begin + return (to_ufixed (l, r'high, r'low) / r); + end function "/"; + + function "/" ( + l : UNRESOLVED_sfixed; -- fixed point input + r : REAL) + return UNRESOLVED_sfixed is + begin + return (l / to_sfixed (r, l'high, l'low)); + end function "/"; + + function "/" ( + l : REAL; + r : UNRESOLVED_sfixed) -- fixed point input + return UNRESOLVED_sfixed is + begin + return (to_sfixed (l, r'high, r'low) / r); + end function "/"; + + function "rem" ( + l : UNRESOLVED_ufixed; -- fixed point input + r : REAL) + return UNRESOLVED_ufixed is + begin + return (l rem to_ufixed (r, l'high, l'low)); + end function "rem"; + + function "rem" ( + l : REAL; + r : UNRESOLVED_ufixed) -- fixed point input + return UNRESOLVED_ufixed is + begin + return (to_ufixed (l, r'high, r'low) rem r); + end function "rem"; + + function "rem" ( + l : UNRESOLVED_sfixed; -- fixed point input + r : REAL) + return UNRESOLVED_sfixed is + begin + return (l rem to_sfixed (r, l'high, l'low)); + end function "rem"; + + function "rem" ( + l : REAL; + r : UNRESOLVED_sfixed) -- fixed point input + return UNRESOLVED_sfixed is + begin + return (to_sfixed (l, r'high, r'low) rem r); + end function "rem"; + + function "mod" ( + l : UNRESOLVED_ufixed; -- fixed point input + r : REAL) + return UNRESOLVED_ufixed is + begin + return (l mod to_ufixed (r, l'high, l'low)); + end function "mod"; + + function "mod" ( + l : REAL; + r : UNRESOLVED_ufixed) -- fixed point input + return UNRESOLVED_ufixed is + begin + return (to_ufixed (l, r'high, r'low) mod r); + end function "mod"; + + function "mod" ( + l : UNRESOLVED_sfixed; -- fixed point input + r : REAL) + return UNRESOLVED_sfixed is + begin + return (l mod to_sfixed (r, l'high, l'low)); + end function "mod"; + + function "mod" ( + l : REAL; + r : UNRESOLVED_sfixed) -- fixed point input + return UNRESOLVED_sfixed is + begin + return (to_sfixed (l, r'high, r'low) mod r); + end function "mod"; + + -- Overloaded math functions for integers + function "+" ( + l : UNRESOLVED_ufixed; -- fixed point input + r : NATURAL) + return UNRESOLVED_ufixed is + begin + return (l + to_ufixed (r, l'high, 0)); + end function "+"; + + function "+" ( + l : NATURAL; + r : UNRESOLVED_ufixed) -- fixed point input + return UNRESOLVED_ufixed is + begin + return (to_ufixed (l, r'high, 0) + r); + end function "+"; + + function "+" ( + l : UNRESOLVED_sfixed; -- fixed point input + r : INTEGER) + return UNRESOLVED_sfixed is + begin + return (l + to_sfixed (r, l'high, 0)); + end function "+"; + + function "+" ( + l : INTEGER; + r : UNRESOLVED_sfixed) -- fixed point input + return UNRESOLVED_sfixed is + begin + return (to_sfixed (l, r'high, 0) + r); + end function "+"; + + -- Overloaded functions + function "-" ( + l : UNRESOLVED_ufixed; -- fixed point input + r : NATURAL) + return UNRESOLVED_ufixed is + begin + return (l - to_ufixed (r, l'high, 0)); + end function "-"; + + function "-" ( + l : NATURAL; + r : UNRESOLVED_ufixed) -- fixed point input + return UNRESOLVED_ufixed is + begin + return (to_ufixed (l, r'high, 0) - r); + end function "-"; + + function "-" ( + l : UNRESOLVED_sfixed; -- fixed point input + r : INTEGER) + return UNRESOLVED_sfixed is + begin + return (l - to_sfixed (r, l'high, 0)); + end function "-"; + + function "-" ( + l : INTEGER; + r : UNRESOLVED_sfixed) -- fixed point input + return UNRESOLVED_sfixed is + begin + return (to_sfixed (l, r'high, 0) - r); + end function "-"; + + -- Overloaded functions + function "*" ( + l : UNRESOLVED_ufixed; -- fixed point input + r : NATURAL) + return UNRESOLVED_ufixed is + begin + return (l * to_ufixed (r, l'high, 0)); + end function "*"; + + function "*" ( + l : NATURAL; + r : UNRESOLVED_ufixed) -- fixed point input + return UNRESOLVED_ufixed is + begin + return (to_ufixed (l, r'high, 0) * r); + end function "*"; + + function "*" ( + l : UNRESOLVED_sfixed; -- fixed point input + r : INTEGER) + return UNRESOLVED_sfixed is + begin + return (l * to_sfixed (r, l'high, 0)); + end function "*"; + + function "*" ( + l : INTEGER; + r : UNRESOLVED_sfixed) -- fixed point input + return UNRESOLVED_sfixed is + begin + return (to_sfixed (l, r'high, 0) * r); + end function "*"; + + -- Overloaded functions + function "/" ( + l : UNRESOLVED_ufixed; -- fixed point input + r : NATURAL) + return UNRESOLVED_ufixed is + begin + return (l / to_ufixed (r, l'high, 0)); + end function "/"; + + function "/" ( + l : NATURAL; + r : UNRESOLVED_ufixed) -- fixed point input + return UNRESOLVED_ufixed is + begin + return (to_ufixed (l, r'high, 0) / r); + end function "/"; + + function "/" ( + l : UNRESOLVED_sfixed; -- fixed point input + r : INTEGER) + return UNRESOLVED_sfixed is + begin + return (l / to_sfixed (r, l'high, 0)); + end function "/"; + + function "/" ( + l : INTEGER; + r : UNRESOLVED_sfixed) -- fixed point input + return UNRESOLVED_sfixed is + begin + return (to_sfixed (l, r'high, 0) / r); + end function "/"; + + function "rem" ( + l : UNRESOLVED_ufixed; -- fixed point input + r : NATURAL) + return UNRESOLVED_ufixed is + begin + return (l rem to_ufixed (r, l'high, 0)); + end function "rem"; + + function "rem" ( + l : NATURAL; + r : UNRESOLVED_ufixed) -- fixed point input + return UNRESOLVED_ufixed is + begin + return (to_ufixed (l, r'high, 0) rem r); + end function "rem"; + + function "rem" ( + l : UNRESOLVED_sfixed; -- fixed point input + r : INTEGER) + return UNRESOLVED_sfixed is + begin + return (l rem to_sfixed (r, l'high, 0)); + end function "rem"; + + function "rem" ( + l : INTEGER; + r : UNRESOLVED_sfixed) -- fixed point input + return UNRESOLVED_sfixed is + begin + return (to_sfixed (l, r'high, 0) rem r); + end function "rem"; + + function "mod" ( + l : UNRESOLVED_ufixed; -- fixed point input + r : NATURAL) + return UNRESOLVED_ufixed is + begin + return (l mod to_ufixed (r, l'high, 0)); + end function "mod"; + + function "mod" ( + l : NATURAL; + r : UNRESOLVED_ufixed) -- fixed point input + return UNRESOLVED_ufixed is + begin + return (to_ufixed (l, r'high, 0) mod r); + end function "mod"; + + function "mod" ( + l : UNRESOLVED_sfixed; -- fixed point input + r : INTEGER) + return UNRESOLVED_sfixed is + begin + return (l mod to_sfixed (r, l'high, 0)); + end function "mod"; + + function "mod" ( + l : INTEGER; + r : UNRESOLVED_sfixed) -- fixed point input + return UNRESOLVED_sfixed is + begin + return (to_sfixed (l, r'high, 0) mod r); + end function "mod"; + + -- overloaded ufixed compare functions with integer + function "=" ( + l : UNRESOLVED_ufixed; + r : NATURAL) -- fixed point input + return BOOLEAN is + begin + return (l = to_ufixed (r, l'high, l'low)); + end function "="; + + function "/=" ( + l : UNRESOLVED_ufixed; + r : NATURAL) -- fixed point input + return BOOLEAN is + begin + return (l /= to_ufixed (r, l'high, l'low)); + end function "/="; + + function ">=" ( + l : UNRESOLVED_ufixed; + r : NATURAL) -- fixed point input + return BOOLEAN is + begin + return (l >= to_ufixed (r, l'high, l'low)); + end function ">="; + + function "<=" ( + l : UNRESOLVED_ufixed; + r : NATURAL) -- fixed point input + return BOOLEAN is + begin + return (l <= to_ufixed (r, l'high, l'low)); + end function "<="; + + function ">" ( + l : UNRESOLVED_ufixed; + r : NATURAL) -- fixed point input + return BOOLEAN is + begin + return (l > to_ufixed (r, l'high, l'low)); + end function ">"; + + function "<" ( + l : UNRESOLVED_ufixed; + r : NATURAL) -- fixed point input + return BOOLEAN is + begin + return (l < to_ufixed (r, l'high, l'low)); + end function "<"; + + function \?=\ ( + l : UNRESOLVED_ufixed; + r : NATURAL) -- fixed point input + return STD_ULOGIC is + begin + return \?=\ (l, to_ufixed (r, l'high, l'low)); + end function \?=\; + + function \?/=\ ( + l : UNRESOLVED_ufixed; + r : NATURAL) -- fixed point input + return STD_ULOGIC is + begin + return \?/=\ (l, to_ufixed (r, l'high, l'low)); + end function \?/=\; + + function \?>=\ ( + l : UNRESOLVED_ufixed; + r : NATURAL) -- fixed point input + return STD_ULOGIC is + begin + return \?>=\ (l, to_ufixed (r, l'high, l'low)); + end function \?>=\; + + function \?<=\ ( + l : UNRESOLVED_ufixed; + r : NATURAL) -- fixed point input + return STD_ULOGIC is + begin + return \?<=\ (l, to_ufixed (r, l'high, l'low)); + end function \?<=\; + + function \?>\ ( + l : UNRESOLVED_ufixed; + r : NATURAL) -- fixed point input + return STD_ULOGIC is + begin + return \?>\ (l, to_ufixed (r, l'high, l'low)); + end function \?>\; + + function \?<\ ( + l : UNRESOLVED_ufixed; + r : NATURAL) -- fixed point input + return STD_ULOGIC is + begin + return \?<\ (l, to_ufixed (r, l'high, l'low)); + end function \?<\; + + function maximum ( + l : UNRESOLVED_ufixed; -- fixed point input + r : NATURAL) + return UNRESOLVED_ufixed is + begin + return maximum (l, to_ufixed (r, l'high, l'low)); + end function maximum; + + function minimum ( + l : UNRESOLVED_ufixed; -- fixed point input + r : NATURAL) + return UNRESOLVED_ufixed is + begin + return minimum (l, to_ufixed (r, l'high, l'low)); + end function minimum; + + -- NATURAL to ufixed + function "=" ( + l : NATURAL; + r : UNRESOLVED_ufixed) -- fixed point input + return BOOLEAN is + begin + return (to_ufixed (l, r'high, r'low) = r); + end function "="; + + function "/=" ( + l : NATURAL; + r : UNRESOLVED_ufixed) -- fixed point input + return BOOLEAN is + begin + return (to_ufixed (l, r'high, r'low) /= r); + end function "/="; + + function ">=" ( + l : NATURAL; + r : UNRESOLVED_ufixed) -- fixed point input + return BOOLEAN is + begin + return (to_ufixed (l, r'high, r'low) >= r); + end function ">="; + + function "<=" ( + l : NATURAL; + r : UNRESOLVED_ufixed) -- fixed point input + return BOOLEAN is + begin + return (to_ufixed (l, r'high, r'low) <= r); + end function "<="; + + function ">" ( + l : NATURAL; + r : UNRESOLVED_ufixed) -- fixed point input + return BOOLEAN is + begin + return (to_ufixed (l, r'high, r'low) > r); + end function ">"; + + function "<" ( + l : NATURAL; + r : UNRESOLVED_ufixed) -- fixed point input + return BOOLEAN is + begin + return (to_ufixed (l, r'high, r'low) < r); + end function "<"; + + function \?=\ ( + l : NATURAL; + r : UNRESOLVED_ufixed) -- fixed point input + return STD_ULOGIC is + begin + return \?=\ (to_ufixed (l, r'high, r'low), r); + end function \?=\; + + function \?/=\ ( + l : NATURAL; + r : UNRESOLVED_ufixed) -- fixed point input + return STD_ULOGIC is + begin + return \?/=\ (to_ufixed (l, r'high, r'low), r); + end function \?/=\; + + function \?>=\ ( + l : NATURAL; + r : UNRESOLVED_ufixed) -- fixed point input + return STD_ULOGIC is + begin + return \?>=\ (to_ufixed (l, r'high, r'low), r); + end function \?>=\; + + function \?<=\ ( + l : NATURAL; + r : UNRESOLVED_ufixed) -- fixed point input + return STD_ULOGIC is + begin + return \?<=\ (to_ufixed (l, r'high, r'low), r); + end function \?<=\; + + function \?>\ ( + l : NATURAL; + r : UNRESOLVED_ufixed) -- fixed point input + return STD_ULOGIC is + begin + return \?>\ (to_ufixed (l, r'high, r'low), r); + end function \?>\; + + function \?<\ ( + l : NATURAL; + r : UNRESOLVED_ufixed) -- fixed point input + return STD_ULOGIC is + begin + return \?<\ (to_ufixed (l, r'high, r'low), r); + end function \?<\; + + function maximum ( + l : NATURAL; + r : UNRESOLVED_ufixed) -- fixed point input + return UNRESOLVED_ufixed is + begin + return maximum (to_ufixed (l, r'high, r'low), r); + end function maximum; + + function minimum ( + l : NATURAL; + r : UNRESOLVED_ufixed) -- fixed point input + return UNRESOLVED_ufixed is + begin + return minimum (to_ufixed (l, r'high, r'low), r); + end function minimum; + + -- overloaded ufixed compare functions with real + function "=" ( + l : UNRESOLVED_ufixed; + r : REAL) + return BOOLEAN is + begin + return (l = to_ufixed (r, l'high, l'low)); + end function "="; + + function "/=" ( + l : UNRESOLVED_ufixed; + r : REAL) + return BOOLEAN is + begin + return (l /= to_ufixed (r, l'high, l'low)); + end function "/="; + + function ">=" ( + l : UNRESOLVED_ufixed; + r : REAL) + return BOOLEAN is + begin + return (l >= to_ufixed (r, l'high, l'low)); + end function ">="; + + function "<=" ( + l : UNRESOLVED_ufixed; + r : REAL) + return BOOLEAN is + begin + return (l <= to_ufixed (r, l'high, l'low)); + end function "<="; + + function ">" ( + l : UNRESOLVED_ufixed; + r : REAL) + return BOOLEAN is + begin + return (l > to_ufixed (r, l'high, l'low)); + end function ">"; + + function "<" ( + l : UNRESOLVED_ufixed; + r : REAL) + return BOOLEAN is + begin + return (l < to_ufixed (r, l'high, l'low)); + end function "<"; + + function \?=\ ( + l : UNRESOLVED_ufixed; + r : REAL) + return STD_ULOGIC is + begin + return \?=\ (l, to_ufixed (r, l'high, l'low)); + end function \?=\; + + function \?/=\ ( + l : UNRESOLVED_ufixed; + r : REAL) + return STD_ULOGIC is + begin + return \?/=\ (l, to_ufixed (r, l'high, l'low)); + end function \?/=\; + + function \?>=\ ( + l : UNRESOLVED_ufixed; + r : REAL) + return STD_ULOGIC is + begin + return \?>=\ (l, to_ufixed (r, l'high, l'low)); + end function \?>=\; + + function \?<=\ ( + l : UNRESOLVED_ufixed; + r : REAL) + return STD_ULOGIC is + begin + return \?<=\ (l, to_ufixed (r, l'high, l'low)); + end function \?<=\; + + function \?>\ ( + l : UNRESOLVED_ufixed; + r : REAL) + return STD_ULOGIC is + begin + return \?>\ (l, to_ufixed (r, l'high, l'low)); + end function \?>\; + + function \?<\ ( + l : UNRESOLVED_ufixed; + r : REAL) + return STD_ULOGIC is + begin + return \?<\ (l, to_ufixed (r, l'high, l'low)); + end function \?<\; + + function maximum ( + l : UNRESOLVED_ufixed; + r : REAL) + return UNRESOLVED_ufixed is + begin + return maximum (l, to_ufixed (r, l'high, l'low)); + end function maximum; + + function minimum ( + l : UNRESOLVED_ufixed; + r : REAL) + return UNRESOLVED_ufixed is + begin + return minimum (l, to_ufixed (r, l'high, l'low)); + end function minimum; + + -- real and ufixed + function "=" ( + l : REAL; + r : UNRESOLVED_ufixed) -- fixed point input + return BOOLEAN is + begin + return (to_ufixed (l, r'high, r'low) = r); + end function "="; + + function "/=" ( + l : REAL; + r : UNRESOLVED_ufixed) -- fixed point input + return BOOLEAN is + begin + return (to_ufixed (l, r'high, r'low) /= r); + end function "/="; + + function ">=" ( + l : REAL; + r : UNRESOLVED_ufixed) -- fixed point input + return BOOLEAN is + begin + return (to_ufixed (l, r'high, r'low) >= r); + end function ">="; + + function "<=" ( + l : REAL; + r : UNRESOLVED_ufixed) -- fixed point input + return BOOLEAN is + begin + return (to_ufixed (l, r'high, r'low) <= r); + end function "<="; + + function ">" ( + l : REAL; + r : UNRESOLVED_ufixed) -- fixed point input + return BOOLEAN is + begin + return (to_ufixed (l, r'high, r'low) > r); + end function ">"; + + function "<" ( + l : REAL; + r : UNRESOLVED_ufixed) -- fixed point input + return BOOLEAN is + begin + return (to_ufixed (l, r'high, r'low) < r); + end function "<"; + + function \?=\ ( + l : REAL; + r : UNRESOLVED_ufixed) -- fixed point input + return STD_ULOGIC is + begin + return \?=\ (to_ufixed (l, r'high, r'low), r); + end function \?=\; + + function \?/=\ ( + l : REAL; + r : UNRESOLVED_ufixed) -- fixed point input + return STD_ULOGIC is + begin + return \?/=\ (to_ufixed (l, r'high, r'low), r); + end function \?/=\; + + function \?>=\ ( + l : REAL; + r : UNRESOLVED_ufixed) -- fixed point input + return STD_ULOGIC is + begin + return \?>=\ (to_ufixed (l, r'high, r'low), r); + end function \?>=\; + + function \?<=\ ( + l : REAL; + r : UNRESOLVED_ufixed) -- fixed point input + return STD_ULOGIC is + begin + return \?<=\ (to_ufixed (l, r'high, r'low), r); + end function \?<=\; + + function \?>\ ( + l : REAL; + r : UNRESOLVED_ufixed) -- fixed point input + return STD_ULOGIC is + begin + return \?>\ (to_ufixed (l, r'high, r'low), r); + end function \?>\; + + function \?<\ ( + l : REAL; + r : UNRESOLVED_ufixed) -- fixed point input + return STD_ULOGIC is + begin + return \?<\ (to_ufixed (l, r'high, r'low), r); + end function \?<\; + + function maximum ( + l : REAL; + r : UNRESOLVED_ufixed) -- fixed point input + return UNRESOLVED_ufixed is + begin + return maximum (to_ufixed (l, r'high, r'low), r); + end function maximum; + + function minimum ( + l : REAL; + r : UNRESOLVED_ufixed) -- fixed point input + return UNRESOLVED_ufixed is + begin + return minimum (to_ufixed (l, r'high, r'low), r); + end function minimum; + + -- overloaded sfixed compare functions with integer + function "=" ( + l : UNRESOLVED_sfixed; + r : INTEGER) + return BOOLEAN is + begin + return (l = to_sfixed (r, l'high, l'low)); + end function "="; + + function "/=" ( + l : UNRESOLVED_sfixed; + r : INTEGER) + return BOOLEAN is + begin + return (l /= to_sfixed (r, l'high, l'low)); + end function "/="; + + function ">=" ( + l : UNRESOLVED_sfixed; + r : INTEGER) + return BOOLEAN is + begin + return (l >= to_sfixed (r, l'high, l'low)); + end function ">="; + + function "<=" ( + l : UNRESOLVED_sfixed; + r : INTEGER) + return BOOLEAN is + begin + return (l <= to_sfixed (r, l'high, l'low)); + end function "<="; + + function ">" ( + l : UNRESOLVED_sfixed; + r : INTEGER) + return BOOLEAN is + begin + return (l > to_sfixed (r, l'high, l'low)); + end function ">"; + + function "<" ( + l : UNRESOLVED_sfixed; + r : INTEGER) + return BOOLEAN is + begin + return (l < to_sfixed (r, l'high, l'low)); + end function "<"; + + function \?=\ ( + l : UNRESOLVED_sfixed; + r : INTEGER) + return STD_ULOGIC is + begin + return \?=\ (l, to_sfixed (r, l'high, l'low)); + end function \?=\; + + function \?/=\ ( + l : UNRESOLVED_sfixed; + r : INTEGER) + return STD_ULOGIC is + begin + return \?/=\ (l, to_sfixed (r, l'high, l'low)); + end function \?/=\; + + function \?>=\ ( + l : UNRESOLVED_sfixed; + r : INTEGER) + return STD_ULOGIC is + begin + return \?>=\ (l, to_sfixed (r, l'high, l'low)); + end function \?>=\; + + function \?<=\ ( + l : UNRESOLVED_sfixed; + r : INTEGER) + return STD_ULOGIC is + begin + return \?<=\ (l, to_sfixed (r, l'high, l'low)); + end function \?<=\; + + function \?>\ ( + l : UNRESOLVED_sfixed; + r : INTEGER) + return STD_ULOGIC is + begin + return \?>\ (l, to_sfixed (r, l'high, l'low)); + end function \?>\; + + function \?<\ ( + l : UNRESOLVED_sfixed; + r : INTEGER) + return STD_ULOGIC is + begin + return \?<\ (l, to_sfixed (r, l'high, l'low)); + end function \?<\; + + function maximum ( + l : UNRESOLVED_sfixed; + r : INTEGER) + return UNRESOLVED_sfixed is + begin + return maximum (l, to_sfixed (r, l'high, l'low)); + end function maximum; + + function minimum ( + l : UNRESOLVED_sfixed; + r : INTEGER) + return UNRESOLVED_sfixed is + begin + return minimum (l, to_sfixed (r, l'high, l'low)); + end function minimum; + + -- integer and sfixed + function "=" ( + l : INTEGER; + r : UNRESOLVED_sfixed) -- fixed point input + return BOOLEAN is + begin + return (to_sfixed (l, r'high, r'low) = r); + end function "="; + + function "/=" ( + l : INTEGER; + r : UNRESOLVED_sfixed) -- fixed point input + return BOOLEAN is + begin + return (to_sfixed (l, r'high, r'low) /= r); + end function "/="; + + function ">=" ( + l : INTEGER; + r : UNRESOLVED_sfixed) -- fixed point input + return BOOLEAN is + begin + return (to_sfixed (l, r'high, r'low) >= r); + end function ">="; + + function "<=" ( + l : INTEGER; + r : UNRESOLVED_sfixed) -- fixed point input + return BOOLEAN is + begin + return (to_sfixed (l, r'high, r'low) <= r); + end function "<="; + + function ">" ( + l : INTEGER; + r : UNRESOLVED_sfixed) -- fixed point input + return BOOLEAN is + begin + return (to_sfixed (l, r'high, r'low) > r); + end function ">"; + + function "<" ( + l : INTEGER; + r : UNRESOLVED_sfixed) -- fixed point input + return BOOLEAN is + begin + return (to_sfixed (l, r'high, r'low) < r); + end function "<"; + + function \?=\ ( + l : INTEGER; + r : UNRESOLVED_sfixed) -- fixed point input + return STD_ULOGIC is + begin + return \?=\ (to_sfixed (l, r'high, r'low), r); + end function \?=\; + + function \?/=\ ( + l : INTEGER; + r : UNRESOLVED_sfixed) -- fixed point input + return STD_ULOGIC is + begin + return \?/=\ (to_sfixed (l, r'high, r'low), r); + end function \?/=\; + + function \?>=\ ( + l : INTEGER; + r : UNRESOLVED_sfixed) -- fixed point input + return STD_ULOGIC is + begin + return \?>=\ (to_sfixed (l, r'high, r'low), r); + end function \?>=\; + + function \?<=\ ( + l : INTEGER; + r : UNRESOLVED_sfixed) -- fixed point input + return STD_ULOGIC is + begin + return \?<=\ (to_sfixed (l, r'high, r'low), r); + end function \?<=\; + + function \?>\ ( + l : INTEGER; + r : UNRESOLVED_sfixed) -- fixed point input + return STD_ULOGIC is + begin + return \?>\ (to_sfixed (l, r'high, r'low), r); + end function \?>\; + + function \?<\ ( + l : INTEGER; + r : UNRESOLVED_sfixed) -- fixed point input + return STD_ULOGIC is + begin + return \?<\ (to_sfixed (l, r'high, r'low), r); + end function \?<\; + + function maximum ( + l : INTEGER; + r : UNRESOLVED_sfixed) + return UNRESOLVED_sfixed is + begin + return maximum (to_sfixed (l, r'high, r'low), r); + end function maximum; + + function minimum ( + l : INTEGER; + r : UNRESOLVED_sfixed) + return UNRESOLVED_sfixed is + begin + return minimum (to_sfixed (l, r'high, r'low), r); + end function minimum; + + -- overloaded sfixed compare functions with real + function "=" ( + l : UNRESOLVED_sfixed; + r : REAL) + return BOOLEAN is + begin + return (l = to_sfixed (r, l'high, l'low)); + end function "="; + + function "/=" ( + l : UNRESOLVED_sfixed; + r : REAL) + return BOOLEAN is + begin + return (l /= to_sfixed (r, l'high, l'low)); + end function "/="; + + function ">=" ( + l : UNRESOLVED_sfixed; + r : REAL) + return BOOLEAN is + begin + return (l >= to_sfixed (r, l'high, l'low)); + end function ">="; + + function "<=" ( + l : UNRESOLVED_sfixed; + r : REAL) + return BOOLEAN is + begin + return (l <= to_sfixed (r, l'high, l'low)); + end function "<="; + + function ">" ( + l : UNRESOLVED_sfixed; + r : REAL) + return BOOLEAN is + begin + return (l > to_sfixed (r, l'high, l'low)); + end function ">"; + + function "<" ( + l : UNRESOLVED_sfixed; + r : REAL) + return BOOLEAN is + begin + return (l < to_sfixed (r, l'high, l'low)); + end function "<"; + + function \?=\ ( + l : UNRESOLVED_sfixed; + r : REAL) + return STD_ULOGIC is + begin + return \?=\ (l, to_sfixed (r, l'high, l'low)); + end function \?=\; + + function \?/=\ ( + l : UNRESOLVED_sfixed; + r : REAL) + return STD_ULOGIC is + begin + return \?/=\ (l, to_sfixed (r, l'high, l'low)); + end function \?/=\; + + function \?>=\ ( + l : UNRESOLVED_sfixed; + r : REAL) + return STD_ULOGIC is + begin + return \?>=\ (l, to_sfixed (r, l'high, l'low)); + end function \?>=\; + + function \?<=\ ( + l : UNRESOLVED_sfixed; + r : REAL) + return STD_ULOGIC is + begin + return \?<=\ (l, to_sfixed (r, l'high, l'low)); + end function \?<=\; + + function \?>\ ( + l : UNRESOLVED_sfixed; + r : REAL) + return STD_ULOGIC is + begin + return \?>\ (l, to_sfixed (r, l'high, l'low)); + end function \?>\; + + function \?<\ ( + l : UNRESOLVED_sfixed; + r : REAL) + return STD_ULOGIC is + begin + return \?<\ (l, to_sfixed (r, l'high, l'low)); + end function \?<\; + + function maximum ( + l : UNRESOLVED_sfixed; + r : REAL) + return UNRESOLVED_sfixed is + begin + return maximum (l, to_sfixed (r, l'high, l'low)); + end function maximum; + + function minimum ( + l : UNRESOLVED_sfixed; + r : REAL) + return UNRESOLVED_sfixed is + begin + return minimum (l, to_sfixed (r, l'high, l'low)); + end function minimum; + + -- REAL and sfixed + function "=" ( + l : REAL; + r : UNRESOLVED_sfixed) -- fixed point input + return BOOLEAN is + begin + return (to_sfixed (l, r'high, r'low) = r); + end function "="; + + function "/=" ( + l : REAL; + r : UNRESOLVED_sfixed) -- fixed point input + return BOOLEAN is + begin + return (to_sfixed (l, r'high, r'low) /= r); + end function "/="; + + function ">=" ( + l : REAL; + r : UNRESOLVED_sfixed) -- fixed point input + return BOOLEAN is + begin + return (to_sfixed (l, r'high, r'low) >= r); + end function ">="; + + function "<=" ( + l : REAL; + r : UNRESOLVED_sfixed) -- fixed point input + return BOOLEAN is + begin + return (to_sfixed (l, r'high, r'low) <= r); + end function "<="; + + function ">" ( + l : REAL; + r : UNRESOLVED_sfixed) -- fixed point input + return BOOLEAN is + begin + return (to_sfixed (l, r'high, r'low) > r); + end function ">"; + + function "<" ( + l : REAL; + r : UNRESOLVED_sfixed) -- fixed point input + return BOOLEAN is + begin + return (to_sfixed (l, r'high, r'low) < r); + end function "<"; + + function \?=\ ( + l : REAL; + r : UNRESOLVED_sfixed) -- fixed point input + return STD_ULOGIC is + begin + return \?=\ (to_sfixed (l, r'high, r'low), r); + end function \?=\; + + function \?/=\ ( + l : REAL; + r : UNRESOLVED_sfixed) -- fixed point input + return STD_ULOGIC is + begin + return \?/=\ (to_sfixed (l, r'high, r'low), r); + end function \?/=\; + + function \?>=\ ( + l : REAL; + r : UNRESOLVED_sfixed) -- fixed point input + return STD_ULOGIC is + begin + return \?>=\ (to_sfixed (l, r'high, r'low), r); + end function \?>=\; + + function \?<=\ ( + l : REAL; + r : UNRESOLVED_sfixed) -- fixed point input + return STD_ULOGIC is + begin + return \?<=\ (to_sfixed (l, r'high, r'low), r); + end function \?<=\; + + function \?>\ ( + l : REAL; + r : UNRESOLVED_sfixed) -- fixed point input + return STD_ULOGIC is + begin + return \?>\ (to_sfixed (l, r'high, r'low), r); + end function \?>\; + + function \?<\ ( + l : REAL; + r : UNRESOLVED_sfixed) -- fixed point input + return STD_ULOGIC is + begin + return \?<\ (to_sfixed (l, r'high, r'low), r); + end function \?<\; + + function maximum ( + l : REAL; + r : UNRESOLVED_sfixed) + return UNRESOLVED_sfixed is + begin + return maximum (to_sfixed (l, r'high, r'low), r); + end function maximum; + + function minimum ( + l : REAL; + r : UNRESOLVED_sfixed) + return UNRESOLVED_sfixed is + begin + return minimum (to_sfixed (l, r'high, r'low), r); + end function minimum; +-- rtl_synthesis off +-- pragma synthesis_off + -- copied from std_logic_textio + 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); + constant NBSP : CHARACTER := CHARACTER'val(160); -- space character + constant NUS : STRING(2 to 1) := (others => ' '); + + -- %%% Replicated Textio functions + procedure Char2TriBits (C : CHARACTER; + RESULT : out STD_ULOGIC_VECTOR(2 downto 0); + GOOD : out BOOLEAN; + ISSUE_ERROR : in BOOLEAN) is + begin + case c is + when '0' => result := o"0"; good := true; + when '1' => result := o"1"; good := true; + when '2' => result := o"2"; good := true; + when '3' => result := o"3"; good := true; + when '4' => result := o"4"; good := true; + when '5' => result := o"5"; good := true; + when '6' => result := o"6"; good := true; + when '7' => result := o"7"; good := true; + when 'Z' => result := "ZZZ"; good := true; + when 'X' => result := "XXX"; good := true; + when others => + assert not ISSUE_ERROR + report fixed_pkg'instance_name + & "OREAD Error: Read a '" & c & + "', expected an Octal character (0-7)." + severity error; + result := "UUU"; + good := false; + end case; + end procedure Char2TriBits; + -- Hex Read and Write procedures for STD_ULOGIC_VECTOR. + -- Modified from the original to be more forgiving. + + procedure Char2QuadBits (C : CHARACTER; + RESULT : out STD_ULOGIC_VECTOR(3 downto 0); + GOOD : out BOOLEAN; + ISSUE_ERROR : in BOOLEAN) is + begin + case c is + when '0' => result := x"0"; good := true; + when '1' => result := x"1"; good := true; + when '2' => result := x"2"; good := true; + when '3' => result := x"3"; good := true; + when '4' => result := x"4"; good := true; + when '5' => result := x"5"; good := true; + when '6' => result := x"6"; good := true; + when '7' => result := x"7"; good := true; + when '8' => result := x"8"; good := true; + when '9' => result := x"9"; good := true; + when 'A' | 'a' => result := x"A"; good := true; + when 'B' | 'b' => result := x"B"; good := true; + when 'C' | 'c' => result := x"C"; good := true; + when 'D' | 'd' => result := x"D"; good := true; + when 'E' | 'e' => result := x"E"; good := true; + when 'F' | 'f' => result := x"F"; good := true; + when 'Z' => result := "ZZZZ"; good := true; + when 'X' => result := "XXXX"; good := true; + when others => + assert not ISSUE_ERROR + report fixed_pkg'instance_name + & "HREAD Error: Read a '" & c & + "', expected a Hex character (0-F)." + severity error; + result := "UUUU"; + good := false; + end case; + end procedure Char2QuadBits; + + -- purpose: Skips white space + procedure skip_whitespace ( + L : inout LINE) is + variable readOk : BOOLEAN; + variable c : CHARACTER; + begin + while L /= null and L.all'length /= 0 loop + if (L.all(1) = ' ' or L.all(1) = NBSP or L.all(1) = HT) then + read (l, c, readOk); + else + exit; + end if; + end loop; + end procedure skip_whitespace; + + function to_ostring (value : STD_ULOGIC_VECTOR) return STRING is + constant ne : INTEGER := (value'length+2)/3; + variable pad : STD_ULOGIC_VECTOR(0 to (ne*3 - value'length) - 1); + variable ivalue : STD_ULOGIC_VECTOR(0 to ne*3 - 1); + variable result : STRING(1 to ne); + variable tri : STD_ULOGIC_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 result; + end if; + end function to_ostring; + ------------------------------------------------------------------- + function to_hstring (value : STD_ULOGIC_VECTOR) return STRING is + constant ne : INTEGER := (value'length+3)/4; + variable pad : STD_ULOGIC_VECTOR(0 to (ne*4 - value'length) - 1); + variable ivalue : STD_ULOGIC_VECTOR(0 to ne*4 - 1); + variable result : STRING(1 to ne); + variable quad : STD_ULOGIC_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 result; + end if; + end function to_hstring; + + +-- %%% END replicated textio functions + + -- purpose: writes fixed point into a line + procedure write ( + L : inout LINE; -- input line + VALUE : in UNRESOLVED_ufixed; -- fixed point input + JUSTIFIED : in SIDE := right; + FIELD : in WIDTH := 0) is + variable s : STRING(1 to value'length +1) := (others => ' '); + variable sindx : INTEGER; + begin -- function write Example: 0011.1100 + sindx := 1; + for i in value'high downto value'low loop + if i = -1 then + s(sindx) := '.'; + sindx := sindx + 1; + end if; + s(sindx) := MVL9_to_char(STD_ULOGIC(value(i))); + sindx := sindx + 1; + end loop; + write(l, s, justified, field); + end procedure write; + + -- purpose: writes fixed point into a line + procedure write ( + L : inout LINE; -- input line + VALUE : in UNRESOLVED_sfixed; -- fixed point input + JUSTIFIED : in SIDE := right; + FIELD : in WIDTH := 0) is + variable s : STRING(1 to value'length +1); + variable sindx : INTEGER; + begin -- function write Example: 0011.1100 + sindx := 1; + for i in value'high downto value'low loop + if i = -1 then + s(sindx) := '.'; + sindx := sindx + 1; + end if; + 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 UNRESOLVED_ufixed) is + -- Possible data: 00000.0000000 + -- 000000000000 + variable c : CHARACTER; + variable readOk : BOOLEAN; + variable i : INTEGER; -- index variable + variable mv : ufixed (VALUE'range); + variable lastu : BOOLEAN := false; -- last character was an "_" + variable founddot : BOOLEAN := false; -- found a "." + begin -- READ + VALUE := (VALUE'range => 'U'); + Skip_whitespace (L); + if VALUE'length > 0 then -- non Null input string + read (l, c, readOk); + i := value'high; + while i >= VALUE'low loop + if readOk = false then -- Bail out if there was a bad read + report fixed_pkg'instance_name & "READ(ufixed) " + & "End of string encountered" + severity error; + return; + elsif c = '_' then + if i = value'high then + report fixed_pkg'instance_name & "READ(ufixed) " + & "String begins with an ""_""" severity error; + return; + elsif lastu then + report fixed_pkg'instance_name & "READ(ufixed) " + & "Two underscores detected in input string ""__""" + severity error; + return; + else + lastu := true; + end if; + elsif c = '.' then -- binary point + if founddot then + report fixed_pkg'instance_name & "READ(ufixed) " + & "Two binary points found in input string" severity error; + return; + elsif i /= -1 then -- Seperator in the wrong spot + report fixed_pkg'instance_name & "READ(ufixed) " + & "Decimal point does not match number format " + severity error; + return; + end if; + founddot := true; + lastu := false; + elsif c = ' ' or c = NBSP or c = HT then -- reading done. + report fixed_pkg'instance_name & "READ(ufixed) " + & "Short read, Space encounted in input string" + severity error; + return; + elsif char_to_MVL9plus(c) = error then + report fixed_pkg'instance_name & "READ(ufixed) " + & "Character '" & + c & "' read, expected STD_ULOGIC literal." + severity error; + return; + else + mv(i) := char_to_MVL9(c); + i := i - 1; + if i < mv'low then + VALUE := mv; + return; + end if; + lastu := false; + end if; + read(L, c, readOk); + end loop; + end if; + end procedure READ; + + procedure READ(L : inout LINE; + VALUE : out UNRESOLVED_ufixed; + GOOD : out BOOLEAN) is + -- Possible data: 00000.0000000 + -- 000000000000 + variable c : CHARACTER; + variable readOk : BOOLEAN; + variable mv : ufixed (VALUE'range); + variable i : INTEGER; -- index variable + variable lastu : BOOLEAN := false; -- last character was an "_" + variable founddot : BOOLEAN := false; -- found a "." + begin -- READ + VALUE := (VALUE'range => 'U'); + Skip_whitespace (L); + if VALUE'length > 0 then + read (l, c, readOk); + i := value'high; + GOOD := false; + while i >= VALUE'low loop + if not readOk then -- Bail out if there was a bad read + return; + elsif c = '_' then + if i = value'high then -- Begins with an "_" + return; + elsif lastu then -- "__" detected + return; + else + lastu := true; + end if; + elsif c = '.' then -- binary point + if founddot then + return; + elsif i /= -1 then -- Seperator in the wrong spot + return; + end if; + founddot := true; + lastu := false; + elsif (char_to_MVL9plus(c) = error) then -- Illegal character/short read + return; + else + mv(i) := char_to_MVL9(c); + i := i - 1; + if i < mv'low then -- reading done + GOOD := true; + VALUE := mv; + return; + end if; + lastu := false; + end if; + read(L, c, readOk); + end loop; + else + GOOD := true; -- read into a null array + end if; + end procedure READ; + + procedure READ(L : inout LINE; + VALUE : out UNRESOLVED_sfixed) is + variable c : CHARACTER; + variable readOk : BOOLEAN; + variable i : INTEGER; -- index variable + variable mv : sfixed (VALUE'range); + variable lastu : BOOLEAN := false; -- last character was an "_" + variable founddot : BOOLEAN := false; -- found a "." + begin -- READ + VALUE := (VALUE'range => 'U'); + Skip_whitespace (L); + if VALUE'length > 0 then -- non Null input string + read (l, c, readOk); + i := value'high; + while i >= VALUE'low loop + if readOk = false then -- Bail out if there was a bad read + report fixed_pkg'instance_name & "READ(sfixed) " + & "End of string encountered" + severity error; + return; + elsif c = '_' then + if i = value'high then + report fixed_pkg'instance_name & "READ(sfixed) " + & "String begins with an ""_""" severity error; + return; + elsif lastu then + report fixed_pkg'instance_name & "READ(sfixed) " + & "Two underscores detected in input string ""__""" + severity error; + return; + else + lastu := true; + end if; + elsif c = '.' then -- binary point + if founddot then + report fixed_pkg'instance_name & "READ(sfixed) " + & "Two binary points found in input string" severity error; + return; + elsif i /= -1 then -- Seperator in the wrong spot + report fixed_pkg'instance_name & "READ(sfixed) " + & "Decimal point does not match number format " + severity error; + return; + end if; + founddot := true; + lastu := false; + elsif c = ' ' or c = NBSP or c = HT then -- reading done. + report fixed_pkg'instance_name & "READ(sfixed) " + & "Short read, Space encounted in input string" + severity error; + return; + elsif char_to_MVL9plus(c) = error then + report fixed_pkg'instance_name & "READ(sfixed) " + & "Character '" & + c & "' read, expected STD_ULOGIC literal." + severity error; + return; + else + mv(i) := char_to_MVL9(c); + i := i - 1; + if i < mv'low then + VALUE := mv; + return; + end if; + lastu := false; + end if; + read(L, c, readOk); + end loop; + end if; + end procedure READ; + + procedure READ(L : inout LINE; + VALUE : out UNRESOLVED_sfixed; + GOOD : out BOOLEAN) is + variable value_ufixed : UNRESOLVED_ufixed (VALUE'range); + begin -- READ + READ (L => L, VALUE => value_ufixed, GOOD => GOOD); + VALUE := UNRESOLVED_sfixed (value_ufixed); + end procedure READ; + + -- octal read and write + procedure owrite ( + L : inout LINE; -- input line + VALUE : in UNRESOLVED_ufixed; -- fixed point input + JUSTIFIED : in SIDE := right; + FIELD : in WIDTH := 0) is + begin -- Example 03.30 + write (L => L, + VALUE => to_ostring (VALUE), + JUSTIFIED => JUSTIFIED, + FIELD => FIELD); + end procedure owrite; + + procedure owrite ( + L : inout LINE; -- input line + VALUE : in UNRESOLVED_sfixed; -- fixed point input + JUSTIFIED : in SIDE := right; + FIELD : in WIDTH := 0) is + begin -- Example 03.30 + write (L => L, + VALUE => to_ostring (VALUE), + JUSTIFIED => JUSTIFIED, + FIELD => FIELD); + end procedure owrite; + + -- purpose: Routines common to the OREAD routines + procedure OREAD_common ( + L : inout LINE; + slv : out STD_ULOGIC_VECTOR; + igood : out BOOLEAN; + idex : out INTEGER; + constant bpoint : in INTEGER; -- binary point + constant message : in BOOLEAN; + constant smath : in BOOLEAN) is + + -- purpose: error message routine + procedure errmes ( + constant mess : in STRING) is -- error message + begin + if message then + if smath then + report fixed_pkg'instance_name + & "OREAD(sfixed) " + & mess + severity error; + else + report fixed_pkg'instance_name + & "OREAD(ufixed) " + & mess + severity error; + end if; + end if; + end procedure errmes; + variable xgood : BOOLEAN; + variable nybble : STD_ULOGIC_VECTOR (2 downto 0); -- 3 bits + variable c : CHARACTER; + variable i : INTEGER; + variable lastu : BOOLEAN := false; -- last character was an "_" + variable founddot : BOOLEAN := false; -- found a dot. + begin + Skip_whitespace (L); + if slv'length > 0 then + i := slv'high; + read (l, c, xgood); + while i > 0 loop + if xgood = false then + errmes ("Error: end of string encountered"); + exit; + elsif c = '_' then + if i = slv'length then + errmes ("Error: String begins with an ""_"""); + xgood := false; + exit; + elsif lastu then + errmes ("Error: Two underscores detected in input string ""__"""); + xgood := false; + exit; + else + lastu := true; + end if; + elsif (c = '.') then + if (i + 1 /= bpoint) then + errmes ("encountered ""."" at wrong index"); + xgood := false; + exit; + elsif i = slv'length then + errmes ("encounted a ""."" at the beginning of the line"); + xgood := false; + exit; + elsif founddot then + errmes ("Two ""."" encounted in input string"); + xgood := false; + exit; + end if; + founddot := true; + lastu := false; + else + Char2triBits(c, nybble, xgood, message); + if not xgood then + exit; + end if; + slv (i downto i-2) := nybble; + i := i - 3; + lastu := false; + end if; + if i > 0 then + read (L, c, xgood); + end if; + end loop; + idex := i; + igood := xgood; + else + igood := true; -- read into a null array + idex := -1; + end if; + end procedure OREAD_common; + + -- Note that for Octal and Hex read, you can not start with a ".", + -- the read is for numbers formatted "A.BC". These routines go to + -- the nearest bounds, so "F.E" will fit into an sfixed (2 downto -3). + procedure OREAD (L : inout LINE; + VALUE : out UNRESOLVED_ufixed) is + constant hbv : INTEGER := (((maximum(3, (VALUE'high+1))+2)/3)*3)-1; + constant lbv : INTEGER := ((mine(0, VALUE'low)-2)/3)*3; + variable slv : STD_ULOGIC_VECTOR (hbv-lbv downto 0); -- high bits + variable valuex : UNRESOLVED_ufixed (hbv downto lbv); + variable igood : BOOLEAN; + variable i : INTEGER; + begin + VALUE := (VALUE'range => 'U'); + OREAD_common ( L => L, + slv => slv, + igood => igood, + idex => i, + bpoint => -lbv, + message => true, + smath => false); + if igood then -- We did not get another error + if not ((i = -1) and -- We read everything, and high bits 0 + (or_reduce (slv(hbv-lbv downto VALUE'high+1-lbv)) = '0')) then + report fixed_pkg'instance_name + & "OREAD(ufixed): Vector truncated." + severity error; + else + if (or_reduce (slv(VALUE'low-lbv-1 downto 0)) = '1') then + assert NO_WARNING + report fixed_pkg'instance_name + & "OREAD(ufixed): Vector truncated" + severity warning; + end if; + valuex := to_ufixed (slv, hbv, lbv); + VALUE := valuex (VALUE'range); + end if; + end if; + end procedure OREAD; + + procedure OREAD(L : inout LINE; + VALUE : out UNRESOLVED_ufixed; + GOOD : out BOOLEAN) is + constant hbv : INTEGER := (((maximum(3, (VALUE'high+1))+2)/3)*3)-1; + constant lbv : INTEGER := ((mine(0, VALUE'low)-2)/3)*3; + variable slv : STD_ULOGIC_VECTOR (hbv-lbv downto 0); -- high bits + variable valuex : UNRESOLVED_ufixed (hbv downto lbv); + variable igood : BOOLEAN; + variable i : INTEGER; + begin + VALUE := (VALUE'range => 'U'); + OREAD_common ( L => L, + slv => slv, + igood => igood, + idex => i, + bpoint => -lbv, + message => false, + smath => false); + if (igood and -- We did not get another error + (i = -1) and -- We read everything, and high bits 0 + (or_reduce (slv(hbv-lbv downto VALUE'high+1-lbv)) = '0')) then + valuex := to_ufixed (slv, hbv, lbv); + VALUE := valuex (VALUE'range); + good := true; + else + good := false; + end if; + end procedure OREAD; + + procedure OREAD(L : inout LINE; + VALUE : out UNRESOLVED_sfixed) is + constant hbv : INTEGER := (((maximum(3, (VALUE'high+1))+2)/3)*3)-1; + constant lbv : INTEGER := ((mine(0, VALUE'low)-2)/3)*3; + variable slv : STD_ULOGIC_VECTOR (hbv-lbv downto 0); -- high bits + variable valuex : UNRESOLVED_sfixed (hbv downto lbv); + variable igood : BOOLEAN; + variable i : INTEGER; + begin + VALUE := (VALUE'range => 'U'); + OREAD_common ( L => L, + slv => slv, + igood => igood, + idex => i, + bpoint => -lbv, + message => true, + smath => true); + if igood then -- We did not get another error + if not ((i = -1) and -- We read everything + ((slv(VALUE'high-lbv) = '0' and -- sign bits = extra bits + or_reduce (slv(hbv-lbv downto VALUE'high+1-lbv)) = '0') or + (slv(VALUE'high-lbv) = '1' and + and_reduce (slv(hbv-lbv downto VALUE'high+1-lbv)) = '1'))) then + report fixed_pkg'instance_name + & "OREAD(sfixed): Vector truncated." + severity error; + else + if (or_reduce (slv(VALUE'low-lbv-1 downto 0)) = '1') then + assert NO_WARNING + report fixed_pkg'instance_name + & "OREAD(sfixed): Vector truncated" + severity warning; + end if; + valuex := to_sfixed (slv, hbv, lbv); + VALUE := valuex (VALUE'range); + end if; + end if; + end procedure OREAD; + + procedure OREAD(L : inout LINE; + VALUE : out UNRESOLVED_sfixed; + GOOD : out BOOLEAN) is + constant hbv : INTEGER := (((maximum(3, (VALUE'high+1))+2)/3)*3)-1; + constant lbv : INTEGER := ((mine(0, VALUE'low)-2)/3)*3; + variable slv : STD_ULOGIC_VECTOR (hbv-lbv downto 0); -- high bits + variable valuex : UNRESOLVED_sfixed (hbv downto lbv); + variable igood : BOOLEAN; + variable i : INTEGER; + begin + VALUE := (VALUE'range => 'U'); + OREAD_common ( L => L, + slv => slv, + igood => igood, + idex => i, + bpoint => -lbv, + message => false, + smath => true); + if (igood -- We did not get another error + and (i = -1) -- We read everything + and ((slv(VALUE'high-lbv) = '0' and -- sign bits = extra bits + or_reduce (slv(hbv-lbv downto VALUE'high+1-lbv)) = '0') or + (slv(VALUE'high-lbv) = '1' and + and_reduce (slv(hbv-lbv downto VALUE'high+1-lbv)) = '1'))) then + valuex := to_sfixed (slv, hbv, lbv); + VALUE := valuex (VALUE'range); + good := true; + else + good := false; + end if; + end procedure OREAD; + + -- hex read and write + procedure hwrite ( + L : inout LINE; -- input line + VALUE : in UNRESOLVED_ufixed; -- fixed point input + JUSTIFIED : in SIDE := right; + FIELD : in WIDTH := 0) is + begin -- Example 03.30 + write (L => L, + VALUE => to_hstring (VALUE), + JUSTIFIED => JUSTIFIED, + FIELD => FIELD); + end procedure hwrite; + + -- purpose: writes fixed point into a line + procedure hwrite ( + L : inout LINE; -- input line + VALUE : in UNRESOLVED_sfixed; -- fixed point input + JUSTIFIED : in SIDE := right; + FIELD : in WIDTH := 0) is + begin -- Example 03.30 + write (L => L, + VALUE => to_hstring (VALUE), + JUSTIFIED => JUSTIFIED, + FIELD => FIELD); + end procedure hwrite; + + -- purpose: Routines common to the OREAD routines + procedure HREAD_common ( + L : inout LINE; + slv : out STD_ULOGIC_VECTOR; + igood : out BOOLEAN; + idex : out INTEGER; + constant bpoint : in INTEGER; -- binary point + constant message : in BOOLEAN; + constant smath : in BOOLEAN) is + + -- purpose: error message routine + procedure errmes ( + constant mess : in STRING) is -- error message + begin + if message then + if smath then + report fixed_pkg'instance_name + & "HREAD(sfixed) " + & mess + severity error; + else + report fixed_pkg'instance_name + & "HREAD(ufixed) " + & mess + severity error; + end if; + end if; + end procedure errmes; + variable xgood : BOOLEAN; + variable nybble : STD_ULOGIC_VECTOR (3 downto 0); -- 4 bits + variable c : CHARACTER; + variable i : INTEGER; + variable lastu : BOOLEAN := false; -- last character was an "_" + variable founddot : BOOLEAN := false; -- found a dot. + begin + Skip_whitespace (L); + if slv'length > 0 then + i := slv'high; + read (l, c, xgood); + while i > 0 loop + if xgood = false then + errmes ("Error: end of string encountered"); + exit; + elsif c = '_' then + if i = slv'length then + errmes ("Error: String begins with an ""_"""); + xgood := false; + exit; + elsif lastu then + errmes ("Error: Two underscores detected in input string ""__"""); + xgood := false; + exit; + else + lastu := true; + end if; + elsif (c = '.') then + if (i + 1 /= bpoint) then + errmes ("encountered ""."" at wrong index"); + xgood := false; + exit; + elsif i = slv'length then + errmes ("encounted a ""."" at the beginning of the line"); + xgood := false; + exit; + elsif founddot then + errmes ("Two ""."" encounted in input string"); + xgood := false; + exit; + end if; + founddot := true; + lastu := false; + else + Char2QuadBits(c, nybble, xgood, message); + if not xgood then + exit; + end if; + slv (i downto i-3) := nybble; + i := i - 4; + lastu := false; + end if; + if i > 0 then + read (L, c, xgood); + end if; + end loop; + idex := i; + igood := xgood; + else + idex := -1; + igood := true; -- read null string + end if; + end procedure HREAD_common; + + procedure HREAD(L : inout LINE; + VALUE : out UNRESOLVED_ufixed) is + constant hbv : INTEGER := (((maximum(4, (VALUE'high+1))+3)/4)*4)-1; + constant lbv : INTEGER := ((mine(0, VALUE'low)-3)/4)*4; + variable slv : STD_ULOGIC_VECTOR (hbv-lbv downto 0); -- high bits + variable valuex : UNRESOLVED_ufixed (hbv downto lbv); + variable igood : BOOLEAN; + variable i : INTEGER; + begin + VALUE := (VALUE'range => 'U'); + HREAD_common ( L => L, + slv => slv, + igood => igood, + idex => i, + bpoint => -lbv, + message => false, + smath => false); + if igood then + if not ((i = -1) and -- We read everything, and high bits 0 + (or_reduce (slv(hbv-lbv downto VALUE'high+1-lbv)) = '0')) then + report fixed_pkg'instance_name + & "HREAD(ufixed): Vector truncated." + severity error; + else + if (or_reduce (slv(VALUE'low-lbv-1 downto 0)) = '1') then + assert NO_WARNING + report fixed_pkg'instance_name + & "HREAD(ufixed): Vector truncated" + severity warning; + end if; + valuex := to_ufixed (slv, hbv, lbv); + VALUE := valuex (VALUE'range); + end if; + end if; + end procedure HREAD; + + procedure HREAD(L : inout LINE; + VALUE : out UNRESOLVED_ufixed; + GOOD : out BOOLEAN) is + constant hbv : INTEGER := (((maximum(4, (VALUE'high+1))+3)/4)*4)-1; + constant lbv : INTEGER := ((mine(0, VALUE'low)-3)/4)*4; + variable slv : STD_ULOGIC_VECTOR (hbv-lbv downto 0); -- high bits + variable valuex : UNRESOLVED_ufixed (hbv downto lbv); + variable igood : BOOLEAN; + variable i : INTEGER; + begin + VALUE := (VALUE'range => 'U'); + HREAD_common ( L => L, + slv => slv, + igood => igood, + idex => i, + bpoint => -lbv, + message => false, + smath => false); + if (igood and -- We did not get another error + (i = -1) and -- We read everything, and high bits 0 + (or_reduce (slv(hbv-lbv downto VALUE'high+1-lbv)) = '0')) then + valuex := to_ufixed (slv, hbv, lbv); + VALUE := valuex (VALUE'range); + good := true; + else + good := false; + end if; + end procedure HREAD; + + procedure HREAD(L : inout LINE; + VALUE : out UNRESOLVED_sfixed) is + constant hbv : INTEGER := (((maximum(4, (VALUE'high+1))+3)/4)*4)-1; + constant lbv : INTEGER := ((mine(0, VALUE'low)-3)/4)*4; + variable slv : STD_ULOGIC_VECTOR (hbv-lbv downto 0); -- high bits + variable valuex : UNRESOLVED_sfixed (hbv downto lbv); + variable igood : BOOLEAN; + variable i : INTEGER; + begin + VALUE := (VALUE'range => 'U'); + HREAD_common ( L => L, + slv => slv, + igood => igood, + idex => i, + bpoint => -lbv, + message => true, + smath => true); + if igood then -- We did not get another error + if not ((i = -1) -- We read everything + and ((slv(VALUE'high-lbv) = '0' and -- sign bits = extra bits + or_reduce (slv(hbv-lbv downto VALUE'high+1-lbv)) = '0') or + (slv(VALUE'high-lbv) = '1' and + and_reduce (slv(hbv-lbv downto VALUE'high+1-lbv)) = '1'))) then + report fixed_pkg'instance_name + & "HREAD(sfixed): Vector truncated." + severity error; + else + if (or_reduce (slv(VALUE'low-lbv-1 downto 0)) = '1') then + assert NO_WARNING + report fixed_pkg'instance_name + & "HREAD(sfixed): Vector truncated" + severity warning; + end if; + valuex := to_sfixed (slv, hbv, lbv); + VALUE := valuex (VALUE'range); + end if; + end if; + end procedure HREAD; + + procedure HREAD(L : inout LINE; + VALUE : out UNRESOLVED_sfixed; + GOOD : out BOOLEAN) is + constant hbv : INTEGER := (((maximum(4, (VALUE'high+1))+3)/4)*4)-1; + constant lbv : INTEGER := ((mine(0, VALUE'low)-3)/4)*4; + variable slv : STD_ULOGIC_VECTOR (hbv-lbv downto 0); -- high bits + variable valuex : UNRESOLVED_sfixed (hbv downto lbv); + variable igood : BOOLEAN; + variable i : INTEGER; + begin + VALUE := (VALUE'range => 'U'); + HREAD_common ( L => L, + slv => slv, + igood => igood, + idex => i, + bpoint => -lbv, + message => false, + smath => true); + if (igood and -- We did not get another error + (i = -1) and -- We read everything + ((slv(VALUE'high-lbv) = '0' and -- sign bits = extra bits + or_reduce (slv(hbv-lbv downto VALUE'high+1-lbv)) = '0') or + (slv(VALUE'high-lbv) = '1' and + and_reduce (slv(hbv-lbv downto VALUE'high+1-lbv)) = '1'))) then + valuex := to_sfixed (slv, hbv, lbv); + VALUE := valuex (VALUE'range); + good := true; + else + good := false; + end if; + end procedure HREAD; + + function to_string (value : UNRESOLVED_ufixed) return STRING is + variable s : STRING(1 to value'length +1) := (others => ' '); + variable subval : UNRESOLVED_ufixed (value'high downto -1); + variable sindx : INTEGER; + begin + if value'length < 1 then + return NUS; + else + if value'high < 0 then + if value(value'high) = 'Z' then + return to_string (resize (sfixed(value), 0, value'low)); + else + return to_string (resize (value, 0, value'low)); + end if; + elsif value'low >= 0 then + if Is_X (value(value'low)) then + subval := (others => value(value'low)); + subval (value'range) := value; + return to_string(subval); + else + return to_string (resize (value, value'high, -1)); + end if; + else + sindx := 1; + for i in value'high downto value'low loop + if i = -1 then + s(sindx) := '.'; + sindx := sindx + 1; + end if; + s(sindx) := MVL9_to_char(STD_ULOGIC(value(i))); + sindx := sindx + 1; + end loop; + return s; + end if; + end if; + end function to_string; + + function to_string (value : UNRESOLVED_sfixed) return STRING is + variable s : STRING(1 to value'length + 1) := (others => ' '); + variable subval : UNRESOLVED_sfixed (value'high downto -1); + variable sindx : INTEGER; + begin + if value'length < 1 then + return NUS; + else + if value'high < 0 then + return to_string (resize (value, 0, value'low)); + elsif value'low >= 0 then + if Is_X (value(value'low)) then + subval := (others => value(value'low)); + subval (value'range) := value; + return to_string(subval); + else + return to_string (resize (value, value'high, -1)); + end if; + else + sindx := 1; + for i in value'high downto value'low loop + if i = -1 then + s(sindx) := '.'; + sindx := sindx + 1; + end if; + s(sindx) := MVL9_to_char(STD_ULOGIC(value(i))); + sindx := sindx + 1; + end loop; + return s; + end if; + end if; + end function to_string; + + function to_ostring (value : UNRESOLVED_ufixed) return STRING is + constant lne : INTEGER := (-VALUE'low+2)/3; + variable subval : UNRESOLVED_ufixed (value'high downto -3); + variable lpad : STD_ULOGIC_VECTOR (0 to (lne*3 + VALUE'low) -1); + variable slv : STD_ULOGIC_VECTOR (value'length-1 downto 0); + begin + if value'length < 1 then + return NUS; + else + if value'high < 0 then + if value(value'high) = 'Z' then + return to_ostring (resize (sfixed(value), 2, value'low)); + else + return to_ostring (resize (value, 2, value'low)); + end if; + elsif value'low >= 0 then + if Is_X (value(value'low)) then + subval := (others => value(value'low)); + subval (value'range) := value; + return to_ostring(subval); + else + return to_ostring (resize (value, value'high, -3)); + end if; + else + slv := to_sulv (value); + if Is_X (value (value'low)) then + lpad := (others => value (value'low)); + else + lpad := (others => '0'); + end if; + return to_ostring(slv(slv'high downto slv'high-VALUE'high)) + & "." + & to_ostring(slv(slv'high-VALUE'high-1 downto 0) & lpad); + end if; + end if; + end function to_ostring; + + function to_hstring (value : UNRESOLVED_ufixed) return STRING is + constant lne : INTEGER := (-VALUE'low+3)/4; + variable subval : UNRESOLVED_ufixed (value'high downto -4); + variable lpad : STD_ULOGIC_VECTOR (0 to (lne*4 + VALUE'low) -1); + variable slv : STD_ULOGIC_VECTOR (value'length-1 downto 0); + begin + if value'length < 1 then + return NUS; + else + if value'high < 0 then + if value(value'high) = 'Z' then + return to_hstring (resize (sfixed(value), 3, value'low)); + else + return to_hstring (resize (value, 3, value'low)); + end if; + elsif value'low >= 0 then + if Is_X (value(value'low)) then + subval := (others => value(value'low)); + subval (value'range) := value; + return to_hstring(subval); + else + return to_hstring (resize (value, value'high, -4)); + end if; + else + slv := to_sulv (value); + if Is_X (value (value'low)) then + lpad := (others => value(value'low)); + else + lpad := (others => '0'); + end if; + return to_hstring(slv(slv'high downto slv'high-VALUE'high)) + & "." + & to_hstring(slv(slv'high-VALUE'high-1 downto 0)&lpad); + end if; + end if; + end function to_hstring; + + function to_ostring (value : UNRESOLVED_sfixed) return STRING is + constant ne : INTEGER := ((value'high+1)+2)/3; + variable pad : STD_ULOGIC_VECTOR(0 to (ne*3 - (value'high+1)) - 1); + constant lne : INTEGER := (-VALUE'low+2)/3; + variable subval : UNRESOLVED_sfixed (value'high downto -3); + variable lpad : STD_ULOGIC_VECTOR (0 to (lne*3 + VALUE'low) -1); + variable slv : STD_ULOGIC_VECTOR (VALUE'high - VALUE'low downto 0); + begin + if value'length < 1 then + return NUS; + else + if value'high < 0 then + return to_ostring (resize (value, 2, value'low)); + elsif value'low >= 0 then + if Is_X (value(value'low)) then + subval := (others => value(value'low)); + subval (value'range) := value; + return to_ostring(subval); + else + return to_ostring (resize (value, value'high, -3)); + end if; + else + pad := (others => value(value'high)); + slv := to_sulv (value); + if Is_X (value (value'low)) then + lpad := (others => value(value'low)); + else + lpad := (others => '0'); + end if; + return to_ostring(pad & slv(slv'high downto slv'high-VALUE'high)) + & "." + & to_ostring(slv(slv'high-VALUE'high-1 downto 0) & lpad); + end if; + end if; + end function to_ostring; + + function to_hstring (value : UNRESOLVED_sfixed) return STRING is + constant ne : INTEGER := ((value'high+1)+3)/4; + variable pad : STD_ULOGIC_VECTOR(0 to (ne*4 - (value'high+1)) - 1); + constant lne : INTEGER := (-VALUE'low+3)/4; + variable subval : UNRESOLVED_sfixed (value'high downto -4); + variable lpad : STD_ULOGIC_VECTOR (0 to (lne*4 + VALUE'low) -1); + variable slv : STD_ULOGIC_VECTOR (value'length-1 downto 0); + begin + if value'length < 1 then + return NUS; + else + if value'high < 0 then + return to_hstring (resize (value, 3, value'low)); + elsif value'low >= 0 then + if Is_X (value(value'low)) then + subval := (others => value(value'low)); + subval (value'range) := value; + return to_hstring(subval); + else + return to_hstring (resize (value, value'high, -4)); + end if; + else + slv := to_sulv (value); + pad := (others => value(value'high)); + if Is_X (value (value'low)) then + lpad := (others => value(value'low)); + else + lpad := (others => '0'); + end if; + return to_hstring(pad & slv(slv'high downto slv'high-VALUE'high)) + & "." + & to_hstring(slv(slv'high-VALUE'high-1 downto 0) & lpad); + end if; + end if; + end function to_hstring; + + -- From string functions allow you to convert a string into a fixed + -- point number. Example: + -- signal uf1 : ufixed (3 downto -3); + -- uf1 <= from_string ("0110.100", uf1'high, uf1'low); -- 6.5 + -- The "." is optional in this syntax, however it exist and is + -- in the wrong location an error is produced. Overflow will + -- result in saturation. + + function from_string ( + bstring : STRING; -- binary string + constant left_index : INTEGER; + constant right_index : INTEGER) + return UNRESOLVED_ufixed is + variable result : UNRESOLVED_ufixed (left_index downto right_index); + variable L : LINE; + variable good : BOOLEAN; + begin + L := new STRING'(bstring); + read (L, result, good); + deallocate (L); + assert (good) + report fixed_pkg'instance_name + & "from_string: Bad string "& bstring severity error; + return result; + end function from_string; + + -- Octal and hex conversions work as follows: + -- uf1 <= from_hstring ("6.8", 3, -3); -- 6.5 (bottom zeros dropped) + -- uf1 <= from_ostring ("06.4", 3, -3); -- 6.5 (top zeros dropped) + function from_ostring ( + ostring : STRING; -- Octal string + constant left_index : INTEGER; + constant right_index : INTEGER) + return UNRESOLVED_ufixed is + variable result : UNRESOLVED_ufixed (left_index downto right_index); + variable L : LINE; + variable good : BOOLEAN; + begin + L := new STRING'(ostring); + oread (L, result, good); + deallocate (L); + assert (good) + report fixed_pkg'instance_name + & "from_ostring: Bad string "& ostring severity error; + return result; + end function from_ostring; + + function from_hstring ( + hstring : STRING; -- hex string + constant left_index : INTEGER; + constant right_index : INTEGER) + return UNRESOLVED_ufixed is + variable result : UNRESOLVED_ufixed (left_index downto right_index); + variable L : LINE; + variable good : BOOLEAN; + begin + L := new STRING'(hstring); + hread (L, result, good); + deallocate (L); + assert (good) + report fixed_pkg'instance_name + & "from_hstring: Bad string "& hstring severity error; + return result; + end function from_hstring; + + function from_string ( + bstring : STRING; -- binary string + constant left_index : INTEGER; + constant right_index : INTEGER) + return UNRESOLVED_sfixed is + variable result : UNRESOLVED_sfixed (left_index downto right_index); + variable L : LINE; + variable good : BOOLEAN; + begin + L := new STRING'(bstring); + read (L, result, good); + deallocate (L); + assert (good) + report fixed_pkg'instance_name + & "from_string: Bad string "& bstring severity error; + return result; + end function from_string; + + function from_ostring ( + ostring : STRING; -- Octal string + constant left_index : INTEGER; + constant right_index : INTEGER) + return UNRESOLVED_sfixed is + variable result : UNRESOLVED_sfixed (left_index downto right_index); + variable L : LINE; + variable good : BOOLEAN; + begin + L := new STRING'(ostring); + oread (L, result, good); + deallocate (L); + assert (good) + report fixed_pkg'instance_name + & "from_ostring: Bad string "& ostring severity error; + return result; + end function from_ostring; + + function from_hstring ( + hstring : STRING; -- hex string + constant left_index : INTEGER; + constant right_index : INTEGER) + return UNRESOLVED_sfixed is + variable result : UNRESOLVED_sfixed (left_index downto right_index); + variable L : LINE; + variable good : BOOLEAN; + begin + L := new STRING'(hstring); + hread (L, result, good); + deallocate (L); + assert (good) + report fixed_pkg'instance_name + & "from_hstring: Bad string "& hstring severity error; + return result; + end function from_hstring; + + -- Same as above, "size_res" is used for it's range only. + function from_string ( + bstring : STRING; -- binary string + size_res : UNRESOLVED_ufixed) + return UNRESOLVED_ufixed is + begin + return from_string (bstring, size_res'high, size_res'low); + end function from_string; + + function from_ostring ( + ostring : STRING; -- Octal string + size_res : UNRESOLVED_ufixed) + return UNRESOLVED_ufixed is + begin + return from_ostring (ostring, size_res'high, size_res'low); + end function from_ostring; + + function from_hstring ( + hstring : STRING; -- hex string + size_res : UNRESOLVED_ufixed) + return UNRESOLVED_ufixed is + begin + return from_hstring(hstring, size_res'high, size_res'low); + end function from_hstring; + + function from_string ( + bstring : STRING; -- binary string + size_res : UNRESOLVED_sfixed) + return UNRESOLVED_sfixed is + begin + return from_string (bstring, size_res'high, size_res'low); + end function from_string; + + function from_ostring ( + ostring : STRING; -- Octal string + size_res : UNRESOLVED_sfixed) + return UNRESOLVED_sfixed is + begin + return from_ostring (ostring, size_res'high, size_res'low); + end function from_ostring; + + function from_hstring ( + hstring : STRING; -- hex string + size_res : UNRESOLVED_sfixed) + return UNRESOLVED_sfixed is + begin + return from_hstring (hstring, size_res'high, size_res'low); + end function from_hstring; + + -- purpose: Calculate the string boundaries + procedure calculate_string_boundry ( + arg : in STRING; -- input string + left_index : out INTEGER; -- left + right_index : out INTEGER) is -- right + -- examples "10001.111" would return +4, -3 + -- "07X.44" would return +2, -2 (then the octal routine would multiply) + -- "A_B_._C" would return +1, -1 (then the hex routine would multiply) + alias xarg : STRING (arg'length downto 1) is arg; -- make it downto range + variable l, r : INTEGER; -- internal indexes + variable founddot : BOOLEAN := false; + begin + if arg'length > 0 then + l := xarg'high - 1; + r := 0; + for i in xarg'range loop + if xarg(i) = '_' then + if r = 0 then + l := l - 1; + else + r := r + 1; + end if; + elsif xarg(i) = ' ' or xarg(i) = NBSP or xarg(i) = HT then + report fixed_pkg'instance_name + & "Found a space in the input STRING " & xarg + severity error; + elsif xarg(i) = '.' then + if founddot then + report fixed_pkg'instance_name + & "Found two binary points in input string " & xarg + severity error; + else + l := l - i; + r := -i + 1; + founddot := true; + end if; + end if; + end loop; + left_index := l; + right_index := r; + else + left_index := 0; + right_index := 0; + end if; + end procedure calculate_string_boundry; + + -- Direct conversion functions. Example: + -- signal uf1 : ufixed (3 downto -3); + -- uf1 <= from_string ("0110.100"); -- 6.5 + -- In this case the "." is not optional, and the size of + -- the output must match exactly. + function from_string ( + bstring : STRING) -- binary string + return UNRESOLVED_ufixed is + variable left_index, right_index : INTEGER; + begin + calculate_string_boundry (bstring, left_index, right_index); + return from_string (bstring, left_index, right_index); + end function from_string; + + -- Direct octal and hex conversion functions. In this case + -- the string lengths must match. Example: + -- signal sf1 := sfixed (5 downto -3); + -- sf1 <= from_ostring ("71.4") -- -6.5 + function from_ostring ( + ostring : STRING) -- Octal string + return UNRESOLVED_ufixed is + variable left_index, right_index : INTEGER; + begin + calculate_string_boundry (ostring, left_index, right_index); + return from_ostring (ostring, ((left_index+1)*3)-1, right_index*3); + end function from_ostring; + + function from_hstring ( + hstring : STRING) -- hex string + return UNRESOLVED_ufixed is + variable left_index, right_index : INTEGER; + begin + calculate_string_boundry (hstring, left_index, right_index); + return from_hstring (hstring, ((left_index+1)*4)-1, right_index*4); + end function from_hstring; + + function from_string ( + bstring : STRING) -- binary string + return UNRESOLVED_sfixed is + variable left_index, right_index : INTEGER; + begin + calculate_string_boundry (bstring, left_index, right_index); + return from_string (bstring, left_index, right_index); + end function from_string; + + function from_ostring ( + ostring : STRING) -- Octal string + return UNRESOLVED_sfixed is + variable left_index, right_index : INTEGER; + begin + calculate_string_boundry (ostring, left_index, right_index); + return from_ostring (ostring, ((left_index+1)*3)-1, right_index*3); + end function from_ostring; + + function from_hstring ( + hstring : STRING) -- hex string + return UNRESOLVED_sfixed is + variable left_index, right_index : INTEGER; + begin + calculate_string_boundry (hstring, left_index, right_index); + return from_hstring (hstring, ((left_index+1)*4)-1, right_index*4); + end function from_hstring; +-- pragma synthesis_on +-- rtl_synthesis on + -- IN VHDL-2006 std_logic_vector is a subtype of std_ulogic_vector, so these + -- extra functions are needed for compatability. + function to_ufixed ( + arg : STD_LOGIC_VECTOR; -- shifted vector + constant left_index : INTEGER; + constant right_index : INTEGER) + return UNRESOLVED_ufixed is + begin + return to_ufixed ( + arg => to_stdulogicvector (arg), + left_index => left_index, + right_index => right_index); + end function to_ufixed; + + function to_ufixed ( + arg : STD_LOGIC_VECTOR; -- shifted vector + size_res : UNRESOLVED_ufixed) -- for size only + return UNRESOLVED_ufixed is + begin + return to_ufixed ( + arg => to_stdulogicvector (arg), + size_res => size_res); + end function to_ufixed; + + function to_sfixed ( + arg : STD_LOGIC_VECTOR; -- shifted vector + constant left_index : INTEGER; + constant right_index : INTEGER) + return UNRESOLVED_sfixed is + begin + return to_sfixed ( + arg => to_stdulogicvector (arg), + left_index => left_index, + right_index => right_index); + end function to_sfixed; + + function to_sfixed ( + arg : STD_LOGIC_VECTOR; -- shifted vector + size_res : UNRESOLVED_sfixed) -- for size only + return UNRESOLVED_sfixed is + begin + return to_sfixed ( + arg => to_stdulogicvector (arg), + size_res => size_res); + end function to_sfixed; + + -- unsigned fixed point + function to_UFix ( + arg : STD_LOGIC_VECTOR; + width : NATURAL; -- width of vector + fraction : NATURAL) -- width of fraction + return UNRESOLVED_ufixed is + begin + return to_UFix ( + arg => to_stdulogicvector (arg), + width => width, + fraction => fraction); + end function to_UFix; + + -- signed fixed point + function to_SFix ( + arg : STD_LOGIC_VECTOR; + width : NATURAL; -- width of vector + fraction : NATURAL) -- width of fraction + return UNRESOLVED_sfixed is + begin + return to_SFix ( + arg => to_stdulogicvector (arg), + width => width, + fraction => fraction); + end function to_SFix; + +end package body fixed_pkg;