-- Company: BUSE
-- Engineer: PAVEL SUNKA
-- 
-- Create Date:   2.3.2017
-- Module Name:   SPI modul s latenci 2
-- Project Name:  Micomp
-- Target Devices: 10M08
-----------------------------         ----------------------------
-- Zpracovani obrazku
-----------------------------         ----------------------------
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.std_logic_signed.all;
--	use IEEE.std_logic_signed.all;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
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 SPI is
	Port(
		ARST     : in  STD_LOGIC;
		CLK_50M  : in  std_logic;
		CLK_25M  : in  std_logic;
		CLK_SPI  : in  std_logic;
		MOSI     : in  std_logic;
		CS       : in  std_logic;
		BYTE     : out std_logic_vector(15 downto 0);
		END_BYTE : out std_logic;
		MISO     : out std_logic;
		END_WR   : out std_logic
	);
end SPI;

architecture Behavioral of SPI is
	component shift_reg_ren
		generic(size : natural);
		port(
			CLK   : in  std_logic;
			ARST  : in  std_logic;
			CEN   : in  std_logic;
			DAT_I : in  std_logic;
			DAT_O : out std_logic_vector(size - 1 downto 0)
		);
	end component shift_reg_ren;

	component metastab
		port(
			CLK   : in  std_logic;
			DAT_I : in  std_logic;
			DAT_O : out std_logic
		);
	end component metastab;

	component cnt_rEN_rst
		generic(stop_b : natural);
		port(
			ARST     : in  std_logic;
			CLK      : in  std_logic;
			EN       : in  std_logic;
			DATA_OUT : out std_logic_vector(stop_b downto 0)
		);
	end component cnt_rEN_rst;

	signal end_write : std_logic;
	-- CS --
	signal not_cs    : std_logic                    := '1'; -- negovany CS signal
	signal cs_shift  : std_logic_vector(3 downto 0) := (others => '1'); -- signal pro pamet 

	-- CLK_spi --
	signal clk_spi_met   : std_logic;   -- hodinovy signal po metastabilite
	signal CLK_spi_shift : std_logic_vector(3 downto 0) := (others => '0'); -- signal pro pamet 
	signal clk_edge      : std_logic                    := '0'; -- detekce hrany

	--data --
	signal dat_shift : std_logic_vector(3 downto 0) := (others => '0'); -- signal pro pamet 
	signal cnt_bit   : std_logic_vector(3 downto 0) := (others => '0'); -- pocet nactenych bitu v bajtu
	signal dat_met   : std_logic;       -- hodinovy signal po metastabilite
	signal dat_res   : std_logic;       -- vysledek snimkovanych dat

	--1 latenci clk edge--	
	signal ltc_clk_edge : std_logic_vector(1 downto 0);

	--:P
begin

	not_cs <= not CS;

	--CS--
	uCs_shift : shift_reg_ren
		generic map(
			size => 4
		)
		port map(
			CLK   => CLK_25M,
			ARST  => ARST,
			CEN   => '1',
			DAT_I => not_cs,
			DAT_O => cs_shift
		);

	end_write <= '1' when cs_shift = "1000" else '0';
	END_WR    <= end_write;

	-- CLK --

	uMet_CLK_50M : metastab
		port map(
			CLK   => CLK_50M,
			DAT_I => CLK_SPI,
			DAT_O => clk_spi_met
		);

	uCLK_50M_shift : shift_reg_ren
		generic map(
			size => 4
		)
		port map(
			CLK   => CLK_50M,
			ARST  => ARST,
			CEN   => '1',
			DAT_I => clk_spi_met,
			DAT_O => CLK_spi_shift
		);

	clk_edge <= '1' when (CLK_spi_shift(3 downto 2) = "00" and CLK_spi_shift(1 downto 0) = "11") else '0';

	-- Dat --

	uMet_Dat : metastab
		port map(
			CLK   => CLK_50M,
			DAT_I => MOSI,
			DAT_O => dat_met
		);
	uDat_shift : shift_reg_ren
		generic map(
			size => 4
		)
		port map(
			CLK   => CLK_50M,
			ARST  => ARST,
			CEN   => '1',
			DAT_I => dat_met,
			DAT_O => dat_shift
		);

	dat_res <= (dat_shift(2) and dat_shift(3)) or (dat_shift(1) and (dat_shift(2) or dat_shift(3)));

	uByte_shift : shift_reg_ren
		generic map(
			size => 16
		)
		port map(
			CLK   => CLK_50M,
			ARST  => ARST,
			CEN   => clk_edge,
			DAT_I => dat_res,
			DAT_O => BYTE
		);

	uCnt_bit : cnt_rEN_rst
		generic map(
			stop_b => 3
		)
		port map(
			ARST     => end_write,
			CLK      => CLK_50M,
			EN       => clk_edge,
			DATA_OUT => cnt_bit
		);

	Latency_clk_edge : process(ARST, CLK_50M)
	begin
		if (ARST = '1') thEN
			ltc_CLK_edge <= "00";

		elsif (rising_edge(CLK_50M)) then

			ltc_clk_edge(0) <= clk_edge;
			ltc_clk_edge(1) <= ltc_clk_edge(0);
		end if;
	end process Latency_clk_edge;

	END_BYTE <= '1' when (cnt_bit = "0000" and ltc_clk_edge(1) = '1') else '0';

	MISO <= '0';
end Behavioral;

