-- 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:					Patrick Lehmann
--
-- Entity:					Counts the most significant data words
--
-- Description:
-- 
-- .. TODO:: No documentation available.
--
-- 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.vectors.all;


entity [docs]stat_Maximum is
	generic (
		DEPTH					: positive		:= 8;
		DATA_BITS			: positive		:= 16;
		COUNTER_BITS	: positive		:= 16
	);
	port (
		Clock					: in	std_logic;
		Reset					: in	std_logic;

		Enable				: in	std_logic;
		DataIn				: in	std_logic_vector(DATA_BITS - 1 downto 0);

		Valids				: out	std_logic_vector(DEPTH - 1 downto 0);
		Maximums			: out	T_SLM(DEPTH - 1 downto 0, DATA_BITS - 1 downto 0);
		Counts				: out	T_SLM(DEPTH - 1 downto 0, COUNTER_BITS - 1 downto 0)
	);
end entity;


architecture [docs]rtl of stat_Maximum is
	type T_TAG_MEMORY				is array(natural range <>) of unsigned(DATA_BITS - 1 downto 0);
	type T_COUNTER_MEMORY		is array(natural range <>) of unsigned(COUNTER_BITS - 1 downto 0);

	-- create matrix from vector-vector
	function [docs]to_slm(usv : T_TAG_MEMORY) return T_SLM is
		variable slm		: T_SLM(usv'range, DATA_BITS - 1 downto 0);
	begin
		for i in usv'range loop
			for j in DATA_BITS - 1 downto 0 loop
				slm(i, j)		:= usv(i)(j);
			end loop;
		end loop;
		return slm;
	end function;

	function [docs]to_slm(usv : T_COUNTER_MEMORY) return T_SLM is
		variable slm		: T_SLM(usv'range, COUNTER_BITS - 1 downto 0);
	begin
		for i in usv'range loop
			for j in COUNTER_BITS - 1 downto 0 loop
				slm(i, j)		:= usv(i)(j);
			end loop;
		end loop;
		return slm;
	end function;

	signal DataIn_us				: unsigned(DataIn'range);

	signal TagHit						: std_logic_vector(DEPTH - 1 downto 0);
	signal MaximumHit				: std_logic_vector(DEPTH - 1 downto 0);
	signal TagMemory				: T_TAG_MEMORY(DEPTH - 1 downto 0)			:= (others => (others => '0'));
	signal CounterMemory		: T_COUNTER_MEMORY(DEPTH - 1 downto 0)	:= (others => (others => '0'));
	signal MaximumIndex			: std_logic_vector(DEPTH - 1 downto 0)	:= '1' & (DEPTH - 2 downto 0 => '0');	--((DEPTH - 1) => '1', others => '0'); -- WORKAROUND: GHDL says  not static choice exclude others choice;  non-locally static choice for an aggregate is allowed only if only choice
	signal ValidMemory			: std_logic_vector(DEPTH - 1 downto 0)	:= (others => '0');

begin
	DataIn_us		<= unsigned(DataIn);

	genTagHit : for i in 0 to DEPTH - 1 generate
		TagHit(i)			<= to_sl(TagMemory(i) = DataIn_us);
		MaximumHit(i)	<= to_sl(TagMemory(i) < DataIn_us);
	end generate;

	process(Clock)
		variable TagHit_idx 			: natural;
	begin
		if rising_edge(Clock) then
			if (Reset = '1') then
				ValidMemory										<= (others => '0');
			elsif ((slv_nand(ValidMemory) and slv_nor(TagHit) and Enable) = '1') then
				for i in DEPTH - 1 downto 1 loop
					if (MaximumHit(i) = '1') then
						TagMemory(i)			<= TagMemory(i - 1);
						ValidMemory(i)		<= ValidMemory(i - 1);
						CounterMemory(i)	<= CounterMemory(i - 1);
					end if;
				end loop;
				for i in 0 to DEPTH - 1 loop
					if (MaximumHit(i) = '1') then
						TagMemory(i)			<= DataIn_us;
						ValidMemory(i)		<= '1';
						CounterMemory(i)	<= to_unsigned(1, COUNTER_BITS);
						exit;
					end if;
				end loop;
			elsif ((slv_or(MaximumHit) and slv_nor(TagHit) and Enable) = '1') then
				for i in DEPTH - 1 downto 1 loop
					if (MaximumHit(i) = '1') then
						TagMemory(i)			<= TagMemory(i - 1);
						ValidMemory(i)		<= ValidMemory(i - 1);
						CounterMemory(i)	<= CounterMemory(i - 1);
					end if;
				end loop;
				for i in 0 to DEPTH - 1 loop
					if (MaximumHit(i) = '1') then
						TagMemory(i)			<= DataIn_us;
						ValidMemory(i)		<= '1';
						CounterMemory(i)	<= to_unsigned(1, COUNTER_BITS);
						exit;
					end if;
				end loop;
			elsif ((slv_or(TagHit) and Enable)= '1') then
				TagHit_idx								:= to_index(onehot2bin(TagHit, 0));
				CounterMemory(TagHit_idx)	<= CounterMemory(TagHit_idx) + 1;
			end if;
		end if;
	end process;

	Valids		<= ValidMemory;
	Maximums	<= to_slm(TagMemory);
	Counts		<= to_slm(CounterMemory);

end architecture;