-- Arithmetic shift right example (sra)
library ieee;
use ieee.std_logic_1164.all;
-- Use Warp's below package so can do math with std_logic_vector's
use work.std_arith.all; 

entity SHIFT is port(
	ShiftIn, Clk, ShiftEnable:	in std_logic;
	ShiftOut:	out std_logic;
	Q:	buffer std_logic_vector(7 downto 0)
);
end SHIFT;

architecture behavior of SHIFT is

type statetype is (s1,s2,s3,s4,s5,s6,s7,s8,s9,s10);
signal state : statetype; 

--procedure declaration
function shift_right(signal Q: in std_logic_vector(7 downto 0);
					 signal ShiftIn: in std_logic) return std_logic_vector is
	variable x:  std_logic_vector(7 downto 0);
	begin	
	  x := Q srl 1;
	  --Q <= Q srl 1;
	  x(7) := ShiftIn;
 	  return x;
end function;

function wait_for_start(signal state: in statetype) return statetype is
	variable temp : statetype;
	begin	
	 
	  temp := state;
	  if state = s1 then
		 if ShiftIn = '0' then	
			temp := s2;
		 end if;
	  end if;
	  return temp;
	end function;

function check_done(signal state: in statetype) return boolean is
	begin
	  if (state = s10) then
 	     return true;
	  else
	     return false;
	  end if;	
	end function;

function waiting(signal state: in statetype) return boolean is
	variable result : boolean;
	begin
	  if (state = s1) then
 	     result := true;
	  else
	     result := false;
	  end if;
	  return result;	
	end function;

function next_state(signal state: in statetype) return statetype is

   variable s : statetype;
	begin
	  case state is
	    when s1 =>
		s := s1;
	    when s2 =>
		s := s3;
	    when s3 =>  
		s := s4;
	    when s4 =>
		s := s5;
	    when s5 => 
		s := s6;
	    when s6 =>
		s := s7;
	    when s7 =>
        s := s8;
	    when s8 =>
		s := s9;
	    when s9 =>
		s := s10;
		when s10 =>
	    s :=  s1;
	  end case;	
		return s;
	end function;

type increment is range 0 to 100;

function "+" (signal state: in statetype;
	     constant skipnum: in increment) return statetype is
  variable counter : increment;
  variable temp_state : statetype;
  begin
    counter := skipnum;
    temp_state := state;
    loop
      if (counter = 0) then
	  exit;
      end if;
      temp_state := next_state(temp_state);
	  counter := counter - 1;
      
    end loop;
		return temp_state;
  end function;

begin -architecture behavior

ShiftIt: process(clk)
	procedure shift_left is
	begin	
		ShiftOut <= Q(7);
		Q <= Q sll 1;
		Q(0) <= ShiftIn;
	end procedure;

	begin -process ShiftIt
		if RISING_EDGE(clk) then
			case ShiftEnable is
				when '1' => 
					state <= wait_for_start(state);
					if not waiting(state) then
						ShiftOut <= Q(0);
						Q <= shift_right(Q,ShiftIn); --procedure call
						state <= state + 2;
					end if;
				when '0' => 
					--shift_left;
					Q <= "00000000";
				when others =>
					Q <= "00000000";
			end case;
		end if;
	end process ShiftIt;
end behavior;



