276 lines
9.4 KiB
VHDL
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;
|