321 lines
10 KiB
VHDL
321 lines
10 KiB
VHDL
|
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;
|