library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;

entity barrel16 is
    port (
        DIN: in STD_LOGIC_VECTOR (15 downto 0);  -- Data inputs
        S: in UNSIGNED (3 downto 0);             -- Shift amount, 0-15
        C: in STD_LOGIC_VECTOR (2 downto 0);     -- Mode control 
        DOUT: out STD_LOGIC_VECTOR (15 downto 0) -- Data bus output
    );
    constant Lrotate:  STD_LOGIC_VECTOR := "000";   -- Define the coding of
    constant Rrotate:  STD_LOGIC_VECTOR := "001";   -- the different shift modes
    constant Llogical: STD_LOGIC_VECTOR := "010";
    constant Rlogical: STD_LOGIC_VECTOR := "011";
    constant Larith:   STD_LOGIC_VECTOR := "100";
    constant Rarith:   STD_LOGIC_VECTOR := "101";
end barrel16;

architecture barrel16_struc of barrel16 is

component rolr16 port (
        DIN:  in STD_LOGIC_VECTOR(15 downto 0); -- Data inputs
        S:    in UNSIGNED(3 downto 0);          -- Shift amount, 0-15
        DIR:  in STD_LOGIC;                     -- Shift direction, 0=>L, 1=>R
        DOUT: out STD_LOGIC_VECTOR(15 downto 0) -- Data bus output
    );  end component;

component fixup port (
        DIN:  in STD_LOGIC_VECTOR(15 downto 0); -- Data inputs
        S:    in UNSIGNED(3 downto 0);          -- Shift amount, 0-15
        FEN:  in STD_LOGIC;                     -- Fixup enable
        FDAT: in STD_LOGIC;                     -- Fixup data
        DOUT: out STD_LOGIC_VECTOR(15 downto 0) -- Data bus output
    );  end component;

signal DIR_RIGHT, FIX_RIGHT, FIX_RIGHT_DAT, FIX_LEFT, FIX_LEFT_DAT: STD_LOGIC;
signal ROUT, FOUT, RFIXIN, RFIXOUT: STD_LOGIC_VECTOR(15 downto 0);
begin
  DIR_RIGHT <= '1' when C = Rrotate or C = Rlogical or C = Rarith else '0';
  FIX_RIGHT <= '1' when DIR_RIGHT='1' and (C = Rlogical or C = Rarith) else '0';
  FIX_RIGHT_DAT <= DIN(15) when C = Rarith else '0';
  FIX_LEFT <= '1' when DIR_RIGHT='0' and (C = Llogical or C = Larith) else '0';
  FIX_LEFT_DAT <= DIN(0) when C = Larith else '0';
  U1: rolr16 port map (DIN, S, DIR_RIGHT, ROUT);
  U2: fixup port map (ROUT, S, FIX_LEFT, FIX_LEFT_DAT, FOUT);
  U3: for i in 0 to 15 generate RFIXIN(i) <= FOUT(15-i); end generate;
  U4: fixup port map (RFIXIN, S, FIX_RIGHT, FIX_RIGHT_DAT, RFIXOUT);
  U5: for i in 0 to 15 generate DOUT(i) <= RFIXOUT(15-i); end generate;
end barrel16_struc;
