----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    15:52:22 12/30/2008 
-- Design Name: 
-- Module Name:    toplevel - 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_UNSIGNED.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 spi is
  
  port (
    -- SPI
    MISO      : in  std_logic;
    MOSI, SCK : out std_logic;
    -- System bus
    DATA_I    : in  std_logic_vector(7 downto 0);
    DATA_O    : out std_logic_vector(7 downto 0);
    START     : in  std_logic;
    BUSY      : out std_logic;
    CLK       : in  std_logic);

end spi;

architecture Behavioral of spi is
type states is (ST_IDLE, ST_TRANSMIT);
signal state : states := ST_IDLE;
  
signal dout_r, din_r : std_logic_vector(7 downto 0) := X"00";
signal count : unsigned(2 downto 0) := to_unsigned(0, 3);
signal spicycle : unsigned(1 downto 0) := to_unsigned(0, 2);

attribute iob : string;
attribute iob of MOSI, SCK : signal is "true";
begin  -- Behavioral

  fsm: process (CLK)
  variable next_state : states;
  begin
    if rising_edge(CLK) then
      next_state := state;
      case state is
        when ST_IDLE =>
          BUSY <= '0';
          SCK <= '0';
          if START = '1' then
            dout_r <= DATA_I;
            spicycle <= to_unsigned(0, spicycle'length);
            count <= to_unsigned(0, count'length);
            next_state := ST_TRANSMIT;
          end if;
        when ST_TRANSMIT =>
          BUSY <= '1';
          if spicycle = 0 then          -- data out
            MOSI <= dout_r(7);
            dout_r <= dout_r(6 downto 0) & '0';
          elsif spicycle = 1 then       -- clock up
            SCK <= '1';
          elsif spicycle = 2 then       -- nop
          elsif spicycle = 3 then       -- clock down, sample data
            SCK <= '0';
            din_r(0) <= MISO;
            din_r(7 downto 1) <= din_r(6 downto 0);
            if count = 7 then
              next_state := ST_IDLE;
            else
              count <= count + 1;
            end if;
          end if;
          spicycle <= spicycle + 1;
        when others => null;
      end case;
      state <= next_state;
    end if;
  end process;
    
  DATA_O <= din_r;
  
end Behavioral;
