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

library UNISIM;
use UNISIM.Vcomponents.all;

entity atlys_sig is
	port (
	rstbtn_n                   : in    std_logic; -- The pink reset button
	clk100                     : in    std_logic; -- 100 MHz osicallator

	-- HDMI
	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;

	-- DDR2
	ddr2_dq                    : inout std_logic_vector(15 downto 0);
	ddr2_a                     : out   std_logic_vector(12 downto 0);
	ddr2_ba                    : out   std_logic_vector( 2 downto 0);
	ddr2_ras_n                 : out   std_logic;
	ddr2_cas_n                 : out   std_logic;
	ddr2_we_n                  : out   std_logic;
	ddr2_odt                   : out   std_logic;
	ddr2_cke                   : out   std_logic;
	ddr2_dm                    : out   std_logic;
	ddr2_udqs                  : inout std_logic;
	ddr2_udqs_n                : inout std_logic;
	ddr2_rzq                   : inout std_logic;
	ddr2_zio                   : inout std_logic;
	ddr2_udm                   : out   std_logic;
	ddr2_dqs                   : inout std_logic;
	ddr2_dqs_n                 : inout std_logic;
	ddr2_clk                   : out   std_logic;
	ddr2_clk_n                 : out   std_logic;

	-- cypress interface
	usb_clk                    : in    std_logic;
	usb_flag_a                 : in    std_logic; -- programmable flag
	usb_flag_b                 : in    std_logic; -- full flag
	usb_flag_c                 : in    std_logic; -- empty flag
	usb_cs                     : inout std_logic; -- put to GND, not need for this application
	usb_oe                     : out   std_logic; -- active_low
	usb_rd                     : out   std_logic; -- active_low
	usb_wr                     : out   std_logic; -- active_low
	usb_pktend                 : out   std_logic; -- active_low
	usb_adr                    : out   std_logic_vector(1 downto 0); -- 00 ep2, 01 ep4, 10 ep6, 11 ep8
	usb_dat                    : inout std_logic_vector(7 downto 0);

	switch                     : in    std_logic_vector(0 downto 0);
	led                        : out   std_logic_vector(7 downto 0)
	);
end atlys_sig;

architecture top of atlys_sig is
	signal rstbtn                    : std_logic;
	signal rst_n                     : std_logic;
	signal rst                       : std_logic;
	signal rst_pll                   : std_logic;

	-- hdmi rx0
	signal rx0_sda_i                 : std_logic;
	signal rx0_sda_o                 : std_logic;
	signal rx0_ddr2_cmd_en           : std_logic;
	signal rx0_ddr2_cmd_instr        : std_logic_vector( 2 downto 0);
	signal rx0_ddr2_cmd_bl           : std_logic_vector( 5 downto 0);
	signal rx0_ddr2_cmd_byte_addr    : std_logic_vector(29 downto 0);
	signal rx0_ddr2_cmd_empty        : std_logic;
	signal rx0_ddr2_cmd_full         : std_logic;
	signal rx0_ddr2_wr_en            : std_logic;
	signal rx0_ddr2_wr_mask          : std_logic_vector( 3 downto 0);
	signal rx0_ddr2_wr_data          : std_logic_vector(31 downto 0);
	signal rx0_ddr2_wr_full          : std_logic;
	signal rx0_ddr2_wr_empty         : std_logic;
	signal rx0_ddr2_wr_count         : std_logic_vector( 6 downto 0);
	signal rx0_ddr2_wr_underrun      : std_logic;
	signal rx0_ddr2_wr_error         : std_logic;

	-- hdmi tx0
	signal tx0_pll_locked            : std_logic;
	signal tx0_ddr2_cmd_en           : std_logic;
	signal tx0_ddr2_cmd_instr        : std_logic_vector( 2 downto 0);
	signal tx0_ddr2_cmd_bl           : std_logic_vector( 5 downto 0);
	signal tx0_ddr2_cmd_byte_addr    : std_logic_vector(29 downto 0);
	signal tx0_ddr2_cmd_empty        : std_logic;
	signal tx0_ddr2_cmd_full         : std_logic;
	signal tx0_ddr2_rd_en            : std_logic;
	signal tx0_ddr2_rd_data          : std_logic_vector(31 downto 0);
	signal tx0_ddr2_rd_full          : std_logic;
	signal tx0_ddr2_rd_empty         : std_logic;
	signal tx0_ddr2_rd_count         : std_logic_vector( 6 downto 0);
	signal tx0_ddr2_rd_overflow      : std_logic;
	signal tx0_ddr2_rd_error         : std_logic;

	-- ddr2
	signal clk333                    : std_logic;
	signal clk333in                  : std_logic;
	signal ddr2_calib_done           : std_logic;
	signal ddr2_clk_out              : std_logic;
	signal ddr2_rst_out              : std_logic;

	-- strm cy_usb
	constant STRM_DDR2_BUS           : integer := 0;
	constant STRM_OUT_SLV_CNT        : integer := 1;
	signal strm_in_data              : std_logic_vector(31 downto 0);
	signal strm_in_eop               : std_logic;
	signal strm_in_sop               : std_logic;
	signal strm_in_en                : std_logic;
	signal strm_in_busy              : std_logic;
	signal strm_out_slv_reqs         : std_logic_vector(STRM_OUT_SLV_CNT-1 downto 0);
	signal strm_out_slv_busy         : std_logic_vector(STRM_OUT_SLV_CNT-1 downto 0);
	signal strm_out_data             : strm_dat_bus_t(STRM_OUT_SLV_CNT-1 downto 0);
	signal strm_out_eop              : std_logic_vector(STRM_OUT_SLV_CNT-1 downto 0);
	signal strm_out_en               : std_logic_vector(STRM_OUT_SLV_CNT-1 downto 0);

	-- strm ddr2
	signal strm_ddr2_cmd_en          : std_logic;
	signal strm_ddr2_cmd_instr       : std_logic_vector( 2 downto 0);
	signal strm_ddr2_cmd_bl          : std_logic_vector( 5 downto 0);
	signal strm_ddr2_cmd_byte_addr   : std_logic_vector(29 downto 0);
	signal strm_ddr2_cmd_empty       : std_logic;
	signal strm_ddr2_cmd_full        : std_logic;
	signal strm_ddr2_wr_en           : std_logic;
	signal strm_ddr2_wr_mask         : std_logic_vector( 3 downto 0);
	signal strm_ddr2_wr_data         : std_logic_vector(31 downto 0);
	signal strm_ddr2_wr_full         : std_logic;
	signal strm_ddr2_wr_empty        : std_logic;
	signal strm_ddr2_wr_count        : std_logic_vector( 6 downto 0);
	signal strm_ddr2_wr_underrun     : std_logic;
	signal strm_ddr2_wr_error        : std_logic;
	signal strm_ddr2_rd_en           : std_logic;
	signal strm_ddr2_rd_data         : std_logic_vector(31 downto 0);
	signal strm_ddr2_rd_full         : std_logic;
	signal strm_ddr2_rd_empty        : std_logic;
	signal strm_ddr2_rd_count        : std_logic_vector( 6 downto 0);
	signal strm_ddr2_rd_overflow     : std_logic;
	signal strm_ddr2_rd_error        : std_logic;
	signal ddr2_strm_in_busy         : std_logic;
	signal ddr2_strm_out_req         : std_logic;
	signal ddr2_strm_out_busy        : std_logic;
	signal ddr2_strm_out_data        : std_logic_vector(31 downto 0);
	signal ddr2_strm_out_eop         : std_logic;
	signal ddr2_strm_out_en          : std_logic;

	signal debug_usb                 : std_logic_vector( 7 downto 0);
	signal debug_strm_ddr2           : std_logic_vector( 7 downto 0);
begin
	rstbtn  <= not rstbtn_n;
	rst_pll <= ddr2_rst_out;
	rst_n   <= not ddr2_rst_out and tx0_pll_locked;
	rst     <= not rst_n;
	led     <= (others => '0');

	dvi2ddr_0: entity work.dvi2ddr
	port map (
		clk                   => ddr2_clk_out,
		rst                   => ddr2_rst_out,

		ctrl_disable_wr       => switch(0),

		rx_tmds               => rx0_tmds,
		rx_tmds_n             => rx0_tmds_n,

		-- memory interface
		ddr2_cmd_en_o         => rx0_ddr2_cmd_en,
		ddr2_cmd_instr_o      => rx0_ddr2_cmd_instr,
		ddr2_cmd_bl_o         => rx0_ddr2_cmd_bl,
		ddr2_cmd_byte_addr_o  => rx0_ddr2_cmd_byte_addr,
		ddr2_cmd_empty_i      => rx0_ddr2_cmd_empty,
		ddr2_cmd_full_i       => rx0_ddr2_cmd_full,
		ddr2_wr_en_o          => rx0_ddr2_wr_en,
		ddr2_wr_mask_o        => rx0_ddr2_wr_mask,
		ddr2_wr_data_o        => rx0_ddr2_wr_data,
		ddr2_wr_full_i        => rx0_ddr2_wr_full,
		ddr2_wr_empty_i       => rx0_ddr2_wr_empty,
		ddr2_wr_count_i       => rx0_ddr2_wr_count,
		ddr2_wr_underrun_i    => rx0_ddr2_wr_underrun,
		ddr2_wr_error_i       => rx0_ddr2_wr_error
	);

	-- ----------------------------------------------------------------------------
	-- 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    => ddr2_clk_out,
		rst_n  => rst_n,
		sda_i  => rx0_sda_i,
		sda_o  => rx0_sda_o,
		scl_i  => rx0_scl
	);

	-- ----------------------------------------------------------------------------
	-- DDR2
	-- ----------------------------------------------------------------------------
	ddr2_0: entity work.ddr2
	port map (
		c3_sys_clk                              => clk100,
		c3_sys_rst_i                            => rstbtn,
		c3_calib_done                           => ddr2_calib_done,
		c3_clk0                                 => ddr2_clk_out,
		c3_rst0                                 => ddr2_rst_out,
		mcb3_dram_dq                            => ddr2_dq,
		mcb3_dram_a                             => ddr2_a,
		mcb3_dram_ba                            => ddr2_ba,
		mcb3_dram_ras_n                         => ddr2_ras_n,
		mcb3_dram_cas_n                         => ddr2_cas_n,
		mcb3_dram_we_n                          => ddr2_we_n,
		mcb3_dram_odt                           => ddr2_odt,
		mcb3_dram_cke                           => ddr2_cke,
		mcb3_dram_dm                            => ddr2_dm,
		mcb3_dram_udqs                          => ddr2_udqs,
		mcb3_dram_udqs_n                        => ddr2_udqs_n,
		mcb3_rzq                                => ddr2_rzq,
		mcb3_zio                                => ddr2_zio,
		mcb3_dram_udm                           => ddr2_udm,
		mcb3_dram_dqs                           => ddr2_dqs,
		mcb3_dram_dqs_n                         => ddr2_dqs_n,
		mcb3_dram_ck                            => ddr2_clk,
		mcb3_dram_ck_n                          => ddr2_clk_n,

		c3_p0_cmd_clk                           => ddr2_clk_out,
		c3_p0_cmd_en                            => tx0_ddr2_cmd_en,
		c3_p0_cmd_instr                         => tx0_ddr2_cmd_instr,
		c3_p0_cmd_bl                            => tx0_ddr2_cmd_bl,
		c3_p0_cmd_byte_addr                     => tx0_ddr2_cmd_byte_addr,
		c3_p0_cmd_empty                         => tx0_ddr2_cmd_empty,
		c3_p0_cmd_full                          => tx0_ddr2_cmd_full,
		c3_p0_wr_clk                            => ddr2_clk_out,
		c3_p0_wr_en                             => '0',
		c3_p0_wr_mask                           => (others => '0'),
		c3_p0_wr_data                           => (others => '0'),
		c3_p0_wr_full                           => open,
		c3_p0_wr_empty                          => open,
		c3_p0_wr_count                          => open,
		c3_p0_wr_underrun                       => open,
		c3_p0_wr_error                          => open,
		c3_p0_rd_clk                            => ddr2_clk_out,
		c3_p0_rd_en                             => tx0_ddr2_rd_en,
		c3_p0_rd_data                           => tx0_ddr2_rd_data,
		c3_p0_rd_full                           => tx0_ddr2_rd_full,
		c3_p0_rd_empty                          => tx0_ddr2_rd_empty,
		c3_p0_rd_count                          => tx0_ddr2_rd_count,
		c3_p0_rd_overflow                       => tx0_ddr2_rd_overflow,
		c3_p0_rd_error                          => tx0_ddr2_rd_error,

		c3_p1_cmd_clk                           => ddr2_clk_out,
		c3_p1_cmd_en                            => rx0_ddr2_cmd_en,
		c3_p1_cmd_instr                         => rx0_ddr2_cmd_instr,
		c3_p1_cmd_bl                            => rx0_ddr2_cmd_bl,
		c3_p1_cmd_byte_addr                     => rx0_ddr2_cmd_byte_addr,
		c3_p1_cmd_empty                         => rx0_ddr2_cmd_empty,
		c3_p1_cmd_full                          => rx0_ddr2_cmd_full,
		c3_p1_wr_clk                            => ddr2_clk_out,
		c3_p1_wr_en                             => rx0_ddr2_wr_en,
		c3_p1_wr_mask                           => rx0_ddr2_wr_mask,
		c3_p1_wr_data                           => rx0_ddr2_wr_data,
		c3_p1_wr_full                           => rx0_ddr2_wr_full,
		c3_p1_wr_empty                          => rx0_ddr2_wr_empty,
		c3_p1_wr_count                          => rx0_ddr2_wr_count,
		c3_p1_wr_underrun                       => rx0_ddr2_wr_underrun,
		c3_p1_wr_error                          => rx0_ddr2_wr_error,
		c3_p1_rd_clk                            => ddr2_clk_out,
		c3_p1_rd_en                             => '0',
		c3_p1_rd_data                           => open,
		c3_p1_rd_full                           => open,
		c3_p1_rd_empty                          => open,
		c3_p1_rd_count                          => open,
		c3_p1_rd_overflow                       => open,
		c3_p1_rd_error                          => open,

		c3_p2_cmd_clk                           => ddr2_clk_out,
		c3_p2_cmd_en                            => strm_ddr2_cmd_en,
		c3_p2_cmd_instr                         => strm_ddr2_cmd_instr,
		c3_p2_cmd_bl                            => strm_ddr2_cmd_bl,
		c3_p2_cmd_byte_addr                     => strm_ddr2_cmd_byte_addr,
		c3_p2_cmd_empty                         => strm_ddr2_cmd_empty,
		c3_p2_cmd_full                          => strm_ddr2_cmd_full,
		c3_p2_wr_clk                            => ddr2_clk_out,
		c3_p2_wr_en                             => strm_ddr2_wr_en,
		c3_p2_wr_mask                           => strm_ddr2_wr_mask,
		c3_p2_wr_data                           => strm_ddr2_wr_data,
		c3_p2_wr_full                           => strm_ddr2_wr_full,
		c3_p2_wr_empty                          => strm_ddr2_wr_empty,
		c3_p2_wr_count                          => strm_ddr2_wr_count,
		c3_p2_wr_underrun                       => strm_ddr2_wr_underrun,
		c3_p2_wr_error                          => strm_ddr2_wr_error,
		c3_p2_rd_clk                            => ddr2_clk_out,
		c3_p2_rd_en                             => strm_ddr2_rd_en,
		c3_p2_rd_data                           => strm_ddr2_rd_data,
		c3_p2_rd_full                           => strm_ddr2_rd_full,
		c3_p2_rd_empty                          => strm_ddr2_rd_empty,
		c3_p2_rd_count                          => strm_ddr2_rd_count,
		c3_p2_rd_overflow                       => strm_ddr2_rd_overflow,
		c3_p2_rd_error                          => strm_ddr2_rd_error,
	
		c3_p3_cmd_clk                           => '0',
		c3_p3_cmd_en                            => '0',
		c3_p3_cmd_instr                         => (others => '0'),
		c3_p3_cmd_bl                            => (others => '0'),
		c3_p3_cmd_byte_addr                     => (others => '0'),
		c3_p3_cmd_empty                         => open,
		c3_p3_cmd_full                          => open,
		c3_p3_wr_clk                            => '0',
		c3_p3_wr_en                             => '0',
		c3_p3_wr_mask                           => (others => '0'),
		c3_p3_wr_data                           => (others => '0'),
		c3_p3_wr_full                           => open,
		c3_p3_wr_empty                          => open,
		c3_p3_wr_count                          => open,
		c3_p3_wr_underrun                       => open,
		c3_p3_wr_error                          => open,
		c3_p3_rd_clk                            => '0',
		c3_p3_rd_en                             => '0',
		c3_p3_rd_data                           => open,
		c3_p3_rd_full                           => open,
		c3_p3_rd_empty                          => open,
		c3_p3_rd_count                          => open,
		c3_p3_rd_overflow                       => open,
		c3_p3_rd_error                          => open
	);

	ddr2dvi_0: entity work.ddr2dvi
	port map (
		clk                   => ddr2_clk_out,
		rst_n                 => rst_n,
		rst_pll               => rst_pll,

		tx_tmds               => tx0_tmds,
		tx_tmds_n             => tx0_tmds_n,
		tx_pll_locked_o       => tx0_pll_locked,

		-- memory interface
		ddr2_cmd_en_o         => tx0_ddr2_cmd_en,
		ddr2_cmd_instr_o      => tx0_ddr2_cmd_instr,
		ddr2_cmd_bl_o         => tx0_ddr2_cmd_bl,
		ddr2_cmd_byte_addr_o  => tx0_ddr2_cmd_byte_addr,
		ddr2_cmd_empty_i      => tx0_ddr2_cmd_empty,
		ddr2_cmd_full_i       => tx0_ddr2_cmd_full,

		ddr2_rd_en_o          => tx0_ddr2_rd_en,
		ddr2_rd_data_i        => tx0_ddr2_rd_data,
		ddr2_rd_full_i        => tx0_ddr2_rd_full,
		ddr2_rd_empty_i       => tx0_ddr2_rd_empty,
		ddr2_rd_count_i       => tx0_ddr2_rd_count,
		ddr2_rd_overflow_i    => tx0_ddr2_rd_overflow,
		ddr2_rd_error_i       => tx0_ddr2_rd_error
	);

	-- ----------------------------------------------------------------------------
	-- USB
	-- ----------------------------------------------------------------------------
	f2p_strm_top_0: entity work.f2p_strm_top
	generic map (STRM_OUT_SLV_CNT => STRM_OUT_SLV_CNT)
	port map (
		clk                   => ddr2_clk_out,
		rst_n                 => rst_n,
		debug                 => debug_usb,

		-- cypress interface
		usb_clk               => usb_clk,
		usb_flag_a_i          => usb_flag_a,
		usb_flag_b_i          => usb_flag_b,
		usb_flag_c_i          => usb_flag_c,
		usb_cs_o              => usb_cs,
		usb_oe_o              => usb_oe,
		usb_rd_o              => usb_rd,
		usb_wr_o              => usb_wr,
		usb_pktend_o          => usb_pktend,
		usb_adr_o             => usb_adr,
		usb_dat_io            => usb_dat,

		-- streaming bus
		strm_in_data_o        => strm_in_data,
		strm_in_eop_o         => strm_in_eop,
		strm_in_sop_o         => strm_in_sop,
		strm_in_en_o          => strm_in_en,
		strm_in_busy_i        => strm_in_busy,
		strm_out_slv_reqs_i   => strm_out_slv_reqs,
		strm_out_slv_busy_o   => strm_out_slv_busy,
		strm_out_data_i       => strm_out_data,
		strm_out_eop_i        => strm_out_eop,
		strm_out_en_i         => strm_out_en
	);

	strm_out_slv_reqs(STRM_DDR2_BUS) <= ddr2_strm_out_req;
	strm_out_eop(STRM_DDR2_BUS)      <= ddr2_strm_out_eop;
	strm_out_en(STRM_DDR2_BUS)       <= ddr2_strm_out_en;
	strm_out_data(STRM_DDR2_BUS)     <= ddr2_strm_out_data;
	ddr2_strm_out_busy               <= strm_out_slv_busy(STRM_DDR2_BUS);
	strm_in_busy                     <= ddr2_strm_in_busy;

	strm_ddr2_0: entity work.strm_ddr2
	port map (
		clk                   => ddr2_clk_out,
		rst_n                 => rst_n,
		debug                 => debug_strm_ddr2,

		-- streaming bus
		strm_in_data_i        => strm_in_data,
		strm_in_eop_i         => strm_in_eop,
		strm_in_sop_i         => strm_in_sop,
		strm_in_en_i          => strm_in_en,
		strm_in_busy_o        => ddr2_strm_in_busy,
		strm_out_req_o        => ddr2_strm_out_req,
		strm_out_busy_i       => ddr2_strm_out_busy,
		strm_out_data_o       => ddr2_strm_out_data,
		strm_out_eop_o        => ddr2_strm_out_eop,
		strm_out_en_o         => ddr2_strm_out_en,

		-- memory interface
		ddr2_cmd_en_o         => strm_ddr2_cmd_en,
		ddr2_cmd_instr_o      => strm_ddr2_cmd_instr,
		ddr2_cmd_bl_o         => strm_ddr2_cmd_bl,
		ddr2_cmd_byte_addr_o  => strm_ddr2_cmd_byte_addr,
		ddr2_cmd_empty_i      => strm_ddr2_cmd_empty,
		ddr2_cmd_full_i       => strm_ddr2_cmd_full,
		ddr2_wr_en_o          => strm_ddr2_wr_en,
		ddr2_wr_mask_o        => strm_ddr2_wr_mask,
		ddr2_wr_data_o        => strm_ddr2_wr_data,
		ddr2_wr_full_i        => strm_ddr2_wr_full,
		ddr2_wr_empty_i       => strm_ddr2_wr_empty,
		ddr2_wr_count_i       => strm_ddr2_wr_count,
		ddr2_wr_underrun_i    => strm_ddr2_wr_underrun,
		ddr2_wr_error_i       => strm_ddr2_wr_error,
		ddr2_rd_en_o          => strm_ddr2_rd_en,
		ddr2_rd_data_i        => strm_ddr2_rd_data,
		ddr2_rd_full_i        => strm_ddr2_rd_full,
		ddr2_rd_empty_i       => strm_ddr2_rd_empty,
		ddr2_rd_count_i       => strm_ddr2_rd_count,
		ddr2_rd_overflow_i    => strm_ddr2_rd_overflow,
		ddr2_rd_error_i       => strm_ddr2_rd_error
	);

end top;
