-------------------------------------------------------------------------------
-- Title      : Interface Logic
-------------------------------------------------------------------------------
-- File       : usb_slave.vhd
-- Author     : Pavan Marisetti
-- Company    : Actel Corporation
-- Device     : SmartFusion
-- Standard   : VHDL
-------------------------------------------------------------------------------
-- Description: This code consists of a 256x32 FIFO and a AHB master interface.
--              The code receives the data from USBee Ex 2.0 Experimenter's board
--              and stored into FIFO.. Then interface logic reads back the 32 bit 
--              data from FIFO and sends to the external SRAM. Once the host complete 
--              the data transfer and MSS stored the complete data into external SRAM, 
--              the interface logic generates an Interrupt to the MSS. 
-------------------------------------------------------------------------------
-- Copyright (c) 2010   Actel Corporation
--                      All rights reserved.
-------------------------------------------------------------------------------
-- Revisions  : V1.0
-------------------------------------------------------------------------------

library ieee;  
use ieee.std_logic_1164.all;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
library smartfusion;
use smartfusion.all;

entity usb_slave is
  port (USB_CLK           : in    std_logic;
		RESET_N           : in    std_logic;
        R_W_N             : in    std_logic;
        USB_DATA_PAD      : inout std_logic_vector(7 downto 0);
        HCLK              : in    std_logic;
        HTRANS            : out   std_logic_vector(1 downto 0);
        HSIZE             : out   std_logic_vector(1 downto 0);
        HWRITE            : out   std_logic;
        HWDATA            : out   std_logic_vector(31 downto 0);
        HADDR             : out   std_logic_vector(31 downto 0);
        HMASTLOCK         : out   std_logic;
        HREADY            : out   std_logic;
        HSEL              : out   std_logic;
        HREADYOUT         : in    std_logic;
        HRESP             : in    std_logic;
        HRDATA            : in    std_logic_vector(31 downto 0);
        FABINT            : out   std_logic
       );
end;

architecture usb_slave of usb_slave is


type fifo_read_states is (idle, get_data1, get_data2, data1, data2, data3, data4);
type ahb_master_states is (address_phase,data_phase); 
type input_data_states is (data1, data2, data3,data4); 

  signal ahb_states        : ahb_master_states;
  signal data_states       : fifo_read_states;
  signal input_states      : input_data_states;
  signal send_data         : std_logic;
  signal usb_32bit_data    : std_logic_vector(31 downto 0);
  signal usb_24bit_data    : std_logic_vector(23 downto 0); 
  signal data_enable       : std_logic;
  signal rd_en             : std_logic;
  signal wr_en             : std_logic;
  signal FIFO_EMPTY        : std_logic;
  signal FIFO_FULL         : std_logic;
  signal USB_DATA_IN       : std_logic_vector(7 downto 0);
  signal USB_DATA_OUT      : std_logic_vector(7 downto 0);
  signal AEMPTY            : std_logic;
  signal HADDR_TEMP        : std_logic_vector(29 downto 0);
  signal INTRPT_COUNT      : std_logic_vector(7 downto 0);
  signal input_32_bit_data : std_logic_vector(31 downto 0);
  signal count             : std_logic_vector(1 downto 0);

  component BIBUF_LVCMOS33U is
    port (D     : in std_logic;
          E     : in std_logic;
          Y     : out std_logic;
          PAD   : inout std_logic
         );

  end component;

  component Em_Fifo_256_32 is 
    port( DATA   : in  std_logic_vector(31 downto 0); 
          Q      : out std_logic_vector(31 downto 0);
          WE     : in  std_logic;
          RE     : in  std_logic;
          WCLOCK : in  std_logic;
          RCLOCK : in  std_logic;
          FULL   : out std_logic;
          EMPTY  : out std_logic;
          RESET  : in  std_logic
          );
  end component;

begin

  GEN: for i in 0 to 7 generate
       DATA_PINS : BIBUF_LVCMOS33U port map(D           => USB_DATA_OUT(i),
                                            E           => data_enable,
                                            Y           => USB_DATA_IN(i),
                                            PAD         => USB_DATA_PAD(i)
                                           );
  end generate GEN;


  FIFO_INST: Em_Fifo_256_32 
    port map( DATA    => input_32_bit_data(31 downto 0),
              Q       => HWDATA(31 downto 0),
              WE      => wr_en,
              RE      => rd_en,
              WCLOCK  => USB_CLK, 
              RCLOCK  => HCLK,
              FULL    => FIFO_FULL,
              EMPTY   => FIFO_EMPTY,
              RESET   => RESET_N
            );



  INPUT_PROCESS:process(USB_CLK, R_W_N)
  begin
    if R_W_N = '1' then       
       input_32_bit_data  <= (others=>'0');
       wr_en <= '1';
       input_states <= data1;
	elsif (USB_CLK'event and USB_CLK = '1') then
       case input_states is
	      when data1 =>
     	     input_32_bit_data(7 downto 0) <= USB_DATA_IN;
             input_states <= data2;
             wr_en <= '1';
	      when data2 =>
     	     input_32_bit_data(15 downto 8) <= USB_DATA_IN;
             input_states <= data3;
	      when data3 =>
     	     input_32_bit_data(23 downto 16) <= USB_DATA_IN;
             input_states <= data4;
	      when data4 =>
     	     input_32_bit_data(31 downto 24) <= USB_DATA_IN;
             input_states <= data1;
             wr_en <= '0';
          when others =>
        end case;
    end if;
  end process;

  
  
  -- data enable signal for Bidirectional buffer
   
  data_enable <= R_W_N;
     
       HMASTLOCK         <= '0';
       HREADY            <= '1'; 
       HADDR             <= HADDR_TEMP&"00";
  
AHB_MASTER: process(hclk, RESET_N)
  begin
    if RESET_N = '0' then
       HTRANS            <= "00";
       HWRITE            <= '0';
       HADDR_TEMP        <= "011011111111111111111111111111"; -- External MEM
       HSEL              <= '0';
       HSIZE             <= "00";
       ahb_states        <=  address_phase; 
       rd_en <= '1';
	elsif (hclk'event and hclk = '1') then
       case ahb_states is
		 when address_phase =>
           if(fifo_empty = '0' and HREADYOUT = '1') then
             rd_en <= '0';
             ahb_states <= data_phase;
             HADDR_TEMP <= HADDR_TEMP + 1;
             HWRITE <= '1';
             HTRANS <= "10";
             HSIZE <= "10";
             HSEL <= '1';
           else
             rd_en <= '1';
             HTRANS            <= "00";
             HWRITE            <= '0';
             HSEL              <= '0';
             HSIZE             <= "00";
             ahb_states <= address_phase;
           end if;
		 when data_phase =>
             rd_en <= '1';
             HTRANS            <= "00";
             HWRITE            <= '0';
             HSEL              <= '0';
             HSIZE             <= "00";
             ahb_states <= address_phase;
         when others =>
       end case;
     end if;
   end process;

INTRPT_PROCESS:process(hclk, RESET_N)
  begin
    if RESET_N = '0' then       
       INTRPT_COUNT  <= (others=>'0');
       FABINT <= '0';
	elsif (hclk'event and hclk = '1') then
       if(rd_en = '0') then
         INTRPT_COUNT <= X"01";
         FABINT <= '0';
       elsif(INTRPT_COUNT = X"00") then
          FABINT <= '0';
       elsif(INTRPT_COUNT = X"FF") then
         FABINT <= '1';
         INTRPT_COUNT <= (others=>'0');
       elsif(INTRPT_COUNT > X"00") then
         INTRPT_COUNT <= INTRPT_COUNT + 1;
       end if;
    end if;
  end process;
         
end usb_slave;