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

library work;
use work.all;

library UNISIM;
use UNISIM.Vcomponents.all;

entity dmb is
	port (
		clk100_i                   : in    std_logic; -- 100 MHz osicallator

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

		-- vcm
		vmc_clk_o                  : out   std_logic;
		vmc_red_o                  : out   std_logic_vector(7 downto 0);
		vmc_green_o                : out   std_logic_vector(7 downto 0);
		vmc_blue_o                 : out   std_logic_vector(7 downto 0);
		vmc_hsync_o                : out   std_logic;
		vmc_vsync_o                : out   std_logic;
		vmc_de_o                   : out   std_logic;

		-- cypress interface
		usb_clk_i                  : in    std_logic;
		usb_flag_a_i               : in    std_logic; -- programmable flag
		usb_flag_b_i               : in    std_logic; -- full flag
		usb_flag_c_i               : in    std_logic; -- empty flag
		usb_cs_io                  : inout std_logic; -- put to GND, not need for this application
		usb_oe_o                   : out   std_logic; -- active_low
		usb_rd_o                   : out   std_logic; -- active_low
		usb_wr_o                   : out   std_logic; -- active_low
		usb_pktend_o               : out   std_logic; -- active_low
		usb_adr_o                  : out   std_logic_vector(1 downto 0); -- 00 ep2, 01 ep4, 10 ep6, 11 ep8
		usb_dat_io                 : inout std_logic_vector(7 downto 0);

		led_o                      : out   std_logic_vector(3 downto 0)
	);
end dmb;

architecture top of dmb is
	signal rst_n                     : std_logic;
	signal rstbtn                    : std_logic;
                                         
	-- hdmi                          
	signal pclk                      : std_logic;
	signal pclkx2                    : std_logic;
	signal pclkx10                   : 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);

	-- clockinga
	signal usb_rst_n                 : std_logic;
	signal usb_clk_locked            : std_logic;
	signal usb_clk_gb                : std_logic;
	signal usb_clk_ib                : std_logic;
	signal usb_clk                   : std_logic;
	signal rst100_n                  : std_logic;
	signal clk100_locked             : std_logic;
	signal clk100_ib                 : std_logic;
	signal clk100_gb                 : std_logic;
	signal clk48_gb                  : std_logic;
	signal clk100                    : std_logic;
	signal clk48                     : std_logic;


	-- strm cy_usb
	constant STRM_REGFILE_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);
	-- regfile
	signal rf_strm_in_busy           : std_logic;
	signal rf_strm_out_req           : std_logic;
	signal rf_strm_out_busy          : std_logic;
	signal rf_strm_out_data          : std_logic_vector(31 downto 0);
	signal rf_strm_out_eop           : std_logic;
	signal rf_strm_out_en            : std_logic;
	constant REG_CNT                 : integer := 8;
	signal regfile                   : std_logic_vector((32*REG_CNT)-1 downto 0);

	signal test                      : std_logic;
begin 
	rstbtn    <= '0';
	usb_rst_n <= usb_clk_locked;
	rst100_n  <= clk100_locked;
	led_o     <= regfile(2 downto 0) & test;

	-- ----------------------------------------------------------------------------
	-- clocking
	-- ----------------------------------------------------------------------------
	-- USB
	ibufg_usb_clk: IBUFG port map (O => usb_clk_ib, I => usb_clk_i);
 	bufg_usb_clk: BUFG port map (O => usb_clk, I => usb_clk_gb);
	dcm_usb_clk: DCM_SP
	generic map (
		CLKDV_DIVIDE          => 2.000,
		CLKFX_DIVIDE          => 1,
		CLKFX_MULTIPLY        => 4,
		CLKIN_DIVIDE_BY_2     => FALSE,
		CLKIN_PERIOD          => 20.833,
		CLKOUT_PHASE_SHIFT    => "NONE",
		CLK_FEEDBACK          => "1X",
		DESKEW_ADJUST         => "SYSTEM_SYNCHRONOUS",
		PHASE_SHIFT           => 0,
		STARTUP_WAIT          => FALSE
	)
	port map (
		CLKIN                 => usb_clk_ib,
		CLKFB                 => usb_clk,
		-- Output clocks
		CLK0                  => usb_clk_gb,
		CLK90                 => open,
		CLK180                => open,
		CLK270                => open,
		CLK2X                 => open,
		CLK2X180              => open,
		CLKFX                 => open,
		CLKFX180              => open,
		CLKDV                 => open,
		-- Ports for dynamic phase shift
		PSCLK                 => '0',
		PSEN                  => '0',
		PSINCDEC              => '0',
		PSDONE                => open,
		-- Other control and status signals
		LOCKED                => usb_clk_locked,
		STATUS                => open,
		RST                   => rstbtn,
		-- Unused pin, tie low 
		DSSEN                 => '0'
	);

	-- MAIN
	process (clk100, rst100_n)
	begin
	if rst100_n = '0' then
		test <= '0';
	elsif rising_edge(clk100) then
		test <= not test;
	end if;
	end process;
	ibufg_clk100: IBUFG port map (O => clk100_ib, I => clk100_i);
 	bufg_clk100: BUFG port map (O => clk100, I => clk100_gb);
 	bufg_clk48: BUFG port map (O => clk48, I => clk48_gb);
	dcm_clk100: DCM_SP
	generic map (
		CLKDV_DIVIDE          => 2.000,
		CLKFX_DIVIDE          => 25,
		CLKFX_MULTIPLY        => 12,
		CLKIN_DIVIDE_BY_2     => FALSE,
		CLKIN_PERIOD          => 10.0,
		CLKOUT_PHASE_SHIFT    => "NONE",
		CLK_FEEDBACK          => "1X",
		DESKEW_ADJUST         => "SYSTEM_SYNCHRONOUS",
		PHASE_SHIFT           => 0,
		STARTUP_WAIT          => FALSE
	)
	port map (
		CLKIN                 => clk100_ib,
		CLKFB                 => clk100,
		-- Output clocks
		CLK0                  => clk100_gb,
		CLK90                 => open,
		CLK180                => open,
		CLK270                => open,
		CLK2X                 => open,
		CLK2X180              => open,
		CLKFX                 => clk48_gb,
		CLKFX180              => open,
		CLKDV                 => open,
		-- Ports for dynamic phase shift
		PSCLK                 => '0',
		PSEN                  => '0',
		PSINCDEC              => '0',
		PSDONE                => open,
		-- Other control and status signals
		LOCKED                => clk100_locked,
		STATUS                => open,
		RST                   => rstbtn,
		-- Unused pin, tie low 
		DSSEN                 => '0'
	);


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

	vmc_clk_ddr: ODDR2
	port map (
		Q     => vmc_clk_o,  -- 1-bit DDR output data
		C0    => pclk,       -- clock input
		C1    => not pclk,   -- clock input, inverted
		CE    => '1',        -- clock enable always
		D0    => '1',        -- sampled on clock posedge, output when clock is HIGH
		D1    => '0',        -- sampled on clock negedge, output when clock is LOW
		R     => '0',        -- set/reset disabled
		S     => '1'         -- set/reset disabled
	);
	--vmc_clk_o    <= pclk;
	vmc_red_o    <= color(RED);
	vmc_green_o  <= color(GREEN);
	vmc_blue_o   <= color(BLUE);
	vmc_hsync_o  <= hsync;
	vmc_vsync_o  <= vsync;
	vmc_de_o     <= dat_en;

	-- ----------------------------------------------------------------------------
	-- core logic
	-- ----------------------------------------------------------------------------
	f2p_strm_top_0: entity work.f2p_strm_top
	generic map (STRM_OUT_SLV_CNT => STRM_OUT_SLV_CNT)
	port map (
		clk                   => usb_clk,
		rst_n                 => usb_rst_n,
		debug                 => open,

		-- cypress interface
		usb_clk               => usb_clk,
		usb_flag_a_i          => usb_flag_a_i,
		usb_flag_b_i          => usb_flag_b_i,
		usb_flag_c_i          => usb_flag_c_i,
		usb_cs_o              => usb_cs_io,
		usb_oe_o              => usb_oe_o,
		usb_rd_o              => usb_rd_o,
		usb_wr_o              => usb_wr_o,
		usb_pktend_o          => usb_pktend_o,
		usb_adr_o             => usb_adr_o,
		usb_dat_io            => usb_dat_io,

		-- 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_REGFILE_BUS) <= rf_strm_out_req;
	strm_out_eop(STRM_REGFILE_BUS)      <= rf_strm_out_eop;
	strm_out_en(STRM_REGFILE_BUS)       <= rf_strm_out_en;
	strm_out_data(STRM_REGFILE_BUS)     <= rf_strm_out_data;
	rf_strm_out_busy                    <= strm_out_slv_busy(STRM_REGFILE_BUS);
	strm_in_busy                        <= rf_strm_in_busy;

	strm_regfile_0: entity work.strm_regfile 
	generic map ( REGISTER_CNT => REG_CNT )
	port map (
		clk                   => usb_clk,
		rst_n                 => usb_rst_n,
		debug                 => open,

		-- 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        => rf_strm_in_busy,
		strm_out_req_o        => rf_strm_out_req,
		strm_out_busy_i       => rf_strm_out_busy,
		strm_out_data_o       => rf_strm_out_data,
		strm_out_eop_o        => rf_strm_out_eop,
		strm_out_en_o         => rf_strm_out_en,

		-- regfile
		regfile_i             => regfile,
		regfile_o             => regfile
	);

end top;
