--------------------------------------------------------------------------------
-- SPI Interface for c't-Lab FPGA und c't-Lab UNIC
-- AVR SPI-Mode CPOL/CPHA 1.1 (SCK normally high)
-- by C. Meyer cm@ctmagazin.de
-- Creative Commons by-nc-sa, use by your own risk
-- Neue Version mit 16-Bit-Registeradressen, Bit 15 = Write Enable
--------------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity SPI_in is
port (
    SYSCLK: in STD_LOGIC;
    SCK   : in STD_LOGIC;
    MOSI  : in STD_LOGIC;
	 DS_N  : in STD_LOGIC;
	 RS_N  : in STD_LOGIC;
    ADDR  : in STD_LOGIC_VECTOR(3 downto 0);
--	 STR0  : out STD_LOGIC;
--	 STR1  : out STD_LOGIC;
--	 STR2  : out STD_LOGIC;
--	 STR3  : out STD_LOGIC;
--	 MISO  : out STD_LOGIC;
--    D0   : in STD_LOGIC_VECTOR(31 downto 0);
--    D1   : in STD_LOGIC_VECTOR(31 downto 0);
--    D2   : in STD_LOGIC_VECTOR(31 downto 0);
--    D3   : in STD_LOGIC_VECTOR(31 downto 0);
--	 
--    D4   : in STD_LOGIC_VECTOR(15 downto 0);
--    D5   : in STD_LOGIC_VECTOR(15 downto 0);
--    D6   : in STD_LOGIC_VECTOR(15 downto 0);
--    D7   : in STD_LOGIC_VECTOR(15 downto 0);
	 
    Q0   : out STD_LOGIC_VECTOR(7 downto 0);
    Q1   : out STD_LOGIC_VECTOR(7 downto 0);
    Q2   : out STD_LOGIC_VECTOR(7 downto 0);
    Q3   : out STD_LOGIC_VECTOR(7 downto 0);
    Q4   : out STD_LOGIC_VECTOR(7 downto 0);
    Q5   : out STD_LOGIC_VECTOR(7 downto 0);
    Q6   : out STD_LOGIC_VECTOR(7 downto 0);
    Q7   : out STD_LOGIC_VECTOR(7 downto 0);
    Q8   : out STD_LOGIC_VECTOR(7 downto 0);
    Q9   : out STD_LOGIC_VECTOR(7 downto 0);
    Q10  : out STD_LOGIC_VECTOR(7 downto 0);
    Q11  : out STD_LOGIC_VECTOR(7 downto 0);
    Q12  : out STD_LOGIC_VECTOR(7 downto 0);
    Q13  : out STD_LOGIC_VECTOR(7 downto 0);
    Q14  : out STD_LOGIC_VECTOR(7 downto 0);
    Q15  : out STD_LOGIC_VECTOR(7 downto 0)
    );
end SPI_in;

architecture behave of SPI_in is

--signal q_sro, q_sro_tmp, q_sri : std_logic_vector(31 downto 0);
signal q_int, q_sri : std_logic_vector(31 downto 0);
signal r_int, r_sri : std_logic_vector(15 downto 0);
signal rs_tick, rs_tmp, ds_tick, ds_tmp, miso_int : std_logic;

begin

process(SCK, DS_N)
-- Schieberegister für Eingangsdaten
begin
	if rising_edge(SCK) then
		if (DS_N='0') then 
			q_sri <= ( q_sri(30 downto 0) & MOSI );
		end if;
	end if;
end process;

process(SCK, RS_N)
-- Schieberegister für Select-Adresse
begin
	if rising_edge(SCK) then
		if (RS_N='0') then 
			r_sri <= ( r_sri(14 downto 0) & MOSI );
		end if;
	end if;
end process;

process(RS_N)
-- Eingangsregister Adresse buffered
begin
	if rising_edge(RS_N) then
		r_int <= r_sri;
	end if;
end process;

process(DS_N)
-- Eingangsregister Daten buffered
begin
	if rising_edge(DS_N) then
		q_int <= q_sri;
	end if;
end process;

--process(SCK, DS_N)
---- Schieberegister für Ausgangsdaten
--begin
--   if DS_N = '1' then	-- Latch für Ausgangsdaten an MISO
--		q_sro_tmp <= q_sro;
--	elsif rising_edge(SCK) then
--		q_sro_tmp <= ( q_sro_tmp(30 downto 0) & '0' );	-- MSB first
--	end if;
--end process;

--miso_int <= q_sro_tmp(31);
--MISO <= miso_int when DS_N = '0' else 'Z';

process(SYSCLK)
-- SPI-Registerwerte zwischenspeichern
begin
	if rising_edge(SYSCLK) then
		if ds_tick = '1' then	-- Daten 
--			STR0 <= '0';
--			STR1 <= '0';
--			STR2 <= '0';
--			STR3 <= '0';
			if (r_int(15 downto 7) = x"80") and (r_int(7 downto 4) = ADDR) then
				case r_int(3 downto 0) is 
					when x"0" =>
--						STR0 <= '1';
						Q0 <= q_int(7 downto 0);
					when x"1" =>
--						STR1 <= '1';
						Q1 <= q_int(7 downto 0);
					when x"2" =>
--						STR2 <= '1';
						Q2 <= q_int(7 downto 0);
					when x"3" =>
--						STR3 <= '1';
						Q3 <= q_int(7 downto 0);
					when x"4" =>
						Q4 <= q_int(7 downto 0);
					when x"5" =>
						Q5 <= q_int(7 downto 0);
					when x"6" =>
						Q6 <= q_int(7 downto 0);
					when x"7" =>
						Q7 <= q_int(7 downto 0);
					when x"8" =>
						Q8 <= q_int(7 downto 0);
					when x"9" =>
						Q9 <= q_int(7 downto 0);
					when x"A" =>
						Q10 <= q_int(7 downto 0);
					when x"B" =>
						Q11 <= q_int(7 downto 0);
					when x"C" =>
						Q12 <= q_int(7 downto 0);
					when x"D" =>
						Q13 <= q_int(7 downto 0);
					when x"E" =>
						Q14 <= q_int(7 downto 0);
					when x"F" =>
						Q15 <= q_int(7 downto 0);
					when others =>
				end case;
			end if;
		end if;
	end if;
end process;

process(SYSCLK)
-- Synchrone Ticks erzeugen bei SlaveSelect-Ende (steigende Flanke)
begin
	if rising_edge(SYSCLK) then
		ds_tmp <= DS_N;
		ds_tick <= (not ds_tmp) and DS_N;
		rs_tmp <= RS_N;
		rs_tick <= (not rs_tmp) and RS_N;
		if rs_tick = '1' then	-- Register-Select geschrieben?
			r_int <= r_sri;
-- Eingangsmultiplexer, aktualisiert mit Schreiben von RS_N
--			if r_sri(7 downto 4) = ADDR then
--				case r_sri(3 downto 0) is -- aktuelle Registeradresse
--					when x"0" =>
--						q_sro <= D0;
--					when x"1" =>
--						q_sro <= D1;
--					when x"2" =>
--						q_sro <= D2;
--					when x"3" =>
--						q_sro <= D3;
--					when x"4" =>
--						q_sro <= D4 & x"0000";	-- bei 16-Bit-Werten MSBs
--					when x"5" =>
--						q_sro <= D5 & x"0000";
--					when x"6" =>
--						q_sro <= D6 & x"0000";
--					when x"7" =>
--						q_sro <= D7 & x"0000";
--					when others =>
--						q_sro <= (others => 'X');
--				end case;
--			end if;
		end if;
	end if;
end process;


end behave;

