-- 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:					Universal Barrel-Shifter
--
-- Description:
-- 
-- This Barrel-Shifter supports:
--
-- * shifting and rotating
-- * right and left operations
-- * arithmetic and logic mode (only valid for shift operations)
--
-- This is equivalent to the CPU instructions: SLL, SLA, SRL, SRA, RL, 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]arith_shifter_barrel is
	generic (
		BITS				: positive		:= 32
	);
  port (
		Input						: in	std_logic_vector(BITS - 1 downto 0);
		ShiftAmount			: in	std_logic_vector(log2ceilnz(BITS) - 1 downto 0);
		ShiftRotate			: in	std_logic;
		LeftRight				: in	std_logic;
		ArithmeticLogic	: in	std_logic;
		Output					: out	std_logic_vector(BITS - 1 downto 0)
	);
end entity;


architecture [docs]rtl of arith_shifter_barrel is
	constant STAGES		: positive		:= log2ceilnz(BITS);

	subtype	T_INTERMEDIATE_RESULT is std_logic_vector(BITS - 1 downto 0);
	type		T_INTERMEDIATE_VECTOR is array (natural range <>) of T_INTERMEDIATE_RESULT;

	signal IntermediateResults	: T_INTERMEDIATE_VECTOR(STAGES downto 0);

begin
	IntermediateResults(0)	<= Input;
	Output									<= IntermediateResults(STAGES);

	genStage : for i in 0 to STAGES - 1 generate
		process(IntermediateResults(i), ShiftRotate, LeftRight, ArithmeticLogic, ShiftAmount)
		begin
			if (ShiftAmount(i) = '0') then
				IntermediateResults(i + 1) <= IntermediateResults(i);																																														-- NOP
			else
				if (ShiftRotate = '0') then
					if (LeftRight = '0') then
						IntermediateResults(i + 1) <= IntermediateResults(i)((BITS - 2**i - 1) downto 0) & ((2**i - 1) downto 0 => '0');														-- SLA, SLL
					else
						if (ArithmeticLogic = '0') then
							IntermediateResults(i + 1) <= ((2**i - 1) downto 0 => IntermediateResults(i)(BITS - 1)) & IntermediateResults(i)(BITS - 1 downto 2**i);		-- SRA
						else
							IntermediateResults(i + 1) <= ((2**i - 1) downto 0 => '0') & IntermediateResults(i)(BITS - 1 downto 2**i);																-- SRL
						end if;
					end if;
				else
					if (LeftRight = '0') then
						IntermediateResults(i + 1) <= IntermediateResults(i)((BITS - 2**i - 1) downto 0) & IntermediateResults(i)(BITS - 1 downto (BITS - 2**i));		-- RL
					else
						IntermediateResults(i + 1) <= IntermediateResults(i)((2**i - 1) downto 0) & IntermediateResults(i)(BITS - 1 downto 2**i);						-- RR
					end if;
				end if;
			end if;
		end process;
	end generate;
end;