---------------------------------------------------------------------------------------------------
--    _____
--   /     \	
--  /____   \____
-- / \===\   \==/
--/___\===\___\/  AVNET
--     \======/   DESIGN
--      \====/    SERVICES
--
---------------------------------------------------------------------------------------------------
--
-- Title: 	
-- Program: 	
-- Filename:	vid_capture_module.vhd
-- PCB P/N:		
-- PCB ASSY:	
--
-- FPGA: 		
-- Author(s): Vince Gavagan
--            Uses I2C modules created/adapted by
--            Matt Schultz & Jim Burnett
--            Avnet Design Services
--
-- Date:      01/20/03		
--
-- Purpose:   This module implements takes data in through an 8-bit 27MHz video interface and stores
--            in a fifo.  Intended for use with upper level opb_vid_capture. 
-- 
--            Control reg will enable ITU-R BT.601 8-bit video data	pass-through from the SAA7111 to
--            the SAA7121.
--
-- Naming convention:
--            Active low signals are indicated by _L.
--
--
-- Disclaimer:
--	Avnet, Inc. makes no warranty for the use of this code or design.  
--	This code is provided  "As Is". Avnet, Inc assumes no responsibility for 
--	any errors, which may appear in this code, nor does it make a commitment 
--	to update the information contained herein. Avnet, Inc specifically 
--	disclaims any implied warranties of fitness for a particular purpose.
--       			 Copyright (c) 2000 Avnet, Inc.
--               			 All rights reserved.
--
---------------------------------------------------------------------------------------------------
-- Revision List
-- Version		Date		Changes
-- 1.0					
--
--
--		02/06/03  Periperal seems to be collecting frames.  Byte count should be 0x5A8, but isn't always.
--	Error counters reveal that count is 0x894 when it isn't the desired 0x598.  Not sure why we sometimes
--	get 894.
--		When using HREF, count is consistant at 0x5a1.  Would expect 0x5a0 (0x5a8 minus SAV/EAV).  Timing
--	for HREF doesn't seem to be specified anywhere, so we could be getting an extra byte at the beginning
--	or end.  This extra byte will probably cause problems for our state machine, byte count vs. fifo write,
--	etc..  Perhaps try using HREF to start the capture and EAV to end it (or SAV/HREF vice versa).
--		Will HREF be consistant for us...same place all the time in relation to vid data?
--		Do we even care about the 0x894's?
--		Lots of extra junk in this version for debug purposes.  Needs clean up.....bad.
--		
--
---------------------------------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity vid_capture_module is
    Port (
		 I2C_SDA_I		 : in std_logic;    -- I2C data line (open-drain bidirectional data line)
		 I2C_SDA_O		 : out std_logic;    -- I2C data line (open-drain bidirectional data line)
		 I2C_SDA_T		 : out std_logic;    -- I2C data line (open-drain bidirectional data line)
		 I2C_CLK		 : out std_logic;    -- I2C clock line (100 kHz)
		 CLK			 : in    std_logic;    -- 27MHz
		 Vin_VPO        : in    std_logic_vector(15 downto 0);
		 Vin_RES		 : in    std_logic;    -- RESET_N output from SAA7111
		 Vin_CE         : out   std_logic;	  -- SAA7111 Chip Enable (active high, low forces RESET_N)
	     Vin_HREF		: in    std_logic;
		 DV_OUT         : out   std_logic_vector(7 downto 0);
		 DV_OUT_RST_N   : out   std_logic;    -- SAA7121 RESET_N (active low)
		 RESET			: in std_logic;
         RD_NWR         : in std_logic;        -- registered read/Nwrite
         Enable         : in std_logic;        -- registered chip select
         Address        : in std_logic_vector(31 downto 0); -- registered address
         Write_Data     : in std_logic_vector(31 downto 0); --0 to 31);
		 Read_Data      : out std_logic_vector(31 downto 0); --0 to 31);
		 Data_Valid     : out std_logic;
		 opb_clk        : in std_logic
	 );
end vid_capture_module;

architecture arch_vid_capture_module of vid_capture_module is

	signal  vid_data : std_logic_vector(31 downto 0);
	signal  RESET_N  : std_logic;
	signal  en_video_pass : std_logic;
	signal  reset_fifo    : std_logic;
	signal  fifo_wr_en    : std_logic;
	signal  fifo_rd_en	  : std_logic;
	signal  fifo_rd_en_internal  : std_logic;
	signal  fifo_rd_en_internal_latched  : std_logic;
	signal  fifo_dout	  : std_logic_vector(31 downto 0);
	signal  fifo_full	  : std_logic;
	signal  fifo_empty    : std_logic;
	signal  frame_byte_count : std_logic_vector(11 downto 0);
--	signal  enable_i2c    : std_logic;
	signal  start_of_video_detect : std_logic;
	signal  status_register : std_logic_vector(31 downto 0);--0 to 31);
	signal  control_register: std_logic_vector(31 downto 0);--0 to 31);
	signal  revision_register: std_logic_vector(31 downto 0);
	signal  enable_i2c : std_logic;
    signal  state_id : std_logic_vector(3 downto 0);
    signal  frame_count : std_logic_vector(31 downto 0);
	signal  colorbar_en : std_logic;
	signal  bytes_per_frame : std_logic_vector(31 downto 0);
	signal  bytes_per_frame_opb_domain : std_logic_vector(31 downto 0);
	SIGNAL  HREF_COUNT : STD_LOGIC_VECTOR(31 DOWNTO 0);
	signal en_video_capture : std_logic;
	signal error_count_5a1 : std_logic_vector(31 downto 0);
	signal error_count_5a0 : std_logic_vector(31 downto 0);
	signal error_count_5a9 : std_logic_vector(31 downto 0);
	signal error_count_5a8 : std_logic_vector(31 downto 0);
	signal errored_size : std_logic_vector(31 downto 0);
	signal count_894	: std_logic_vector(31 downto 0);

    type rx_video_fifo_states is (init, collect_bytes, finish);
    signal rx_video_fifo_state : rx_video_fifo_states;

	component control_i2c is
	    Port (
		 I2C_SDA_I		 : in std_logic;    -- I2C data line (open-drain bidirectional data line)
		 I2C_SDA_O		 : out std_logic;    -- I2C data line (open-drain bidirectional data line)
		 I2C_SDA_T		 : out std_logic;    -- I2C data line (open-drain bidirectional data line)
		 I2C_CLK		 : out std_logic;    -- I2C clock line (100 kHz)
		 CLK_200kHz_out : out   std_logic;    -- continuous clock for logic analyzer
		 CLK			 : in    std_logic;    -- 27MHz
		 SWITCH_general : in    std_logic;	  -- high enables this block
         colorbar_en : in    std_logic;
		 testpoint	 : out   std_logic
		 );
	end component control_i2c;

	component fifo_dual_clk_32_511 IS
		port (
		din: IN std_logic_VECTOR(31 downto 0);
		wr_en: IN std_logic;
		wr_clk: IN std_logic;
		rd_en: IN std_logic;
		rd_clk: IN std_logic;
		ainit: IN std_logic;
		dout: OUT std_logic_VECTOR(31 downto 0);
		full: OUT std_logic;
		empty: OUT std_logic);
	end component;
	
--	component sync_fifo_32_512 is 
--		port (
--		clk: IN std_logic;
--		sinit: IN std_logic;
--		din: IN std_logic_VECTOR(31 downto 0);
--		wr_en: IN std_logic;
--		rd_en: IN std_logic;
--		dout: OUT std_logic_VECTOR(31 downto 0);
--		full: OUT std_logic;
--		empty: OUT std_logic;
--		data_count: OUT std_logic_VECTOR(0 downto 0));
--	end component;
-- XST black box declaration
attribute box_type : string;
attribute box_type of fifo_dual_clk_32_511: component is "black_box";

-- Synplicity black box declaration
--attribute syn_black_box : boolean;
--attribute syn_black_box of fifo_dual_clk_32_511: component is true;


---------------------------------------------------------------------------------------------------
begin

	control_for_i2c: control_i2c
	    Port map(
		 I2C_SDA_I      => I2C_SDA_I,       
		 I2C_SDA_O      => I2C_SDA_O,       
		 I2C_SDA_T      => I2C_SDA_T,       
		 I2C_CLK        => I2C_CLK,       
		 CLK_200kHz_out => open,
		 CLK            => CLK,           
		 SWITCH_general => enable_i2c,
		 colorbar_en 	=> colorbar_en,
		 testpoint      => open
		 );

--	video_data_fifo : sync_fifo_32_512
--		port map (
--			clk => clk,
--			sinit => reset_fifo,
--			din => vid_data,
--			wr_en => fifo_wr_en,
--			rd_en => fifo_rd_en,
--			dout => fifo_dout,
--			full => fifo_full,
--			empty => fifo_empty,
--			data_count => open
--			);

    video_data_fifo : fifo_dual_clk_32_511
		port map (
			din    => vid_data,
			wr_en  => fifo_wr_en,
		    wr_clk => clk,
			rd_en  => fifo_rd_en,
		    rd_clk => opb_clk,
		    ainit  => reset_fifo,
			dout => fifo_dout,
			full => fifo_full,
			empty => fifo_empty
			);
	
	
	
	latch_data_31_24 : process (CLK, Vin_VPO, RESET_N)
	begin
	  if RESET_N = '0' then
		 vid_data(31 downto 24) <= (others => '0');
	  elsif (CLK'event and CLK = '1') then       
		 vid_data(31 downto 24) <= Vin_VPO(15 downto 8);
	  end if;
	end process;
	
	latch_data_23_16 : process (CLK, Vin_VPO, RESET_N)
	begin
	  if RESET_N = '0' then
		 vid_data(23 downto 16) <= (others => '0');
	  elsif (CLK'event and CLK = '1') then       
		 vid_data(23 downto 16) <= vid_data(31 downto 24);
	  end if;
	end process;

	latch_data_15_8 : process (CLK, Vin_VPO, RESET_N)
	begin
	  if RESET_N = '0' then
		 vid_data(15 downto 8) <= (others => '0');
	  elsif (CLK'event and CLK = '1') then       
		 vid_data(15 downto 8) <= vid_data(23 downto 16);
	  end if;
	end process;

	latch_data_7_0 : process (CLK, Vin_VPO, RESET_N)
	begin
	  if RESET_N = '0' then
		 vid_data(7 downto 0) <= (others => '0');
	  elsif (CLK'event and CLK = '1') then       
		 vid_data(7 downto 0) <= vid_data(15 downto 8);
	  end if;
	end process;

	----------------------------------------------------------------------------------
	--  
	--	
	----------------------------------------------------------------------------------
	capture_the_video_data : process(RESET_N, CLK, en_video_capture)
--	capture_the_video_data : process(RESET_N, CLK)
	variable i : integer := 0;
	begin
		if RESET_N = '0' or en_video_capture = '0' then
--		if RESET_N = '0' then
			rx_video_fifo_state <= init;
			start_of_video_detect <= '0';
			frame_byte_count <= (others => '0');
			bytes_per_frame <= (others => '0');
--			fifo_wr_en <= '0';
--            state_id <= (others => '0');
			error_count_5a9 <= (others => '0');
			error_count_5a8 <= (others => '0');
			errored_size <= (others => '0');
			count_894 <= (others => '0');
		elsif CLK'event and CLK = '0' then
			case rx_video_fifo_state is
				--
				when init =>
                    state_id <= x"1";
--					if vid_data = x"800000FF" then
					if ((vid_data and x"500000FF") = x"000000FF") then
						start_of_video_detect <= '1';
						frame_byte_count <= x"004";
						rx_video_fifo_state <= collect_bytes;
--						fifo_wr_en <= '1';
					else
						frame_byte_count <= x"000";
					end if;
				--
				when collect_bytes =>
                    state_id <= x"2";
					start_of_video_detect <= '0';
					frame_byte_count <= frame_byte_count + x"001";
--					if vid_data = x"B60000FF" then
					if ((vid_data and x"500000FF") = x"100000FF") then
						rx_video_fifo_state <= finish;
					end if;
				--
				when finish =>
					state_id <= x"3";
					bytes_per_frame(11 downto 0) <= frame_byte_count;
--					fifo_wr_en <= '0';
					if frame_byte_count = x"894" then
						count_894 <= count_894 + '1';
					end if;
					if frame_byte_count /= x"5a8" then
						error_count_5a8 <= error_count_5a8 + '1';
						errored_size(11 downto 0) <= frame_byte_count;
					end if;

					rx_video_fifo_state <= init;
				--
				when others => null;
			end case;
		end if;
	end process;

--	capture_the_video_data : process(RESET_N, CLK, en_video_capture)
--	variable i : integer := 0;
--	begin
--		if RESET_N = '0' or en_video_capture = '0' then
--			rx_video_fifo_state <= init;
--			start_of_video_detect <= '0';
--			frame_byte_count <= (others => '0');
--			bytes_per_frame <= (others => '0');
--			error_count_5a1 <= (others => '0');
--			error_count_5a0 <= (others => '0');
--		elsif CLK'event and CLK = '0' then
--			case rx_video_fifo_state is
--				--
--				when init =>
--					state_id <= x"1";
--					if Vin_HREF = '1' then
----					if ((vid_data and x"500000FF") = x"000000FF") then
--						start_of_video_detect <= '1';
----						frame_byte_count <= x"004";
--						frame_byte_count <= x"001";
--						rx_video_fifo_state <= collect_bytes;
--					else
--						frame_byte_count <= x"000";
--					end if;
--				--
--				when collect_bytes =>
--                    state_id <= x"2";
--					start_of_video_detect <= '0';
--					frame_byte_count <= frame_byte_count + x"001";
--					if Vin_HREF = '0' then
----					if ((vid_data and x"500000FF") = x"100000FF") then
--						rx_video_fifo_state <= finish;
--					end if;
--				--
--				when finish =>
--					state_id <= x"3";
--					bytes_per_frame(11 downto 0) <= frame_byte_count;
--					if frame_byte_count /= x"5a1" then
--						error_count_5a1 <= error_count_5a1 + '1';
--					end if;
--					if frame_byte_count /= x"5a0" then
--						error_count_5a0 <= error_count_5a0 + '1';
--					end if;
--
--					rx_video_fifo_state <= init;
--				--
--				when others => null;
--			end case;
--		end if;
--	end process;

	fifo_wr_en	<= '1' when (rx_video_fifo_state = collect_bytes or
	                         rx_video_fifo_state = finish)       and
                            (frame_byte_count(3 downto 0) = x"4" or
                             frame_byte_count(3 downto 0) = x"8" or
                             frame_byte_count(3 downto 0) = x"C" or
                             frame_byte_count(3 downto 0) = x"0") 
                            else '0';

	frame_counter : process(RESET_N, CLK)
	begin
		if RESET_N = '0' then
			frame_count <= (others => '0');
		elsif CLK'event and CLK = '0' then
			if rx_video_fifo_state = finish then
				frame_count <= frame_count + '1';
			end if;
		end if;
	end process;

	byte_per_frame_x_domains : process (CLK, RESET_N, opb_clk)
	begin
	  if RESET_N = '0' then
		 bytes_per_frame_opb_domain <= (others => '0');
	  elsif (opb_clk'event and opb_clk = '1') then
		  if CLK = '1' then
		 	bytes_per_frame_opb_domain <= bytes_per_frame;
		  else
		 	bytes_per_frame_opb_domain <= bytes_per_frame_opb_domain;
		  end if;
	  end if;
	end process;
	
--	COUNT_HREF_CLOCKS : process (CLK, RESET_N, Vin_HREF)
--	begin
--	  if RESET_N = '0' then
--		 HREF_COUNT <= (others => '0');
--	  elsif (CLK'event and CLK = '1') then
--		  if Vin_HREF = '1' then
--			  HREF_COUNT <= HREF_COUNT + '1';
--		  else
--			  HREF_COUNT <= (OTHERS => '0');
--		  END IF;
--	  end if;
--	end process;
	
	----------------------------------------------------------------------------------
	----------------------------------------------------------------------------------
	-- opb interface logic
	----------------------------------------------------------------------------------
	----------------------------------------------------------------------------------
	revision_register <= x"0000000F";
	
	Read_Data <=  fifo_dout when Address(11 downto 0) = x"000" else
                  status_register when Address(11 DOWNTO 0) = x"004" else
                  control_register when Address(11 DOWNTO 0) = x"008" else
                  revision_register when Address(11 DOWNTO 0) = x"00C" else
				  state_id(3 downto 0) & x"0000" & frame_byte_count(11 downto 0)
                                    when Address(11 DOWNTO 0) = x"010" else
                  frame_count when Address(11 DOWNTO 0) = x"014" else
                  vid_data when Address(11 DOWNTO 0) = x"018" else
				  bytes_per_frame_opb_domain when Address(11 downto 0) = x"1C" else
				  count_894 when Address(11 downto 0) = x"20" else
				  error_count_5a8 when Address(11 downto 0) = x"24" else
				  errored_size when Address(11 downto 0) = x"28" else
                  x"5a5a5a5a";-- when others;

	write_to_registers : process(RESET_N, opb_clk, Enable)
	begin
		if RESET_N = '0' then
--			status_register <= (others => '0');
			control_register <= (others => '0');
		elsif opb_clk'event and opb_clk = '1' then--  and Enable = '1' then
			if RD_NWR = '0' and Enable = '1' then
								--		   0  read only
				if 		Address(11 DOWNTO 0)	= x"008" then
					control_register <= Write_Data;
				end if;
			end if;
		end if;
	end process;

	generate_xfer_ack : process(RESET_N, opb_clk)
	begin											-- Enable is our registered CS signal.  We want 
		if RESET_N = '0' then						-- the Data_Valid to be delayed by one cycle so
			Data_Valid <= '0';						-- the bram has time to clock read data out.
		elsif opb_clk'event and opb_clk = '1' then  -- Our upper level opb interface will register
			Data_Valid <= Enable;                   -- the read data and xfer_ack based off the 
		end if;                                     -- Data_Valid signal.
	end process;
	
    ----------------------------------------------------------------------------------
    --   This section will generate a pulse on fifo_rd_en, one cycle wide when the 
    -- fifo_rd_en_internal goes low-to-high.
    fifo_rd_en_internal <= '1' when Enable = '1' and RD_NWR = '1' and   -- RD_NWR=high for read  
                               fifo_empty = '0' and                     -- don't read when empty
                               Address(11 downto 0) = x"000"            -- Address 0
                               else '0';

    register_rd_internal : process(RESET_N, opb_clk)
    begin
        if RESET_N = '0' then
            fifo_rd_en_internal_latched <= '0';
        elsif opb_clk'event and opb_clk = '1' then
            fifo_rd_en_internal_latched <= fifo_rd_en_internal;
        end if;
    end process;
	
    fifo_rd_en <= fifo_rd_en_internal and not(fifo_rd_en_internal_latched);		
    ----------------------------------------------------------------------------------

--	status bit assignment --
	status_register  <= x"0000000" & '0' & Vin_RES & fifo_full & fifo_empty;
	
--	resets / control register bit assignment --
	RESET_N      <= not(RESET);
	reset_fifo   <= RESET or control_register(0);
	Vin_CE       <= RESET_N and not(control_register(1));  -- SAA7111 Chip Enable (active high, low forces Vin_RES_N)
--	Vin_CE       <= 'Z';
	DV_OUT_RST_N <= RESET_N and Vin_RES and not(control_register(2));
	enable_i2c   <= control_register(3);
	en_video_pass <= control_register(4);
	en_video_capture <= control_register(5);
	colorbar_en <= control_register(31);
	
--	video pass through (loopback to other chip) --
	DV_OUT <= vid_data(7 DOWNTO 0) when en_video_pass = '1' else (others => '0');
--	DV_OUT <= 	Vin_VPO(15 downto 8) when en_video_pass = '1' else 
--				vid_data(7 DOWNTO 0) when control_register(6) = '1' else
--				(others => '0');

end arch_vid_capture_module;
