--=============================================================================
--! @file dualSERDES_1to4_rtl.vhd
--=============================================================================
--
-------------------------------------------------------------------------------
-- --
-- University of Bristol, High Energy Physics Group.
-- --
------------------------------------------------------------------------------- --
-- VHDL Architecture work.dualSERDES_1to4.rtl
--
--! @brief Two 1:4 Deserializers. One has input delayed w.r.t. other\n
--! based on TDC by Alvaro Dosil\n
--
--! @author David Cussans , David.Cussans@bristol.ac.uk
--
--! @date 12:06:53 11/16/12
--
--! @version v0.1
--
--! @details
--! data_o(7) is the most recently arrived data , data_o(0) is the oldest data.
--!
--! <b>Dependencies:</b>\n
--!
--! <b>References:</b>\n
--!
--! <b>Modified by: Alvaro Dosil , alvaro.dosil@usc.es </b>\n
--! Author: 
-------------------------------------------------------------------------------
--! \n\n<b>Last changes:</b>\n
-------------------------------------------------------------------------------
--! @todo Implement a periodic calibration sequence\n
--! <another thing to do> \n
--
--------------------------------------------------------------------------------
-- 
-- Created using using Mentor Graphics HDL Designer(TM) 2010.3 (Build 21)
--
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all;

library unisim ;
use unisim.vcomponents.all;


ENTITY dualSERDES_1to4 IS
   PORT( 
      serdes_reset_i : IN     std_logic;                      --! Starts recalibration sequence and resets the ISERDES
      data_i         : IN     std_logic;
      fastClk_i      : IN     std_logic;                      --! 4x fabric clock. e.g. 640MHz
      fabricClk_i    : IN     std_logic;                      --! clock for output to FPGA. e.g. 160MHz
      strobe_i       : IN     std_logic;                      --! Strobes once every 4 cycles of fastClk
      data_o         : OUT    std_logic_vector (7 DOWNTO 0);  --! Deserialized data. Interleaved between prompt and delayed  serdes.
                                                              --! data_o(0) is the oldest data
      serdes_ready_o : OUT    std_logic                       --! goes low during calibration sequence.
   );

-- Declarations

END ENTITY dualSERDES_1to4 ;

--
ARCHITECTURE rtl OF dualSERDES_1to4 IS

  constant c_S : positive := 4;                     -- ! SERDES division ratio

  signal s_Data_i_d_p   : std_logic;
  signal s_Data_i_d_d   : std_logic;
  signal s_busy_idelay_m  : std_logic;              -- Indicates that the IDELAY isn't calibrating.
  signal s_busy_idelay_s  : std_logic;              -- Indicates that the IDELAY isn't calibrating.
  signal s_data_o       : std_logic_vector(7 downto 0);  --! Deserialized data
  signal s_rst          : std_logic := '0';         -- IODELAY and ISERDES reset
  signal s_cal_FSM      : std_logic := '0';         --! Take high to calibrate the IDELAY components
  signal s_rst_FSM      : std_logic := '0';         -- IODELAY reset
  signal s_initial_cal  : std_logic := '1';         -- Start up calibration flag
  signal s_calibration  : std_logic := '0';         -- Start calibration
  --! Calibration FSM state values
  type state_values is (st0, st1, st2, st3, st4);
  signal pres_state, next_state: state_values := st0;
  
BEGIN
  --! Calibration start condition
  s_calibration <= serdes_reset_i or s_initial_cal;
  s_rst <= s_rst_FSM; -- or serdes_reset_i;
  
  --! Calibration FSM register
  statereg: process(fabricClk_i, serdes_reset_i)
  begin
	 if rising_edge(fabricClk_i) then
		pres_state <= next_state;     -- Move to next state
        
	 end if;
  end process statereg;


  --! Calibration FSM combinational block
  fsm: process(pres_state, s_calibration, s_busy_idelay_m)
  begin
	 next_state <= pres_state;
	 -- Default values
    s_Rst_FSM <= '0';
    s_cal_FSM <= '0';
	 
    case pres_state is
	  
	   -- st0 - IDLE
		when st0=>
        if ( s_calibration = '1') then 
          next_state <= st1;            -- Next state is "st1 - SEND CALIBRATION SIGNAL"
        end if;
		
		-- st1 - SEND CALIBRATION SIGNAL
		when st1=>
		  s_cal_FSM <= '1';
		  s_initial_cal <= '0';
        if s_busy_idelay_m = '1' then 
          next_state <= st2;            -- Next state is "st2 - WAIT BUSY = '0'"
        end if;
      
		-- st2 - WAIT BUSY = '0'
		when st2=>
        if s_busy_idelay_m = '0' then 
          next_state <= st3;            -- Next state is "st3 - RESET STATE"
        end if;
		
		-- st3 - RESET STATE
		when st3=>
		  s_Rst_FSM <= '1';
		  if s_busy_idelay_m = '1' then 
          next_state <= st4;              -- Next state is "st4 - WAIT BUSY = '0'"
        end if;
		  
		-- st4 - WAIT BUSY = '0'
		when st4=>
		  if s_busy_idelay_m = '0' then 
          next_state <= st0;              -- Next state is "st0 - IDLE"
        end if;
	 end case;
	 
  end process fsm;

    IODELAY2_Prompt : IODELAY2
  generic map (
    COUNTER_WRAPAROUND => "STAY_AT_LIMIT",  -- "STAY_AT_LIMIT" or "WRAPAROUND" 
    DATA_RATE          => "SDR",            -- "SDR" or "DDR" 
    DELAY_SRC          => "IDATAIN",        -- "IO", "ODATAIN" or "IDATAIN" 
    IDELAY_MODE        => "NORMAL",         -- "NORMAL" or "PCI" 
	 --SERDES_MODE   	  => "MASTER", 			-- <NONE>, MASTER, SLAVE
    IDELAY_TYPE        => "VARIABLE_FROM_HALF_MAX",          -- "FIXED", "DEFAULT", "VARIABLE_FROM_ZERO", "VARIABLE_FROM_HALF_MAX" 
                              --  or "DIFF_PHASE_DETECTOR" 
    IDELAY_VALUE     => 0,                -- Amount of taps for fixed input delay (0-255)
    IDELAY2_VALUE    => 0,                -- Delay value when IDELAY_MODE="PCI" (0-255)
    ODELAY_VALUE     => 0                -- Amount of taps fixed output delay (0-255)
    --SIM_TAPDELAY_VALUE=> 50               -- Per tap delay used for simulation in ps
   )
  port map (
    BUSY     => s_busy_idelay_m,  -- 1-bit output: Busy output after CAL
    DATAOUT  => s_Data_i_d_p,     -- 1-bit output: Delayed data output to ISERDES/input register
    DATAOUT2 => open,             -- 1-bit output: Delayed data output to general FPGA fabric
    DOUT     => open,             -- 1-bit output: Delayed data output
    TOUT     => open,             -- 1-bit output: Delayed 3-state output
    CAL      => s_cal_FSM,     -- 1-bit input: Initiate calibration input
    CE       => '0',              -- 1-bit input: Enable INC input
    CLK      => fabricClk_i,      -- 1-bit input: Clock input
    IDATAIN  => data_i,           -- 1-bit input: Data input (connect to top-level port or I/O buffer)
    INC      => '0',              -- 1-bit input: Increment / decrement input
    IOCLK0   => fastClk_i,        -- 1-bit input: Input from the I/O clock network
    IOCLK1   => '0',              -- 1-bit input: Input from the I/O clock network
    ODATAIN  => '0',              -- 1-bit input: Output data input from output register or OSERDES2.
    RST      => s_rst,            -- 1-bit input: reset_i to zero or 1/2 of total delay period
    T        => '0'               -- 1-bit input: 3-state input signal
   );


  IODELAY2_Delayed : IODELAY2
  generic map (
    COUNTER_WRAPAROUND => "WRAPAROUND",  -- "STAY_AT_LIMIT" or "WRAPAROUND" 
    DATA_RATE          => "SDR",         -- "SDR" or "DDR" 
    DELAY_SRC          => "IDATAIN",     -- "IO", "ODATAIN" or "IDATAIN" 
    IDELAY_MODE        => "NORMAL",      -- "NORMAL" or "PCI" 
	 --SERDES_MODE   	  => "SLAVE", 			-- <NONE>, MASTER, SLAVE
    IDELAY_TYPE        => "FIXED",       -- "FIXED", "DEFAULT", "VARIABLE_FROM_ZERO", "VARIABLE_FROM_HALF_MAX" 
                              --  or "DIFF_PHASE_DETECTOR" 
    IDELAY_VALUE       => 0,             -- Amount of taps for fixed input delay (0-255) 10->0.75nS, 11->0.825nS
    IDELAY2_VALUE      => 0,             -- Delay value when IDELAY_MODE="PCI" (0-255)
    ODELAY_VALUE       => 0              -- Amount of taps fixed output delay (0-255)
    --SIM_TAPDELAY_VALUE => 43              -- Per tap delay used for simulation in ps
   )
  port map (
    BUSY     => s_busy_idelay_s,  -- 1-bit output: Busy output after CAL
    DATAOUT  => s_Data_i_d_d,     -- 1-bit output: Delayed data output to ISERDES/input register
    DATAOUT2 => open,             -- 1-bit output: Delayed data output to general FPGA fabric
    DOUT     => open,             -- 1-bit output: Delayed data output
    TOUT     => open,             -- 1-bit output: Delayed 3-state output
    CAL      => '0',              -- 1-bit input: Initiate calibration input
    CE       => '0',              -- 1-bit input: Enable INC input
    CLK      => '0',              -- 1-bit input: Clock input
    IDATAIN  => Data_i,           -- 1-bit input: Data input (connect to top-level port or I/O buffer)
    INC      => '0',              -- 1-bit input: Increment / decrement input
    IOCLK0   => '0',              -- 1-bit input: Input from the I/O clock network
    IOCLK1   => '0',              -- 1-bit input: Input from the I/O clock network
    ODATAIN  => '0',              -- 1-bit input: Output data input from output register or OSERDES2.
    RST      => s_rst,            -- 1-bit input: reset_i to zero or 1/2 of total delay period
    T        => '0'               -- 1-bit input: 3-state input signal
   );


  ISERDES2_Prompt : ISERDES2
  generic map (
    BITSLIP_ENABLE => FALSE,         -- Enable Bitslip Functionality (TRUE/FALSE)
    DATA_RATE      => "SDR",         -- Data-rate ("SDR" or "DDR")
    DATA_WIDTH     => c_S,           -- Parallel data width selection (2-8)
    INTERFACE_TYPE => "RETIMED",     -- "NETWORKING", "NETWORKING_PIPELINED" or "RETIMED" 
    SERDES_MODE    => "NONE"         -- "NONE", "MASTER" or "SLAVE" 
   )
  port map (
    -- Q1 - Q4: 1-bit (each) output Registered outputs to FPGA logic
	 Q1     => s_Data_o(0),           -- oldest data
    Q2     => s_Data_o(2),
    Q3     => s_Data_o(4),
    Q4     => s_Data_o(6),           -- most recent data
    --SHIFTOUT => SHIFTOUTsig,       -- 1-bit output Cascade output signal for master/slave I/O
    VALID   => open,                 -- 1-bit output Output status of the phase detector
    BITSLIP => '0',                  -- 1-bit input Bitslip enable input
    CE0     => '1',                  -- 1-bit input Clock enable input
    CLK0    => fastClk_i,            -- 1-bit input I/O clock network input
    CLK1    => '0',                  -- 1-bit input Secondary I/O clock network input
    CLKDIV  => fabricClk_i,          -- 1-bit input FPGA logic domain clock input
    D       => s_Data_i_d_p,         -- 1-bit input Input data
    IOCE    => strobe_i,             -- 1-bit input Data strobe_i input
    RST     => serdes_reset_i,       -- 1-bit input Asynchronous reset_i input
    SHIFTIN => '0'                   -- 1-bit input Cascade input signal for master/slave I/O
   );

  ISERDES2_Delayed : ISERDES2
  generic map (
    BITSLIP_ENABLE => FALSE,       -- Enable Bitslip Functionality (TRUE/FALSE)
    DATA_RATE      => "SDR",       -- Data-rate ("SDR" or "DDR")
    DATA_WIDTH     => c_S,         -- Parallel data width selection (2-8)
    INTERFACE_TYPE => "RETIMED",   -- "NETWORKING", "NETWORKING_PIPELINED" or "RETIMED" 
    SERDES_MODE    => "NONE"       -- "NONE", "MASTER" or "SLAVE" 
   )
  port map (
    -- Q1 - Q4: 1-bit (each) output Registered outputs to FPGA logic
	 Q1     => s_Data_o(1),         -- Oldest data
    Q2     => s_Data_o(3),
    Q3     => s_Data_o(5),
    Q4     => s_Data_o(7),         -- most recent data
    --SHIFTOUT => SHIFTOUTsig,     -- 1-bit output Cascade output signal for master/slave I/O
    VALID   => open,               -- 1-bit output Output status of the phase detector
    BITSLIP => '0',                -- 1-bit input Bitslip enable input
    CE0     => '1',                -- 1-bit input Clock enable input
    CLK0    => fastClk_i,          -- 1-bit input I/O clock network input
    CLK1    => '0',                -- 1-bit input Secondary I/O clock network input
    CLKDIV  => fabricClk_i,        -- 1-bit input FPGA logic domain clock input
    D       => s_Data_i_d_d,       -- 1-bit input Input data
    IOCE    => strobe_i,           -- 1-bit input Data strobe_i input
    RST     => serdes_reset_i,     -- 1-bit input Asynchronous reset_i input
    SHIFTIN => '0'                 -- 1-bit input Cascade input signal for master/slave I/O
   );

reg_out : process(fabricClk_i)
begin
  if rising_edge(fabricClk_i) then
    Data_o <= s_Data_o;
  end if;
end process;

END ARCHITECTURE rtl;

