----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    16:26:11 07/16/2009 
-- Design Name: 
-- Module Name:    spi - 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.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

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

entity spi is
    Port ( clk : in  STD_LOGIC;
           clk66 : in std_logic;
           reset : in  STD_LOGIC;
           
           address : in  STD_LOGIC_VECTOR (31 downto 2);
           enable : in std_logic;
           byte_we : in std_logic_vector(3 downto 0);
           data_read : out std_logic_vector(31 downto 0);
           data_write : in  STD_LOGIC_VECTOR (31 downto 0);
           
           spi_miso : out  STD_LOGIC;
           spi_mosi : in  STD_LOGIC;
           spi_clk : in  STD_LOGIC;
           spi_cs : in  STD_LOGIC);
end spi;

architecture Behavioral of spi is

   signal transmit_buffer_do : std_logic_vector(7 downto 0);
   signal receive_buffer_do : std_logic_vector(7 downto 0);

   signal transmit_buffer_wea, receive_buffer_wea : std_logic;

   signal spi_transmit_buffer_data : std_logic_vector(7 downto 0);
   signal spi_transmit_buffer_address : std_logic_vector(10 downto 0) := (others=>'0');

   signal spi_receive_buffer_data : std_logic_vector(7 downto 0);
   signal spi_receive_buffer_address : std_logic_vector(10 downto 0) := (others=>'0');
   signal spi_receive_buffer_we, spi_receive_buffer_we_last : std_logic;
   
   signal spi_bit_counter : std_logic_vector(2 downto 0) := (others=>'0');

   signal spi_clk_reg : std_logic_vector(1 downto 0) := (others=>'0');
   signal spi_cs_reg  : std_logic_vector(1 downto 0) := (others=>'1');
   signal spi_bit_in  : std_logic_vector(1 downto 0) := (others=>'0');
   
   signal spi_in : std_logic_vector(7 downto 0) := (others=>'0');
   signal spi_out : std_logic_vector(7 downto 0) := (others=>'0');
   
begin

--   transmit_buffer_wea<=byte_we(0) and not address(13);
--   receive_buffer_wea<=byte_we(0) and address(13);

--   data_read(7 downto 0)<=transmit_buffer_do when address(13)='0' else receive_buffer_do;

   transmit_buffer: RAMB16_S9_S9
      port map (
      CLKA  => clk, 
      ADDRA => address(12 downto 2),
      ENA   => enable,
      WEA   => byte_we(0),

      DIA   => data_write(7 downto 0),
      DIPA  => (others=>'0'),

      DOA   => open,
      DOPA  => open,

      SSRA  => '0',


      CLKB  => clk66,
      ADDRB => spi_transmit_buffer_address,
      ENB   => '1',
      WEB   => '0',

      DOB   => spi_transmit_buffer_data,
      DOPB  => open,      

      DIB   => (others=>'0'),
      DIPB  => (others=>'0'),

      SSRB  => '0'
      );
      
   receive_buffer: RAMB16_S9_S9
      port map (
      CLKA  => clk, 
      ADDRA => address(12 downto 2),
      ENA   => enable,
      WEA   => '0',

      DIA   => data_write(7 downto 0),
      DIPA  => (others=>'0'),

      DOA   => data_read(7 downto 0),
      DOPA  => open,

      SSRA  => '0',


      CLKB  => clk66,
      ADDRB => spi_receive_buffer_address,
      ENB   => '1',
      WEB   => spi_receive_buffer_we,

      DOB   => open,
      DOPB  => open,      

      DIB   => spi_in,
      DIPB  => (others=>'0'),

      SSRB  => '0'
      );      
      
      
      
   spi_clk_sample: process(clk66,spi_clk) is
   begin
      if rising_edge(clk66) then
         spi_clk_reg<=spi_clk_reg(0)&spi_clk;
      end if;
   end process;

   spi_cs_sample: process(clk66,spi_cs) is
   begin
      if rising_edge(clk66) then
         spi_cs_reg<=spi_cs_reg(0)&spi_cs;
      end if;
   end process;
   
   spi_mosi_sample: process(clk66,spi_mosi) is
   begin
      if rising_edge(clk66) then
         spi_bit_in<=spi_bit_in(0)&spi_mosi;
      end if;
   end process;

   spi_transfer: process(clk66,spi_cs_reg,spi_clk_reg,spi_bit_counter,spi_bit_in) is
   begin
      if rising_edge(clk66) then
         spi_receive_buffer_we<='0';
                   spi_receive_buffer_we_last<=spi_receive_buffer_we;
                   if(spi_receive_buffer_we_last='1') then
                      spi_receive_buffer_address<=spi_receive_buffer_address+1;
                   end if;
         case spi_cs_reg is
            when "11" =>
               spi_bit_counter<=(others=>'0');
               spi_transmit_buffer_address<=(others=>'0');
               spi_receive_buffer_address<=(others=>'0');
            when "10" =>
               spi_out<=spi_transmit_buffer_data;
               spi_transmit_buffer_address<=spi_transmit_buffer_address+1;
            when "00" =>
               case spi_clk_reg is
                  when "01" =>
                     spi_bit_counter<=spi_bit_counter+1;
                     spi_in<=spi_in(6 downto 0)&spi_bit_in(1);
                     if(spi_bit_counter="111") then
                        spi_receive_buffer_we<='1';
                     end if;
                  when "10" =>
                     if(spi_bit_counter="000") then
                        spi_out<=spi_transmit_buffer_data;
                        spi_transmit_buffer_address<=spi_transmit_buffer_address+1;
                     else
                        spi_out<=spi_out(6 downto 0)&'0';
                     end if;
                  when others =>
               end case;            
            when others =>
         end case;
      end if;
   end process;

   spi_miso<=spi_out(7);

end Behavioral;