-- ----------------------------------------------------------------------------- -- Copyright (c) 2013 Benjamin Krill -- -- 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; use work.dvi_package.all; library UNISIM; use UNISIM.Vcomponents.all; entity phsaligner is generic ( OPENEYE_CNT_WD : integer := 3; -- valid open eye counter width CTKNCNTWD : integer := 7; -- Control Token Counter Width SRCHTIMERWD : integer := 12 -- Idle Timer Width ); port ( rst_n : in std_logic; clk : in std_logic; sdata_i : in std_logic_vector(9 downto 0); flipgear_o : out std_logic; bitslip_o : out std_logic; psaligned_o : out std_logic ); end phsaligner; architecture phsaligner of phsaligner is signal flipgear : std_logic; signal bitslip : std_logic; signal psaligned : std_logic; signal rcvd_ctkn : std_logic; signal rcvd_ctkn_q : std_logic; signal blnkbgn : std_logic; -- blank period begins signal ctkn_srh_timer : unsigned(SRCHTIMERWD-1 downto 0); signal ctkn_srh_rst : std_logic; -- FSM output signal ctkn_counter : unsigned(CTKNCNTWD-1 downto 0); signal ctkn_cnt_rst : std_logic; -- FSM output signal ctkn_srh_tout : std_logic; signal ctkn_cnt_tout : std_logic; constant BLNKPRD_CNT_WD : integer := 1; signal blnkprd_cnt : unsigned(BLNKPRD_CNT_WD-1 downto 0) := (others => '0'); signal bitslip_cnt : unsigned(2 downto 0); type sm_t is (INIT, SEARCH, BITSLIPS, RCVDCTKN, BLNKPRD, PSALGND); signal sm_c : sm_t; signal sm_n : sm_t; begin flipgear_o <= flipgear; bitslip_o <= bitslip; psaligned_o <= psaligned; -- ---------------------------------------------------------- -- Control Token Detection -- ---------------------------------------------------------- process (clk, rst_n) begin if rst_n = '0' then rcvd_ctkn <= '0'; rcvd_ctkn_q <= '0'; blnkbgn <= '0'; elsif rising_edge(clk) then rcvd_ctkn <= '0'; if sdata_i = CTRLTOKEN0 or sdata_i = CTRLTOKEN1 or sdata_i = CTRLTOKEN2 or sdata_i = CTRLTOKEN3 then rcvd_ctkn <= '1'; end if; rcvd_ctkn_q <= rcvd_ctkn; blnkbgn <= rcvd_ctkn and not rcvd_ctkn_q; end if; end process; -- ---------------------------------------------------------- -- Control Token Search Timer -- -- DVI 1.0 Spec. says periodic blanking should start -- no less than every 50ms or 20HZ -- 2^24 of 74.25MHZ cycles is about 200ms -- ---------------------------------------------------------- process (clk, rst_n) begin if rst_n = '0' then ctkn_srh_timer <= (others => '0'); ctkn_srh_tout <= '0'; elsif rising_edge(clk) then if ctkn_srh_rst = '1' then ctkn_srh_timer <= (others => '0'); else ctkn_srh_timer <= ctkn_srh_timer + "1"; end if; ctkn_srh_tout <= '0'; if ctkn_srh_timer = (SRCHTIMERWD-1 downto 0 => '1') then ctkn_srh_tout <= '1'; end if; end if; end process; -- ---------------------------------------------------------- -- Contorl Token Event Counter -- -- DVI 1.0 Spec. says the minimal blanking period -- is at least 128 pixels long in order to achieve -- synchronization -- -- HDMI reduces this to as little as 8 -- ---------------------------------------------------------- process (clk, rst_n) begin if rst_n = '0' then ctkn_counter <= (others => '0'); ctkn_cnt_tout <= '0'; elsif rising_edge(clk) then if ctkn_cnt_rst = '1' then ctkn_counter <= (others => '0'); else ctkn_counter <= ctkn_counter + "1"; end if; ctkn_cnt_tout <= '0'; if ctkn_srh_timer = (CTKNCNTWD-1 downto 0 => '1') then ctkn_cnt_tout <= '1'; end if; end if; end process; -- ---------------------------------------------------------- -- Below starts the phase alignment state machine -- ---------------------------------------------------------- process (clk, rst_n) begin if rst_n = '0' then sm_c <= INIT; elsif rising_edge(clk) then sm_c <= sm_n; end if; end process; -- ---------------------------------------------------------- -- Counter counts number of blank period detected -- in order to qualify the bitslip position -- ---------------------------------------------------------- process (clk, rst_n) begin if rst_n = '0' then sm_n <= INIT; elsif rising_edge(clk) then case sm_c is when INIT => if ctkn_srh_tout = '1' then sm_n <= SEARCH; end if; when SEARCH => if blnkbgn = '1' then sm_n <= RCVDCTKN; elsif ctkn_srh_tout = '1' then sm_n <= BITSLIPS; end if; when BITSLIPS => sm_n <= SEARCH; when RCVDCTKN => if rcvd_ctkn = '1' then if ctkn_cnt_tout = '1' then sm_n <= BLNKPRD; end if; else sm_n <= SEARCH; end if; when BLNKPRD => if blnkprd_cnt = (BLNKPRD_CNT_WD-1 downto 0 => '1') then sm_n <= PSALGND; else sm_n <= SEARCH; end if; when PSALGND => sm_n <= PSALGND; -- Phase aligned so hang around here end case; end if; end process; process (clk, rst_n) begin if rst_n = '0' then psaligned <= '0'; -- phase alignment success flag bitslip <= '0'; ctkn_srh_rst <= '1'; -- control token search timer reset ctkn_cnt_rst <= '1'; -- control token counter reset bitslip_cnt <= (others => '0'); flipgear <= '0'; blnkprd_cnt <= (others => '0'); elsif rising_edge(clk) then case sm_c is when INIT => ctkn_srh_rst <= '0'; ctkn_cnt_rst <= '1'; psaligned <= '0'; bitslip <= '0'; bitslip_cnt <= (others => '0'); flipgear <= '0'; blnkprd_cnt <= (others => '0'); when SEARCH => ctkn_srh_rst <= '0'; ctkn_cnt_rst <= '1'; bitslip <= '0'; psaligned <= '0'; when BITSLIPS => ctkn_srh_rst <= '1'; bitslip <= '1'; bitslip_cnt <= bitslip_cnt + "1"; flipgear <= bitslip_cnt(2); -- bitslip has toggled for 4 times when RCVDCTKN => ctkn_srh_rst <= '0'; ctkn_cnt_rst <= '0'; when BLNKPRD => blnkprd_cnt <= blnkprd_cnt + "1"; when PSALGND => psaligned <= '1'; end case; end if; end process; end phsaligner;