---------------------------------------------------------------------------------------------------
--    _____
--   /     \	
--  /____   \____
-- / \===\   \==/
--/___\===\___\/  AVNET
--     \======/   DESIGN
--      \====/    SERVICES
--
---------------------------------------------------------------------------------------------------
--
-- Title: 	
-- Program: 	
-- Filename:	opb_video_capture.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 a simple I2C control interface to  
--            the SAA7111A video input processor and SAA7121 digital video 
--
-- 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					
--							
---------------------------------------------------------------------------------------------------

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

library proc_common_v1_00_b;
use proc_common_v1_00_b.pselect;

entity opb_video_capture is
    generic (
      C_OPB_AWIDTH	: integer := 32;
      C_OPB_DWIDTH	: integer := 32;
      C_BASEADDR		: std_logic_vector := X"FFFF_0000";
      C_HIGHADDR		: std_logic_vector := X"FFFF_00FF"
      );
    port (
      OPB_Clk		: in std_logic;
      OPB_Rst		: in std_logic;
      Interrupt     : out std_logic;
      -- OPB signals
      OPB_ABus		: in std_logic_vector(0 to C_OPB_AWIDTH-1);
      OPB_BE		: in std_logic_vector(0 to C_OPB_DWIDTH/8-1);	-- Not used
      OPB_DBus		: in std_logic_vector(0 to C_OPB_DWIDTH-1);
      OPB_RNW		: in std_logic;	-- Not used read only
      OPB_select		: in std_logic;
      OPB_seqAddr		: in std_logic;	-- Not used

      VID_CAPTURE_DBus		: out std_logic_vector(0 to C_OPB_DWIDTH-1);
      VID_CAPTURE_errAck	: out std_logic;	-- Tied Low
      VID_CAPTURE_retry		: out std_logic;	-- Tied Low
      VID_CAPTURE_toutSup	: out std_logic;	-- Tied Low
      VID_CAPTURE_xferAck	: out std_logic;

--      I2C_SDA        : inout std_logic;   -- I2C data line (open-drain bidirectional data line)
      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)
--      I2C_CLK_I      : in std_logic;   -- I2C clock line (100 kHz)
--      I2C_CLK_O      : out std_logic;  -- I2C clock line (100 kHz)
--      I2C_CLK_T      : out std_logic;  -- I2C clock line (100 kHz)
      Video_CLK      : in    std_logic;-- 27MHz
      Vin_VPO        : in    std_logic_vector(15 downto 0);	--video data in
      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)
      );
end opb_video_capture;

architecture arch_opb_video_capture of opb_video_capture is

-- signal declarations

signal RD_NWR       : std_logic;        -- registered read/Nwrite     
signal Enable       : std_logic;        -- registered chip select     
signal Address      : std_logic_vector(0 to 31); -- registered address
signal Write_Data   : std_logic_vector(0 to 31);                     
signal Read_Data    : std_logic_vector(0 to 31);
signal Video_CS     : std_logic;
signal Data_Valid   : std_logic;

-------------------------------------------------------------------
-- Special function to calculate number of bits need to be decoded
-- based on C_BASEADDR and C_HIGHADDR.
--
-- If C_BASEADDR = x”FFF0_0000” and C_HIGHADDR = x”FFF0_00FF”,
-- the function returns 24.
--
function Addr_Bits (x,y : std_logic_vector(0 to C_OPB_AWIDTH-1))
	return integer is
	variable addr_nor : std_logic_vector(0 to C_OPB_AWIDTH-1);
	begin
		addr_nor := x xor y;
		for i in 0 to C_OPB_AWIDTH-1 loop
			if addr_nor(i)='1' then return i;
			end if;
		end loop;
	return(C_OPB_AWIDTH);
end function Addr_Bits;

constant C_AB : integer := Addr_Bits(C_HIGHADDR,C_BASEADDR);
-------------------------------------------------------------------

-- COMPONENTS
	component 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 component vid_capture_module;

	component pselect is
	generic (
		C_AB 	: integer;
		C_AW 	: integer;
		C_BAR 	: std_logic_vector
		);
	port (
		A 	: in std_logic_vector(0 to C_AW-1);
		AValid: in std_logic;
		CS 	: out std_logic --changed from PS
		);
	end component pselect;

begin

	video_capture_block :  vid_capture_module
	    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            =>  Video_CLK,     -- 27MHz
		 Vin_VPO        =>  Vin_VPO,       --video data in 15 downto 0
		 Vin_RES        =>  Vin_RES,       -- RESET_N output from SAA7111
		 Vin_CE         =>  Vin_CE,        -- SAA7111 Chip Enable (active high, low forces RESET_N)
	     Vin_HREF		=>  Vin_HREF,
		 DV_OUT         =>  DV_OUT,        --video data out
		 DV_OUT_RST_N   =>  DV_OUT_RST_N,  --out to SAA7121 RESET_N (active low)
		 RESET          =>  OPB_Rst, 
         RD_NWR         =>  RD_NWR,    -- registered read/Nwrite
         Enable         =>  Enable,    -- registered chip select
         Address        =>  Address,   -- registered address
         Write_Data     =>  Write_Data,
		 Read_Data      =>  Read_Data,
		 Data_Valid     =>  Data_Valid,
		 opb_clk        =>  opb_clk
		 );

---------------------------------------------------
-- Address Decoding
---------------------------------------------------
-- OPB address decoding using pselect.vhd.
-- The generic map C_BASEADDR is passed from entity,
-- C_AB is the return value from function Addr_Bits().
-- If C_AB gets bigger, the logic of pselect gets bigger.
--
-- OPB_ABus and OPB_select come from the ports.
-- Video_CS has to be registered prior to usage.
-- Use OPB_ABus_reg and OPB_select_reg if non-registered
-- signals don’t meet timing.
	pselect_I : pselect
	generic map (
		C_AB    => C_AB,
		C_AW    => OPB_ABus'length,
		C_BAR   => C_BASEADDR
			)
	port map (
		A       => OPB_ABus,
		AValid  => OPB_select,
		CS      => Video_CS     --changed from PS
		);    
---------------------------------------------------

	
latch_data : process(OPB_CLK, OPB_Rst)
begin
	if OPB_Rst = '1' then
		VID_CAPTURE_xferAck <= '0';
		VID_CAPTURE_Dbus    <= (others => '0');
		RD_NWR              <= '0';			   -- registered read/Nwrite
		Enable              <= '0';			   -- registered chip select
		Address             <= (others => '0');-- registered address
		Write_Data          <= (others => '0');
	elsif OPB_CLK'event and OPB_CLK= '1' then
		if (Video_CS = '1' and OPB_RNW = '0') then     -- write cycle	
			RD_NWR <= '0';
			Enable <= '1';
			Address <= OPB_Abus;
			Write_Data <= OPB_DBus;	
			if Data_Valid = '1' then          -- from our custom block
				VID_CAPTURE_xferAck <= '1';
			else
				VID_CAPTURE_xferAck <= '0';
			end if;				
		elsif (Video_CS = '1' and OPB_RNW = '1') then  -- read cycle	
			RD_NWR <= '1';
			Enable <= '1';
			Address <= OPB_Abus;
			Write_Data <= (others => '0');    -- doesn't matter, this is a read cycle	
			if Data_Valid = '1' then
				VID_CAPTURE_Dbus <= Read_Data;
				VID_CAPTURE_xferAck <= '1';
			else
				VID_CAPTURE_Dbus <= (others => '0');
				VID_CAPTURE_xferAck <= '0';
			end if;				
		else
			VID_CAPTURE_xferAck 	<= '0';
			VID_CAPTURE_Dbus		<= (others => '0');
			RD_NWR <= '1';
			Enable <= '0';
		end if;
	end if;
end process;

VID_CAPTURE_errAck	<= '0';
VID_CAPTURE_retry		<= '0';
VID_CAPTURE_toutSup	<= '0';

end arch_opb_video_capture;
