-- 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:				 	Generic arbiter
--
-- Description:
-- 
-- This module implements a generic arbiter. It currently supports the
-- following arbitration strategies:
--
-- * Round Robin (RR)
--
-- 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.utils.all;


entity [docs]bus_Arbiter is
	generic (
		STRATEGY									: string										:= "RR";			-- RR, LOT
		PORTS											: positive									:= 1;
		WEIGHTS										: T_INTVEC									:= (0 => 1);
		OUTPUT_REG								: boolean										:= TRUE
	);
	port (
		Clock											: in	std_logic;
		Reset											: in	std_logic;

		Arbitrate									: in	std_logic;
		Request_Vector						: in	std_logic_vector(PORTS - 1 downto 0);

		Arbitrated								: out	std_logic;
		Grant_Vector							: out	std_logic_vector(PORTS - 1 downto 0);
		Grant_Index								: out	std_logic_vector(log2ceilnz(PORTS) - 1 downto 0)
	);
end entity;


architecture [docs]rtl of bus_Arbiter is
	attribute KEEP										: boolean;
	attribute FSM_ENCODING						: string;

begin

	-- Assert STRATEGY for known strings
	-- ==========================================================================================================================================================
	assert ((STRATEGY = "RR") or (STRATEGY = "LOT"))
		report "Unknown arbiter strategy." severity FAILURE;

	-- Round Robin Arbiter
	-- ==========================================================================================================================================================
	genRR : if STRATEGY = "RR" generate
		signal RequestLeft								: unsigned(PORTS - 1 downto 0);
		signal SelectLeft									: unsigned(PORTS - 1 downto 0);
		signal SelectRight								: unsigned(PORTS - 1 downto 0);

		signal ChannelPointer_en					: std_logic;
		signal ChannelPointer							: std_logic_vector(PORTS - 1 downto 0);
		signal ChannelPointer_d						: std_logic_vector(PORTS - 1 downto 0)								:= to_slv(1, PORTS);
		signal ChannelPointer_nxt					: std_logic_vector(PORTS - 1 downto 0);

	begin

		ChannelPointer_en		<= Arbitrate;

		RequestLeft					<= (not ((unsigned(ChannelPointer_d) - 1) or unsigned(ChannelPointer_d))) and unsigned(Request_Vector);
		SelectLeft					<= (unsigned(not RequestLeft) + 1)		and RequestLeft;
		SelectRight					<= (unsigned(not Request_Vector) + 1)	and unsigned(Request_Vector);
		ChannelPointer_nxt	<= std_logic_vector(ite((RequestLeft = (RequestLeft'range => '0')), SelectRight, SelectLeft));

		-- generate ChannelPointer register and unregistered outputs
		genREG0 : if not OUTPUT_REG generate
			process(Clock)
			begin
				if rising_edge(Clock) then
					if (Reset = '1') then
						ChannelPointer_d		<= to_slv(1, PORTS);
					elsif (ChannelPointer_en = '1') then
						ChannelPointer_d		<= ChannelPointer_nxt;
					end if;
				end if;
			end process;

			Arbitrated				<= Arbitrate;
			Grant_Vector			<= ChannelPointer_nxt;
			Grant_Index				<= std_logic_vector(onehot2bin(ChannelPointer_nxt));
		end generate;

		-- generate ChannelPointer register and registered outputs
		genREG1 : if OUTPUT_REG generate
			signal ChannelPointer_bin_d				: std_logic_vector(log2ceilnz(PORTS) - 1 downto 0)		:= (others => '0');
		begin
			process(Clock)
			begin
				if rising_edge(Clock) then
					if (Reset = '1') then
						ChannelPointer_d			<= to_slv(1, PORTS);
						ChannelPointer_bin_d	<=  (others => '0');
					elsif (ChannelPointer_en = '1') then
						ChannelPointer_d			<= ChannelPointer_nxt;
						ChannelPointer_bin_d	<= std_logic_vector(onehot2bin(ChannelPointer_nxt));
					end if;
				end if;
			end process;

			Arbitrated				<= Arbitrate when rising_edge(Clock);
			Grant_Vector			<= ChannelPointer_d;
			Grant_Index				<= ChannelPointer_bin_d;
		end generate;
	end generate;

	-- Lottery Arbiter
	-- ==========================================================================================================================================================
--	genLOT : if (STRATEGY = "RR") generate
--	begin
--
--	end generate;
end architecture;