library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;

entity barrelse 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 barrelse;

architecture barrelse_behavioral of barrelse 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
with C select
  DOUT <= Vrol(DIN,S) when Lrotate,
  DOUT <= Vror(DIN,S) when Rrotate,
  DOUT <= Vsll(DIN,S) when Llogical,
  DOUT <= Vsrl(DIN,S) when Rlogical,
  DOUT <= Vsla(DIN,S) when Larith,
  DOUT <= Vsra(DIN,S) when Rarith,
  DOUT <= DIN when others;
end barrelse_behavioral;

