---------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------
--  File:          spi_rcv_shift_reg_16.vhd
--
--
--  Original file: spi_rcv_shift_reg.vhd
--
--  Created:  9-6-00 ALS
--  SPI shift register that shifts data in on MISO. No data is shifted out.
--  This is an 8-bit register clocked on the outgoing SCK. The data input
--  on the MISO pin is first clocked by two registers - one on the rising edge
--  of SCK and one on the falling edge of SCK. The data selected to be input into the
--  shift register is determined by a control bit in the control register (RCV_CPOL).
--  When all bits have been shifted in, the data is loaded into the uC SPI Receive Data
--  register.
--
--  Revised: 9-11-00 ALS
--  Revised: 10-17-00 ALS
--  Revised: 12-12-02 JRH
    
---------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------
--  Modified from 8 to 16 bit word size by Patrick Vogler
--  18th November 2009
--
--	 Modifications are marked by: *Mod: <modification>
--
--  Cleaned up by Quirin Weitzel
--  21th January 2010
---------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;

entity spi_rcv_shift_reg is
  port(  
    -- shift control and data
    miso      : in  STD_LOGIC;                       -- Serial data in
    shift_en  : in  STD_LOGIC;                       -- Active low shift enable    

    -- parallel data out
    data_out  : out STD_LOGIC_VECTOR (15 downto 0); -- Shifted data, *Mod: 15 instead of 7, parallel output extended from 8 to 16 bit    

    rcv_load  : out std_logic;                      -- load signal to uC register
    
    -- rising edge and falling SCK edges
    sck_re    : in  std_logic;                      -- rising edge of SCK
    sck_fe    : in  std_logic;                      -- falling edge of SCK
         
    -- uC configuration for receive clock polarity
    rcv_cpol  : in  STD_LOGIC;                      -- receive clock polarity
    cpol      : in  std_logic;                      -- spi clock polarity
      
    ss_in_int : in  STD_LOGIC;                      -- signal indicating another master is on the bus
    
    reset     : in  STD_LOGIC;                      -- reset
    sclk      : in  STD_LOGIC                       -- clock        
  );        
end spi_rcv_shift_reg;

architecture DEFINITION of spi_rcv_shift_reg is

  --******************************** Constants ***********************
  constant RESET_ACTIVE   : std_logic := '0';

  --******************************** Signals *************************
  signal data_int       : STD_LOGIC_VECTOR (15 downto 0);-- *Mod: 15 instead of 7, extension form 8 to 16 bit
  signal shift_in       : STD_LOGIC;                     -- data to be shifted in
  signal miso_neg       : STD_LOGIC;                     -- data clocked on neg SCK
  signal miso_pos       : STD_LOGIC;                     -- data clocked on pos SCK

  signal rcv_bitcnt_int : unsigned(2 downto 0); -- internal bit count
  signal rcv_bitcnt     : std_logic_vector(2 downto 0); -- bit count

begin

  --******************************** SPI Receive Shift Register ***********************
  -- This shift register is clocked on the SCK output from the CPLD

  rcv_shift_reg: process(sclk, reset, ss_in_int)
  begin          
    -- Clear output register
    if (reset = RESET_ACTIVE or ss_in_int = '0') then
      data_int <= (others => '0');
           
      -- On rising edge of spi clock, shift in data
    elsif sclk'event and sclk = '1' then

      -- If shift enable is high
      if shift_en = '0' then

        -- Shift the data
        data_int <= data_int(14 downto 0) & shift_in;   -- *Mod: 14 instead of 6
            
      end if;

    end if;

  end process;

  --******************************** MISO Input Registers *********************** 
  -- The MISO signal is clocked on both the rising and falling edges of SCK. The output
  -- of both these registers is then multiplexed with the RCV_CPOL control bit choosing
  -- which data is the valid data for the system. This data is then the input to the
  -- shift register.

  -- SCK rising edge register
  inreg_pos: process (sclk, reset, ss_in_int)
  begin
    if reset = RESET_ACTIVE or ss_in_int = '0' then
      miso_pos <= '0';
    elsif sclk'event and sclk = '1' then    
      miso_pos <= miso;
    end if;
  end process;

  -- SCK falling edge register
  inreg_neg: process (sclk, reset, ss_in_int)
  begin
    if reset = RESET_ACTIVE or ss_in_int = '0' then
      miso_neg <= '0';
    elsif sclk'event and sclk = '0' then    
      miso_neg <= miso;
    end if;
  end process;

  -- RCV_CPOL multiplexor to determine shift in data
  miso_mux: process (miso_neg, miso_pos, rcv_cpol)
  begin
    if rcv_cpol = '1' then
      shift_in <= miso_pos;
    else
      shift_in <= miso_neg;
    end if;
  end process;

  --******************************** Parallel Data Out ***********************

  data_out <= data_int(14 downto 0) & shift_in;	--*Mod: 14 instead of 6

  --******************************** Receive Bit Counter ***********************
  -- Count bits loading into the SPI receive shift register based on SCK
  -- assert RCV_LOAD when bit count is 0
  RCV_BITCNT_PROC: process(sclk, reset, shift_en)
  begin
    if reset = RESET_ACTIVE or shift_en = '1' then
      rcv_bitcnt_int <= (others => '0');
    elsif sclk'event and sclk = '1' then
      rcv_bitcnt_int <= rcv_bitcnt_int + 1;
    end if;
  end process;

  rcv_bitcnt <= STD_LOGIC_VECTOR(rcv_bitcnt_int);

  --******************************** Receive Load ***********************
  -- If RCV_CPOL = '0', want to assert RCV_LOAD with falling edge of SCK
  -- If RCV_CPOL = '1', want to assert RCV_LOAD with rising edge of SCK 
  -- only want RCV_LOAD to be 1 system clock pulse in width
  rcv_load <= '1' when ( shift_en = '0' and
                         (  (rcv_bitcnt="000" and cpol='0' and rcv_cpol='1' and sck_re='1')
                            or (rcv_bitcnt="000" and cpol='1' and rcv_cpol='1' and sck_re='1')
                            or (rcv_bitcnt="000" and cpol='0' and rcv_cpol='0' and sck_fe='1')
                            or (rcv_bitcnt="111" and cpol='1' and rcv_cpol='0' and sck_fe='1') )
                         )
              else '0';

end DEFINITION;
