hdmi/serdes_1_to_5_diff_data.vhd

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;