hdmi/phsaligner.vhd

243 lines
7.1 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;
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;