library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;
use ieee.math_real.all;
use std.textio.all;

package body fixed_ja is

	-------------------------------------------------------------
	-- Local Procedures
	-------------------------------------------------------------
	-- adds 1 to the LSB of the number
	procedure round_up
	(
		src       : in  ufixed_t;
		result    : out ufixed_t;
		overflowx : out BOOLEAN ) is
		
	variable srcuns, resuns : UNSIGNED (src'high-src'low+1 downto 0) := (others => '0');
	begin  -- round_up
	srcuns (srcuns'high-1 downto 0) := to_unsigned (src);
	resuns                          := srcuns + 1;

	result := to_ufixed(resuns(src'high-src'low downto 0), src);
	overflowx := (resuns(resuns'high) = '1');

	end procedure round_up;

	-------------------------------------------------------------
	-- adds 1 to the LSB of the number
	procedure round_up 
	(
		src       : in  sfixed_t;
		result    : out sfixed_t;
		overflowx : out BOOLEAN ) is
	
	variable srcs, ress : SIGNED (src'high-src'low+1 downto 0);
	begin  -- round_up
	srcs (srcs'high-1 downto 0) := to_signed (src);
	srcs(srcs'high)             := src(src'high);  -- sign extend
	ress                        := srcs + 1;

	result := to_sfixed(ress (ress'high-1 downto 0), src);
	overflowx := ((src(src'high) /= ress(ress'high-1)) and (or_red (sfixed_t(ress)) /= '0'));

	end procedure round_up;
	
	-------------------------------------------------------------
	-- Local functions
	-------------------------------------------------------------
	-- round_fixed()
--	function round_fixed
--	(
--		src : ufixed_t;
--		remainder : ufixed_t;
--		rnd_mode : round_mode_t := default_round_mode
--	) return ufixed_t is
--	variable res : ufixed_t(src'range);
--	begin
--	return res;
--
--	end round_fixed;
		
	-------------------------------------------------------------
--	function round_fixed 
--	(
--		src : sfixed_t;
--		remainder : sfixed_t;
--		rnd_mode : round_mode_t := default_round_mode
--	) return sfixed_t is
--	variable res : to_signed(src'length-1 downto 0);
--	begin
--	return src;
--
--	end round_fixed;

	-------------------------------------------------------------
	function reshape
	(
		src : ufixed_t;
		proto : ufixed_t;
		rnd_mode : round_mode_t := default_round_mode;
		sat_mode : saturate_mode_t := default_saturate_mode
	) return ufixed_t is

	variable RemainLow : ufixed_t (proto'low-1 downto src'low) := (others => '0');
	variable RemainHigh : ufixed_t (src'high downto proto'high+1) := (others => '0');
	variable dst, tmp : ufixed_t (proto'high downto proto'low) := (others => '0');
	variable ovf, isTruncLo, isTruncHi : boolean := false;
	begin

	if proto'high < -1 then
		assert false report "U: reshape: Bad dual point (Upper bound < (-1))" severity error;
	end if;	

	-- Check for high and low truncation
	isTruncLo := (src'low < dst'low);
	isTruncHi := (src'high > dst'high);
	
	-- Reshape
	dst := (others => '0');
	dst(min(src'high, dst'high) downto max(src'low, dst'low)) := src(min(src'high, dst'high) downto max(src'low, dst'low));
	tmp := dst;

	-- Get low remainder
	if isTruncLo then
		RemainLow := src(RemainLow'range);
	end if;
	
	-- Get high remainder
	if isTruncHi then
		RemainHigh := src(RemainHigh'range);
	end if;	

	ovf := false;

	-- Rounding
	if isTruncLo then

		case rnd_mode is

		-- Round to positive infinity (round ceiling)
		when round_pos_infinity =>
			if or_red(RemainLow) = '1' then
				round_up(tmp, dst, ovf);
			end if;

		-- Round Half-up
		-- Round nearest
		when round_half_up | round_nearest => 
			if (RemainLow(RemainLow'high) = '1') then
				round_up(tmp, dst, ovf);
			end if;

		-- Round convergent
		when round_convergent =>
			if RemainLow(RemainLow'high) = '1' then
				if or_red(RemainLow(RemainLow'high-1 downto RemainLow'low)) = '1' then
					round_up(tmp, dst, ovf);
				elsif tmp(dst'low) = '1' then
					round_up(tmp, dst, ovf);
				end if;	
			end if;
			
		-- Round to zero
		when round_to_zero | none => null;
		
		when others =>
		assert false report "Reshape(U): Rounding mode (" & round_mode_t'image(rnd_mode) & ") not implemented!" severity error;

		end case;
	end if;	

	-- Saturating
	if sat_mode = saturate then

		-- Check overflow
		if isTruncHi then
			ovf := ovf or or_red(RemainHigh) = '1';
		end if;	

		-- Saturate
		if ovf then
			dst := (others => '1');
		end if;

	end if;
	
	return dst;

	end reshape;

	-------------------------------------------------------------
	function reshape
	(
		src : ufixed_t;
		nbits : integer;
		nbits_int : integer;
		rnd_mode : round_mode_t := default_round_mode;
		sat_mode : saturate_mode_t := default_saturate_mode
	) return ufixed_t is
	
	begin
	return reshape(src, uproto(nbits, nbits_int), rnd_mode, sat_mode);
	
	end reshape;

	-------------------------------------------------------------
	function reshape
	(
		src : sfixed_t;
		proto : sfixed_t;
		rnd_mode : round_mode_t := default_round_mode;
		sat_mode : saturate_mode_t := default_saturate_mode
	) return sfixed_t is

	variable RemainLow : sfixed_t (proto'low-1 downto src'low) := (others => '0');
	variable RemainHigh : sfixed_t (src'high-1 downto proto'high) := (others => '0');
	variable dst, tmp : sfixed_t (proto'high downto proto'low) := (others => '0');
	variable ovf, isTruncLo, isTruncHi : boolean := false;
	variable sign : std_logic; 
	begin

	if proto'high < 0 then
		assert false report "Reshape(S): Bad dual point (Upper bound < (0))" severity error;
	end if;
	
	-- Check for high and low truncation
	isTruncLo := (src'low < dst'low);
	isTruncHi := (src'high > dst'high);
	
	-- Reshape
	sign := src(src'high);
	dst := (others => '0');
	dst(dst'high downto max(src'low, dst'low)) := (dst'high downto min(src'high, dst'high) => sign) & src(min(src'high, dst'high)-1 downto max(src'low, dst'low));
	tmp := dst;
	
	-- Get low remainder
	if isTruncLo then
		RemainLow := src(RemainLow'range);
	end if;
	
	-- Get high remainder
	if isTruncHi then
		RemainHigh := src(RemainHigh'range);
	end if;	

	ovf := false;

	-- Rounding
	if isTruncLo then

		case rnd_mode is

		-- Round to positive infinity (round ceiling)
		when round_pos_infinity =>
			round_up(tmp, dst, ovf);
			if ovf then
				dst(dst'high) := '0';
			end if;	

		-- Round Half-up
		when round_half_up => 
			if RemainLow(RemainLow'high) = '1' then
				round_up(tmp, dst, ovf);
			end if;	

		-- Round nearest
		when round_nearest =>
			if RemainLow(RemainLow'high) = '1' then
				if RemainLow'length = 1 then
					if sign = '0' then
						round_up(tmp, dst, ovf);
					end if;
				elsif sign = '0' or (sign and or_red(RemainLow(RemainLow'high-1 downto RemainLow'low))) = '1' then
						round_up(tmp, dst, ovf);
				end if;	
			end if;	
		
		-- Round convergent
		when round_convergent =>
			if RemainLow(RemainLow'high) = '1' then
				if or_red(RemainLow(RemainLow'high-1 downto RemainLow'low)) = '1' then
					round_up(tmp, dst, ovf);
				elsif tmp(dst'low) = '1' then
					round_up(tmp, dst, ovf);
				end if;	
			end if;

		-- Round to zero
		when round_to_zero =>
			if (or_red(RemainLow) = '1' and sign = '1') then
				round_up(tmp, dst, ovf);
			end if;

		-- No Round
		when none =>
			-- Same as RoundToZero but overflow detection is omitted
			dst := tmp + (or_red(RemainLow) and sign);

		when others =>
		assert false report "Reshape(S): Rounding mode (" & round_mode_t'image(rnd_mode) & ") not implemented!" severity error;
		
		end case;
		
		-- Check negative zero
		if dst(dst'high) = '1' then
			if or_red(dst(dst'high-1 downto dst'low)) = '0' then
				dst(dst'high) := '0';
			--	assert false report "Reshape(S): -0 detected" severity note;
			end if;	
		end if;	
	end if;	

	-- Saturating
	if sat_mode = saturate then

		-- Check overflow
		if isTruncHi then
			ovf :=	ovf or
					(sign = '1' and src(dst'high) = '0' and or_red(tmp(dst'high-1 downto dst'low)) = '1') or
					(sign = '1' and src(dst'high) = '1' and or_red(tmp(dst'high-1 downto dst'low)) = '0') or
					(sign = '0' and or_red(RemainHigh) = '1');
		end if;
		
		-- Saturate
		if ovf then
			if (sign = '1') then
				dst := '1' & (dst'high-1 downto dst'low+1 => '0') & '1';
			else
				dst := '0' & (dst'high-1 downto dst'low => '1');
			end if;
		end if;
		
	end if;
	
	return dst;

	end reshape;

	-------------------------------------------------------------
	function reshape
	(
		src : sfixed_t;
		nbits : integer;
		nbits_int : integer;
		rnd_mode : round_mode_t := default_round_mode;
		sat_mode : saturate_mode_t := default_saturate_mode
	) return sfixed_t is
	
	begin
	return reshape(src, sproto(nbits, nbits_int), rnd_mode, sat_mode);
	
	end reshape;

	-------------------------------------------------------------
	-- Constuctor helpers
	-------------------------------------------------------------
	function uproto (nbits : integer; nbits_int : integer) return ufixed_t is
	constant result : ufixed_t (nbits_int-1 downto nbits_int-nbits) := (others => '0');
	begin 
	return result(nbits_int-1 downto nbits_int-nbits);
	end uproto;

	-------------------------------------------------------------
	function sproto (nbits : integer; nbits_int : integer) return sfixed_t is
	constant result : sfixed_t (nbits_int downto nbits_int-nbits+1) := (others => '0');
	begin 
	return result(nbits_int downto nbits_int-nbits+1);
	end sproto;

	-------------------------------------------------------------
	function uproto (a : ufixed_t; op : character; b : ufixed_t) return ufixed_t is
	constant result : ufixed_t(a'high + b'high + 4 downto a'low + b'low - 4) := (others => '0');
	variable hi, lo : integer := 0;

	begin

	case op is
		when '+' =>
		hi := max(a'high, b'high);
		if a'high = b'high then
			hi := hi + 1;
		end if;	
		lo := min(a'low, b'low);

		when '-' =>  
		hi := max(a'high, b'high);
		lo := min(a'low, b'low);

		when '*' => 
		hi := a'high + b'high + 1;
		if (a'high < 0 or b'high < 0) then
			if (hi > -1) then
				hi := hi-1;
			end if;
		end if;
		lo := hi - a'length - b'length + 1;

		when others => null;

	end case;

	return result(hi downto lo);
	end uproto;

	-------------------------------------------------------------
	function sproto (a : sfixed_t; op : character; b : sfixed_t) return sfixed_t is
	constant result : sfixed_t(a'high + b'high + 4 downto a'low + b'low - 4) := (others => '0');
	variable hi, lo : integer := 0;

	begin

	case op is
		when '+' =>
		hi := max(a'high, b'high);
		if a'high = b'high then
			hi := hi + 1;
		end if;	
		lo := min(a'low, b'low);

		when '-' =>  
		hi := max(a'high, b'high);
		lo := min(a'low, b'low);

		when '*' =>  
		hi := a'high + b'high;
		if (a'high = 0 or b'high = 0) then
			if (hi > 0) then
				hi := hi-1;
			end if;
		end if;
		lo := hi - a'length - b'length + 1;

		when others => null;

	end case;

	return result(hi downto lo);
	end sproto;

	-------------------------------------------------------------
	-- Type conversions
	-------------------------------------------------------------
    -- ufixed <= ufixed
	function to_ufixed(src : ufixed_t) return ufixed_t is
	begin
	return to_ufixed(src, src);

	end to_ufixed;
	
	-------------------------------------------------------------
    -- ufixed <= sfixed
	function to_ufixed(src : sfixed_t) return ufixed_t is
	variable dst : ufixed_t(src'range) := (others => '0');
	begin
	dst := ufixed_t(abs(src));
	return dst(src'high-1 downto src'low);

	end to_ufixed;
	
	-------------------------------------------------------------
    -- sfixed <= sfixed
	function to_sfixed(src : sfixed_t) return sfixed_t is
	begin
	return src;

	end to_sfixed;
	
	-------------------------------------------------------------
    -- sfixed <= ufixed
	function to_sfixed(src : ufixed_t) return sfixed_t is
	variable dst : sfixed_t(src'high+1 downto src'low) := (others => '0');
	begin
	dst(src'range) := sfixed_t(src);
	return dst;

	end to_sfixed;

	-------------------------------------------------------------
    -- ufixed <= ufixed
	function to_ufixed
	(
		src : ufixed_t;
		nbits : integer;
		nbits_int : integer;
		rnd_mode : round_mode_t := default_round_mode;
		sat_mode : saturate_mode_t := default_saturate_mode
	) return ufixed_t is
	begin
	return reshape(src, nbits, nbits_int, rnd_mode, sat_mode);
	
	end to_ufixed;
	
	-------------------------------------------------------------
    -- ufixed <= ufixed
	function to_ufixed
	(
		src : ufixed_t; 
		proto : ufixed_t;
		rnd_mode : round_mode_t := default_round_mode;
		sat_mode : saturate_mode_t := default_saturate_mode
	) return ufixed_t is
	begin
	return reshape(src, proto, rnd_mode, sat_mode);
	
	end to_ufixed;
	
	-------------------------------------------------------------
    -- sfixed <= sfixed
	function to_sfixed
	(
		src : sfixed_t;
		nbits : integer;
		nbits_int : integer;
		rnd_mode : round_mode_t := default_round_mode;
		sat_mode : saturate_mode_t := default_saturate_mode
	) return sfixed_t is
	begin
	return reshape(src, nbits, nbits_int, rnd_mode, sat_mode);
	
	end to_sfixed;
	
	-------------------------------------------------------------
    -- sfixed <= sfixed
	function to_sfixed
	(
		src : sfixed_t; 
		proto : sfixed_t;
		rnd_mode : round_mode_t := default_round_mode;
		sat_mode : saturate_mode_t := default_saturate_mode
	) return sfixed_t is
	begin
	return reshape(src, proto, rnd_mode, sat_mode);
	
	end to_sfixed;

	-------------------------------------------------------------
	-- ufixed <= integer
	function to_ufixed (src : integer; nbits : integer; nbits_int : integer) return ufixed_t is
	begin
	return to_ufixed(src, uproto(nbits, nbits_int));
		
	end to_ufixed;

	function to_ufixed (src : integer; proto : ufixed_t) return ufixed_t is
	begin
	return to_ufixed(to_unsigned(src, proto'length), proto);
		
	end to_ufixed;
	
	-------------------------------------------------------------
	-- ufixed <= unsigned
	function to_ufixed (src : unsigned; nbits : integer; nbits_int : integer) return ufixed_t is
	begin
	return to_ufixed(src, uproto(nbits, nbits_int));

	end to_ufixed;
	
	-------------------------------------------------------------
	-- ufixed <= unsigned
	function to_ufixed(src : unsigned; proto : ufixed_t) return ufixed_t is
	variable dst : ufixed_t(proto'high downto proto'low) := (others => '0');
	begin
	
	dst(dst'low + min(dst'length, src'length)-1 downto dst'low) := ufixed_t(src(min(dst'length, src'length)-1 downto 0));	

	return dst;

	end to_ufixed;

	-------------------------------------------------------------
	-- sfixed <= integer
	function to_sfixed (src : integer; nbits : integer; nbits_int : integer) return sfixed_t is
	begin
	return to_sfixed(src, sproto(nbits, nbits_int));
		
	end to_sfixed;

	function to_sfixed (src : integer; proto : sfixed_t) return sfixed_t is
	begin
	
	return to_sfixed(to_signed(src, proto'length), proto);
		
	end to_sfixed;
	
	-------------------------------------------------------------
	-- sfixed <= signed
	function to_sfixed (src : signed; nbits : integer; nbits_int : integer) return sfixed_t is
	begin
	return to_sfixed(src, sproto(nbits, nbits_int));
	
	end to_sfixed;

	-------------------------------------------------------------
	-- sfixed <= signed
	function to_sfixed(src : signed; proto : sfixed_t) return sfixed_t is
	variable dst : sfixed_t(proto'high downto proto'low) := (others => '0');
	begin

	dst(dst'low + min(dst'length, src'length)-2 downto dst'low) := sfixed_t(src(min(dst'length, src'length)-2 downto 0));	
	dst(dst'high) := src(src'high);

	return dst;
	
	end to_sfixed;

	-------------------------------------------------------------
	function to_ufixed (src : STD_LOGIC_VECTOR;	proto : ufixed_t) return ufixed_t is
	variable result : ufixed_t (proto'left downto proto'right);
	begin
	if (result'length < 1) then
		return result;
	else
		result := to_ufixed (unsigned(src), proto);
	return result;
	end if;
	
	end function to_ufixed;

	-------------------------------------------------------------
	function to_ufixed (src : STD_LOGIC_VECTOR;	nbits : integer; nbits_int : integer) return ufixed_t is
	begin
	return to_ufixed(src, uproto(nbits, nbits_int));
	
	end function to_ufixed;

	-------------------------------------------------------------
	function to_sfixed (src : STD_LOGIC_VECTOR;	proto : sfixed_t) return sfixed_t is
	variable result : sfixed_t (proto'left downto proto'right);
	begin
	if (result'length < 1) then
		return result;
	else
		result := to_sfixed (signed(src), proto);
	return result;
	end if;
	
	end function to_sfixed;

	-------------------------------------------------------------
	function to_sfixed (src : STD_LOGIC_VECTOR; nbits : integer; nbits_int : integer) return sfixed_t is
	begin
	return to_sfixed(src, sproto(nbits, nbits_int));
	
	end to_sfixed;
	-------------------------------------------------------------
	
	-- ufixed <= real
	function to_ufixed
	(
		src : real; 
		nbits : integer;
		nbits_int : integer;
		rnd_mode : round_mode_t := default_round_mode;
		sat_mode : saturate_mode_t := default_saturate_mode
	) return ufixed_t is

	constant nbits_ext : integer := nbits + 1;
	constant fix_hi : integer := nbits_int - 1;
	constant fix_lo : integer := nbits_int - nbits_ext;
	
	variable dst : ufixed_t (fix_hi downto fix_lo) := (others => '0');
	variable i : integer := 0;
	variable remain : real := 0.0;
	
	begin
	
	if (nbits_int < 0) then
		assert false report "to_ufixed: Bad dual point (N integer bits < 0)" severity error;
	end if;
	
	if ((2.0**nbits_int - 1.0) < ipart(abs(src))) then
--		assert ASSERT_NO_WARN report "to_ufixed: Overflow (" & REAL'image(src) & ") "  severity warning;
--		print_info(dst, "dst: ");
	end if;
	
	remain := abs(src);
    for i in dst'range loop
		if remain >= 2.0**i then
			dst(i) := '1';
			remain := remain - 2.0**i;
		else
			dst(i) := '0';
		end if;
    end loop;
	
	return to_ufixed(dst, nbits, nbits_int, rnd_mode, sat_mode);

	end to_ufixed;

	-------------------------------------------------------------
	-- sfixed <= real
	function to_sfixed
	(
		src : real;
		proto : sfixed_t;
		rnd_mode : round_mode_t := default_round_mode;
		sat_mode : saturate_mode_t := default_saturate_mode
	) return sfixed_t is

	variable utmp : ufixed_t(proto'high-1 downto proto'low) := (others => '0');
	variable dst : sfixed_t(proto'high downto proto'low) := (others => '0');
	
	begin
	utmp := to_ufixed(src, utmp, rnd_mode, sat_mode);
	if (src < 0.0) then
		dst := -to_sfixed(utmp);
	else
		dst := to_sfixed(utmp);
	end if;
	
	return dst;
	end to_sfixed;  

	-------------------------------------------------------------
	-- ufixed <= real
	function to_ufixed
	(
		src : real;
		proto : ufixed_t;
		rnd_mode : round_mode_t := default_round_mode;
		sat_mode : saturate_mode_t := default_saturate_mode
	) return ufixed_t is
	begin
		return to_ufixed(src, proto'length, proto'high+1, rnd_mode, sat_mode);
	end to_ufixed;

	-------------------------------------------------------------
	-- sfixed <= real
	function to_sfixed
	(
		src : real;
		nbits : integer;
		nbits_int : integer;
		rnd_mode : round_mode_t := default_round_mode;
		sat_mode : saturate_mode_t := default_saturate_mode
	) return sfixed_t is
	begin
		return to_sfixed(src, sproto(nbits, nbits_int), rnd_mode, sat_mode);
	end to_sfixed;

	-------------------------------------------------------------------------------
	-- ufixed <= ufixed_array(i)
	function to_ufixed(src : ufixed_array_t; index : integer) return ufixed_t is
	variable dst : ufixed_t(src'range(2));
	begin
		for j in src'range(2) loop
			dst(j) := src(index, j);
		end loop;
		
		return dst;
		
	end to_ufixed;	
	
	-------------------------------------------------------------------------------
	-- sfixed <= sfixed_array(i)
	function to_sfixed(src : sfixed_array_t; index : integer) return sfixed_t is
	variable dst : sfixed_t(src'range(2));
	begin
		for j in src'range(2) loop
			dst(j) := src(index, j);
		end loop;
		
		return dst;
		
	end to_sfixed;	
	
	-------------------------------------------------------------
	-- ufixed <= string
	function to_ufixed (src : string) return ufixed_t is
	
	variable i, j, nbits, nbits_int, nbits_frac : integer := 0;
	variable dst : unsigned(src'length downto 0) := (others => '0');
	variable dp_found : boolean := false;
	begin
	
	for i in src'reverse_range loop
		case src(i) is 
			when '.' =>
			if dp_found then
				assert false report "More than one DP not found." severity error;
			else
				dp_found := true;
				nbits_frac := j;
			end if;  
		
			when '0' => dst(nbits) := '0'; nbits := nbits + 1; j := j + 1;
			when '1' => dst(nbits) := '1'; nbits := nbits + 1; j := j + 1;
			when others => 
			assert false report "Illegal character in binary string." severity error;
			
		end case;
	
	end loop ;
	if not dp_found then
		assert ASSERT_NO_WARN report "DP not found. Using left alignment." severity warning;
	end if;	
	
	nbits_int := nbits - nbits_frac;
	
	return to_ufixed(dst(nbits-1 downto 0), nbits, nbits_int);
	
	end to_ufixed;

	-------------------------------------------------------------
	-- sfixed <= string
	function to_sfixed (src : string) return sfixed_t is
	
	variable i, j, nbits, nbits_int, nbits_frac : integer := 0;
	variable dst : signed(src'length downto 0) := (others => '0');
	variable dp_found : boolean := false;
	variable is_neg : boolean := false;
	begin

	is_neg := src(src'left) = '-';
	
	for i in src'reverse_range loop
		case src(i) is 
			when '-' => null;
			when '+' => null;
	
			when '.' =>
			if dp_found then
				assert false report "More than one DP not found." severity error;
			else
				dp_found := true;
				nbits_frac := j;
			end if;  
	
			when '0' => dst(nbits) := '0'; nbits := nbits + 1; j := j + 1;
			when '1' => dst(nbits) := '1'; nbits := nbits + 1; j := j + 1;
			when others => 
			assert false report "Illegal character in binary string." severity error;
		end case;
	end loop ;
	nbits := nbits + 1;

	if not dp_found then
		assert ASSERT_NO_WARN report "DP not found. Using left alignment." severity warning;
	end if;	
	
	nbits_int := nbits - nbits_frac-1;

	if is_neg then
		dst(nbits-1 downto 0) := -dst(nbits-1 downto 0);
	end if;

	return to_sfixed(dst(nbits-1 downto 0), nbits, nbits_int);

	end to_sfixed;

	-------------------------------------------------------------
	function to_unsigned (src : ufixed_t) return UNSIGNED is
	subtype  t is UNSIGNED(src'high - src'low downto 0);
	variable slv : t;
	begin
	slv := t(src);
	return UNSIGNED(to_X01(std_logic_vector(slv)));

	end function to_unsigned;

	-------------------------------------------------------------
	function to_signed (src : sfixed_t) return SIGNED is
	subtype  t is SIGNED(src'high - src'low downto 0);
	variable slv : t;
	begin
	slv := t(src);
	return SIGNED(to_X01(std_logic_vector(slv)));

	end function to_signed;
	
	-------------------------------------------------------------
	-- integer <= ufixed
	function to_integer (src : ufixed_t) return integer is
	begin
		return to_integer(to_unsigned(src));
	end to_integer;	

	-------------------------------------------------------------
	-- integer <= sfixed
	function to_integer (src : sfixed_t) return integer is
	begin
		return to_integer(to_signed(src));
	end to_integer;	

	-------------------------------------------------------------
	--  to_real
	function to_real(src : ufixed_t) return real is
	variable dst : real := 0.0;
	begin
	for i in src'range loop
		if (src(i) = '1') then
			dst := dst + real(2.0**i);
		end if;	
	end loop;
	return dst;

	end to_real;		

	-------------------------------------------------------------
	function to_real(src : sfixed_t) return real is
	variable dst : real := 0.0;
	begin
	dst := to_real(to_ufixed(src));

	if (src(src'high) = '1') then
		dst := -dst;
	end if;

	return dst;

	end to_real;		

	-------------------------------------------------------------
	--  to_slv
	function to_slv (src : ufixed_t) return STD_LOGIC_VECTOR is
	subtype t is STD_LOGIC_VECTOR (src'high - src'low downto 0);
	variable slv : t;
	begin
	if src'length < 1 then
		return NSLV;
	end if;
	slv := t (src);
	return slv;

	end function to_slv;

	-------------------------------------------------------------
	--  to_slv
	function to_slv (src : sfixed_t) return STD_LOGIC_VECTOR is
	subtype t is STD_LOGIC_VECTOR (src'high - src'low downto 0);
	variable slv : t;
	begin
	if src'length < 1 then
		return NSLV;
	end if;
	slv := t (src);
	return slv;

	end function to_slv;

	-------------------------------------------------------------
	function to_string(src : ufixed_t) return string is
	variable str : string(src'length+1 downto 1) := (others => '0');
	variable i, j : integer := 0;

	begin
	j := src'length+1;
	for i in src'high downto 0 loop
		if (src(i) = '1') then
			str(j) := '1';
		end if;
		j := j - 1;
	end loop;

	str(j) := '.';
	j := j - 1;

	for i in -1 downto src'low loop
		if (src(i) = '1') then
			str(j) := '1';
		end if;
		j := j - 1;
	end loop;

	return str;

	end to_string;

	-------------------------------------------------------------
	function to_string(src : sfixed_t) return string is
	variable str : string(src'length+1 downto 1) := (others => '0');
	variable i, j, start : integer := 0;
	variable strlen : integer := 0;
	variable src_abs : sfixed_t(src'range) := (others => '0');

	begin
	if (src'high < 0) then
		assert false report "Illegal signed fix point number" severity error;
	end if;
	
	start := src'high;
	strlen := src'length;

	j := src'length+1;
	if (src(start) = '1') then
		str(j) := '-';
		j := j - 1;
		start := start - 1;
		strlen := strlen + 1;
	end if;

	src_abs := abs(src);

	for i in start downto 0 loop
		if (src_abs(i) = '1') then
			str(j) := '1';
		end if;
		j := j - 1;
	end loop;

	str(j) := '.';
	j := j - 1;

	for i in -1 downto src'low loop
		if (src_abs(i) = '1') then
			str(j) := '1';
		end if;
		j := j - 1;
	end loop;

	return str(strlen downto 1);

	end to_string;

	-------------------------------------------------------------
	function to_string(src : std_logic_vector) return string is
	variable str : string(src'length downto 1) := (others => '0');
	variable i : integer := 0;

	begin
	for i in src'range loop
		if (src(i) = '1') then
			str(i+1) := '1';
		end if;
	end loop;

	return str;

	end to_string;

	-------------------------------------------------------------
	-- Binary Operators
	-------------------------------------------------------------
	function "sla" (src : ufixed_t; count : integer) return ufixed_t is
	variable result : ufixed_t (src'high downto src'low) := (others => '0');
	
	begin 
	if (count = 0) then
		result := src;
	elsif (count < 0) then
		result := src sra -count;
	elsif (count < src'length) then
		result(src'high downto src'low) := src(src'high-count downto src'low) & (count-1 downto 0 => '0');
	end if;	
	return result;
	
	end "sla";

	-------------------------------------------------------------
	function "sla" (src : sfixed_t; count : integer) return sfixed_t is
	variable result : sfixed_t (src'high downto src'low) := (others => '0');
	variable sign : std_logic := '0';
	
	begin 
	sign := src(src'high);
	if (count = 0) then
		result := src;
	elsif (count < 0) then
		result := src sra -count;
	elsif (count < src'length-1) then
		result(src'high downto src'low) := sign & src(src'high-count-1 downto src'low) & (count-1 downto 0 => '0');
	end if;	
	return result;
	
	end "sla";

	-------------------------------------------------------------
	function "sra" (src : ufixed_t; count : integer) return ufixed_t is
	variable result : ufixed_t (src'high downto src'low) := (others => '0');

	begin 
	if (count = 0) then
		result := src;
	elsif (count < 0) then
		result := src sla -count;
	elsif (count < src'length) then
		result(src'high downto src'low) := (count-1 downto 0 => '0') & src(src'high downto src'low + count);
	end if;	
	return result;

	end "sra";
	
	-------------------------------------------------------------
	function "sra" (src : sfixed_t; count : integer) return sfixed_t is
	variable result : sfixed_t (src'high downto src'low) := (others => '0');
	variable res_slv, src_slv : signed (src'length-1 downto 0) := (others => '0');
	variable sign, do_sub : std_logic := '0';
	
	begin 
	src_slv := to_signed(src);
	sign := src(src'high);
	do_sub := src(src'high) and src(src'low);
	if (count = 0) then
		result := src;
	elsif (count < 0) then
		result := src sla -count;
	elsif (count < src'length-1) then
		res_slv := (count downto 0 => sign) & src_slv(src'length-2 downto count);
		if (do_sub = '1') then
			result(src'high downto src'low) := to_sfixed(res_slv+1, result);
		else
			result(src'high downto src'low) := to_sfixed(res_slv, result);
		end if;	
	end if;	
	return result;

	end "sra";
	
	-------------------------------------------------------------
	function "*" (a : ufixed_t; b : ufixed_t) return ufixed_t is
	variable result : ufixed_t (uproto(a,'*',b)'high downto uproto(a,'*',b)'low);

	begin 
	if (a'high < 0 and b'high >= 0) or (a'high >= 0 and b'high < 0)  then
		result := to_ufixed(to_unsigned(a) * to_unsigned(b), result) sla 1;
	else	
		result := to_ufixed(to_unsigned(a) * to_unsigned(b), result);
	end if;	
	return result;

	end "*";

	-------------------------------------------------------------
	function "*" (a : sfixed_t; b : sfixed_t) return sfixed_t is
	variable result : sfixed_t (sproto(a,'*',b)'high downto sproto(a,'*',b)'low);

	begin 
	if (a'high = 0 and b'high > 0) or (a'high > 0 and b'high = 0)  then
		result := to_sfixed(to_signed(a) * to_signed(b), result) sla 2;
	else
		result := to_sfixed(to_signed(a) * to_signed(b), result) sla 1;
 	end if;
	return result;

	end "*";

	-------------------------------------------------------------
	function "*" (a : ufixed_t; b : sfixed_t) return sfixed_t is

	begin 
	return to_sfixed(a) * b;

	end "*";

	-------------------------------------------------------------
	function "*" (a : sfixed_t; b : ufixed_t) return sfixed_t is

	begin 
	return b * a;

	end "*";

	-------------------------------------------------------------
	function "+" (a : ufixed_t; b : ufixed_t) return ufixed_t is
	variable result : ufixed_t (uproto(a,'+',b)'high downto uproto(a,'+',b)'low);

	begin 
	result := ufixed_t(to_unsigned(reshape(a, result)) + to_unsigned(reshape(b, result)));
	return result;

	end "+";

	-------------------------------------------------------------
	function "+" (a : sfixed_t; b : sfixed_t) return sfixed_t is
	variable result : sfixed_t (sproto(a,'+',b)'high downto sproto(a,'+',b)'low);

	begin 
	result := to_sfixed(to_signed(reshape(a,result)) + to_signed(reshape(b,result)), result);
--	result := to_sfixed(to_signed(a) + to_signed(b), result);
	return result;

	end "+";

	-------------------------------------------------------------
	function "+" (a : ufixed_t; b : sfixed_t) return sfixed_t is

	begin 
	return to_sfixed(a) + b;

	end "+";

	-------------------------------------------------------------
	function "+" (a : sfixed_t; b : ufixed_t) return sfixed_t is

	begin 
	return b + a;

	end "+";

	-------------------------------------------------------------
	function "+" (a : ufixed_t; b : unsigned) return ufixed_t is

	begin 
	
	return ufixed_t(to_unsigned(a) + b);

	end "+";

	-------------------------------------------------------------
	function "+" (a : sfixed_t; b : signed) return sfixed_t is

	begin 

	return sfixed_t(to_signed(a) + b);

	end "+";

	-------------------------------------------------------------
	function "+" (a : ufixed_t; b : integer) return ufixed_t is

	begin 
	
	return ufixed_t(to_unsigned(a) + to_unsigned(b, a'length));

	end "+";

	-------------------------------------------------------------
	function "+" (a : sfixed_t; b : integer) return sfixed_t is

	begin 

	return sfixed_t(to_signed(a) + to_signed(b, a'length));

	end "+";

	-------------------------------------------------------------
	function "+" (a : ufixed_t; b : std_logic) return ufixed_t is
	variable result : ufixed_t (a'high downto a'low);
	variable buns : unsigned(a'length-1 downto 0);

	begin 
	buns := (a'length-1 downto 1 => '0') & b;
	result := ufixed_t(to_unsigned(a) + buns);
	return result;

	end "+";

	-------------------------------------------------------------
	function "+" (a : sfixed_t; b : std_logic) return sfixed_t is
	variable result : sfixed_t (a'high downto a'low);
	variable bs : signed(a'length-1 downto 0);

	begin 
	bs := (a'length-1 downto 1 => '0') & b;
	result := sfixed_t(to_signed(a) + bs);
	return result;

	end "+";

	-------------------------------------------------------------
	function "-" (a : ufixed_t; b : ufixed_t) return ufixed_t is
	variable result : ufixed_t (uproto(a,'-',b)'high downto uproto(a,'-',b)'low);
	begin 
	result := to_ufixed(to_sfixed(a) - to_sfixed(b));
	return result;

	end "-";

	-------------------------------------------------------------
	function "-" (a : sfixed_t; b : sfixed_t) return sfixed_t is
	variable result : sfixed_t (sproto(a,'-',b)'high downto sproto(a,'-',b)'low);

	begin 
	result := to_sfixed(to_signed(reshape(a,result)) - to_signed(reshape(b,result)), result);
	return result;

	end "-";

	-------------------------------------------------------------
	function "-" (a : ufixed_t; b : sfixed_t) return sfixed_t is
	begin 
	return to_sfixed(a) - b;

	end "-";

	-------------------------------------------------------------
	function "-" (a : sfixed_t; b : ufixed_t) return sfixed_t is

	begin 
	return a - to_sfixed(b);

	end "-";

	-------------------------------------------------------------
	function "-" (a : ufixed_t; b : unsigned) return ufixed_t is

	begin 
	return ufixed_t(to_unsigned(a) - b);

	end "-";

	-------------------------------------------------------------
	function "-" (a : sfixed_t; b : signed) return sfixed_t is

	begin 
	return sfixed_t(to_signed(a) - b);

	end "-";

	-------------------------------------------------------------
	function "-" (a : ufixed_t; b : integer) return ufixed_t is

	begin 
	
	return ufixed_t(to_unsigned(a) - to_unsigned(b, a'length));

	end "-";

	-------------------------------------------------------------
	function "-" (a : sfixed_t; b : integer) return sfixed_t is

	begin 

	return sfixed_t(to_signed(a) - to_signed(b, a'length));

	end "-";

	-------------------------------------------------------------
	function "-" (a : ufixed_t; b : std_logic) return ufixed_t is
	variable result : ufixed_t (a'high downto a'low);
	variable buns : unsigned(a'length-1 downto 0);

	begin 
	buns := (a'length-1 downto 1 => '0') & b;
	result := ufixed_t(to_unsigned(a) - buns);
	return result;

	end "-";

	-------------------------------------------------------------
	function "-" (a : sfixed_t; b : std_logic) return sfixed_t is
	variable result : sfixed_t (a'high downto a'low);
	variable bs : signed(a'length-1 downto 0);

	begin 
	bs := (a'length-1 downto 1 => '0') & b;
	result := sfixed_t(to_signed(a) - bs);
	return result;

	end "-";

	-------------------------------------------------------------
	-- Unary Operators
	-------------------------------------------------------------
	function "abs" (src : sfixed_t) return sfixed_t is
	begin
	return to_sfixed(abs(to_signed(src)), src);

	end "abs";

	-------------------------------------------------------------
	function "-" (src : ufixed_t) return sfixed_t is
	begin
	return -to_sfixed(src);

	end "-";

	-------------------------------------------------------------
	function "-" (src : sfixed_t) return sfixed_t is
	begin
	return to_sfixed(-to_signed(src), src);

	end "-";

	-------------------------------------------------------------
	-- Binary Equality
	-------------------------------------------------------------
	function "=" (a : ufixed_t; b : ufixed_t) return boolean is
	variable ta, tb: ufixed_t(max(a'high, b'high) downto min(a'low, b'low));
	begin
	ta := (others => '0');
	tb := (others => '0');
	ta := to_ufixed(a, ta);
	tb := to_ufixed(b, tb);
	return to_unsigned(ta) = to_unsigned(tb);

	end "=";
	
	-------------------------------------------------------------
	function "=" (a : sfixed_t; b : sfixed_t) return boolean is
	variable ta, tb: sfixed_t(max(a'high, b'high) downto min(a'low, b'low));
	begin
	ta := (others => '0');
	tb := (others => '0');
	ta := to_sfixed(a, ta);
	tb := to_sfixed(b, tb);
	return to_signed(ta) = to_signed(tb);

	end "=";
	
	-------------------------------------------------------------
	function "=" (a : ufixed_t; b : sfixed_t) return boolean is
	begin
	return to_sfixed(a) = b;
	end "=";
	
	-------------------------------------------------------------
	function "=" (a : sfixed_t; b : ufixed_t) return boolean is
	begin
	return b = a;
	end "=";
	
	-------------------------------------------------------------
	-- Binary Inequality
	-------------------------------------------------------------
	function "/=" (a : ufixed_t; b : ufixed_t) return boolean is
	begin
	return not (a = b);

	end "/=";
	
	-------------------------------------------------------------
	function "/=" (a : sfixed_t; b : sfixed_t) return boolean is
	begin
	return not (a = b);

	end "/=";
	
	-------------------------------------------------------------
	function "/=" (a : ufixed_t; b : sfixed_t) return boolean is
	begin
	return not (a = b);
	end "/=";
	
	-------------------------------------------------------------
	function "/=" (a : sfixed_t; b : ufixed_t) return boolean is
	begin
	return not (a = b);
	end "/=";
	
	-------------------------------------------------------------
	-- Binary less than
	-------------------------------------------------------------
	function "<" (a : ufixed_t; b : ufixed_t) return boolean is
	variable ta, tb: ufixed_t(max(a'high, b'high) downto min(a'low, b'low));
	begin
	ta := (others => '0');
	tb := (others => '0');
	ta := to_ufixed(a, ta);
	tb := to_ufixed(b, tb);
	return to_unsigned(ta) < to_unsigned(tb);
	
	end "<";
	
	-------------------------------------------------------------
	function "<" (a : sfixed_t; b : sfixed_t) return boolean is
	variable ta, tb: sfixed_t(max(a'high, b'high) downto min(a'low, b'low));
	begin
	ta := (others => '0');
	tb := (others => '0');
	ta := to_sfixed(a, ta);
	tb := to_sfixed(b, tb);
	return to_signed(ta) < to_signed(tb);
	
	end "<";

	-------------------------------------------------------------
	function "<" (a : ufixed_t; b : sfixed_t) return boolean is
	begin
	return to_sfixed(a) < b;
	
	end "<";

	-------------------------------------------------------------
	function "<" (a : sfixed_t; b : ufixed_t) return boolean is
	begin
	return a < to_sfixed(b);
	
	end "<";
	
	-------------------------------------------------------------
	-- Binary greater than
	-------------------------------------------------------------
	function ">" (a : ufixed_t; b : ufixed_t) return boolean is
	variable ta, tb: ufixed_t(max(a'high, b'high) downto min(a'low, b'low));
	begin
	ta := (others => '0');
	tb := (others => '0');
	ta := to_ufixed(a, ta);
	tb := to_ufixed(b, tb);
	return to_unsigned(ta) > to_unsigned(tb);
	
	end ">";

	-------------------------------------------------------------
	function ">" (a : sfixed_t; b : sfixed_t) return boolean is
	variable ta, tb: sfixed_t(max(a'high, b'high) downto min(a'low, b'low));
	begin
	ta := (others => '0');
	tb := (others => '0');
	ta := to_sfixed(a, ta);
	tb := to_sfixed(b, tb);
	return to_signed(ta) > to_signed(tb);
	
	end ">";

	-------------------------------------------------------------
	function ">" (a : ufixed_t; b : sfixed_t) return boolean is
	begin
	return to_sfixed(a) > b;
	end ">";
	
	-------------------------------------------------------------
	function ">" (a : sfixed_t; b : ufixed_t) return boolean is
	begin
	return a > to_sfixed(b);
	end ">";
	
	-------------------------------------------------------------
	-- Binary less equal than
	-------------------------------------------------------------
	function "<=" (a : ufixed_t; b : ufixed_t) return boolean is
	begin
	return not (a > b);
	end "<=";
	
	function "<=" (a : sfixed_t; b : sfixed_t) return boolean is
	begin
	return not (a > b);
	end "<=";

	function "<=" (a : ufixed_t; b : sfixed_t) return boolean is
	begin
	return not (a > b);
	end "<=";

	function "<=" (a : sfixed_t; b : ufixed_t) return boolean is
	begin
	return not (a > b);
	end "<=";
	
	-------------------------------------------------------------
	-- Binary greater or equal than
	-------------------------------------------------------------
	function ">=" (a : ufixed_t; b : ufixed_t) return boolean is
	begin
	return not (a < b);
	end ">=";

	function ">=" (a : sfixed_t; b : sfixed_t) return boolean is
	begin
	return not (a < b);
	end ">=";

	function ">=" (a : ufixed_t; b : sfixed_t) return boolean is
	begin
	return not (a < b);
	end ">=";

	function ">=" (a : sfixed_t; b : ufixed_t) return boolean is
	begin
	return not (a < b);
	end ">=";

	-------------------------------------------------------------
	-- Misc. Operators
	-------------------------------------------------------------
	function ipart (src : ufixed_t) return ufixed_t is
	begin
		return src(src'high downto 0);
	end ipart;
	
	function fpart (src : ufixed_t) return ufixed_t is
	begin
		return src(-1 downto src'low);
	end fpart;
	
	function ipart (src : sfixed_t) return sfixed_t is
	begin
		return src(src'high-1 downto 0);
	end ipart;
	
	function fpart (src : sfixed_t) return sfixed_t is
	begin
		return src(-1 downto src'low);
	end fpart;

	-------------------------------------------------------------
	-- Print functions
	-------------------------------------------------------------
	procedure print_info(src : in ufixed_t; prefix : in string) is
	variable L : line;

	begin
	write (L, prefix & "'length     = ");write (L, src'length);
	writeline (output, L);

	write (L, prefix & "'high(left) = ");
	write (L, src'high);
	write (L, '(');
	write (L, src'left);
	write (L, ')');
	writeline (output, L);

	write (L, prefix & "'low(right) = ");
	write (L, src'low);
	write (L, '(');
	write (L, src'right);
	write (L, ')');
	writeline (output, L);

	write (L, prefix & "'value      = B");write (L, to_string(src));
	writeline (output, L);

	write (L, prefix & "'value      = ");write (L, to_real(src));
	writeline (output, L);

	--      write (L, prefix & "'cmsb       = ");write (L, cmsb(src));
	--      writeline (output, L);

	--      write (L, prefix & "'clsb       = ");write (L, clsb(src));
	--      writeline (output, L);

	writeline (output, L);

	end print_info;

	-------------------------------------------------------------
	procedure print_info(src : in sfixed_t; prefix : in string) is
	variable L : line;

	begin
	write (L, prefix & "'length     = ");write (L, src'length);
	writeline (output, L);

	write (L, prefix & "'high(left) = ");
	write (L, src'high);
	write (L, '(');
	write (L, src'left);
	write (L, ')');
	writeline (output, L);

	write (L, prefix & "'low(right) = ");
	write (L, src'low);
	write (L, '(');
	write (L, src'right);
	write (L, ')');
	writeline (output, L);

	write (L, prefix & "'value      = B");write (L, to_string(src));
	writeline (output, L);

	write (L, prefix & "'value      = ");write (L, to_real(src));
	writeline (output, L);

	--      write (L, prefix & "'cmsb       = ");write (L, cmsb(src));
	--      writeline (output, L);

	--      write (L, prefix & "'clsb       = ");write (L, clsb(src));
	--      writeline (output, L);

	writeline (output, L);

	end print_info;

	-------------------------------------------------------------
	procedure print_info(src : in string; prefix : in string) is
	variable L : line;

	begin
	write (L, prefix & "'length     = ");write (L, src'length);
	writeline (output, L);

	write (L, prefix & "'high(left) = ");
	write (L, src'high);
	write (L, '(');
	write (L, src'left);
	write (L, ')');
	writeline (output, L);

	write (L, prefix & "'low(right) = ");
	write (L, src'low);
	write (L, '(');
	write (L, src'right);
	write (L, ')');
	writeline (output, L);

	writeline (output, L);

	end print_info;

	-------------------------------------------------------------
	-- Helpers
	-------------------------------------------------------------
	-- Count significant bits for integer part    
	function cmsb(src : ufixed_t) return integer is
	variable j, i : integer := src'high;
	begin
	for i in src'range loop
		if src(i) = '1' then
			exit;
		end if;
		j := j - 1;
	end loop;

	-- LRM nachlesen: hier is i=src'high re-initialisert

	return j;

	end cmsb;

	-------------------------------------------------------------
	-- Count significant bits for fractional part    
	function clsb(src : ufixed_t) return integer is
	variable j, i : integer := src'low;
	begin
	for i in src'reverse_range loop
		if src(i) = '1' then
			exit;
		end if;
		j := j + 1;
	end loop;

	-- LRM nachlesen: hier is i=src'low re-initialisert

	return j;

	end clsb;

	-------------------------------------------------------------
	function MIN (X, Y: INTEGER) return INTEGER is
	variable res : integer := X;
	begin
	if Y < X then
		res := Y;
	end if;

	return res;

	end MIN;

	-------------------------------------------------------------
	function MAX (X, Y: INTEGER) return INTEGER is
	variable res : integer := X;
	begin
	if Y > X then
		res := Y;
	end if;

	return res;
	
	end MAX;

	-------------------------------------------------------------
	function "MOD" (X, Y: in REAL ) return REAL is
	-- Description:
	--        See function declaration in IEEE Std 1076.2-1996
	-- Notes:
	--        a) Returns 0.0 on error

	variable XNEGATIVE : BOOLEAN := X < 0.0;
	variable YNEGATIVE : BOOLEAN := Y < 0.0;
	variable VALUE : REAL;
	begin
	-- Check validity of input arguments
	if (Y = 0.0) then
		 assert FALSE
				report "MOD(X, 0.0) is undefined"
				severity ERROR;
		 return 0.0;
	end if;

	-- Compute value
	if ( XNEGATIVE ) then
			if ( YNEGATIVE ) then
					VALUE := X + (FLOOR(ABS(X)/ABS(Y)))*ABS(Y);
			else
					VALUE := X + (CEIL(ABS(X)/ABS(Y)))*ABS(Y);
			end if;
	else
			if ( YNEGATIVE ) then
					VALUE := X - (CEIL(ABS(X)/ABS(Y)))*ABS(Y);
			else
					VALUE := X - (FLOOR(ABS(X)/ABS(Y)))*ABS(Y);
			end if;
	end if;

	return VALUE;

	end "MOD";

	-------------------------------------------------------------
	-- misc. conversion
	function ipart(src : real) return real is
	begin
	return floor(src);

	end ipart;

	-------------------------------------------------------------
	function fpart(src : real) return real is
	begin
	return src - floor(src);

	end fpart;

	-------------------------------------------------------------
	function or_red (arg : STD_LOGIC_VECTOR)
	return STD_LOGIC is
	variable Upper, Lower : STD_LOGIC;
	variable Half         : INTEGER;
	variable BUS_int      : STD_LOGIC_VECTOR (arg'length - 1 downto 0);
	variable Result       : STD_LOGIC;
	begin
	if (arg'length < 1) then            -- In the case of a NULL range
		Result := '0';
	else
		BUS_int := to_ux01 (arg);
		if (BUS_int'length = 1) then
			Result := BUS_int (BUS_int'left);
		elsif (BUS_int'length = 2) then
			Result := BUS_int (BUS_int'right) or BUS_int (BUS_int'left);
		else
			Half   := (BUS_int'length + 1) / 2 + BUS_int'right;
			Upper  := or_red (BUS_int (BUS_int'left downto Half));
			Lower  := or_red (BUS_int (Half - 1 downto BUS_int'right));
			Result := Upper or Lower;
		end if;
	end if;
	return Result;

	end function or_red;

	-------------------------------------------------------------
	function and_red (arg : STD_LOGIC_VECTOR)
	return STD_LOGIC is
	variable Upper, Lower : STD_LOGIC;
	variable Half         : INTEGER;
	variable BUS_int      : STD_LOGIC_VECTOR (arg'length - 1 downto 0);
	variable Result       : STD_LOGIC;
	begin
	if (arg'length < 1) then            -- In the case of a NULL range
		Result := '1';
	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_red (BUS_int (BUS_int'left downto Half));
			Lower  := and_red (BUS_int (Half - 1 downto BUS_int'right));
			Result := Upper and Lower;
		end if;
	end if;
	return Result;

	end function and_red;

	-------------------------------------------------------------
	function xor_red (arg : STD_LOGIC_VECTOR) return STD_ULOGIC is
	variable Upper, Lower : STD_ULOGIC;
	variable Half         : INTEGER;
	variable BUS_int      : STD_LOGIC_VECTOR (arg'length - 1 downto 0);
	variable Result       : STD_ULOGIC := '0';  -- In the case of a NULL range
	begin
	if (arg'length >= 1) then
		BUS_int := to_ux01 (arg);
		if (BUS_int'length = 1) then
			Result := BUS_int (BUS_int'left);
		elsif (BUS_int'length = 2) then
			Result := BUS_int(BUS_int'right) xor BUS_int(BUS_int'left);
		else
			Half   := (BUS_int'length + 1) / 2 + BUS_int'right;
			Upper  := xor_red (BUS_int (BUS_int'left downto Half));
			Lower  := xor_red (BUS_int (Half - 1 downto BUS_int'right));
			Result := Upper xor Lower;
		end if;
	end if;
	return Result;

	end function xor_red;

	-------------------------------------------------------------
	-- Reduction operators, same as numeric_std functions
	function and_red(arg : ufixed_t) return STD_ULOGIC is
	begin
		return and_red (to_slv(arg));
	end function and_red;

	function nand_red(arg : ufixed_t) return STD_ULOGIC is
	begin
		return not and_red (to_slv(arg));
	end function nand_red;

	function or_red(arg : ufixed_t) return STD_ULOGIC is
	begin
		return or_red (to_slv(arg));
	end function or_red;

	function nor_red(arg : ufixed_t) return STD_ULOGIC is
	begin
		return not or_red (to_slv(arg));
	end function nor_red;

	function xor_red(arg : ufixed_t) return STD_ULOGIC is
	begin
		return xor_red (to_slv(arg));
	end function xor_red;

	function xnor_red(arg : ufixed_t) return STD_ULOGIC is
	begin
		return not xor_red (to_slv(arg));
	end function xnor_red;

	function and_red(arg : sfixed_t) return STD_ULOGIC is
	begin
		return and_red (to_slv(arg));
	end function and_red;

	function nand_red(arg : sfixed_t) return STD_ULOGIC is
	begin
		return not and_red (to_slv(arg));
	end function nand_red;

	function or_red(arg : sfixed_t) return STD_ULOGIC is
	begin
		return or_red (to_slv(arg));
	end function or_red;

	function nor_red(arg : sfixed_t) return STD_ULOGIC is
	begin
		return not or_red (to_slv(arg));
	end function nor_red;

	function xor_red(arg : sfixed_t) return STD_ULOGIC is
	begin
		return xor_red (to_slv(arg));
	end function xor_red;

	function xnor_red(arg : sfixed_t) return STD_ULOGIC is
	begin
		return not xor_red (to_slv(arg));
	end function xnor_red;

	-------------------------------------------------------------

end; -- package body fixed_ja;
