-- Derived from: coregen/cg_io_deser_dly.vhd
--    (c) Copyright 2009 - 2011 Xilinx, Inc. All rights reserved.
-- 
--
-- Matt Warren 2014
------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_misc.all;
use ieee.numeric_std.all;

library unisim;
use unisim.vcomponents.all;

entity iserdes2_4b is
  generic
    (                                   -- width of the data for the system
      --sys_w               :     integer := 1;
      -- width of the data for the device
      dev_w : integer := 2);
  port
    (
      -- From the system into the device
      --DATA_IN_FROM_PINS_P : in  std_logic_vector(sys_w-1 downto 0);
      --DATA_IN_FROM_PINS_N : in  std_logic_vector(sys_w-1 downto 0);
      serdata_i : in std_logic;

      --DATA_IN_TO_DEVICE : out std_logic_vector(dev_w-1 downto 0);
      pardata_o             : out std_logic_vector(dev_w-1 downto 0);
      serdata_delayed_o : out std_logic;
-- Input, Output delay control signals
      DELAY_BUSY            : out std_logic;
      DELAY_CLK             : in  std_logic;
      delay_rst_i           : in  std_logic;
      DELAY_DATA_CAL        : in  std_logic;
      DELAY_DATA_CE         : in  std_logic;  -- Enable signal for delay 
      DELAY_DATA_INC        : in  std_logic;  -- Delay increment (high), decrement (low) signal
      BITSLIP               : in  std_logic;
-- Clock and reset signals
      --CLK_IN         : in  std_logic;   -- Single ended Fast clock from IOB
      clk_io_i              : in  std_logic;
      iserdes_strb_i        : in  std_logic;

      clk_fabric_i : in std_logic;
      --CLK_DIV_OUT    : out std_logic;   -- Slow clock output
      IO_RESET     : in std_logic       -- Reset signal for IO circuit
      );
end iserdes2_4b;

architecture rtl of iserdes2_4b is
-- attribute CORE_GENERATION_INFO : string;
-- attribute CORE_GENERATION_INFO of xilinx :
-- architecture is "cg_io_deser_dly, selectio_wiz_v4_1,
-- {
-- component_name = cg_io_deser_dly,
-- bus_dir = INPUTS,
-- bus_sig_type = DIFF,
-- bus_io_std = LVDS_25,
-- use_serialization = true,
-- use_phase_detector = false,
-- serialization_factor = 8,
-- enable_bitslip = true,
-- enable_train = false,
-- system_data_width = 1,
-- bus_in_delay = VARIABLE,
-- bus_out_delay = NONE,
-- clk_sig_type = SINGLE,
-- clk_io_std = LVCMOS12,
-- clk_buf = BUFIO2,
-- active_edge = RISING,
-- clk_delay = FIXED,
-- v6_bus_in_delay = NONE,
-- v6_bus_out_delay = NONE,
-- v6_clk_buf = BUFIO,
-- v6_active_edge = NOT_APP,
-- v6_ddr_alignment = SAME_EDGE_PIPELINED,
-- v6_oddr_alignment = SAME_EDGE, ddr_alignment = C0,
-- v6_interface_type = NETWORKING,
-- interface_type = RETIMED,
-- v6_bus_in_tap = 0, v6_bus_out_tap = 0,
-- v6_clk_io_std = LVCMOS18,
-- v6_clk_sig_type = DIFF
-- }";

  constant clock_enable : std_logic := '1';
  signal unused         : std_logic;
--  signal   clk_in_int       : std_logic;
  signal clk_div        : std_logic;
  signal clk_div_int    : std_logic;
  signal clk_in_int_buf : std_logic;
--  signal   clk_in_int_delay : std_logic;


  -- After the buffer
  signal data_in_from_pins_int   : std_logic;  --_vector(sys_w-1 downto 0);
  -- Between the delay and serdes
  signal data_in_from_pins_delay : std_logic;  --_vector(sys_w-1 downto 0);
  signal delay_data_busy         : std_logic;  --_vector(sys_w-1 downto 0);
  constant num_serial_bits       : integer                      := dev_w;  --/sys_w;
  --type serdarr is array (0 to 7) of std_logic_vector(sys_w-1 downto 0);
  -- Array to use intermediately from the serdes to the internal
  --  devices. bus "0" is the leftmost bus
  -- * fills in starting with 0
  signal iserdes_q               : std_logic_vector(7 downto 0) := (others => '0');  --serdarr := (( others => (others => '0')));
  signal serdesstrobe            : std_logic;
  signal icascade                : std_logic;  --_vector(sys_w-1 downto 0);
  signal slave_shiftout          : std_logic;  --_vector(sys_w-1 downto 0);



begin

  DELAY_BUSY <= delay_data_busy;        --or_reduce(delay_data_busy);


--   -- Create the clock logic
--   ibufg_clk_inst : IBUFG
--     generic map (
--       IOSTANDARD => "LVCMOS12")
--     port map (
--       I          => CLK_IN,
--       O          => clk_in_int);

--   -- delay the input clock
--   iodelay2_clk : IODELAY2
--     generic map (
--       DATA_RATE          => "SDR",
--       IDELAY_VALUE       => 0,
--       IDELAY_TYPE        => "FIXED",
--       COUNTER_WRAPAROUND => "STAY_AT_LIMIT",
--       DELAY_SRC          => "IDATAIN",
--       SERDES_MODE        => "NONE",
--       SIM_TAPDELAY_VALUE => 75)
--     port map (
--       -- required datapath
--       IDATAIN            => clk_in_int,
--       DATAOUT            => clk_in_int_delay,
--       T                  => '1',
--       -- inactive data connections
--       DATAOUT2           => open,
--       DOUT               => open,
--       ODATAIN            => '0',
--       TOUT               => open,
--       -- tie off the clocks
--       IOCLK0             => '0',        -- No calibration needed
--       IOCLK1             => '0',        -- No calibration needed
--       -- Tie of the variable delay programming
--       CLK                => '0',
--       CAL                => '0',
--       INC                => '0',
--       CE                 => '0',
--       BUSY               => open,
--       RST                => '0');

--   -- Set up the clock for use in the serdes
--   bufio2_inst : BUFIO2
--     generic map (
--       DIVIDE_BYPASS => false,
--       I_INVERT      => false,
--       USE_DOUBLER   => false,
--       DIVIDE        => 8)
--     port map (
--       DIVCLK        => clk_div,
--       IOCLK         => clk_in_int_buf,
--       SERDESSTROBE  => serdesstrobe,
--       I             => clk_in_int_delay);


  serdesstrobe   <= iserdes_strb_i;
  clk_in_int_buf <= clk_io_i;

--   -- Buffer up the divided clock
--   clkdiv_buf_inst : BUFG
--     port map (
--       O => clk_div_int,
--       I => clk_div);

--   CLK_DIV_OUT <= clk_div_int;
  clk_div_int <= clk_fabric_i;


  -- We have multiple bits- step over every bit, instantiating the required elements
  --pins          : for pin_count in 0 to sys_w-1 generate
  --begin
  -- Instantiate the buffers
  ----------------------------------
  -- Instantiate a buffer for every bit of the data bus
--  ibufds_inst : IBUFDS
--    generic map (
--      DIFF_TERM  => false,            -- Differential termination
--      IOSTANDARD => "LVDS_25")
--    port map (
--      I          => DATA_IN_FROM_PINS_P (pin_count),
--      IB         => DATA_IN_FROM_PINS_N (pin_count),
--      O          => data_in_from_pins_int(pin_count));

  data_in_from_pins_int <= serdata_i;

  -- Instantiate the delay primitive
  -----------------------------------
  iodelay2_bus : IODELAY2
    generic map (
      DATA_RATE          => "SDR",
      IDELAY_VALUE       => 0,
      IDELAY_TYPE        => "VARIABLE_FROM_ZERO",
      COUNTER_WRAPAROUND => "STAY_AT_LIMIT",
      DELAY_SRC          => "IDATAIN",
      SERDES_MODE        => "NONE",
      SIM_TAPDELAY_VALUE => 75
      )
    port map (
      -- required datapath
      IDATAIN  => data_in_from_pins_int,    -- (pin_count),
      DATAOUT  => data_in_from_pins_delay,  --(pin_count),
      T        => '1',
      -- inactive data connections
      DATAOUT2 => serdata_delayed_o,
      DOUT     => open,
      ODATAIN  => '0',
      TOUT     => open,
      -- connect up the clocks
      IOCLK0   => clk_in_int_buf,  -- High speed clock for calibration for SDR/DDR
      IOCLK1   => '0',             -- High speed clock for calibration for DDR
      CLK      => DELAY_CLK,
      CAL      => DELAY_DATA_CAL,
      INC      => DELAY_DATA_INC,
      CE       => DELAY_DATA_CE,
      BUSY     => delay_data_busy,      --(pin_count),
      RST      => delay_rst_i);



  -- Instantiate the serdes primitive
  ----------------------------------
  -- declare the iserdes
  iserdes2_master : ISERDES2
    generic map (
      BITSLIP_ENABLE => true,
      DATA_RATE      => "SDR",
      DATA_WIDTH     => 4,
      INTERFACE_TYPE => "RETIMED",
      SERDES_MODE    => "NONE")
    port map (
      Q1       => iserdes_q(3),         --(pin_count),
      Q2       => iserdes_q(2),         --(pin_count),
      Q3       => iserdes_q(1),         --(pin_count),
      Q4       => iserdes_q(0),         --(pin_count),
      SHIFTOUT => open,
      INCDEC   => open,
      VALID    => open,
      BITSLIP  => '0',  -- 1-bit Invoke Bitslip. This can be used with any DATA_WIDTH, cascaded or not.
      -- The amount of bitslip is fixed by the DATA_WIDTH selection.
      CE0      => clock_enable,         -- 1-bit Clock enable input
      CLK0     => clk_in_int_buf,  -- 1-bit IO Clock network input. Optionally Invertible. This is the primary clock
      -- input used when the clock doubler circuit is not engaged (see DATA_RATE
      -- attribute).
      CLK1     => '0',
      CLKDIV   => clk_div_int,  -- 1-bit Global clock network input. This is the clock for the fabric domain.
      D        => data_in_from_pins_delay,  --(pin_count),  -- 1-bit Input signal from IOB.
      IOCE     => serdesstrobe,  -- 1-bit Data strobe signal derived from BUFIO CE. Strobes data capture for
                                   -- NETWORKING and NETWORKING_PIPELINES alignment modes.

      RST     => IO_RESET,              -- 1-bit Asynchronous reset only.
      SHIFTIN => '0',                   --(pin_count),


      -- unused connections
      FABRICOUT => open,
      CFB0      => open,
      CFB1      => open,
      DFB       => open);




  -- Concatenate the serdes outputs together. Keep the timesliced
  --   bits together, and placing the earliest bits on the right
  --   ie, if data comes in 0, 1, 2, 3, 4, 5, 6, 7, ...
  --       the output will be 3210, 7654, ...
  -------------------------------------------------------------

  in_slices : for slice_count in 0 to num_serial_bits-1 generate
  begin
    -- This places the first data in time on the right
    --DATA_IN_TO_DEVICE(slice_count) <=
    --iserdes_q(num_serial_bits-slice_count-1)(0);
        -- To place the first data in time on the left, use the
            --   following code, instead
    --DATA_IN_TO_DEVICE(slice_count) <= iserdes_q(slice_count);
    pardata_o(slice_count) <= iserdes_q(slice_count);
  end generate in_slices;
--end generate pins;


end rtl;