----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    15:26:08 04/08/2007 
-- Design Name: 
-- Module Name:    piso - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity piso is
Generic ( width : integer := 8 );
Port (
	rst		: in  STD_LOGIC;
	clk		: in  STD_LOGIC;
	pdi		: in  UNSIGNED (width-1 downto 0);
	pvi		: in  STD_LOGIC;
	prdyo	: out STD_LOGIC;
	sdo		: out STD_LOGIC;
	sso		: out STD_LOGIC;
	srdyi	: in  STD_LOGIC
	);
end piso;

architecture Behavioral of piso is

type sstate_t is (reset, idle, ready, sync, active);

constant idle_pol : std_logic := '0';
signal reg : UNSIGNED (width-1 downto 0);
signal shift_en, counter_srst, counter_rdy : std_logic;
signal sstate, sstate_next : sstate_t;

begin

par_in:
process (rst, clk, pvi, reg, shift_en)
begin
	if rst = '1' then
		reg <= (others => idle_pol);
	elsif rising_edge(clk) then
		if pvi = '1' then
			reg <= pdi;
		elsif shift_en = '1' then
			reg <= reg(width-2 downto 0) & idle_pol;
		end if;	
	end if;
	sdo <= reg(width-1);
end process;

counter:
process (rst, counter_srst, clk)
variable counter : integer range 0 to width-1;
begin
	if rst = '1' then
		counter_rdy <= '0';
	elsif rising_edge(clk) then
		if counter_srst = '1' then
			counter := width-4;
			counter_rdy <= '0';
		elsif counter /= 0 then	
			counter := counter - 1;
		else	
			counter_rdy <= '1';
		end if;	
	end if;
end process;

ser_sm:
process (rst, clk, pvi, sstate, counter_rdy, srdyi)
begin
	sstate_next <= sstate;
	prdyo <= '0';
	sso <= '0';
	shift_en <= '0';
	counter_srst <= '1';
	
	case sstate is
	when reset =>
		sstate_next <= idle;
	when idle =>
		sstate_next <= ready;
	when ready =>	
		prdyo <= srdyi;
		if pvi = '1' then
			sstate_next <= sync;
		end if;	
	when sync =>	
		sso <= '1';
		sstate_next <= active;
		shift_en <= '1';
	when active =>	
		shift_en <= '1';
		counter_srst <= '0';
		if counter_rdy = '1' then
			sstate_next <= idle;
		end if;	
	when others =>	
		sstate_next <= idle;
		
	end case;
end process;
	
state_proc:
process (rst, clk, sstate_next)
begin
	if rst = '1' then
		sstate <= reset;
	elsif rising_edge(clk) then
		sstate <= sstate_next;
	end if;
end process;

end Behavioral;

