---------------------------------------------------------------------------
-- NDT Solutions Ltd. Proprietary Information
-- Company Confidential
-- Copyright 2007
--
-- Filename: SpiAD.vhd
-- Language: VHDL '93
-- Project:  NDTS2100
--
-- Design Description:
-- SPI interface as used on AD Adcs etc
--
-- The clock will be 2*gHCycle input clock cycles long
---------------------------------------------------------------------------

library IEEE;
use IEEE.Std_Logic_1164.all;
use IEEE.Std_Logic_Arith.all;

entity SpiAD is
  generic(gHCycle: integer := 2);
  port(nReset   : in    std_ulogic;
       Clk      : in    std_ulogic;
       SerWr    : in    std_ulogic;
       Inst     : in    std_logic_vector(15 downto 0);
       DataIn   : out   std_logic_vector(7 downto 0);
       DataOut  : in    std_logic_vector(7 downto 0);
       ResetWr  : in    std_ulogic;
       Busy     : out   std_ulogic;
       --
       CSB      : out   std_ulogic;
       SClk     : out   std_ulogic;
       SDIO     : inout std_logic;
       Reset    : out   std_ulogic); -- active low
end entity SpiAD;


architecture Rtl of SpiAD is
  signal ClkCount : integer range 0 to gHCycle*2;
  signal InstCount: integer range 0 to 16;
  signal DataCount: integer range 0 to 8;
  signal RstCount : integer range 0 to gHCycle*2;
  signal InstShiftReg: std_logic_vector(15 downto 0);
  signal DataShiftReg: std_logic_vector(7 downto 0);
  signal DInLat      : std_ulogic;
  signal SDOut       : std_ulogic;
  signal nSDOutOe    : std_ulogic;
  signal nCsbOe      : std_ulogic;
begin

  StateM: process(nReset, Clk)
  begin
    if nReset = '0' then
      ClkCount <= 0;
      InstCount <= 0;
      DataCount <= 0;
      DInLat <= '0';
      InstShiftReg <= (others => '0');
      DataShiftReg <= (others => '0');
      DataIn <= (others => '0');
      Busy <= '0';

      nCsbOe <= '1';
      SClk <= '0';
      nSDOutOe <= '1';
      Reset <= '1';
    elsif rising_edge(Clk) then
      if InstCount /= 0 then
        if ClkCount = 0 then
          nCsbOe <= '0';
          SClk <= '0';
          nSDOutOe <= '0';
          SDOut <= InstShiftReg(15);
          InstShiftReg <= InstShiftReg(14 downto 0) & '0';
        end if;
        if ClkCount = gHCycle then
          SClk <= '1';
        end if;
        if ClkCount = (gHCycle*2)-1 then
          ClkCount <= 0;
          InstCount <= InstCount - 1;
        else
          ClkCount <= ClkCount + 1;
        end if;

      elsif DataCount /= 0 then
        if ClkCount = 0 then
          nCsbOe <= '0';
          SClk <= '0';
          if Inst(15) = '0' then -- Write
            nSDOutOe <= '0';
            SDOut <= DataShiftReg(7);
            DataShiftReg <= DataShiftReg(6 downto 0) & '0';
          else
            nSDOutOe <= '1';
          end if;
        end if;
        if ClkCount = gHCycle then
          SClk <= '1';
          if Inst(15) = '1' then -- Read
            DataShiftReg <= DataShiftReg(6 downto 0) & SDIO;
          end if;
        end if;
        if ClkCount = (gHCycle*2)-1 then
          ClkCount <= 0;
          DataCount <= DataCount - 1;
        else
          ClkCount <= ClkCount + 1;
        end if;
        DInLat <= '1';
      elsif SerWr = '1' then
        InstCount <= 16;
        InstShiftReg <= Inst;
        DataCount <= 8;
        DataShiftReg <= DataOut;
        Busy <= '1';
      else
        nSDOutOe <= '1';
        nCsbOe <= '1';
        SClk <= '0';
        if DInLat = '1' then
          DInLat <= '0';
          DataIn <= DataShiftReg;
        end if;
        Busy <= '0';
      end if;

      if ResetWr = '1' then
        Reset <= '0';
        RstCount <= gHCycle*2;
      elsif RstCount /= 0 then
        Reset <= '0';
        RstCount <= RstCount - 1;
      else
        Reset <= '1';
      end if;
    end if;
  end process StateM;

  SDIO <= SDOut when nSDOutOe = '0' else 'Z';
  CSB <= '0' when nCsbOe = '0' else 'Z';

end architecture rtl;
