-- 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;
				
begin

ShiftIt: process(clk)

procedure shift_left is
begin	
	  ShiftOut <= Q(7);
	  Q <= Q sll 1;
	  Q(0) <= ShiftIn;

end procedure;

	 begin
	  			
			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 <= next_state(state);
	    	            end if;
 
						
					when '0' => 
						--shift_left;
							Q <= "00000000";
					when others =>
   		         		    Q <= "00000000";
				end case;
			end if;
	  end process ShiftIt;

end behavior;



