OpenCores
URL https://opencores.org/ocsvn/arm4u/arm4u/trunk

Subversion Repositories arm4u

[/] [arm4u/] [trunk/] [hdl/] [barrelshift.vhd] - Rev 2

Compare with Previous | Blame | View Log

-- This file is part of ARM4U CPU
-- 
-- This is a creation of the Laboratory of Processor Architecture
-- of Ecole Polytechnique Fédérale de Lausanne ( http://lap.epfl.ch )
--
-- barrelshift.vhd  --  Describes the barrel shifter inside the execute pipeline stage
--
-- Written By -  Jonathan Masur and Xavier Jimenez (2013)
--
-- This program is free software; you can redistribute it and/or modify it
-- under the terms of the GNU General Public License as published by the
-- Free Software Foundation; either version 2, or (at your option) any
-- later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.
--
-- In other words, you are welcome to use, share and improve this program.
-- You are forbidden to forbid anyone else to use, share and improve
-- what you give them.   Help stamp out software-hoarding!
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.arm_types.all;
 
entity barrelshift is
	port(
		c : in std_logic;
		exe_barrelshift_operand : in std_logic;
		exe_barrelshift_type : in std_logic_vector(1 downto 0);
		exe_literal_shift_amnt : in std_logic_vector(4 downto 0);
		exe_literal_data : in std_logic_vector(23 downto 0);
		exe_opb_is_literal : in std_logic;
		op_b_data : in unsigned(31 downto 0);
		op_c_data : in unsigned(31 downto 0);
		barrelshift_c : out std_logic;
		barrelshift_out : out unsigned(31 downto 0)
	);
end;
 
-- Note : This architecture synthetizes poorly
architecture rtl of barrelshift is
begin
	-- barrel shifter
	barrelshift : process(exe_barrelshift_operand, exe_barrelshift_type, op_b_data, op_c_data, exe_opb_is_literal, exe_literal_shift_amnt, exe_literal_data, c) is
	variable shift_positions : integer range 0 to 31;
	variable shift_in : unsigned(31 downto 0);
	begin
			-- shift by register (opc)
		if exe_barrelshift_operand = '1'
		then
			shift_positions := to_integer(op_c_data(4 downto 0));
		else
			-- shift by literal value
			shift_positions := to_integer(unsigned(exe_literal_shift_amnt));
		end if;
 
		if exe_opb_is_literal = '1'
		then
			-- sign extend literal value
			shift_in := (31 downto 24 => exe_literal_data(23)) & unsigned(exe_literal_data);
		else
			shift_in := op_b_data;
		end if;
 
		case exe_barrelshift_type is	
		-- LSR
		when "01" =>
			-- shift by register > 32 -> overflows, all bits are out
			if exe_barrelshift_operand = '1' and op_c_data(7 downto 0) > x"20"
			then
				barrelshift_out <= (others => '0');
				barrelshift_c <= '0';
 
			-- shift by register or literal, 32 positions
			elsif (exe_barrelshift_operand = '1' and op_c_data(7 downto 0) = x"20")
			   or (exe_barrelshift_operand = '0' and exe_literal_shift_amnt = "00000")
			then
				barrelshift_out <= (others => '0');
				barrelshift_c <= shift_in(31);
 
 
			-- shift by register = 0, opb passes through and C is unaffected
			elsif exe_barrelshift_operand = '1' and op_c_data(7 downto 0) = x"00"
			then
				barrelshift_out <= shift_in;
				barrelshift_c <= c;
 
			-- shift by literal or register, range 1..31
			else
				barrelshift_out <= shift_in srl shift_positions;
				barrelshift_c <= shift_in(shift_positions - 1);
			end if;
 
		-- ASR
		when "10" =>
			-- shift by register or literal >= 32 -> overflows, all bits are the sign bit
			-- shift by register or literal, 32 positions
			if (exe_barrelshift_operand = '1' and op_c_data(7 downto 0) >= x"20")
			or (exe_barrelshift_operand = '0' and exe_literal_shift_amnt = "00000")
			then
				barrelshift_out <= (others => shift_in(31));
				barrelshift_c <= shift_in(31);
 
			-- shift by register = 0, opb passes through and C is unaffected
			elsif exe_barrelshift_operand = '1' and op_c_data(7 downto 0) = x"00"
			then
				barrelshift_out <= shift_in;
				barrelshift_c <= c;
 
			-- shift by literal or register, range 1..31
			else			
				barrelshift_out <= unsigned(shift_right(signed(shift_in), shift_positions));
				barrelshift_c <= shift_in(shift_positions - 1);
			end if;
 
		-- ROR / RRX
		when "11" =>
			-- RRX - 33 bit rotation with carry
			if exe_barrelshift_operand = '0' and exe_literal_shift_amnt = "00000"
			then
				barrelshift_out <= c & shift_in(31 downto 1);
				barrelshift_c <= shift_in(0);
 
			-- ROR by register = 0, opb passes through and C is unaffected
			elsif exe_barrelshift_operand = '1' and op_c_data(7 downto 0) = x"00"
			then
				barrelshift_out <= shift_in;
				barrelshift_c <= c;
 
			-- ROR by register = 32, 64, etc.... opb passes through but C is affected
			elsif exe_barrelshift_operand = '1' and op_c_data(4 downto 0) = "00000"
			then
				barrelshift_out <= shift_in;
				barrelshift_c <= shift_in(31);
 
			-- ROR by literal or register, range 1..31 (if ROR by register, 33 => 1, 34 => 2, etc....)
			else
				barrelshift_out <= shift_in ror shift_positions;
				barrelshift_c <= shift_in(shift_positions - 1);
			end if;
 
		-- LSL
		when others =>	-- "00"
			-- shift by register > 32 -> overflows, all bits are out
			if exe_barrelshift_operand = '1' and op_c_data(7 downto 0) > x"20"
			then
				barrelshift_out <= (others => '0');
				barrelshift_c <= '0';
 
			-- shift by register = 32 positions
			elsif exe_barrelshift_operand = '1' and op_c_data(7 downto 0) = x"20"
			then
				barrelshift_out <= (others => '0');
				barrelshift_c <= shift_in(0);
 
			-- shift by register = 0 or literal = 0, opb passes through and C is unaffected
			elsif shift_positions = 0
			then
				barrelshift_out <= shift_in;
				barrelshift_c <= c;
 
			-- shift by literal or register, range 1..31
			else
				barrelshift_out <= shift_in sll shift_positions;
				barrelshift_c <= shift_in(32 - shift_positions);
			end if;
		end case;
	end process;
end;
 
-- optimized architecture expliciting all stages of the barrel shifter
-- (individual shifters by power of 2 bits in series)
-- synthetizes in something way better
architecture optimized of barrelshift is
	signal shift_in : unsigned(31 downto 0);
	signal shift_amnt : unsigned(4 downto 0);
	signal stage1_dout, stage2_dout, stage3_dout, stage4_dout, stage5_dout : unsigned(31 downto 0);
	signal stage1_cout, stage2_cout, stage3_cout, stage4_cout, stage5_cout : std_logic;
begin
	-- Barrelshifter made manually with 5 individual shift stages in series
 
	-- shift by 1 position
	stage1 : process(shift_in, c, shift_amnt, exe_barrelshift_type) is
	begin
		if shift_amnt(0) = '1'
		then	
			case exe_barrelshift_type is
			when "00" =>		-- LSL #1
				stage1_dout <= shift_in(30 downto 0) & '0';
				stage1_cout <= shift_in(31);
			when "01" =>		-- LSR #1
				stage1_dout <= '0' & shift_in(31 downto 1);
				stage1_cout <= shift_in(0);
			when "10" =>		-- ASR #1
				stage1_dout <= shift_in(31) & shift_in(31 downto 1);
				stage1_cout <= shift_in(0);
			when others =>		-- ROR #1
				stage1_dout <= shift_in(0) & shift_in(31 downto 1);
				stage1_cout <= shift_in(0);
			end case;
		else
			stage1_dout <= shift_in;
			stage1_cout <= c;
		end if;
	end process;
 
	-- shift by 2 positions
	stage2 : process(stage1_dout, stage1_cout, shift_amnt, exe_barrelshift_type) is
	begin
		if shift_amnt(1) = '1'
		then
			case exe_barrelshift_type is
			when "00" =>		-- LSL #2
				stage2_dout <= stage1_dout(29 downto 0) & "00";
				stage2_cout <= stage1_dout(30);
			when "01" =>		-- LSR #2
				stage2_dout <= "00" & stage1_dout(31 downto 2);
				stage2_cout <= stage1_dout(1);
			when "10" =>		-- ASR #2
				stage2_dout <= (1 downto 0 => stage1_dout(31)) & stage1_dout(31 downto 2);
				stage2_cout <= stage1_dout(1);
			when others =>		-- ROR #2
				stage2_dout <= stage1_dout(1 downto 0) & stage1_dout(31 downto 2);
				stage2_cout <= stage1_dout(1);
			end case;
		else
			stage2_dout <= stage1_dout;
			stage2_cout <= stage1_cout;
		end if;
	end process;
 
	-- shift by 4 positions
	stage3 : process(stage2_dout, stage2_cout, shift_amnt, exe_barrelshift_type) is
	begin
		if shift_amnt(2) = '1'
		then
			case exe_barrelshift_type is
			when "00" =>		-- LSL #4
				stage3_dout <= stage2_dout(27 downto 0) & "0000";
				stage3_cout <= stage2_dout(28);
			when "01" =>		-- LSR #4
				stage3_dout <= "0000" & stage2_dout(31 downto 4);
				stage3_cout <= stage2_dout(3);
			when "10" =>		-- ASR #4
				stage3_dout <= (3 downto 0 => stage2_dout(31)) & stage2_dout(31 downto 4);
				stage3_cout <= stage2_dout(3);
			when others =>		-- ROR #4
				stage3_dout <= stage2_dout(3 downto 0) & stage2_dout(31 downto 4);
				stage3_cout <= stage2_dout(3);
			end case;
		else
			stage3_dout <= stage2_dout;
			stage3_cout <= stage2_cout;
		end if;
	end process;
 
	-- shift by 8 positions
	stage4 : process(stage3_dout, stage3_cout, shift_amnt, exe_barrelshift_type) is
	begin
		if shift_amnt(3) = '1'
		then
			case exe_barrelshift_type is
			when "00" =>		-- LSL #8
				stage4_dout <= stage3_dout(23 downto 0) & (7 downto 0 => '0');
				stage4_cout <= stage3_dout(24);
			when "01" =>		-- LSR #8
				stage4_dout <= (7 downto 0 => '0') & stage3_dout(31 downto 8);
				stage4_cout <= stage3_dout(7);
			when "10" =>		-- ASR #8
				stage4_dout <= (7 downto 0 => stage3_dout(31)) & stage3_dout(31 downto 8);
				stage4_cout <= stage3_dout(7);
			when others =>		-- ROR #8
				stage4_dout <= stage3_dout(7 downto 0) & stage3_dout(31 downto 8);
				stage4_cout <= stage3_dout(7);
			end case;
		else
			stage4_dout <= stage3_dout;
			stage4_cout <= stage3_cout;
		end if;
	end process;
 
	-- shift by 16 positions
	stage5 : process(stage4_dout, stage4_cout, shift_amnt, exe_barrelshift_type) is
	begin
		if shift_amnt(4) = '1'
		then
			case exe_barrelshift_type is
			when "00" =>		-- LSL #16
				stage5_dout <= stage4_dout(15 downto 0) & (15 downto 0 => '0');
				stage5_cout <= stage4_dout(15);
			when "01" =>		-- LSR #16
				stage5_dout <= (15 downto 0 => '0') & stage4_dout(31 downto 16);
				stage5_cout <= stage4_dout(15);
			when "10" =>		-- ASR #16
				stage5_dout <= (15 downto 0 => stage4_dout(31)) & stage4_dout(31 downto 16);
				stage5_cout <= stage4_dout(15);
			when others =>		-- ROR #16
				stage5_dout <= stage4_dout(15 downto 0) & stage4_dout(31 downto 16);
				stage5_cout <= stage4_dout(15);
			end case;
		else
			stage5_dout <= stage4_dout;
			stage5_cout <= stage4_cout;
		end if;
	end process;
 
	-- Barelshifter control logic
	barrelshift : process(exe_barrelshift_operand, exe_barrelshift_type, op_b_data, op_c_data, exe_opb_is_literal,
						  exe_literal_shift_amnt, exe_literal_data, c, shift_in, stage5_dout, stage5_cout) is
	begin
			-- shift by register (opc)
		if exe_barrelshift_operand = '1'
		then
			shift_amnt <= op_c_data(4 downto 0);
		else
			-- shift by literal value
			shift_amnt <= unsigned(exe_literal_shift_amnt);
		end if;
 
		if exe_opb_is_literal = '1'
		then
			-- sign extend literal value
			shift_in <= (31 downto 24 => exe_literal_data(23)) & unsigned(exe_literal_data);
		else
			shift_in <= op_b_data;
		end if;
 
		case exe_barrelshift_type is	
		-- LSL
		when "00" =>
			-- shift by register > 32 -> overflows, all bits are out
			if exe_barrelshift_operand = '1' and op_c_data(7 downto 0) > x"20"
			then
				barrelshift_out <= (others => '0');
				barrelshift_c <= '0';
 
			-- shift by register = 32 positions
			elsif exe_barrelshift_operand = '1' and op_c_data(7 downto 0) = x"20"
			then
				barrelshift_out <= (others => '0');
				barrelshift_c <= shift_in(0);
 
			-- shift by literal or register, range 0..31
			else
				barrelshift_out <= stage5_dout;
				barrelshift_c <= stage5_cout;
			end if;
 
		-- LSR
		when "01" =>
			-- shift by register > 32 -> overflows, all bits are out
			if exe_barrelshift_operand = '1' and op_c_data(7 downto 0) > x"20"
			then
				barrelshift_out <= (others => '0');
				barrelshift_c <= '0';
 
			-- shift by register or literal = 0, 32 positions
			elsif (exe_barrelshift_operand = '1' and op_c_data(7 downto 0) = x"20")
			   or (exe_barrelshift_operand = '0' and exe_literal_shift_amnt = "00000")
			then
				barrelshift_out <= (others => '0');
				barrelshift_c <= shift_in(31);
 
			-- shift by literal or register, range 0..31
			else
				barrelshift_out <= stage5_dout;
				barrelshift_c <= stage5_cout;
			end if;
 
		-- ASR
		when "10" =>
			-- shift by register >= 32 or literal = 0, 32 positions -> overflows, all bits are the sign bit
			if (exe_barrelshift_operand = '1' and op_c_data(7 downto 0) >= x"20")
			or (exe_barrelshift_operand = '0' and exe_literal_shift_amnt = "00000")
			then
				barrelshift_out <= (others => shift_in(31));
				barrelshift_c <= shift_in(31);
 
			-- shift by literal or register, range 0..31
			else			
				barrelshift_out <= stage5_dout;
				barrelshift_c <= stage5_cout;
			end if;
 
		-- ROR / RRX
		when others =>		-- "11"
			-- RRX - 33 bit rotation with carry
			if exe_barrelshift_operand = '0' and exe_literal_shift_amnt = "00000"
			then
				barrelshift_out <= c & op_b_data(31 downto 1);
				barrelshift_c <= shift_in(0);
 
			-- ROR by register = 32, 64, etc.... opb passes through but C is affected
			elsif exe_barrelshift_operand = '1' and op_c_data(4 downto 0) = "00000"
			then
				barrelshift_out <= stage5_dout;
				barrelshift_c <= shift_in(31);
 
			-- ROR by literal or register, range 0..31 (if ROR by register, 33 => 1, 34 => 2, etc....)
			else
				barrelshift_out <= stage5_dout;
				barrelshift_c <= stage5_cout;
			end if;
		end case;
	end process;
 
end;

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.