-- EMACS settings: -*-  tab-width: 2; indent-tabs-mode: t -*-
-- vim: tabstop=2:shiftwidth=2:noexpandtab
-- kate: tab-width 2; replace-tabs off; indent-width 2;
-- =============================================================================
-- Authors:					Thomas B. Preusser
--									Martin Zabel
--									Patrick Lehmann
--
-- Package:					Common functions and types
--
-- Description:
-- 
--		For detailed documentation see below.
--
-- License:
-- =============================================================================
-- Copyright 2007-2016 Technische Universitaet Dresden - Germany
--										 Chair of VLSI-Design, Diagnostics and Architecture
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--		http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
-- =============================================================================

library	IEEE;
use			IEEE.std_logic_1164.all;
use			IEEE.numeric_std.all;

library	PoC;
use			PoC.utils.all;
use			PoC.strings.all;


package [docs]vectors is
	-- ==========================================================================
	-- Type declarations
	-- ==========================================================================
	-- STD_LOGIC_VECTORs
	subtype T_SLV_2							is std_logic_vector(1 downto 0);
	subtype T_SLV_3							is std_logic_vector(2 downto 0);
	subtype T_SLV_4							is std_logic_vector(3 downto 0);
	subtype T_SLV_8							is std_logic_vector(7 downto 0);
	subtype T_SLV_12						is std_logic_vector(11 downto 0);
	subtype T_SLV_16						is std_logic_vector(15 downto 0);
	subtype T_SLV_24						is std_logic_vector(23 downto 0);
	subtype T_SLV_32						is std_logic_vector(31 downto 0);
	subtype T_SLV_48						is std_logic_vector(47 downto 0);
	subtype T_SLV_64						is std_logic_vector(63 downto 0);
	subtype T_SLV_96						is std_logic_vector(95 downto 0);
	subtype T_SLV_128						is std_logic_vector(127 downto 0);
	subtype T_SLV_256						is std_logic_vector(255 downto 0);
	subtype T_SLV_512						is std_logic_vector(511 downto 0);

	-- STD_LOGIC_VECTOR_VECTORs
	--	type		T_SLVV							is array(NATURAL range <>) of STD_LOGIC_VECTOR;					-- VHDL 2008 syntax - not yet supported by Xilinx
	type		T_SLVV_2						is array(natural range <>) of T_SLV_2;
	type		T_SLVV_3						is array(natural range <>) of T_SLV_3;
	type		T_SLVV_4						is array(natural range <>) of T_SLV_4;
	type		T_SLVV_8						is array(natural range <>) of T_SLV_8;
	type		T_SLVV_12						is array(natural range <>) of T_SLV_12;
	type		T_SLVV_16						is array(natural range <>) of T_SLV_16;
	type		T_SLVV_24						is array(natural range <>) of T_SLV_24;
	type		T_SLVV_32						is array(natural range <>) of T_SLV_32;
	type		T_SLVV_48						is array(natural range <>) of T_SLV_48;
	type		T_SLVV_64						is array(natural range <>) of T_SLV_64;
	type		T_SLVV_128					is array(natural range <>) of T_SLV_128;
	type		T_SLVV_256					is array(natural range <>) of T_SLV_256;
	type		T_SLVV_512					is array(natural range <>) of T_SLV_512;

	-- STD_LOGIC_MATRIXs
	type		T_SLM								is array(natural range <>, natural range <>) of std_logic;
	-- ATTENTION:
	-- 1.	you MUST initialize your matrix signal with 'Z' to get correct simulation results (iSIM, vSIM, ghdl/gtkwave)
	--    Example: signal myMatrix	: T_SLM(3 downto 0, 7 downto 0)      := (others => (others => 'Z'));
	-- 2.	Xilinx iSIM bug: DON'T use myMatrix'range(n) for n >= 2
	--    myMatrix'range(2) returns always myMatrix'range(1);	see work-around notes below
	--
	-- USAGE NOTES:
	--  dimension 1 => rows       - e.g. Words
	--  dimension 2 => columns    - e.g. Bits/Bytes in a word
	--
	-- WORKAROUND: for Xilinx ISE/iSim
	--  Version:	14.2
	--  Issue:		myMatrix'range(n) for n >= 2 returns always myMatrix'range(1)

  -- ==========================================================================
  -- Function declarations
  -- ==========================================================================
  -- slicing boundary calulations
  function [docs]low (lenvec : T_POSVEC; index : natural) return natural;
  function [docs]high(lenvec : T_POSVEC; index : natural) return natural;

	-- Assign procedures: assign_*
	procedure [docs]assign_row(signal slm : out T_SLM; slv : std_logic_vector; constant RowIndex : natural);																	-- assign vector to complete row
	procedure [docs]assign_row(signal slm : out T_SLM; slv : std_logic_vector; constant RowIndex : natural; Position : natural);							-- assign short vector to row starting at position
	procedure [docs]assign_row(signal slm : out T_SLM; slv : std_logic_vector; constant RowIndex : natural; High : natural; Low : natural);		-- assign short vector to row in range high:low
	procedure [docs]assign_col(signal slm : out T_SLM; slv : std_logic_vector; constant ColIndex : natural);																	-- assign vector to complete column
	-- ATTENTION:	see T_SLM definition for further details and work-arounds

	-- Matrix to matrix conversion: slm_slice*
	function [docs]slm_slice(slm : T_SLM; RowIndex : natural; ColIndex : natural; Height : natural; Width : natural) return T_SLM;						-- get submatrix in boundingbox RowIndex,ColIndex,Height,Width
	function [docs]slm_slice_rows(slm : T_SLM; High : natural; Low : natural) return T_SLM;																										-- get submatrix / all rows in RowIndex range high:low
	function [docs]slm_slice_cols(slm : T_SLM; High : natural; Low : natural) return T_SLM;																										-- get submatrix / all columns in ColIndex range high:low

	-- Boolean Operators
	function [docs]"not" (a    : t_slm) return t_slm;
	function [docs]"and" (a, b : t_slm) return t_slm;
	function [docs]"or"  (a, b : t_slm) return t_slm;
	function [docs]"xor" (a, b : t_slm) return t_slm;
	function [docs]"nand"(a, b : t_slm) return t_slm;
	function [docs]"nor" (a, b : t_slm) return t_slm;
	function [docs]"xnor"(a, b : t_slm) return t_slm;

	-- Matrix concatenation: slm_merge_*
	function [docs]slm_merge_rows(slm1 : T_SLM; slm2 : T_SLM) return T_SLM;
	function [docs]slm_merge_cols(slm1 : T_SLM; slm2 : T_SLM) return T_SLM;

	-- Matrix to vector conversion: get_*
	function [docs]get_col(slm : T_SLM; ColIndex : natural) return std_logic_vector;																	-- get a matrix column
	function [docs]get_row(slm : T_SLM; RowIndex : natural)	return std_logic_vector;																	-- get a matrix row
	function [docs]get_row(slm : T_SLM; RowIndex : natural; Length : positive)	return std_logic_vector;							-- get a matrix row of defined length [length - 1 downto 0]
	function [docs]get_row(slm : T_SLM; RowIndex : natural; High : natural; Low : natural) return std_logic_vector;		-- get a sub vector of a matrix row at high:low

	-- Convert to vector: to_slv
	function [docs]to_slv(slvv : T_SLVV_2)							return std_logic_vector;								-- convert vector-vector to flatten vector
	function [docs]to_slv(slvv : T_SLVV_4)							return std_logic_vector;								-- ...
	function [docs]to_slv(slvv : T_SLVV_8)							return std_logic_vector;								-- ...
	function [docs]to_slv(slvv : T_SLVV_12)							return std_logic_vector;								-- ...
	function [docs]to_slv(slvv : T_SLVV_16)							return std_logic_vector;								-- ...
	function [docs]to_slv(slvv : T_SLVV_24)							return std_logic_vector;								-- ...
	function [docs]to_slv(slvv : T_SLVV_32)							return std_logic_vector;								-- ...
	function [docs]to_slv(slvv : T_SLVV_64)							return std_logic_vector;								-- ...
	function [docs]to_slv(slvv : T_SLVV_128)						return std_logic_vector;								-- ...
	function [docs]to_slv(slm : T_SLM)									return std_logic_vector;								-- convert matrix to flatten vector

	-- Convert flat vector to avector-vector: to_slvv_*
	function [docs]to_slvv_4(slv : std_logic_vector)		return T_SLVV_4;												--
	function [docs]to_slvv_8(slv : std_logic_vector)		return T_SLVV_8;												--
	function [docs]to_slvv_12(slv : std_logic_vector)		return T_SLVV_12;												--
	function [docs]to_slvv_16(slv : std_logic_vector)		return T_SLVV_16;												--
	function [docs]to_slvv_32(slv : std_logic_vector)		return T_SLVV_32;												--
	function [docs]to_slvv_64(slv : std_logic_vector)		return T_SLVV_64;												--
	function [docs]to_slvv_128(slv : std_logic_vector)	return T_SLVV_128;											--
	function [docs]to_slvv_256(slv : std_logic_vector)	return T_SLVV_256;											--
	function [docs]to_slvv_512(slv : std_logic_vector)	return T_SLVV_512;											--

	-- Convert matrix to avector-vector: to_slvv_*
	function [docs]to_slvv_4(slm : T_SLM)		return T_SLVV_4;																		--
	function [docs]to_slvv_8(slm : T_SLM)		return T_SLVV_8;																		--
	function [docs]to_slvv_12(slm : T_SLM)	return T_SLVV_12;																		--
	function [docs]to_slvv_16(slm : T_SLM)	return T_SLVV_16;																		--
	function [docs]to_slvv_32(slm : T_SLM)	return T_SLVV_32;																		--
	function [docs]to_slvv_64(slm : T_SLM)	return T_SLVV_64;																		--
	function [docs]to_slvv_128(slm : T_SLM)	return T_SLVV_128;																	--
	function [docs]to_slvv_256(slm : T_SLM)	return T_SLVV_256;																	--
	function [docs]to_slvv_512(slm : T_SLM)	return T_SLVV_512;																	--

	-- Convert vector-vector to matrix: to_slm
	function [docs]to_slm(slv : std_logic_vector; ROWS : positive; COLS : positive) return T_SLM;	-- create matrix from vector
	function [docs]to_slm(slvv : T_SLVV_4) return T_SLM;																					-- create matrix from vector-vector
	function [docs]to_slm(slvv : T_SLVV_8) return T_SLM;																					-- create matrix from vector-vector
	function [docs]to_slm(slvv : T_SLVV_12) return T_SLM;																					-- create matrix from vector-vector
	function [docs]to_slm(slvv : T_SLVV_16) return T_SLM;																					-- create matrix from vector-vector
	function [docs]to_slm(slvv : T_SLVV_32) return T_SLM;																					-- create matrix from vector-vector
	function [docs]to_slm(slvv : T_SLVV_48) return T_SLM;																					-- create matrix from vector-vector
	function [docs]to_slm(slvv : T_SLVV_64) return T_SLM;																					-- create matrix from vector-vector
	function [docs]to_slm(slvv : T_SLVV_128) return T_SLM;																				-- create matrix from vector-vector
	function [docs]to_slm(slvv : T_SLVV_256) return T_SLM;																				-- create matrix from vector-vector
	function [docs]to_slm(slvv : T_SLVV_512) return T_SLM;																				-- create matrix from vector-vector

	-- Change vector direction
	function [docs]dir(slvv : T_SLVV_8)			return T_SLVV_8;

	-- Reverse vector elements
	function [docs]rev(slvv : T_SLVV_4)			return T_SLVV_4;
	function [docs]rev(slvv : T_SLVV_8)			return T_SLVV_8;
	function [docs]rev(slvv : T_SLVV_12)		return T_SLVV_12;
	function [docs]rev(slvv : T_SLVV_16)		return T_SLVV_16;
	function [docs]rev(slvv : T_SLVV_32)		return T_SLVV_32;
	function [docs]rev(slvv : T_SLVV_64)		return T_SLVV_64;
	function [docs]rev(slvv : T_SLVV_128)		return T_SLVV_128;
	function [docs]rev(slvv : T_SLVV_256)		return T_SLVV_256;
	function [docs]rev(slvv : T_SLVV_512)		return T_SLVV_512;

	-- TODO:
	function [docs]resize(slm : T_SLM; size : positive) return T_SLM;

	-- to_string
	function [docs]to_string(slvv : T_SLVV_8; sep : character := ':') return string;
	function [docs]to_string(slm : T_SLM; groups : positive := 4; format : character := 'b') return string;
end package vectors;


package body vectors is
	-- slicing boundary calulations
	-- ==========================================================================
	function low(lenvec : T_POSVEC; index : natural) return natural is
		variable pos		: natural		:= 0;
	begin
		for i in lenvec'low to index - 1 loop
			pos := pos + lenvec(i);
		end loop;
		return pos;
	end function;

	function high(lenvec : T_POSVEC; index : natural) return natural is
		variable pos		: natural		:= 0;
	begin
		for i in lenvec'low to index loop
			pos := pos + lenvec(i);
		end loop;
		return pos - 1;
	end function;

	-- Assign procedures: assign_*
	-- ==========================================================================
	procedure assign_row(signal slm : out T_SLM; slv : std_logic_vector; constant RowIndex : natural) is
		variable temp : std_logic_vector(slm'high(2) downto slm'low(2));					-- WORKAROUND: Xilinx iSIM work-around, because 'range(2) evaluates to 'range(1); see work-around notes at T_SLM type declaration
	begin
		temp := slv;
		for i in temp'range loop
			slm(RowIndex, i)  <= temp(i);
		end loop;
	end procedure;

	procedure assign_row(signal slm : out T_SLM; slv : std_logic_vector; constant RowIndex : natural; Position : natural) is
		variable temp : std_logic_vector(Position + slv'length - 1 downto Position);
	begin
		temp := slv;
		for i in temp'range loop
			slm(RowIndex, i)  <= temp(i);
		end loop;
	end procedure;

	procedure assign_row(signal slm : out T_SLM; slv : std_logic_vector; constant RowIndex : natural; High : natural; Low : natural) is
		variable temp : std_logic_vector(High downto Low);
	begin
		temp := slv;
		for i in temp'range loop
			slm(RowIndex, i)  <= temp(i);
		end loop;
	end procedure;

	procedure assign_col(signal slm : out T_SLM; slv : std_logic_vector; constant ColIndex : natural) is
		variable temp : std_logic_vector(slm'range(1));
	begin
		temp := slv;
		for i in temp'range loop
			slm(i, ColIndex)  <= temp(i);
		end loop;
	end procedure;

	-- Matrix to matrix conversion: slm_slice*
	-- ==========================================================================
	function slm_slice(slm : T_SLM; RowIndex : natural; ColIndex : natural; Height : natural; Width : natural) return T_SLM is
		variable Result		: T_SLM(Height - 1 downto 0, Width - 1 downto 0)		:= (others => (others => '0'));
	begin
		for i in 0 to Height - 1 loop
			for j in 0 to Width - 1 loop
				Result(i, j)		:= slm(RowIndex + i, ColIndex + j);
			end loop;
		end loop;
		return Result;
	end function;

	function slm_slice_rows(slm : T_SLM; High : natural; Low : natural) return T_SLM is
		variable Result		: T_SLM(High - Low downto 0, slm'length(2) - 1 downto 0)		:= (others => (others => '0'));
	begin
		for i in 0 to High - Low loop
			for j in 0 to slm'length(2) - 1 loop
				Result(i, j)		:= slm(Low + i, slm'low(2) + j);
			end loop;
		end loop;
		return Result;
	end function;

	function slm_slice_cols(slm : T_SLM; High : natural; Low : natural) return T_SLM is
		variable Result		: T_SLM(slm'length(1) - 1 downto 0, High - Low downto 0)		:= (others => (others => '0'));
	begin
		for i in 0 to slm'length(1) - 1 loop
			for j in 0 to High - Low loop
				Result(i, j)		:= slm(slm'low(1) + i, Low + j);
			end loop;
		end loop;
		return Result;
	end function;

	-- Boolean Operators
	function "not"(a : t_slm) return t_slm is
		variable  res : t_slm(a'range(1), a'range(2));
	begin
		for i in res'range(1) loop
			for j in res'range(2) loop
				res(i, j) := not a(i, j);
			end loop;
		end loop;
		return  res;
	end function;

	function "and"(a, b : t_slm) return t_slm is
		variable  bb, res : t_slm(a'range(1), a'range(2));
	begin
		bb := b;
		for i in res'range(1) loop
			for j in res'range(2) loop
				res(i, j) := a(i, j) and bb(i, j);
			end loop;
		end loop;
		return  res;
	end function;

	function "or"(a, b : t_slm) return t_slm is
		variable  bb, res : t_slm(a'range(1), a'range(2));
	begin
		bb := b;
		for i in res'range(1) loop
			for j in res'range(2) loop
				res(i, j) := a(i, j) or bb(i, j);
			end loop;
		end loop;
		return  res;
	end function;

	function "xor"(a, b : t_slm) return t_slm is
		variable  bb, res : t_slm(a'range(1), a'range(2));
	begin
		bb := b;
		for i in res'range(1) loop
			for j in res'range(2) loop
				res(i, j) := a(i, j) xor bb(i, j);
			end loop;
		end loop;
		return  res;
	end function;

	function "nand"(a, b : t_slm) return t_slm is
	begin
		return  not(a and b);
	end function;

  function "nor"(a, b : t_slm) return t_slm is
	begin
		return  not(a or b);
	end function;

	function "xnor"(a, b : t_slm) return t_slm is
	begin
		return  not(a xor b);
	end function;

	-- Matrix concatenation: slm_merge_*
	function slm_merge_rows(slm1 : T_SLM; slm2 : T_SLM) return T_SLM is
		constant ROWS			: positive		:= slm1'length(1) + slm2'length(1);
		constant COLUMNS	: positive		:= slm1'length(2);
		variable slm			: T_SLM(ROWS - 1 downto 0, COLUMNS - 1 downto 0);
	begin
		for i in slm1'range(1) loop
			for j in slm1'low(2) to slm1'high(2) loop					-- WORKAROUND: Xilinx iSIM work-around, because 'range(2) evaluates to 'range(1); see work-around notes at T_SLM type declaration
				slm(i, j)		:= slm1(i, j);
			end loop;
		end loop;
		for i in slm2'range(1) loop
			for j in slm2'low(2) to slm2'high(2) loop					-- WORKAROUND: Xilinx iSIM work-around, because 'range(2) evaluates to 'range(1); see work-around notes at T_SLM type declaration
				slm(slm1'length(1) + i, j)		:= slm2(i, j);
			end loop;
		end loop;
		return slm;
	end function;

	function slm_merge_cols(slm1 : T_SLM; slm2 : T_SLM) return T_SLM is
		constant ROWS			: positive		:= slm1'length(1);
		constant COLUMNS	: positive		:= slm1'length(2) + slm2'length(2);
		variable slm			: T_SLM(ROWS - 1 downto 0, COLUMNS - 1 downto 0);
	begin
		for i in slm1'range(1) loop
			for j in slm1'low(2) to slm1'high(2) loop					-- WORKAROUND: Xilinx iSIM work-around, because 'range(2) evaluates to 'range(1); see work-around notes at T_SLM type declaration
				slm(i, j)		:= slm1(i, j);
			end loop;
			for j in slm2'low(2) to slm2'high(2) loop					-- WORKAROUND: Xilinx iSIM work-around, because 'range(2) evaluates to 'range(1); see work-around notes at T_SLM type declaration
				slm(i, slm1'length(2) + j)		:= slm2(i, j);
			end loop;
		end loop;
		return slm;
	end function;


	-- Matrix to vector conversion: get_*
	-- ==========================================================================
	-- get a matrix column
	function get_col(slm : T_SLM; ColIndex : natural) return std_logic_vector is
		variable slv		: std_logic_vector(slm'range(1));
	begin
		for i in slm'range(1) loop
			slv(i)	:= slm(i, ColIndex);
		end loop;
		return slv;
	end function;

	-- get a matrix row
	function get_row(slm : T_SLM; RowIndex : natural) return std_logic_vector is
		variable slv		: std_logic_vector(slm'high(2) downto slm'low(2));					-- WORKAROUND: Xilinx iSIM work-around, because 'range(2) evaluates to 'range(1); see work-around notes at T_SLM type declaration
	begin
		for i in slv'range loop
			slv(i)	:= slm(RowIndex, i);
		end loop;
		return slv;
	end function;

	-- get a matrix row of defined length [length - 1 downto 0]
	function get_row(slm : T_SLM; RowIndex : natural; Length : positive) return std_logic_vector is
	begin
		return get_row(slm, RowIndex, (Length - 1), 0);
	end function;

	-- get a sub vector of a matrix row at high:low
	function get_row(slm : T_SLM; RowIndex : natural; High : natural; Low : natural) return std_logic_vector is
		variable slv		: std_logic_vector(High downto Low);
	begin
		for i in slv'range loop
			slv(i)	:= slm(RowIndex, i);
		end loop;
		return slv;
	end function;

	-- Convert to vector: to_slv
	-- ==========================================================================
	-- convert vector-vector to flatten vector
	function to_slv(slvv : T_SLVV_2) return std_logic_vector is
		variable slv			: std_logic_vector((slvv'length * 2) - 1 downto 0);
	begin
		for i in slvv'range loop
			slv((i * 2) + 1 downto (i * 2))		:= slvv(i);
		end loop;
		return slv;
	end function;

	function to_slv(slvv : T_SLVV_4) return std_logic_vector is
		variable slv			: std_logic_vector((slvv'length * 4) - 1 downto 0);
	begin
		for i in slvv'range loop
			slv((i * 4) + 3 downto (i * 4))		:= slvv(i);
		end loop;
		return slv;
	end function;

	function to_slv(slvv : T_SLVV_8) return std_logic_vector is
		variable slv			: std_logic_vector((slvv'length * 8) - 1 downto 0);
	begin
		for i in slvv'range loop
			slv((i * 8) + 7 downto (i * 8))		:= slvv(i);
		end loop;
		return slv;
	end function;

	function to_slv(slvv : T_SLVV_12) return std_logic_vector is
		variable slv			: std_logic_vector((slvv'length * 12) - 1 downto 0);
	begin
		for i in slvv'range loop
			slv((i * 12) + 11 downto (i * 12))		:= slvv(i);
		end loop;
		return slv;
	end function;

	function to_slv(slvv : T_SLVV_16) return std_logic_vector is
		variable slv			: std_logic_vector((slvv'length * 16) - 1 downto 0);
	begin
		for i in slvv'range loop
			slv((i * 16) + 15 downto (i * 16))		:= slvv(i);
		end loop;
		return slv;
	end function;

	function to_slv(slvv : T_SLVV_24) return std_logic_vector is
		variable slv			: std_logic_vector((slvv'length * 24) - 1 downto 0);
	begin
		for i in slvv'range loop
			slv((i * 24) + 23 downto (i * 24))		:= slvv(i);
		end loop;
		return slv;
	end function;

	function to_slv(slvv : T_SLVV_32) return std_logic_vector is
		variable slv			: std_logic_vector((slvv'length * 32) - 1 downto 0);
	begin
		for i in slvv'range loop
			slv((i * 32) + 31 downto (i * 32))		:= slvv(i);
		end loop;
		return slv;
	end function;

	function to_slv(slvv : T_SLVV_64) return std_logic_vector is
		variable slv			: std_logic_vector((slvv'length * 64) - 1 downto 0);
	begin
		for i in slvv'range loop
			slv((i * 64) + 63 downto (i * 64))		:= slvv(i);
		end loop;
		return slv;
	end function;

	function to_slv(slvv : T_SLVV_128) return std_logic_vector is
		variable slv			: std_logic_vector((slvv'length * 128) - 1 downto 0);
	begin
		for i in slvv'range loop
			slv((i * 128) + 127 downto (i * 128))		:= slvv(i);
		end loop;
		return slv;
	end function;

	-- convert matrix to flatten vector
	function to_slv(slm : T_SLM) return std_logic_vector is
		variable slv			: std_logic_vector((slm'length(1) * slm'length(2)) - 1 downto 0);
	begin
		for i in slm'range(1) loop
			for j in slm'high(2) downto slm'low(2) loop					-- WORKAROUND: Xilinx iSIM work-around, because 'range(2) evaluates to 'range(1); see work-around notes at T_SLM type declaration
				slv((i * slm'length(2)) + j)		:= slm(i, j);
			end loop;
		end loop;
		return slv;
	end function;


	-- Convert flat vector to a vector-vector: to_slvv_*
	-- ==========================================================================
	-- create vector-vector from vector (4 bit)
	function to_slvv_4(slv : std_logic_vector) return T_SLVV_4 is
		variable Result		: T_SLVV_4((slv'length / 4) - 1 downto 0);
	begin
		if ((slv'length mod 4) /= 0) then	report "to_slvv_4: width mismatch - slv'length is no multiple of 4 (slv'length=" & INTEGER'image(slv'length) & ")" severity FAILURE;	end if;

		for i in Result'range loop
			Result(i)	:= slv((i * 4) + 3 downto (i * 4));
		end loop;
		return Result;
	end function;

	-- create vector-vector from vector (8 bit)
	function to_slvv_8(slv : std_logic_vector) return T_SLVV_8 is
		variable Result		: T_SLVV_8((slv'length / 8) - 1 downto 0);
	begin
		if ((slv'length mod 8) /= 0) then	report "to_slvv_8: width mismatch - slv'length is no multiple of 8 (slv'length=" & INTEGER'image(slv'length) & ")" severity FAILURE;	end if;

		for i in Result'range loop
			Result(i)	:= slv((i * 8) + 7 downto (i * 8));
		end loop;
		return Result;
	end function;

	-- create vector-vector from vector (12 bit)
	function to_slvv_12(slv : std_logic_vector) return T_SLVV_12 is
		variable Result		: T_SLVV_12((slv'length / 12) - 1 downto 0);
	begin
		if ((slv'length mod 12) /= 0) then	report "to_slvv_12: width mismatch - slv'length is no multiple of 12 (slv'length=" & INTEGER'image(slv'length) & ")" severity FAILURE;	end if;

		for i in Result'range loop
			Result(i)	:= slv((i * 12) + 11 downto (i * 12));
		end loop;
		return Result;
	end function;

	-- create vector-vector from vector (16 bit)
	function to_slvv_16(slv : std_logic_vector) return T_SLVV_16 is
		variable Result		: T_SLVV_16((slv'length / 16) - 1 downto 0);
	begin
		if ((slv'length mod 16) /= 0) then	report "to_slvv_16: width mismatch - slv'length is no multiple of 16 (slv'length=" & INTEGER'image(slv'length) & ")" severity FAILURE;	end if;

		for i in Result'range loop
			Result(i)	:= slv((i * 16) + 15 downto (i * 16));
		end loop;
		return Result;
	end function;

	-- create vector-vector from vector (32 bit)
	function to_slvv_32(slv : std_logic_vector) return T_SLVV_32 is
		variable Result		: T_SLVV_32((slv'length / 32) - 1 downto 0);
	begin
		if ((slv'length mod 32) /= 0) then	report "to_slvv_32: width mismatch - slv'length is no multiple of 32 (slv'length=" & INTEGER'image(slv'length) & ")" severity FAILURE;	end if;

		for i in Result'range loop
			Result(i)	:= slv((i * 32) + 31 downto (i * 32));
		end loop;
		return Result;
	end function;

	-- create vector-vector from vector (64 bit)
	function to_slvv_64(slv : std_logic_vector) return T_SLVV_64 is
		variable Result		: T_SLVV_64((slv'length / 64) - 1 downto 0);
	begin
		if ((slv'length mod 64) /= 0) then	report "to_slvv_64: width mismatch - slv'length is no multiple of 64 (slv'length=" & INTEGER'image(slv'length) & ")" severity FAILURE;	end if;

		for i in Result'range loop
			Result(i)	:= slv((i * 64) + 63 downto (i * 64));
		end loop;
		return Result;
	end function;

	-- create vector-vector from vector (128 bit)
	function to_slvv_128(slv : std_logic_vector) return T_SLVV_128 is
		variable Result		: T_SLVV_128((slv'length / 128) - 1 downto 0);
	begin
		if ((slv'length mod 128) /= 0) then	report "to_slvv_128: width mismatch - slv'length is no multiple of 128 (slv'length=" & INTEGER'image(slv'length) & ")" severity FAILURE;	end if;

		for i in Result'range loop
			Result(i)	:= slv((i * 128) + 127 downto (i * 128));
		end loop;
		return Result;
	end function;

	-- create vector-vector from vector (256 bit)
	function to_slvv_256(slv : std_logic_vector) return T_SLVV_256 is
		variable Result		: T_SLVV_256((slv'length / 256) - 1 downto 0);
	begin
		if ((slv'length mod 256) /= 0) then	report "to_slvv_256: width mismatch - slv'length is no multiple of 256 (slv'length=" & INTEGER'image(slv'length) & ")" severity FAILURE;	end if;

		for i in Result'range loop
			Result(i)	:= slv((i * 256) + 255 downto (i * 256));
		end loop;
		return Result;
	end function;

	-- create vector-vector from vector (512 bit)
	function to_slvv_512(slv : std_logic_vector) return T_SLVV_512 is
		variable Result		: T_SLVV_512((slv'length / 512) - 1 downto 0);
	begin
		if ((slv'length mod 512) /= 0) then	report "to_slvv_512: width mismatch - slv'length is no multiple of 512 (slv'length=" & INTEGER'image(slv'length) & ")" severity FAILURE;	end if;

		for i in Result'range loop
			Result(i)	:= slv((i * 512) + 511 downto (i * 512));
		end loop;
		return Result;
	end function;

	-- Convert matrix to avector-vector: to_slvv_*
	-- ==========================================================================
	-- create vector-vector from matrix (4 bit)
	function to_slvv_4(slm : T_SLM) return T_SLVV_4 is
		variable Result		: T_SLVV_4(slm'range(1));
	begin
		if (slm'length(2) /= 4) then	report "to_slvv_4: type mismatch - slm'length(2)=" & integer'image(slm'length(2)) severity FAILURE;	end if;

		for i in slm'range(1) loop
			Result(i)	:= get_row(slm, i);
		end loop;
		return Result;
	end function;

	-- create vector-vector from matrix (8 bit)
	function to_slvv_8(slm : T_SLM) return T_SLVV_8 is
		variable Result		: T_SLVV_8(slm'range(1));
	begin
		if (slm'length(2) /= 8) then	report "to_slvv_8: type mismatch - slm'length(2)=" & integer'image(slm'length(2)) severity FAILURE;	end if;

		for i in slm'range(1) loop
			Result(i)	:= get_row(slm, i);
		end loop;
		return Result;
	end function;

	-- create vector-vector from matrix (12 bit)
	function to_slvv_12(slm : T_SLM) return T_SLVV_12 is
		variable Result		: T_SLVV_12(slm'range(1));
	begin
		if (slm'length(2) /= 12) then	report "to_slvv_12: type mismatch - slm'length(2)=" & integer'image(slm'length(2)) severity FAILURE;	end if;

		for i in slm'range(1) loop
			Result(i)	:= get_row(slm, i);
		end loop;
		return Result;
	end function;

	-- create vector-vector from matrix (16 bit)
	function to_slvv_16(slm : T_SLM) return T_SLVV_16 is
		variable Result		: T_SLVV_16(slm'range(1));
	begin
		if (slm'length(2) /= 16) then	report "to_slvv_16: type mismatch - slm'length(2)=" & integer'image(slm'length(2)) severity FAILURE;	end if;

		for i in slm'range(1) loop
			Result(i)	:= get_row(slm, i);
		end loop;
		return Result;
	end function;

	-- create vector-vector from matrix (32 bit)
	function to_slvv_32(slm : T_SLM) return T_SLVV_32 is
		variable Result		: T_SLVV_32(slm'range(1));
	begin
		if (slm'length(2) /= 32) then	report "to_slvv_32: type mismatch - slm'length(2)=" & integer'image(slm'length(2)) severity FAILURE;	end if;

		for i in slm'range(1) loop
			Result(i)	:= get_row(slm, i);
		end loop;
		return Result;
	end function;

	-- create vector-vector from matrix (64 bit)
	function to_slvv_64(slm : T_SLM) return T_SLVV_64 is
		variable Result		: T_SLVV_64(slm'range(1));
	begin
		if (slm'length(2) /= 64) then	report "to_slvv_64: type mismatch - slm'length(2)=" & integer'image(slm'length(2)) severity FAILURE;	end if;

		for i in slm'range(1) loop
			Result(i)	:= get_row(slm, i);
		end loop;
		return Result;
	end function;

	-- create vector-vector from matrix (128 bit)
	function to_slvv_128(slm : T_SLM) return T_SLVV_128 is
		variable Result		: T_SLVV_128(slm'range(1));
	begin
		if (slm'length(2) /= 128) then	report "to_slvv_128: type mismatch - slm'length(2)=" & integer'image(slm'length(2)) severity FAILURE;	end if;

		for i in slm'range(1) loop
			Result(i)	:= get_row(slm, i);
		end loop;
		return Result;
	end function;

	-- create vector-vector from matrix (256 bit)
	function to_slvv_256(slm : T_SLM) return T_SLVV_256 is
		variable Result		: T_SLVV_256(slm'range);
	begin
		if (slm'length(2) /= 256) then	report "to_slvv_256: type mismatch - slm'length(2)=" & integer'image(slm'length(2)) severity FAILURE;	end if;

		for i in slm'range loop
			Result(i)	:= get_row(slm, i);
		end loop;
		return Result;
	end function;

	-- create vector-vector from matrix (512 bit)
	function to_slvv_512(slm : T_SLM) return T_SLVV_512 is
		variable Result		: T_SLVV_512(slm'range(1));
	begin
		if (slm'length(2) /= 512) then	report "to_slvv_512: type mismatch - slm'length(2)=" & integer'image(slm'length(2)) severity FAILURE;	end if;

		for i in slm'range(1) loop
			Result(i)	:= get_row(slm, i);
		end loop;
		return Result;
	end function;

	-- Convert vector-vector to matrix: to_slm
	-- ==========================================================================
	-- create matrix from vector
	function to_slm(slv : std_logic_vector; ROWS : positive; COLS : positive) return T_SLM is
		variable slm		: T_SLM(ROWS - 1 downto 0, COLS - 1 downto 0);
	begin
		for i in 0 to ROWS - 1 loop
			for j in 0 to COLS - 1 loop
				slm(i, j)	:= slv((i * COLS) + j);
			end loop;
		end loop;
		return slm;
	end function;

	-- create matrix from vector-vector
	function to_slm(slvv : T_SLVV_4) return T_SLM is
		variable slm		: T_SLM(slvv'range, 3 downto 0);
	begin
		for i in slvv'range loop
			for j in T_SLV_4'range loop
				slm(i, j)		:= slvv(i)(j);
			end loop;
		end loop;
		return slm;
	end function;

	function to_slm(slvv : T_SLVV_8) return T_SLM is
--		variable test		: STD_LOGIC_VECTOR(T_SLV_8'range);
--		variable slm		: T_SLM(slvv'range, test'range);				-- BUG: iSIM 14.5 cascaded 'range accesses let iSIM break down
--		variable slm		: T_SLM(slvv'range, T_SLV_8'range);			-- BUG: iSIM 14.5 allocates 9 bits in dimension 2
		variable slm		: T_SLM(slvv'range, 7 downto 0);					-- WORKAROUND: use constant range
	begin
--		report "slvv:    slvv.length=" & INTEGER'image(slvv'length) &			"  slm.dim0.length=" & INTEGER'image(slm'length(1)) & "  slm.dim1.length=" & INTEGER'image(slm'length(2)) severity NOTE;
--		report "T_SLV_8:     .length=" & INTEGER'image(T_SLV_8'length) &	"  .high=" & INTEGER'image(T_SLV_8'high) &	"  .low=" & INTEGER'image(T_SLV_8'low)	severity NOTE;
--		report "test:    test.length=" & INTEGER'image(test'length) &			"  .high=" & INTEGER'image(test'high) &			"  .low=" & INTEGER'image(test'low)			severity NOTE;
		for i in slvv'range loop
			for j in T_SLV_8'range loop
				slm(i, j)		:= slvv(i)(j);
			end loop;
		end loop;
		return slm;
	end function;

	function to_slm(slvv : T_SLVV_12) return T_SLM is
		variable slm		: T_SLM(slvv'range, 11 downto 0);
	begin
		for i in slvv'range loop
			for j in T_SLV_12'range loop
				slm(i, j)		:= slvv(i)(j);
			end loop;
		end loop;
		return slm;
	end function;

	function to_slm(slvv : T_SLVV_16) return T_SLM is
		variable slm		: T_SLM(slvv'range, 15 downto 0);
	begin
		for i in slvv'range loop
			for j in T_SLV_16'range loop
				slm(i, j)		:= slvv(i)(j);
			end loop;
		end loop;
		return slm;
	end function;

	function to_slm(slvv : T_SLVV_32) return T_SLM is
		variable slm		: T_SLM(slvv'range, 31 downto 0);
	begin
		for i in slvv'range loop
			for j in T_SLV_32'range loop
				slm(i, j)		:= slvv(i)(j);
			end loop;
		end loop;
		return slm;
	end function;

	function to_slm(slvv : T_SLVV_48) return T_SLM is
		variable slm		: T_SLM(slvv'range, 47 downto 0);
	begin
		for i in slvv'range loop
			for j in T_SLV_48'range loop
				slm(i, j)		:= slvv(i)(j);
			end loop;
		end loop;
		return slm;
	end function;

	function to_slm(slvv : T_SLVV_64) return T_SLM is
		variable slm		: T_SLM(slvv'range, 63 downto 0);
	begin
		for i in slvv'range loop
			for j in T_SLV_64'range loop
				slm(i, j)		:= slvv(i)(j);
			end loop;
		end loop;
		return slm;
	end function;

	function to_slm(slvv : T_SLVV_128) return T_SLM is
		variable slm		: T_SLM(slvv'range, 127 downto 0);
	begin
		for i in slvv'range loop
			for j in T_SLV_128'range loop
				slm(i, j)		:= slvv(i)(j);
			end loop;
		end loop;
		return slm;
	end function;

	function to_slm(slvv : T_SLVV_256) return T_SLM is
		variable slm		: T_SLM(slvv'range, 255 downto 0);
	begin
		for i in slvv'range loop
			for j in T_SLV_256'range loop
				slm(i, j)		:= slvv(i)(j);
			end loop;
		end loop;
		return slm;
	end function;

	function to_slm(slvv : T_SLVV_512) return T_SLM is
		variable slm		: T_SLM(slvv'range, 511 downto 0);
	begin
		for i in slvv'range loop
			for j in T_SLV_512'range loop
				slm(i, j)		:= slvv(i)(j);
			end loop;
		end loop;
		return slm;
	end function;

	-- Change vector direction
	-- ==========================================================================
	function dir(slvv : T_SLVV_8) return T_SLVV_8 is
		variable Result : T_SLVV_8(slvv'reverse_range);
	begin
		Result := slvv;
		return Result;
	end function;

	-- Reverse vector elements
	function rev(slvv : T_SLVV_4) return T_SLVV_4 is
		variable Result : T_SLVV_4(slvv'range);
	begin
		for i in slvv'low to slvv'high loop
			Result(slvv'high - i) := slvv(i);
		end loop;
		return Result;
	end function;

	function rev(slvv : T_SLVV_8) return T_SLVV_8 is
		variable Result : T_SLVV_8(slvv'range);
	begin
		for i in slvv'low to slvv'high loop
			Result(slvv'high - i) := slvv(i);
		end loop;
		return Result;
	end function;

	function rev(slvv : T_SLVV_12) return T_SLVV_12 is
		variable Result : T_SLVV_12(slvv'range);
	begin
		for i in slvv'low to slvv'high loop
			Result(slvv'high - i) := slvv(i);
		end loop;
		return Result;
	end function;

	function rev(slvv : T_SLVV_16) return T_SLVV_16 is
		variable Result : T_SLVV_16(slvv'range);
	begin
		for i in slvv'low to slvv'high loop
			Result(slvv'high - i) := slvv(i);
		end loop;
		return Result;
	end function;

	function rev(slvv : T_SLVV_32) return T_SLVV_32 is
		variable Result : T_SLVV_32(slvv'range);
	begin
		for i in slvv'low to slvv'high loop
			Result(slvv'high - i) := slvv(i);
		end loop;
		return Result;
	end function;

	function rev(slvv : T_SLVV_64) return T_SLVV_64 is
		variable Result : T_SLVV_64(slvv'range);
	begin
		for i in slvv'low to slvv'high loop
			Result(slvv'high - i) := slvv(i);
		end loop;
		return Result;
	end function;

	function rev(slvv : T_SLVV_128) return T_SLVV_128 is
		variable Result : T_SLVV_128(slvv'range);
	begin
		for i in slvv'low to slvv'high loop
			Result(slvv'high - i) := slvv(i);
		end loop;
		return Result;
	end function;

	function rev(slvv : T_SLVV_256) return T_SLVV_256 is
		variable Result : T_SLVV_256(slvv'range);
	begin
		for i in slvv'low to slvv'high loop
			Result(slvv'high - i) := slvv(i);
		end loop;
		return Result;
	end function;

	function rev(slvv : T_SLVV_512) return T_SLVV_512 is
		variable Result : T_SLVV_512(slvv'range);
	begin
		for i in slvv'low to slvv'high loop
			Result(slvv'high - i) := slvv(i);
		end loop;
		return Result;
	end function;

	-- Resize functions
	-- ==========================================================================
	-- Resizes the vector to the specified length. Input vectors larger than the specified size are truncated from the left side. Smaller input
	-- vectors are extended on the left by the provided fill value (default: '0'). Use the resize functions of the numeric_std package for
	-- value-preserving resizes of the signed and unsigned data types.
	function resize(slm : T_SLM; size : positive) return T_SLM is
		variable Result		: T_SLM(size - 1 downto 0, slm'high(2) downto slm'low(2))		:= (others => (others => '0'));					-- WORKAROUND: Xilinx iSIM work-around, because 'range(2) evaluates to 'range(1); see work-around notes at T_SLM type declaration
	begin
		for i in slm'range(1) loop
			for j in slm'high(2) downto slm'low(2) loop					-- WORKAROUND: Xilinx iSIM work-around, because 'range(2) evaluates to 'range(1); see work-around notes at T_SLM type declaration
				Result(i, j)	:= slm(i, j);
			end loop;
		end loop;
		return Result;
	end function;

	function to_string(slvv : T_SLVV_8; sep : character := ':') return string is
		constant hex_len			: positive								:= ite((sep = C_POC_NUL), (slvv'length * 2), (slvv'length * 3) - 1);
		variable Result				: string(1 to hex_len)		:= (others => sep);
		variable pos					: positive								:= 1;
	begin
		for i in slvv'range loop
			Result(pos to pos + 1)	:= to_string(slvv(i), 'h');
			pos											:= pos + ite((sep = C_POC_NUL), 2, 3);
		end loop;
		return Result;
	end function;

	function to_string_bin(slm : T_SLM; groups : positive := 4; format : character := 'h') return string is
		variable PerLineOverheader	: positive	:= div_ceil(slm'length(2), groups);
		variable Result							: string(1 to (slm'length(1) * (slm'length(2) + PerLineOverheader)) + 10);
		variable Writer							: positive;
		variable GroupCounter				: natural;
	begin
		Result				:= (others => C_POC_NUL);
		Result(1)			:= LF;
		Writer				:= 2;
		GroupCounter	:= 0;
		for i in slm'low(1) to slm'high(1) loop
			for j in slm'high(2) downto slm'low(2) loop					-- WORKAROUND: Xilinx iSIM work-around, because 'range(2) evaluates to 'range(1); see work-around notes at T_SLM type declaration
				Result(Writer)		:= to_char(slm(i, j));
				Writer						:= Writer + 1;
				GroupCounter			:= GroupCounter + 1;
				if GroupCounter = groups then
					Result(Writer)	:= ' ';
					Writer					:= Writer + 1;
					GroupCounter		:= 0;
				end if;
			end loop;
			Result(Writer - 1)	:= LF;
			GroupCounter				:= 0;
		end loop;
		return str_trim(Result);
	end function;

	function to_string(slm : T_SLM; groups : positive := 4; format : character := 'b') return string is
	begin
		if (format = 'b') then
			return to_string_bin(slm, groups);
		else
			return "Format not supported.";
		end if;
	end function;
end package body;