-- -----------------------------------------------------------------------------
-- 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 work;
use work.dvi_package.all;

library UNISIM;
use UNISIM.Vcomponents.all;

entity ddr2dvi is
	port (
		clk                   : in  std_logic;
		rst_n                 : in  std_logic;
		rst_pll               : in  std_logic;

		tx_tmds               : out std_logic_vector(3 downto 0);
		tx_tmds_n             : out std_logic_vector(3 downto 0);
		tx_pll_locked_o       : out std_logic;

		-- memory interface
		ddr2_cmd_en_o         : out std_logic;
		ddr2_cmd_instr_o      : out std_logic_vector( 2 downto 0);
		ddr2_cmd_bl_o         : out std_logic_vector( 5 downto 0);
		ddr2_cmd_byte_addr_o  : out std_logic_vector(29 downto 0);
		ddr2_cmd_empty_i      : in  std_logic;
		ddr2_cmd_full_i       : in  std_logic;

		ddr2_rd_en_o          : out std_logic;
		ddr2_rd_data_i        : in  std_logic_vector(31 downto 0);
		ddr2_rd_full_i        : in  std_logic;
		ddr2_rd_empty_i       : in  std_logic;
		ddr2_rd_count_i       : in  std_logic_vector( 6 downto 0);
		ddr2_rd_overflow_i    : in  std_logic;
		ddr2_rd_error_i       : in  std_logic
	);
end ddr2dvi;

architecture ddr2dvi of ddr2dvi is
	signal pclk                     : std_logic;
	signal pclk_buf                 : std_logic;
	signal tx_hsync                 : std_logic;
	signal tx_vsync                 : std_logic;
	signal tx_color_en              : std_logic;
	signal tx_color                 : color_t(COLOR_CNT-1 downto 0);
	signal tx_pclkx2                : std_logic;
	signal tx_pclkx10               : std_logic;
	signal tx_reset_n               : std_logic;
	signal tx_serdesstrobe          : std_logic;
	signal tx_clkfbout              : std_logic;
	signal tx_clkfbin               : std_logic;
	signal tx_plllckd               : std_logic;
	signal tx_pllclk0               : std_logic;
	signal tx_pllclk2               : std_logic;
	signal tx_bufpll_lock           : std_logic;
begin
	tx_pll_locked_o <= tx_plllckd;

	-- ----------------------------------------------------------------------------
	-- DDR2 READ Signal Generator
	-- ----------------------------------------------------------------------------
	sig_read_0: entity work.sig_read
	generic map (
		MEM_START_ADR  => "00" & x"0000000",
		H_ACTIVE_PIXEL => x"500",
		H_BLANKING     => x"198",
		H_SYNC_WIDTH   => x"070",
		H_SYNC_OFFSET  => x"030",
		V_ACTIVE_LINES => x"400",
		V_BLANKING     => x"02a",
		V_SYNC_WIDTH   => x"01",
		V_SYNC_OFFSET  => x"03"
	)
	port map (
		clk                   => pclk,
		rst_n                 => rst_n,

		-- memory interface
		ddr2_clk              => clk,
		ddr2_cmd_en_o         => ddr2_cmd_en_o,
		ddr2_cmd_instr_o      => ddr2_cmd_instr_o,
		ddr2_cmd_bl_o         => ddr2_cmd_bl_o,
		ddr2_cmd_byte_addr_o  => ddr2_cmd_byte_addr_o,
		ddr2_cmd_empty_i      => ddr2_cmd_empty_i,
		ddr2_cmd_full_i       => ddr2_cmd_full_i,

		ddr2_rd_en_o          => ddr2_rd_en_o,
		ddr2_rd_data_i        => ddr2_rd_data_i,
		ddr2_rd_full_i        => ddr2_rd_full_i,
		ddr2_rd_empty_i       => ddr2_rd_empty_i,
		ddr2_rd_count_i       => ddr2_rd_count_i,
		ddr2_rd_overflow_i    => ddr2_rd_overflow_i,
		ddr2_rd_error_i       => ddr2_rd_error_i,

		en_stb_i              => '1',
		hsync_o               => tx_hsync,
		vsync_o               => tx_vsync,
		color_en_o            => tx_color_en,
		color_o               => tx_color
	);

	-- ----------------------------------------------------------------------------
	-- Instantiate a dedicate PLL for output port
	-- ----------------------------------------------------------------------------
	--pclk <= ddr2_clk_out;
	pll_oserdes_0: PLL_BASE
	generic map (
		CLKIN_PERIOD   => 9.0,
		CLKFBOUT_MULT  => 29, --10 --set VCO to 10x of CLKIN
		DIVCLK_DIVIDE  => 3,
		CLKOUT0_DIVIDE => 1,
		CLKOUT1_DIVIDE => 10,
		CLKOUT2_DIVIDE => 5,
		COMPENSATION   => "SOURCE_SYNCHRONOUS"
	)
	port map (
		CLKFBOUT  => tx_clkfbout,
		CLKOUT0   => tx_pllclk0,
		CLKOUT1   => pclk_buf,
		CLKOUT2   => tx_pllclk2,
		CLKOUT3   => open,
		CLKOUT4   => open,
		CLKOUT5   => open,
		LOCKED    => tx_plllckd,
		CLKFBIN   => tx_clkfbin,
		CLKIN     => clk,
		RST       => rst_pll
	);

	pclk_buf_0: BUFG port map(I => pclk_buf, O => pclk);

	-- ----------------------------------------------------------------------------
	-- 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
	-- ----------------------------------------------------------------------------
	tx_clkfb_buf: BUFG port map(I => tx_clkfbout, O => tx_clkfbin);

	-- --------------------------------
	-- regenerate pclkx2 for TX
	-- --------------------------------
	tx_pclkx2_buf: BUFG port map(I => tx_pllclk2, O => tx_pclkx2);

	-- --------------------------------
	-- regenerate pclkx10 for TX
	-- --------------------------------
	tx_ioclk_buf: BUFPLL
	generic map ( DIVIDE => 5 )
	port map (
		PLLIN        => tx_pllclk0,
		GCLK         => tx_pclkx2,
		LOCKED       => tx_plllckd,
		IOCLK        => tx_pclkx10,
		SERDESSTROBE => tx_serdesstrobe,
		LOCK         => tx_bufpll_lock
	);
	tx_reset_n <= tx_bufpll_lock;

	dvi_encoder_0: entity work.dvi_encoder
	port map (
		rst_n          => tx_reset_n,
		pclk           => pclk,
		pclkx2         => tx_pclkx2,
		pclkx10        => tx_pclkx10,
		serdesstrobe_i => tx_serdesstrobe,
		color_i        => tx_color,
		hsync_i        => tx_hsync,
		vsync_i        => tx_vsync,
		dat_en_i       => tx_color_en,
		tmds_p         => tx_tmds,
		tmds_n         => tx_tmds_n
	);

end ddr2dvi;
