
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.MATH_REAL.ALL;

library IEEE;
use IEEE.fixed_float_types.all;
use IEEE.fixed_pkg.all;

package fixed_util_pkg is

	-------------------------------------------------------------
	-- Frequently used constants
	constant pi			: real := 3.141592653589793e+000;
	constant sqrt2		: real := 1.414213562373095e+000;
	constant sqrt2_inv	: real := 7.071067811865475e-001;

	-- Constructor helpers
	-- Use: variable v8u6 : ufixed_t(ufixed(8,6)'range);
	function uproto (constant nbits : integer; constant nbits_frac : integer) return ufixed;

	-- Use: variable v8s6 : sfixed_t(sfixed(8,6)'range);
	function sproto (constant nbits : integer; constant nbits_frac : integer) return sfixed;

	-- Safe variant of uproto
	function uhi (constant nbits : integer; constant nbits_frac : integer) return integer;
	function ulo (constant nbits : integer; constant nbits_frac : integer) return integer;

	-- Safe variant of sproto
	function shi (constant nbits : integer; constant nbits_frac : integer) return integer;
	function slo (constant nbits : integer; constant nbits_frac : integer) return integer;

	function to_unsigned (src : ufixed) return UNSIGNED;
	function to_signed (src : sfixed) return SIGNED;

	type real_array_t is array (natural range <>) of real;
	type natural_array_t is array (natural range <>) of natural;
	type ufixed_array_t is array (natural range <>, integer range <>) of STD_LOGIC;
	type sfixed_array_t is array (natural range <>, integer range <>) of STD_LOGIC;

	function to_sfixed_array(x : real_array_t; proto : sfixed) return sfixed_array_t;
	function to_sfixed_array(x : real_array_t; nbits, nbits_int : integer) return sfixed_array_t;

	-- Slicing functions for unconstrained array types
	function to_ufixed(src : ufixed_array_t; index : integer) return ufixed;
	function to_sfixed(src : sfixed_array_t; index : integer) return sfixed;
	
-------------------------------------------------------------------------------
end; -- package fixed_util_pkg;

package body fixed_util_pkg is

	-------------------------------------------------------------
	-- Constuctor helpers
	function uproto (constant nbits : integer; constant nbits_frac : integer) return ufixed is
	constant result : ufixed (uhi(nbits,nbits_frac) downto ulo(nbits,nbits_frac)) := (others => '0');
	begin 
	return result(uhi(nbits,nbits_frac) downto ulo(nbits,nbits_frac));
	end uproto;

	-------------------------------------------------------------
	function sproto (constant nbits : integer; constant nbits_frac : integer) return sfixed is
	constant result : sfixed (shi(nbits,nbits_frac) downto slo(nbits,nbits_frac)) := (others => '0');
	begin 
	return result(shi(nbits,nbits_frac) downto slo(nbits,nbits_frac));
	end sproto;

	-------------------------------------------------------------
	function uhi (constant nbits : integer; constant nbits_frac : integer) return integer is
	begin 
	return nbits-nbits_frac-1;
	end uhi;

	-------------------------------------------------------------
	function ulo (constant nbits : integer; constant nbits_frac : integer) return integer is
	begin 
	return -nbits_frac;
	end ulo;

	-------------------------------------------------------------
	function shi (constant nbits : integer; constant nbits_frac : integer) return integer is
	begin 
	return nbits-nbits_frac;
	end shi;

	-------------------------------------------------------------
	function slo (constant nbits : integer; constant nbits_frac : integer) return integer is
	begin 
	return -nbits_frac+1;
	end slo;

	-------------------------------------------------------------
	function to_unsigned (src : ufixed) 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) 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;
	
	function to_sfixed_array(x : real_array_t; proto : sfixed) return sfixed_array_t is
	variable res : sfixed_array_t(0 to x'length-1, proto'range);
	variable tt : sfixed(proto'range);
	begin
		for i in x'range loop
			tt := to_sfixed(x(i), proto);
			for j in proto'range loop
				res(i,j) := tt(j);
			end loop;	
		end loop;
		return res;
	end to_sfixed_array;	

	---------------------------------------------------------------------------
	function to_sfixed_array(x : real_array_t; nbits, nbits_int : integer) return sfixed_array_t is
	variable p : sfixed(shi(nbits, nbits_int) downto slo(nbits, nbits_int));
	begin
		return to_sfixed_array(x, p);
	end to_sfixed_array;	
		
	-------------------------------------------------------------------------------
	-- ufixed <= ufixed_array(i)
	function to_ufixed(src : ufixed_array_t; index : integer) return ufixed is
	variable dst : ufixed(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 is
	variable dst : sfixed(src'range(2));
	begin
		for j in src'range(2) loop
			dst(j) := src(index, j);
		end loop;
		
		return dst;
		
	end to_sfixed;	

-------------------------------------------------------------------------------
end; -- package fixed_util_pkg;
