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_behavioral of barrel16 is
subtype DATAWORD is STD_LOGIC_VECTOR(15 downto 0);

function Vrol (D: DATAWORD; S: UNSIGNED) 
     return DATAWORD is
  variable N: INTEGER;
  variable TMPD: DATAWORD;
  begin 
    N := CONV_INTEGER(S); TMPD := D;
    for i in 1 to N loop
      TMPD := TMPD(14 downto 0) & TMPD(15);
    end loop;
    return TMPD;
  end Vrol;

function Vror (D: DATAWORD; S: UNSIGNED) 
     return DATAWORD is
  variable N: INTEGER;
  variable TMPD: DATAWORD;
  begin 
    N := CONV_INTEGER(S); TMPD := D;
    for i in 1 to N loop
      TMPD := TMPD(0) & TMPD(15 downto 1);
    end loop;
    return TMPD;
  end Vror;

function Vsll (D: DATAWORD; S: UNSIGNED) 
     return DATAWORD is
  variable N: INTEGER;
  variable TMPD: DATAWORD;
  begin 
    N := CONV_INTEGER(S); TMPD := D;
    for i in 1 to N loop
      TMPD := TMPD(14 downto 0) & '0';
    end loop;
    return TMPD;
  end Vsll;

function Vsrl (D: DATAWORD; S: UNSIGNED) 
     return DATAWORD is
  variable N: INTEGER;
  variable TMPD: DATAWORD;
  begin 
    N := CONV_INTEGER(S); TMPD := D;
    for i in 1 to N loop
      TMPD := '0' & TMPD(15 downto 1);
    end loop;
    return TMPD;
  end Vsrl;

function Vsla (D: DATAWORD; S: UNSIGNED) 
     return DATAWORD is
  variable N: INTEGER;
  variable TMPD: DATAWORD;
  begin 
    N := CONV_INTEGER(S); TMPD := D;
    for i in 1 to N loop
      TMPD := TMPD(14 downto 0) & TMPD(0);
    end loop;
    return TMPD;
  end Vsla;

function Vsra (D: DATAWORD; S: UNSIGNED) 
     return DATAWORD is
  variable N: INTEGER;
  variable TMPD: DATAWORD;
  begin 
    N := CONV_INTEGER(S); TMPD := D;
    for i in 1 to N loop
      TMPD := TMPD(15) & TMPD(15 downto 1);
    end loop;
    return TMPD;
  end Vsra;

begin
process(DIN, S, C)
  begin
    case C is
      when Lrotate  => DOUT <= Vrol(DIN,S);
      when Rrotate  => DOUT <= Vror(DIN,S);
      when Llogical => DOUT <= Vsll(DIN,S);
      when Rlogical => DOUT <= Vsrl(DIN,S);
      when Larith   => DOUT <= Vsla(DIN,S);
      when Rarith   => DOUT <= Vsra(DIN,S);    
      when others   => null;
    end case;
  end process;
end barrel16_behavioral;

