hdet/fpga/src/top/atlys.vhd

276 lines
9.4 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 work;
use work.all;
library UNISIM;
use UNISIM.Vcomponents.all;
entity atlys is
generic ( MODE : string := "encode");
--generic ( MODE : string := "direct");
port (
rstbtn_n : in std_logic; -- The pink reset button
clk100 : in std_logic; -- 100 MHz osicallator
tx0_tmds : out std_logic_vector(3 downto 0);
tx0_tmds_n : out std_logic_vector(3 downto 0);
rx0_tmds : in std_logic_vector(3 downto 0);
rx0_tmds_n : in std_logic_vector(3 downto 0);
rx0_sda : inout std_logic;
rx0_scl : in std_logic;
tx1_tmds : out std_logic_vector(3 downto 0);
tx1_tmds_n : out std_logic_vector(3 downto 0);
rx1_tmds : in std_logic_vector(3 downto 0);
rx1_tmds_n : in std_logic_vector(3 downto 0);
switch : in std_logic_vector(1 downto 0);
led : out std_logic_vector(7 downto 0)
);
end atlys;
architecture top of atlys is
signal rstbtn : std_logic;
signal rst_n : std_logic;
signal rst : std_logic;
signal pclk : std_logic;
signal pclkx2 : std_logic;
signal pclkx10 : std_logic;
signal pllclk1 : std_logic;
signal pllclk1bg : std_logic;
signal pll_lckd : std_logic;
signal serdesstrobe : std_logic;
signal tmdsclk : std_logic;
signal hsync : std_logic;
signal vsync : std_logic;
signal dat_en : std_logic;
signal valid : std_logic_vector(COLOR_CNT-1 downto 0);
signal ready : std_logic_vector(COLOR_CNT-1 downto 0);
signal psalgnerr : std_logic;
signal color : color_t(COLOR_CNT-1 downto 0);
signal sdout : sdat_t(COLOR_CNT-1 downto 0);
signal rx0_sda_i : std_logic;
signal rx0_sda_o : std_logic;
signal rx0_tmds_s : std_logic_vector(3 downto 0);
signal toggle : std_logic;
signal tmdsclkint : std_logic_vector(4 downto 0);
type tmds_data_t is array(natural range <>) of std_logic_vector(4 downto 0);
signal tmds_data : tmds_data_t(COLOR_CNT-1 downto 0);
signal tmdsint : std_logic_vector(2 downto 0);
signal tmds_clk : std_logic;
signal sdata : std_logic_vector(29 downto 0);
signal tx0_pclkx2 : std_logic;
signal tx0_pclkx10 : std_logic;
signal tx0_reset_n : std_logic;
signal tx0_serdesstrobe : std_logic;
signal tx0_clkfbout : std_logic;
signal tx0_clkfbin : std_logic;
signal tx0_plllckd : std_logic;
signal tx0_pllclk0 : std_logic;
signal tx0_pllclk2 : std_logic;
signal tx0_bufpll_lock : std_logic;
begin
rstbtn <= not rstbtn_n;
rst <= not rst_n;
led <= ready(RED) & ready(GREEN) & ready(BLUE) & valid(RED) & valid(GREEN) & valid(BLUE) & dat_en & rst_n;
dvi_decoder_0: entity work.dvi_decoder
port map (
ext_rst => rstbtn,
tmdsclk_p => rx0_tmds(3),
tmdsclk_n => rx0_tmds_n(3),
din_p => rx0_tmds(2 downto 0),
din_n => rx0_tmds_n(2 downto 0),
reset_n => rst_n, -- rx reset
pclk_o => pclk, -- regenerated pixel clock
pclkx2_o => pclkx2, -- double rate pixel clock
pclkx10_o => pclkx10, -- 10x pixel as IOCLK
pll_lckd_o => pll_lckd, -- send pll_lckd out so it can be fed into a different BUFPLL
serdesstrobe_o => serdesstrobe, -- BUFPLL serdesstrobe output
tmdsclk_o => tmdsclk, -- TMDS cable clock
hsync_o => hsync, -- hsync data
vsync_o => vsync, -- vsync data
dat_en_o => dat_en, -- data enable
valid_o => valid,
ready_o => ready,
psalgnerr_o => psalgnerr,
sdout_o => sdout,
color_o => color
);
direct: if MODE = "direct" generate
-- ----------------------------------------------------------
-- Forward TMDS Clock Using OSERDES2 block
-- ----------------------------------------------------------
process (pclkx2, rst_n)
begin
if rst_n = '0' then
toggle <= '0';
tmdsclkint <= (others => '0');
elsif rising_edge(pclkx2) then
toggle <= not toggle;
if toggle = '1' then
tmdsclkint <= (others => '1');
else
tmdsclkint <= (others => '0');
end if;
end if;
end process;
clkout: entity work.serdes_n_to_1
generic map (SF => 5)
port map (
ioclk => pclkx10,
gclk => pclkx2,
rst => rst,
serdesstrobe_i => serdesstrobe,
data_i => tmdsclkint,
data_o => tmds_clk
);
TMDS3: OBUFDS port map (I => tmds_clk, O => tx0_tmds(3), OB => tx0_tmds_n(3)); -- clock
d: for I in 0 to COLOR_CNT-1 generate
outI: entity work.serdes_n_to_1
generic map (SF => 5)
port map (
ioclk => pclkx10,
gclk => pclkx2,
rst => rst,
serdesstrobe_i => serdesstrobe,
data_i => tmds_data(I),
data_o => tmdsint(I)
);
tx_tmdsI: OBUFDS port map (i => tmdsint(I), o => tx0_tmds(I), ob => tx0_tmds_n(I));
end generate;
sdata <= sdout(RED)(9 downto 5) & sdout(GREEN)(9 downto 5) & sdout(BLUE)(9 downto 5)
& sdout(RED)(4 downto 0) & sdout(GREEN)(4 downto 0) & sdout(BLUE)(4 downto 0);
pixel2x: entity work.convert_30to15_fifo
port map (
rst => rst,
clk => pclk,
clkx2 => pclkx2,
data_i => sdata,
data_o( 4 downto 0) => tmds_data(0),
data_o( 9 downto 5) => tmds_data(1),
data_o(14 downto 10) => tmds_data(2)
);
end generate;
decode: if MODE = "encode" generate
-- ----------------------------------------------------------------------------
-- Instantiate a dedicate PLL for output port
-- ----------------------------------------------------------------------------
pll_oserdes_0: PLL_BASE
generic map (
CLKIN_PERIOD => 10.0,
CLKFBOUT_MULT => 10, --set VCO to 10x of CLKIN
CLKOUT0_DIVIDE => 1,
CLKOUT1_DIVIDE => 10,
CLKOUT2_DIVIDE => 5,
COMPENSATION => "SOURCE_SYNCHRONOUS"
)
port map (
CLKFBOUT => tx0_clkfbout,
CLKOUT0 => tx0_pllclk0,
CLKOUT1 => open,
CLKOUT2 => tx0_pllclk2,
CLKOUT3 => open,
CLKOUT4 => open,
CLKOUT5 => open,
LOCKED => tx0_plllckd,
CLKFBIN => tx0_clkfbin,
CLKIN => pclk, -- pllclk1bg,
RST => rst
);
-- ----------------------------------------------------------------------------
-- This BUFG is needed in order to deskew between PLL clkin and clkout
-- So the tx0 pclkx2 and pclkx10 will have the same phase as the pclk input
-- ----------------------------------------------------------------------------
tx0_clkfb_buf: BUFG port map(I => tx0_clkfbout, O => tx0_clkfbin);
-- --------------------------------
-- regenerate pclkx2 for TX
-- --------------------------------
tx0_pclkx2_buf: BUFG port map(I => tx0_pllclk2, O => tx0_pclkx2);
-- --------------------------------
-- regenerate pclkx10 for TX
-- --------------------------------
tx0_ioclk_buf: BUFPLL
generic map ( DIVIDE => 5 )
port map (
PLLIN => tx0_pllclk0,
GCLK => tx0_pclkx2,
LOCKED => tx0_plllckd,
IOCLK => tx0_pclkx10,
SERDESSTROBE => tx0_serdesstrobe,
LOCK => tx0_bufpll_lock
);
tx0_reset_n <= tx0_bufpll_lock;
dvi_encoder_0: entity work.dvi_encoder
port map (
rst_n => tx0_reset_n,
pclk => pclk,
pclkx2 => tx0_pclkx2,
pclkx10 => tx0_pclkx10,
serdesstrobe_i => tx0_serdesstrobe,
color_i => color,
hsync_i => hsync,
vsync_i => vsync,
dat_en_i => dat_en,
tmds_p => tx0_tmds,
tmds_n => tx0_tmds_n
);
end generate;
-- ----------------------------------------------------------------------------
-- I2C EDID Emulation
-- ----------------------------------------------------------------------------
rx0_sda_i <= rx0_sda;
rx0_sda <= '0' when rx0_sda_o = '0' else 'Z';
i2c_rom_0: entity work.i2c_rom
port map (
clk => clk100,
rst_n => rstbtn_n,
sda_i => rx0_sda_i,
sda_o => rx0_sda_o,
scl_i => rx0_scl
);
end top;