342 lines
11 KiB
VHDL
342 lines
11 KiB
VHDL
-- -----------------------------------------------------------------------------
|
|
-- Copyright (c) 2013 Benjamin Krill <benjamin@krll.de>
|
|
--
|
|
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
-- of this software and associated documentation files (the "Software"), to deal
|
|
-- in the Software without restriction, including without limitation the rights
|
|
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
-- copies of the Software, and to permit persons to whom the Software is
|
|
-- furnished to do so, subject to the following conditions:
|
|
--
|
|
-- The above copyright notice and this permission notice shall be included in
|
|
-- all copies or substantial portions of the Software.
|
|
--
|
|
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
-- THE SOFTWARE.
|
|
-- -----------------------------------------------------------------------------
|
|
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
|
|
library UNISIM;
|
|
use UNISIM.Vcomponents.all;
|
|
|
|
entity serdes_1_to_5_diff_data is
|
|
generic (
|
|
DIFF_TERM : boolean := true;
|
|
SIM_TAP_DELAY : integer := 49;
|
|
BITSLIP_ENABLE : boolean := false );
|
|
port (
|
|
rst : in std_logic; -- Reset line
|
|
gclk : in std_logic; -- Global clock
|
|
rxioclk_i : in std_logic; -- IO Clock network
|
|
datain_p : in std_logic; -- Input from LVDS receiver pin
|
|
datain_n : in std_logic; -- Input from LVDS receiver pin
|
|
use_phase_detector_i : in std_logic; -- '1' enables the phase detector logic
|
|
rxserdesstrobe_i : in std_logic; -- Parallel data capture strobe
|
|
bitslip_i : in std_logic; -- Bitslip control line
|
|
data_o : out std_logic_vector(4 downto 0) -- Output data
|
|
);
|
|
end serdes_1_to_5_diff_data;
|
|
|
|
architecture serdes_1_to_5_diff_data of serdes_1_to_5_diff_data is
|
|
type sm_cal_t is (IDLE, CALIBRATE, IODELAY_RST, IODELAY_WAIT,
|
|
IODELAY_WAIT_OCCASIONAL_ENABLE, CAL_SLAVE,
|
|
WAIT_COMMAND_ACCEPTED, IODELAY_WAIT_ALL);
|
|
signal sm_cal : sm_cal_t;
|
|
|
|
signal cal_cnt : unsigned(8 downto 0);
|
|
signal cal_enable : std_logic;
|
|
signal data_in : std_logic;
|
|
signal data_cal_master : std_logic;
|
|
signal data_cal_sint : std_logic;
|
|
signal data_busy : std_logic;
|
|
signal data_busy_q : std_logic;
|
|
signal data_rst : std_logic;
|
|
signal data_flag : std_logic;
|
|
signal data_ce : std_logic;
|
|
signal data_inc : std_logic;
|
|
signal data_ce_int : std_logic;
|
|
signal data_valid : std_logic;
|
|
signal data_valid_q : std_logic;
|
|
signal data_incdec : std_logic;
|
|
signal data_incdec_q : std_logic;
|
|
signal pdcounter : unsigned(4 downto 0);
|
|
signal ddly_s : std_logic;
|
|
signal ddly_m : std_logic;
|
|
signal pd_edge : std_logic;
|
|
signal cascade : std_logic;
|
|
begin
|
|
-- ----------------------------------------------------------
|
|
-- IDELAY Calibration FSM
|
|
-- ----------------------------------------------------------
|
|
process (gclk, rst)
|
|
begin
|
|
if rst = '1' then
|
|
sm_cal <= IDLE;
|
|
cal_cnt <= (others => '0');
|
|
cal_enable <= '0';
|
|
data_cal_master <= '0';
|
|
data_cal_sint <= '0';
|
|
data_rst <= '0';
|
|
elsif rising_edge(gclk) then
|
|
cal_cnt <= cal_cnt + 1;
|
|
if cal_cnt(8) = '1' then
|
|
cal_cnt <= (others => '0');
|
|
end if;
|
|
cal_enable <= cal_enable;
|
|
if cal_cnt(5) = '1' then
|
|
cal_enable <= '1';
|
|
end if;
|
|
|
|
case sm_cal is
|
|
when IDLE =>
|
|
if cal_enable = '1' then
|
|
data_cal_master <= '0';
|
|
data_cal_sint <= '0';
|
|
data_rst <= '0';
|
|
if data_busy_q = '0' then
|
|
sm_cal <= CALIBRATE;
|
|
end if;
|
|
end if;
|
|
when CALIBRATE =>
|
|
data_cal_master <= '1';
|
|
data_cal_sint <= '1';
|
|
if data_busy_q = '1' then
|
|
sm_cal <= IODELAY_RST;
|
|
end if;
|
|
when IODELAY_RST =>
|
|
data_cal_master <= '0';
|
|
data_cal_sint <= '0';
|
|
if data_busy_q = '0' then
|
|
data_rst <= '1';
|
|
sm_cal <= IODELAY_WAIT;
|
|
end if;
|
|
when IODELAY_WAIT =>
|
|
data_rst <= '0';
|
|
if data_busy_q = '0' then
|
|
sm_cal <= IODELAY_WAIT_OCCASIONAL_ENABLE;
|
|
end if;
|
|
when IODELAY_WAIT_OCCASIONAL_ENABLE =>
|
|
if cal_cnt(8) = '1' then
|
|
sm_cal <= CAL_SLAVE;
|
|
end if;
|
|
when CAL_SLAVE =>
|
|
if data_busy_q = '0' then
|
|
data_cal_sint <= '1';
|
|
sm_cal <= WAIT_COMMAND_ACCEPTED;
|
|
end if;
|
|
when WAIT_COMMAND_ACCEPTED =>
|
|
data_cal_sint <= '0';
|
|
if data_busy_q = '1' then
|
|
sm_cal <= IODELAY_WAIT_ALL;
|
|
end if;
|
|
when IODELAY_WAIT_ALL =>
|
|
data_cal_sint <= '0';
|
|
if data_busy_q = '0' then
|
|
sm_cal <= IODELAY_WAIT_OCCASIONAL_ENABLE;
|
|
end if;
|
|
end case;
|
|
end if;
|
|
end process;
|
|
|
|
-- Per-bit phase detection state machine
|
|
process (gclk, rst)
|
|
begin
|
|
if rst = '1' then
|
|
data_busy_q <= '0';
|
|
data_flag <= '0';
|
|
pdcounter <= "10000";
|
|
elsif rising_edge(gclk) then
|
|
data_busy_q <= data_busy;
|
|
|
|
if use_phase_detector_i = '1' then
|
|
data_incdec_q <= data_incdec;
|
|
data_valid_q <= data_valid;
|
|
|
|
if data_ce_int = '1' then
|
|
data_ce <= '1';
|
|
else
|
|
data_ce <= '0';
|
|
end if;
|
|
|
|
if sm_cal = IODELAY_WAIT_ALL then
|
|
data_flag <= '0';
|
|
elsif sm_cal /= IODELAY_WAIT_OCCASIONAL_ENABLE or data_busy_q = '1' then
|
|
-- Reset filter if state machine issues a cal command or unit is busy
|
|
pdcounter <= "10000";
|
|
data_ce_int <= '0';
|
|
elsif pdcounter = "11111" and data_flag = '0' then
|
|
-- Filter has reached positive max - increment the tap count
|
|
data_ce_int <= '1';
|
|
data_inc <= '1';
|
|
data_flag <= '1';
|
|
pdcounter <= "10000";
|
|
elsif pdcounter = "00000" and data_flag = '0' then
|
|
-- Filter has reached negative max - decrement the tap count
|
|
data_ce_int <= '1';
|
|
data_inc <= '0';
|
|
data_flag <= '1';
|
|
pdcounter <= "10000";
|
|
elsif data_valid_q = '1' then
|
|
-- increment filter
|
|
data_ce_int <= '0';
|
|
if data_incdec_q = '1' and pdcounter /= "11111" then
|
|
pdcounter <= pdcounter + "00001";
|
|
elsif data_incdec_q = '0' and pdcounter /= "00000" then
|
|
-- decrement filter
|
|
pdcounter <= pdcounter + "11111";
|
|
end if;
|
|
else
|
|
data_ce_int <= '0';
|
|
end if;
|
|
else
|
|
data_ce <= '0';
|
|
--data_inc <= '0';
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
data_in_0: IBUFDS
|
|
generic map ( DIFF_TERM => DIFF_TERM )
|
|
port map ( I => datain_p, IB => datain_n, O => data_in );
|
|
|
|
-- ----------------------------------------------------------
|
|
-- Master IDELAY
|
|
-- ----------------------------------------------------------
|
|
iodelay_m: IODELAY2
|
|
generic map (
|
|
DATA_RATE => "SDR",
|
|
IDELAY_VALUE => 0,
|
|
IDELAY2_VALUE => 0,
|
|
IDELAY_MODE => "NORMAL",
|
|
ODELAY_VALUE => 0,
|
|
IDELAY_TYPE => "DIFF_PHASE_DETECTOR",
|
|
COUNTER_WRAPAROUND => "STAY_AT_LIMIT", --("WRAPAROUND"),
|
|
DELAY_SRC => "IDATAIN",
|
|
SERDES_MODE => "MASTER",
|
|
SIM_TAPDELAY_VALUE => SIM_TAP_DELAY)
|
|
port map (
|
|
IDATAIN => data_in, -- data from IBUFDS
|
|
TOUT => open, -- tri-state signal to IOB
|
|
DOUT => open, -- output data to IOB
|
|
T => '1', -- tri-state control from OLOGIC/OSERDES2
|
|
ODATAIN => '0', -- data from OLOGIC/OSERDES2
|
|
DATAOUT => ddly_m, -- Output data 1 to ILOGIC/ISERDES2
|
|
DATAOUT2 => open, -- Output data 2 to ILOGIC/ISERDES2
|
|
IOCLK0 => rxioclk_i, -- High speed clock for calibration
|
|
IOCLK1 => '0', -- High speed clock for calibration
|
|
CLK => gclk, -- Fabric clock (GCLK) for control signals
|
|
CAL => data_cal_master, -- Calibrate control signal
|
|
INC => data_inc, -- Increment counter
|
|
CE => data_ce, -- Clock Enable
|
|
RST => data_rst, -- Reset delay line
|
|
BUSY => open -- output signal indicating sync circuit has finished / calibration has finished
|
|
);
|
|
|
|
-- ----------------------------------------------------------
|
|
-- Slave IDELAY
|
|
-- ----------------------------------------------------------
|
|
iodelay_s: IODELAY2
|
|
generic map (
|
|
DATA_RATE => "SDR",
|
|
IDELAY_VALUE => 0,
|
|
IDELAY2_VALUE => 0,
|
|
IDELAY_MODE => "NORMAL",
|
|
ODELAY_VALUE => 0,
|
|
IDELAY_TYPE => "DIFF_PHASE_DETECTOR",
|
|
COUNTER_WRAPAROUND => "WRAPAROUND",
|
|
DELAY_SRC => "IDATAIN",
|
|
SERDES_MODE => "SLAVE",
|
|
SIM_TAPDELAY_VALUE => SIM_TAP_DELAY)
|
|
port map (
|
|
IDATAIN => data_in, -- data from IBUFDS
|
|
TOUT => open, -- tri-state signal to IOB
|
|
DOUT => open, -- output data to IOB
|
|
T => '1', -- tri-state control from OLOGIC/OSERDES2
|
|
ODATAIN => '0', -- data from OLOGIC/OSERDES2
|
|
DATAOUT => ddly_s, -- Slave output data to ILOGIC/ISERDES2
|
|
DATAOUT2 => open, --
|
|
IOCLK0 => rxioclk_i, -- High speed IO clock for calibration
|
|
IOCLK1 => '0',
|
|
CLK => gclk, -- Fabric clock (GCLK) for control signals
|
|
CAL => data_cal_sint, -- Calibrate control signal
|
|
INC => data_inc, -- Increment counter
|
|
CE => data_ce, -- Clock Enable
|
|
RST => data_rst, -- Reset delay line
|
|
BUSY => data_busy -- output signal indicating sync circuit has finished / calibration has finished
|
|
);
|
|
|
|
-- ----------------------------------------------------------
|
|
-- Master ISERDES
|
|
-- ----------------------------------------------------------
|
|
iserdes_m: ISERDES2
|
|
generic map (
|
|
DATA_WIDTH => 5,
|
|
DATA_RATE => "SDR",
|
|
BITSLIP_ENABLE => BITSLIP_ENABLE,
|
|
SERDES_MODE => "MASTER",
|
|
INTERFACE_TYPE => "RETIMED")
|
|
port map (
|
|
D => ddly_m,
|
|
CE0 => '1',
|
|
CLK0 => rxioclk_i,
|
|
CLK1 => '0',
|
|
IOCE => rxserdesstrobe_i,
|
|
RST => rst,
|
|
CLKDIV => gclk,
|
|
SHIFTIN => pd_edge,
|
|
BITSLIP => bitslip_i,
|
|
FABRICOUT => open,
|
|
Q4 => data_o(4),
|
|
Q3 => data_o(3),
|
|
Q2 => data_o(2),
|
|
Q1 => data_o(1),
|
|
DFB => open,
|
|
CFB0 => open,
|
|
CFB1 => open,
|
|
VALID => data_valid,
|
|
INCDEC => data_incdec,
|
|
SHIFTOUT => cascade
|
|
);
|
|
|
|
-- ----------------------------------------------------------
|
|
-- Slave ISERDES
|
|
-- ----------------------------------------------------------
|
|
iserdes_s: ISERDES2
|
|
generic map (
|
|
DATA_WIDTH => 5,
|
|
DATA_RATE => "SDR",
|
|
BITSLIP_ENABLE => BITSLIP_ENABLE,
|
|
SERDES_MODE => "SLAVE",
|
|
INTERFACE_TYPE => "RETIMED")
|
|
port map (
|
|
D => ddly_s,
|
|
CE0 => '1',
|
|
CLK0 => rxioclk_i,
|
|
CLK1 => '0',
|
|
IOCE => rxserdesstrobe_i,
|
|
RST => rst,
|
|
CLKDIV => gclk,
|
|
SHIFTIN => cascade,
|
|
BITSLIP => bitslip_i,
|
|
FABRICOUT => open,
|
|
Q4 => data_o(0),
|
|
Q3 => open,
|
|
Q2 => open,
|
|
Q1 => open,
|
|
DFB => open,
|
|
CFB0 => open,
|
|
CFB1 => open,
|
|
VALID => open,
|
|
INCDEC => open,
|
|
SHIFTOUT => pd_edge
|
|
);
|
|
|
|
end serdes_1_to_5_diff_data;
|