-- 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:				 	optimized down-counter to control timings for low speed signals
--
-- Description:
-- 
-- This down-counter can be configured with a ``TIMING_TABLE`` (a ROM), from which
-- the initial counter value is loaded. The table index can be selected by
-- ``Slot``. ``Timeout`` is a registered output. Up to 16 values fit into one ROM
-- consisting of ``log2ceilnz(imax(TIMING_TABLE)) + 1`` 6-input LUTs.
--
-- License:
-- =============================================================================
-- Copyright 2007-2015 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.my_config.all;
use			PoC.utils.all;


entity [docs]io_TimingCounter is
  generic (
	  TIMING_TABLE	: T_NATVEC																					-- timing table
	);
  port (
	  Clock					: in	std_logic;																		-- clock
		Enable				: in	std_logic;																		-- enable counter
		Load					: in	std_logic;																		-- load Timing Value from TIMING_TABLE selected by slot
		Slot					: in	natural range 0 to (TIMING_TABLE'length - 1);	--
		Timeout				: out std_logic																			-- timing reached
	);
end entity;


architecture [docs]rtl of io_TimingCounter is
	function [docs]transform(vec : T_NATVEC) return T_INTVEC is
    variable Result : T_INTVEC(vec'range);
  begin
		assert (not MY_VERBOSE) report "TIMING_TABLE (transformed):" severity NOTE;
    for i in vec'range loop
			Result(i)	 := vec(i) - 1;
			assert (not MY_VERBOSE) report "  " & integer'image(i) & " - " & INTEGER'image(Result(i)) severity NOTE;
		end loop;
		return Result;
  end;

	constant TIMING_TABLE2	: T_INTVEC		:= transform(TIMING_TABLE);
	constant TIMING_MAX			: natural			:= imax(TIMING_TABLE2);
	constant COUNTER_BITS		: natural			:= log2ceilnz(TIMING_MAX + 1);

	signal Counter_s				: signed(COUNTER_BITS downto 0)		:= to_signed(TIMING_TABLE2(0), COUNTER_BITS + 1);

begin
	process(Clock)
	begin
		if rising_edge(Clock) then
			if (Load = '1') then
				Counter_s		<= to_signed(TIMING_TABLE2(Slot), Counter_s'length);
			elsif ((Enable = '1') and (Counter_s(Counter_s'high) = '0')) then
				Counter_s	<= Counter_s - 1;
			end if;
		end if;
	end process;

	Timeout <= Counter_s(Counter_s'high);
end;