-------EAGLE IN A RACK--------
-- Main File
-- Copyright Colin O'Flynn (c) 2004
-- see www.newae.com or e-mail me at coflynn@newae.com




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

use work.PS2_mouse.all;
use work.i2c_control.all;
use work.freq_table.all;
use work.video_utils.all;


--  Uncomment the following lines to use the declarations that are
--  provided for instantiating Xilinx primitive components.
--library UNISIM;
--use UNISIM.VComponents.all;



entity video is
    Port ( 	  

--System connections
    CLK_IN     : in std_logic; ---50 MHz system clock
    RESET_IN   : in std_logic; --Active high reset, the pushbutton on the board
    nRESET_IN  : in std_logic; --Active low reset, this is connected to the Power On Reset
    						 --circuit and the front-panel reset button
    LED_OUT    : out std_logic; --Heartbeat LED

    mouseOK_OUT : out std_logic; --LED that lights up when mouse is connected

    videoOK_OUT : out std_logic; --LED that lights up when video signal is OK, 
                                 --blinks when macrovision protected, and is off
                                 --when video not present

    systemOK_OUT : out std_logic; --LED that mights up when the System is A-OK
    trackOK_OUT : inout std_logic; --LED that lights up when the video track is good

--PS/2 Pointing Device (mouse, trackball)
    ps2_clk_inout  : inout std_logic;   --PS2 clock, OC
    ps2_data_inout : inout std_logic;   --PS2 data, OC

--Serial Port
    TX_out     : out std_logic;

--Video source selection connections
    VideoA     : inout std_logic; --select actual video source
    VideoB     : out std_logic; --select video blanking source

--Connections of TVP5145
    PCLK_in    : in std_logic; --line locked pixel clock
    PREF_in    : in std_logic; --line locked phase ref
    SCLK_in    : in std_logic; --line locked system clock at twice PCLK
    AVID_in    : in std_logic; --active video indicator
    FID_in     : in std_logic; --even/odd, 1 = odd
    PALI_in    : in std_logic; --PAL Line Indicator
    VSYNC_in   : in std_logic; --Vertical Sync
    HSYNC_in   : in std_logic; --Horizontal Sync

    UV_in		: in std_logic_vector (9 downto 0); --UV Input
    Y_in		: in std_logic_vector (9 downto 0); --Y Input
	
    SCL_inout  : inout std_logic; -- I2C Clock
    SDA_inout  : inout std_logic; -- I2C Data
    SAS_out    : out std_logic --I2C Address Select
    );

    attribute clkdv_divide: string; 

end video;

architecture Behavioral of video is

                                                   
   --Reset signals (Reset = active high, nReset = active low), Reset_sig is used to create Reset and nReset 
   signal Reset, nReset, Reset_sig, nReset_sig    : std_logic;                                                                         
   
   --mouse controls
   signal x_mouse, y_mouse : std_logic_vector (9 downto 0);
   signal rightbut, leftbut: std_logic;

   --standard port pin signal buffer
   component IBUF port (i: in std_logic; o: out std_logic); 
   end component; 

   --global clock buffer
   component BUFG port (i: in std_logic; o: out std_logic); 
   end component; 

   --CLKDLL, for clock control
   component CLKDLL port (CLKIN: in std_logic; CLKFB: in std_logic; CLK0: out std_logic;
                          CLKDV: out std_logic; RST: in std_logic);
   end component;
   signal CLK0             : std_logic;
   signal CLK0_BUFG        : std_logic;


   --clock running at 1/16 the main clock speed
   signal SLOW_CLK         : std_logic;
   attribute clkdv_divide of clkdiv1 : label is "16.0";

    
   --Current Line Counter
   signal line_counter	  : unsigned (9 downto 0);

   --Current Pixel Counter on the line 
   signal pixel_counter 	  : unsigned (9 downto 0);

   --Buffers for clock signals that aren't on global clock pins
   signal PCLK             : std_logic;
   signal SCLK			  : std_logic;
   signal PREF			  : std_logic;
   signal HSYNC            : std_logic;
   signal AVID             : std_logic;
   signal VSYNC            : std_logic;
   signal FID              : std_logic;
   signal FID_sync         : std_logic;

   --Video source selectors
   signal VideoA_vert, VideoA_horiz : std_logic;
   signal VideoA_vertbox, VideoA_horizbox : std_logic;

   --Serial Port Components
  component TxUnit
  port (
     Clk    : in  std_logic;  -- Clock signal
     Reset  : in  std_logic;  -- Reset input
     Enable : in  std_logic;  -- Enable input
     LoadA  : in  std_logic;  -- Asynchronous Load
     TxD    : out std_logic;  -- RS-232 data output
     Busy   : out std_logic;  -- Tx Busy
     DataI  : in  std_logic_vector(7 downto 0)); -- Byte to transmit
   end component;

  component Counter
  generic(COUNT: INTEGER range 0 to 65535); -- Count revolution
  port (
     Clk      : in  std_logic;  -- Clock
     Reset    : in  std_logic;  -- Reset input
     CE       : in  std_logic;  -- Chip Enable
     O        : out std_logic); -- Output
  end component;

   signal  EnabRx,  EnabTx : std_logic;
   signal TX_load		: std_logic;
   signal TX_busy		: std_logic;
   signal TX_data		: std_logic_vector (7 downto 0);

   --Baudrate = Freq(SLOW_CLK) / BRDIVISOR / 4
   --BRDIVISOR = (Freq / 4) / (BaudRate)
   --SLOW_CLK is 3.125 MHz (3125000 Hz)  
   constant BRDIVISOR : integer := 81;
		 

   --Cursor Locations
   signal x_cursor       : unsigned (9 downto 0);
   signal y_cursor       : unsigned (9 downto 0);

   signal x_cursor_int	: integer range 0 to 1023;
   signal y_cursor_int	: integer range 0 to 1023;

   signal	x_cursor_autoaim : unsigned (9 downto 0);
   signal y_cursor_autoaim : unsigned (9 downto 0);

   type cursor_avg_type is array (0 to 9) of unsigned (9 downto 0);
   signal y_cursor_avg		 : cursor_avg_type;
   signal y_cursor_avg_add	 : unsigned (12 downto 0);

   signal x_cursor_avg		 : cursor_avg_type;
   signal x_cursor_avg_add	 : unsigned (12 downto 0);

   signal	x_cursor_autoaim_int : integer range 0 to 1023;
   signal y_cursor_autoaim_int : integer range 0 to 1023;

   --There is a problem with the TVp5145 delaying the video signal, so by the tim
   --we get information from it the actual pizel has passed. To counter this weneed to
   --create several cursors that are offset this delay, so the user is actually clicking where
   --the data IS, not where the pointer is
   signal x_cursor_fixed : unsigned (9 downto 0);
   signal y_cursor_fixed : unsigned (9 downto 0);

   constant X_CURSOR_CORR : integer := 74; 
   constant Y_CURSOR_CORR : integer := 0; 

   --How big each quadrent is - 50 means 50 each quadrent is a 50 pixel box
   --for example, this will eventually be driven by a mouse wheel
   --constant QUADSIZE	: integer := 50;

   signal quadsize_vector       : std_logic_vector (7 downto 0);
   signal quadsize			  : unsigned (7 downto 0);

   --used to create the blinking Video OK LED
   constant VIDEOOK_COUNTER_MAX : integer := 1562500;

   --Signals used to get the video OK light to do its stuff
   signal videook_counter : integer range 0 to VIDEOOK_COUNTER_MAX;
   signal video_macro    : std_logic;
   signal video_lock     : std_logic;


   --this signal is 'fixed' so that the quadrents appear where the DATA is from
   signal video_location	: video_location_type;
   --this signal is where the video signal is in real life on the video out display
   signal actual_location : video_location_type;

   --signals used in the colour counter
   --these ones are based on the overall window counter that will
   --count the most common colour in the window
   signal resetout_window : std_logic;
   signal resetin_window	 : std_logic;
   signal datardy_window  : std_logic;
   signal record_window	 : std_logic;
   signal outrdy_window	 : std_logic;
   signal sort_addr_window: std_logic_vector(2 downto 0);
   signal data_window	 : std_logic_vector(7 downto 0);
   signal data_window_latched : std_logic_vector(7 downto 0);
   --signal datacount_window: std_logic_vector(9 downto 0);

   --these ones are based on the overall outside window counter that will
   --count the most common colour outside the window
   signal resetout_outside : std_logic;
   signal resetin_outside	 : std_logic;
   signal datardy_outside  : std_logic;
   signal record_outside	 : std_logic;
   signal outrdy_outside	 : std_logic;
   signal sort_addr_outside: std_logic_vector(2 downto 0);
   signal data_outside	 : std_logic_vector(7 downto 0);
   signal data_outside_latched : std_logic_vector(7 downto 0);

   --all four quadrents reset at the same time
   signal resetin_quad    : std_logic;

   --all four quadrents get same input data
   signal datain_quad	 : std_logic_vector(7 downto 0);

   type quad_status_type is (quad_reset, quad_record, quad_output);
   signal quad_status	 : quad_status_type; 

   --each quadrent needs several connection signals
   signal resetout_quad1	 : std_logic;
   signal datardy_quad1	 : std_logic;
   signal datacount_quad1 : std_logic_vector (9 downto 0);
   signal datacount_quad1_count : std_logic_vector (9 downto 0);
   signal quad1_ratio	 : std_logic_vector (7 downto 0);
   signal quad1_ratio_target		: std_logic_vector (7 downto 0);
   signal quad1_ratio_unlatched 	: std_logic_vector (7 downto 0);
   signal quad1_ratio_error		: signed (8 downto 0);
   signal quad1_ratio_error_small  : signed (8 downto 0);
   signal quad1_ratio_error_very_small  : signed (8 downto 0);


   
   --each quadrent needs several connection signals
   signal resetout_quad2	 : std_logic;
   signal datardy_quad2	 : std_logic;
   signal datacount_quad2 : std_logic_vector (9 downto 0);
   signal datacount_quad2_count : std_logic_vector (9 downto 0);
   signal quad2_ratio	 : std_logic_vector (7 downto 0);
   signal quad2_ratio_target		: std_logic_vector (7 downto 0);
   signal quad2_ratio_unlatched 	: std_logic_vector (7 downto 0);
   signal quad2_ratio_error		: signed (8 downto 0);
   signal quad2_ratio_error_small  : signed (8 downto 0);
   signal quad2_ratio_error_very_small  : signed (8 downto 0);


   --each quadrent needs several connection signals
   signal resetout_quad3	 : std_logic;
   signal datardy_quad3	 : std_logic;
   signal datacount_quad3 : std_logic_vector (9 downto 0);
   signal datacount_quad3_count : std_logic_vector (9 downto 0);
   signal quad3_ratio	 : std_logic_vector (7 downto 0);
   signal quad3_ratio_target		: std_logic_vector (7 downto 0);
   signal quad3_ratio_unlatched 	: std_logic_vector (7 downto 0);
   signal quad3_ratio_error		: signed (8 downto 0);
   signal quad3_ratio_error_small  : signed (8 downto 0);
   signal quad3_ratio_error_very_small  : signed (8 downto 0);


   --each quadrent needs several connection signals
   signal resetout_quad4	 : std_logic;
   signal datardy_quad4	 : std_logic;
   signal datacount_quad4 : std_logic_vector (9 downto 0);
   signal datacount_quad4_count : std_logic_vector (9 downto 0);
   signal quad4_ratio	 : std_logic_vector (7 downto 0);
   signal quad4_ratio_target		: std_logic_vector (7 downto 0);
   signal quad4_ratio_unlatched 	: std_logic_vector (7 downto 0);
   signal quad4_ratio_error		: signed (8 downto 0);
   signal quad4_ratio_error_small  : signed (8 downto 0);
   signal quad4_ratio_error_very_small  : signed (8 downto 0);


   signal datacount_window_total 	: std_logic_vector (9 downto 0);

   signal quad_status_output		: std_logic;
   signal quad_status_reset		: std_logic;

   type states_type is (unlocked, locking, almost_locked, locked);
   signal state : states_type;

   signal VSYNC_counter: integer range 0 to 60;
   signal VSYNC_max: integer range 0 to 60;


	
   --what is the lower limit of data, below this we ignore for the colour counter
   constant LOWERCAP_LIMIT : std_logic_vector(7 downto 0) := "00000000";
   --upper limit
   constant UPPERCAP_LIMIT : std_logic_vector(7 downto 0) := "11111111";

   constant colour_var	   : std_logic_vector(3 downto 0) := "0001";

   type freq_table_reset_type is (reset_state, run, track);
   signal freq_table_reset : freq_table_reset_type;

   type UV_status_type is (U, V);
   signal UV_status 	: UV_status_type;

   signal same_colour : std_logic;

   signal data_U, data_V, data_UV, data_UV_sig : std_logic_vector (7 downto 0);

   --used to count how many frames we are counting
   --signal VSYNC_max		: integer range 0 to 60;

   --this is the target colour of interest
   signal colour_target	: std_logic_vector(7 downto 0);

   --used to dram both the white pixels and colour the selecting box in white
   signal colour_rdy	: std_logic;
   signal quad_match_1, quad_match_2, quad_match_3, quad_match_4	: std_logic;
   signal match_video	: std_logic;

   --division core
   component division_core
	port (
	dividend: IN std_logic_VECTOR(9 downto 0);
	divisor: IN std_logic_VECTOR(9 downto 0);
	quot: OUT std_logic_VECTOR(9 downto 0);
	remd: OUT std_logic_VECTOR(7 downto 0);
	c: IN std_logic);
   end component;


   begin

   --need to stop ISE from deciding that these signals are global clocks
   --and complaining when they aren't routed to global clock pins
   ibuf1: IBUF port map(i => PCLK_in, o => PCLK); 
   ibuf2: IBUF port map(i => HSYNC_IN, o => HSYNC); 
   ibuf3: IBUF port map(i => VSYNC_IN, o => VSYNC); 
   ibuf4: IBUF port map(i => SCLK_in, o => SCLK);
   ibuf5: IBUF port map(i => PREF_in, o => PREF);

   --Need to stop ISE from claiming that this pin shouldn't be connected to a
   --global clock
   bufg1: BUFG port map(i => RESET_in, o => Reset_sig); 
   bufg2: BUFG port map(i => nRESET_in, o => nReset_sig);

   --Create a low-frequency clock signal 
   clkdiv1: CLKDLL port map(CLKIN => CLK_IN, CLK0 => CLK0, CLKFB => CLK0_BUFG, RST => '0',
                           CLKDV => SLOW_CLK);  
   bufg3: BUFG port map(i => CLK0, o => CLK0_BUFG);


   process(reset_sig, nReset_sig, SLOW_CLK)
   begin
   if (reset_sig = '1' or nReset_sig = '0') then
   	Reset <= '1';
   elsif rising_edge(SLOW_CLK) then
   	Reset <= '0';
   end if;
   end process;

   --some things need active low reset
   nReset <= not Reset;
   
   --mapped to actual signal names in case a buffer ever needs to be inserted
   --AVID <= AVID_in;
   AVID <= '1' when pixel_counter < CONV_UNSIGNED(700, 10) and 
   			     pixel_counter > CONV_UNSIGNED(2, 10) and
     			line_counter < CONV_UNSIGNED(550, 10) and
   				line_counter > CONV_UNSIGNED(2, 10)  else '0';
   FID <= FID_in;

   --connect up the I2C init part that will initilize the TVP5145
   i2c_ctrl: controlchip port map (RESET_in => Reset, CLK_in => clk_in,
                  Lock_out => video_lock, Macro_out => video_macro,
                  SCL_inout => SCL_inout, SDA_inout => SDA_inout, SAS_out => SAS_out);

   LED_out <= '1';

   systemOK_out <= nReset;

 --connect up the mouse controller 
ps2: mouse port map (clk_i => clk_in, rst_i => Reset, nrst_i => nReset, y_loc_o => y_mouse, 
                     x_loc_o => x_mouse, z_loc_o => quadsize_vector, mouseok_o => mouseok_out, slow_clk => slow_clk, 
				 rightbut_o => rightbut, leftbut_o => leftbut, 
                     ps2_clk_io => ps2_clk_inout, ps2_data_io => ps2_data_inout);

  quadsize <= unsigned(quadsize_vector);


   --connect up serial transmitter
  Uart_Rxrate : Counter -- Baud Rate adjust
     generic map (COUNT => BRDIVISOR)
     port map (slow_clk, '0', '1', EnabRx);
  Uart_Txrate : Counter -- 4 Divider for Tx
     generic map (COUNT => 4)
     port map (slow_clk, '0', EnabRx, EnabTx);
  Tx1: TxUnit port map(
     Clk    => slow_clk,
	Reset  => Reset,
     Enable => EnabTX,
     LoadA  => TX_load,
     TxD    => TX_out,
     Busy   => TX_busy,
     DataI  => TX_data);


   linecount1: location_counter port map (VSYNC_in => VSYNC, HSYNC_in => HSYNC, FID_in => FID, PCLK_in => PCLK,
   								  pixel_out => pixel_counter, line_out => line_counter);



   x_cursor_fixed <= x_cursor +  X_CURSOR_CORR;
   y_cursor_fixed <= y_cursor +  Y_CURSOR_CORR;

   --y_cursor_vector <= std_logic_vector(CONV_UNSIGNED(y_cursor, 10));
   --x_cursor_vector <= std_logic_vector(CONV_UNSIGNED(x_cursor, 10));

   --y_cursor_fixed_vector <= std_logic_vector(CONV_UNSIGNED(y_cursor_fixed, 10));
   --x_cursor_fixed_vector <= std_logic_vector(CONV_UNSIGNED(x_cursor_fixed, 10));



   --find what quadrent we are in currently in
   quadfixed: quadrent_location port map(PCLK_in => PCLK, pixel_in => pixel_counter, line_in => line_counter, 
    							    quadrentsize_in => QUADSIZE, x_cursor_in => x_cursor_fixed, y_cursor_in => y_cursor_fixed,
							    video_loc_out => video_location);


   quadreal: quadrent_location port map(PCLK_in => PCLK, pixel_in => pixel_counter, line_in => line_counter, 
    							    quadrentsize_in => quadsize, x_cursor_in => x_cursor, y_cursor_in => y_cursor,
							    video_loc_out => actual_location);


   quad_status <= quad_reset when line_counter > (y_cursor + CONV_UNSIGNED(10, 10)) else
   			   quad_output when line_counter > (y_cursor + CONV_UNSIGNED(5, 10)) else
			   quad_record;

   process(PREF)
   begin
   if rising_edge(PREF) then
   	if quad_status = quad_reset then
		datacount_quad1 <= (others => '0');
   	elsif data_UV > ((colour_target(7 downto 4) - colour_var) & (colour_target(3 downto 0) - colour_var)) and data_UV < ((colour_target(7 downto 4) + colour_var) & (colour_target(3 downto 0) + colour_var))  and UV_status = V and video_location = quad1 then
	  if datacount_quad1 = "1111111111" then
	     datacount_quad1 <= "1111111111";
       else
	     datacount_quad1 <= datacount_quad1 + "0000000001";
       end if;
     end if;
   end if;
   end process;

      process(PREF)
   begin
   if rising_edge(PREF) then
   	if quad_status = quad_reset then
		datacount_quad2 <= (others => '0');
   	elsif data_UV > ((colour_target(7 downto 4) - colour_var) & (colour_target(3 downto 0) - colour_var)) and data_UV < ((colour_target(7 downto 4) + colour_var) & (colour_target(3 downto 0) + colour_var)) and UV_status = V and video_location = quad2 then
	  if datacount_quad2 = "1111111111" then
	     datacount_quad2 <= "1111111111";
       else
	     datacount_quad2 <= datacount_quad2 + "0000000001";
       end if;
     end if;
   end if;
   end process;

      process(PREF)
   begin
   if rising_edge(PREF) then
   	if quad_status = quad_reset then
		datacount_quad3 <= (others => '0');
   	elsif data_UV > ((colour_target(7 downto 4) - colour_var) & (colour_target(3 downto 0) - colour_var)) and data_UV < ((colour_target(7 downto 4) + colour_var) & (colour_target(3 downto 0) + colour_var)) and UV_status = V and video_location = quad3 then
	  if datacount_quad3 = "1111111111" then
	     datacount_quad3 <= "1111111111";
       else
	     datacount_quad3 <= datacount_quad3 + "0000000001";
       end if;
     end if;
   end if;
   end process;

      process(PREF)
   begin
   if rising_edge(PREF) then
   	if quad_status = quad_reset then
		datacount_quad4 <= (others => '0');
   	elsif data_UV > ((colour_target(7 downto 4) - colour_var) & (colour_target(3 downto 0) - colour_var)) and data_UV < ((colour_target(7 downto 4) + colour_var) & (colour_target(3 downto 0) + colour_var)) and UV_status = V and video_location = quad4 then
	  if datacount_quad4 = "1111111111" then
	     datacount_quad4 <= "1111111111";
       else
	     datacount_quad4 <= datacount_quad4 + "0000000001";
       end if;
     end if;
   end if;
   end process;


  quad1_ratio_error <= SIGNED('0' & quad1_ratio) - SIGNED('0' & quad1_ratio_target);--CONV_SIGNED(65, 9);
  quad2_ratio_error <= SIGNED('0' & quad2_ratio) - SIGNED('0' & quad2_ratio_target);--CONV_SIGNED(65, 9);
  quad3_ratio_error <= SIGNED('0' & quad3_ratio) - SIGNED('0' & quad3_ratio_target);--CONV_SIGNED(65, 9);
  quad4_ratio_error <= SIGNED('0' & quad4_ratio) - SIGNED('0' & quad4_ratio_target);--CONV_SIGNED(65, 9);

  quad1_ratio_error_small <= ("1111" & quad1_ratio_error(7 downto 3)) when quad1_ratio_error(8) = '1' else
  					    ("0000" & quad1_ratio_error(7 downto 3));

  quad2_ratio_error_small <= ("1111" & quad2_ratio_error(7 downto 3)) when quad2_ratio_error(8) = '1' else
  					    ("0000" & quad2_ratio_error(7 downto 3));

  quad3_ratio_error_small <= ("1111" & quad3_ratio_error(7 downto 3)) when quad3_ratio_error(8) = '1' else
  					    ("0000" & quad3_ratio_error(7 downto 3));

					     --"1111" & quad4_ratio_error(7 downto 3)
  quad4_ratio_error_small <= ("1111" & quad4_ratio_error(7 downto 3)) when quad4_ratio_error(8) = '1' else
  					    ("0000" & quad4_ratio_error(7 downto 3));

  quad1_ratio_error_very_small <= ("11111" & quad1_ratio_error(7 downto 4)) when quad1_ratio_error(8) = '1' else
  					    ("00000" & quad1_ratio_error(7 downto 4));

  quad2_ratio_error_very_small <= ("11111" & quad2_ratio_error(7 downto 4)) when quad2_ratio_error(8) = '1' else
  					    ("00000" & quad2_ratio_error(7 downto 4));

  quad3_ratio_error_very_small <= ("11111" & quad3_ratio_error(7 downto 4)) when quad3_ratio_error(8) = '1' else
  					    ("00000" & quad3_ratio_error(7 downto 4));

  quad4_ratio_error_very_small <= ("11111" & quad4_ratio_error(7 downto 4)) when quad4_ratio_error(8) = '1' else
  					    ("00000" & quad4_ratio_error(7 downto 4));
					  		   


  quad_status_output <= '1' when quad_status = quad_output else '0';


   datacount_window_total <= datacount_quad1 + datacount_quad2 + datacount_quad3 + datacount_quad4;
   
   --the ratio of the colour of interest quadrent  1
   quad1_ratio_div : division_core
		port map (
			dividend => datacount_quad1,
			divisor => datacount_window_total,
			remd => quad1_ratio_unlatched,
			c => clk_in);

   --the ratio of the colour of interest quadrent  2
   quad2_ratio_div : division_core
		port map (
			dividend => datacount_quad2,
			divisor => datacount_window_total,
			remd => quad2_ratio_unlatched,
			c => clk_in);

   --the ratio of the colour of interest quadrent  3
   quad3_ratio_div : division_core
		port map (
			dividend => datacount_quad3,
			divisor => datacount_window_total,
			remd => quad3_ratio_unlatched,
			c => clk_in);

   --the ratio of the colour of interest quadrent  4
   quad4_ratio_div : division_core
		port map (
			dividend => datacount_quad4,
			divisor => datacount_window_total,
			remd => quad4_ratio_unlatched,
			c => clk_in);


   process(quad_status)
   begin
   if rising_edge(quad_status_output) then
	if state = almost_locked then
	  quad1_ratio_target <= quad1_ratio_unlatched(7 downto 0);
	  quad2_ratio_target <= quad2_ratio_unlatched(7 downto 0);
	  quad3_ratio_target <= quad3_ratio_unlatched(7 downto 0);
	  quad4_ratio_target <= quad4_ratio_unlatched(7 downto 0);
     end if;
   end if;
   end process;


   process(quad_status)
   begin
   if rising_edge(quad_status_output) then
	quad1_ratio <= quad1_ratio_unlatched(7 downto 0);
	quad2_ratio <= quad2_ratio_unlatched(7 downto 0);
	quad3_ratio <= quad3_ratio_unlatched(7 downto 0);
	quad4_ratio <= quad4_ratio_unlatched(7 downto 0);
   end if;
   end process;


   --reset all the counters when done
   quad_status_reset <= '1' when quad_status = quad_reset else '0';
   process(quad_status, resetout_quad1, resetout_quad2, resetout_quad3, resetout_quad4)
   begin
   if (quad_status /= quad_reset) then
   	resetin_quad <= '0';	    
   elsif state = almost_locked and outrdy_window = '1' then
   	resetin_quad <= '1';
   elsif rising_edge(quad_status_reset) then
     --when we are locking onto object do NOT reset counters
     if state /= almost_locked then 
   		resetin_quad <= '1';
     end if;
   end if;
   end process;


   process(slow_clk, reset)
   type state_txd_data_type is (txdreset, txdmarkera, txdmarkerb, txdquad1ta, txdquad1tb, txdquad2ta, txdquad2tb, txdquad3ta, txdquad3tb, txdquad4ta,  txdquad4tb, txdquad1a, txdquad1b, txdquad2a, txdquad2b, txdquad3a, txdquad3b, txdquad4a, txdquad4b);
   variable state_txd_data : state_txd_data_type;
   variable nxt_state : state_txd_data_type;
   variable clk_counter : integer range 0 to 3000001;
   begin
   
   case state_txd_data is

     when txdreset =>
	    TX_load <= '0';
	    nxt_state := txdmarkera;

   	when txdmarkera =>
		TX_data <= x"FF";
		TX_load <= '1';
		nxt_state := txdmarkerb;
				
	when txdmarkerb =>
		TX_load <= '0';
		nxt_state := txdquad1ta;

   	when txdquad1ta =>
--		TX_data <= quad1_ratio_error(8 downto 1);
		TX_load <= '1';
		nxt_state := txdquad1tb;
				
	when txdquad1tb =>
		TX_load <= '0';
		nxt_state := txdquad2ta;

   	when txdquad2ta =>
--		TX_data <= quad2_ratio_error(8 downto 1);
		TX_load <= '1';
		nxt_state := txdquad2tb;
				
	when txdquad2tb =>
		TX_load <= '0';
		nxt_state := txdquad3ta;

   	when txdquad3ta =>
--		TX_data <= quad3_ratio_error(8 downto 1);
		TX_load <= '1';
		nxt_state := txdquad3tb;
				
	when txdquad3tb =>
		TX_load <= '0';
		nxt_state := txdquad4ta;
		
   	when txdquad4ta =>
--		TX_data <= quad4_ratio_error(8 downto 1);
		TX_load <= '1';
		nxt_state := txdquad4tb;
				
	when txdquad4tb =>
		TX_load <= '0';
		nxt_state := txdmarkera;   	

	when others =>
   end case;
		
   
   
   if reset = '1' then
   	state_txd_data := txdreset;
   elsif rising_edge(slow_clk) then
    if clk_counter = 3000000 then
	state_txd_data := nxt_state;
	clk_counter := 0;
    else
     clk_counter := clk_counter + 1;
    end if;
   end if;
   end process;


   process(VSYNC)
   begin
   if state = locking then
     --y_cursor_autoaim <= y_cursor;
	--x_cursor_autoaim <= x_cursor;

	x_cursor_avg(0) <= x_cursor;   
	x_cursor_avg(1) <= x_cursor;
	x_cursor_avg(2) <= x_cursor;
	x_cursor_avg(3) <= x_cursor;
	x_cursor_avg(4) <= x_cursor;
	x_cursor_avg(5) <= x_cursor;
	x_cursor_avg(6) <= x_cursor;
	x_cursor_avg(7) <= x_cursor;


	y_cursor_avg(0) <= y_cursor;   
	y_cursor_avg(1) <= y_cursor;
	y_cursor_avg(2) <= y_cursor;
	y_cursor_avg(3) <= y_cursor;
	y_cursor_avg(4) <= y_cursor;
	y_cursor_avg(5) <= y_cursor;
	y_cursor_avg(6) <= y_cursor;
	y_cursor_avg(7) <= y_cursor;

   elsif rising_edge(VSYNC) then
   	--now we move the cursor in the direction of excess pixels: for left quadrents (1 and 4) move cursor in left (-) x direction
	--when excess pixels. For right quadrents (2 and 3) move cursor in right (+) x direction for excess pixels

	if FID = '1' then
	
--	x_cursor_autoaim <= CONV_UNSIGNED((SIGNED('0' & x_cursor) - SIGNED(quad1_ratio_error_small) + SIGNED(quad2_ratio_error_small) + SIGNED(quad3_ratio_error_small) - SIGNED(quad4_ratio_error_small)), 10);
	x_cursor_avg(7) <= CONV_UNSIGNED((SIGNED('0' & x_cursor) - SIGNED(quad1_ratio_error_small) + SIGNED(quad2_ratio_error_small) + SIGNED(quad3_ratio_error_small) - SIGNED(quad4_ratio_error_small)), 10);
	x_cursor_avg(6) <= x_cursor_avg(7);
	x_cursor_avg(5) <= x_cursor_avg(6);
	x_cursor_avg(4) <= x_cursor_avg(5);
	x_cursor_avg(3) <= x_cursor_avg(4);
	x_cursor_avg(2) <= x_cursor_avg(3);
	x_cursor_avg(1) <= x_cursor_avg(2);
	x_cursor_avg(0) <= x_cursor_avg(1);

	else

--     y_cursor_autoaim <= CONV_UNSIGNED((SIGNED("0" & y_cursor_autoaim) - SIGNED(quad1_ratio_error_small) - SIGNED(quad2_ratio_error_small) + SIGNED(quad3_ratio_error_small) + SIGNED(quad4_ratio_error_small)), 10);
	y_cursor_avg(7) <= CONV_UNSIGNED((SIGNED('0' & y_cursor) - SIGNED(quad1_ratio_error_very_small)- SIGNED(quad2_ratio_error_very_small) + SIGNED(quad3_ratio_error_very_small) + SIGNED(quad4_ratio_error_very_small)), 10);   
	y_cursor_avg(6) <= y_cursor_avg(7);
	y_cursor_avg(5) <= y_cursor_avg(6);
	y_cursor_avg(4) <= y_cursor_avg(5);
	y_cursor_avg(3) <= y_cursor_avg(4);
	y_cursor_avg(2) <= y_cursor_avg(3);
	y_cursor_avg(1) <= y_cursor_avg(2);
	y_cursor_avg(0) <= y_cursor_avg(1);

	end if;
	
	--y_cursor_autoaim <= y_cursor;
	--x_cursor_autoaim <= x_cursor;

   end if;

   end process;	




   y_cursor_avg_add <= CONV_UNSIGNED(y_cursor_avg(7), 13) + CONV_UNSIGNED(y_cursor_avg(6), 13) + CONV_UNSIGNED(y_cursor_avg(5), 13) + CONV_UNSIGNED(y_cursor_avg(4), 13) + CONV_UNSIGNED(y_cursor_avg(3), 13) + CONV_UNSIGNED(y_cursor_avg(2), 13) + CONV_UNSIGNED(y_cursor_avg(1), 13) + CONV_UNSIGNED(y_cursor_avg(0), 13);
   y_cursor_autoaim <= UNSIGNED(y_cursor_avg_add(12 downto 3));

   x_cursor_avg_add <= CONV_UNSIGNED(x_cursor_avg(7), 13) + CONV_UNSIGNED(x_cursor_avg(6), 13) + CONV_UNSIGNED(x_cursor_avg(5), 13) + CONV_UNSIGNED(x_cursor_avg(4), 13) + CONV_UNSIGNED(x_cursor_avg(3), 13) + CONV_UNSIGNED(x_cursor_avg(2), 13) + CONV_UNSIGNED(x_cursor_avg(1), 13) + CONV_UNSIGNED(x_cursor_avg(0), 13);
   x_cursor_autoaim <= UNSIGNED(x_cursor_avg_add(12 downto 3));

   window_colour: frequency_table port map(
   	reset_in => resetin_window,
	reset_out => resetout_window,
	dataclk_in => PCLK,
	dataclk90_in => PREF,
	dbldataclk_in => SCLK,
	data_in => data_UV_sig,
	data_rdy_in => datardy_window,
	record_in => record_window,
	lowerlimit_in => LOWERCAP_LIMIT,
	upperlimit_in => UPPERCAP_LIMIT,
	data_rdy_out => outrdy_window,
	sort_addr_in => sort_addr_window,
	data_out => data_window);

   outside_colour: frequency_table port map(
   	reset_in => resetin_outside,
	reset_out => resetout_outside,
	dataclk_in => PCLK,
	dataclk90_in => PREF,
	dbldataclk_in => SCLK,
	data_in => data_UV_sig,
	data_rdy_in => datardy_outside,
	record_in => record_outside,
	lowerlimit_in => LOWERCAP_LIMIT,
	upperlimit_in => UPPERCAP_LIMIT,
	data_rdy_out => outrdy_outside,
	sort_addr_in => sort_addr_outside,
	data_out => data_outside);


     --lb1 : line_buffer
	--	port map (
	--		CLK => PCLK,
	--		D => data_UV_sig,
	--		Q => data_UV,
	--		CE => '1');

	data_UV <= data_UV_sig;

--	process(SCLK)
--	begin
--	if falling_edge(SCLK) then
--	if PCLK = '0' and PREF = '1' then
--		if UV_status = U then
--			data_U <= UV_in(9 downto 2);
--		end if;
--	end if;
--	end if;
--	end process; 
  --
--	process(SCLK)
--	begin
--	if falling_edge(SCLK) then
--	if PCLK = '0' and PREF = '1' then
--		if UV_status = V then
--			data_V <= UV_in(9 downto 2);
--		end if;
--	end if;
--	end if;
--	end process; 

	process(SCLK)
	begin
	if SCLK = '0' and PCLK = '0' and PREF = '1' then
		if UV_status = U then
			data_U <= UV_in(9 downto 2);
		else
			data_V <= UV_in(9 downto 2);
		end if;
	end if;
	end process; 

   data_UV_sig <= data_U(7 downto 4) & data_V(7 downto 4);

   sort_addr_window <= "000";

   --add in U and V
   datardy_window <= '1' when ((UV_status = V) and (video_location /= outside)) else '0';

   datardy_outside <= '1' when ((UV_status = V) and (video_location = outside)) else '0';

      
   --process(VSYNC, VSYNC_max, freq_table_reset)
   --variable VSYNC_counter: integer range 0 to 60;
   --begin
   --if VSYNC_counter = 0 or VSYNC_counter = 1 then
   	--resetin_window <= '1';
--	record_window <= '1';
   --elsif VSYNC_counter = VSYNC_max then
   	--resetin_window <= '0';
	--record_window <= '0';
  -- else
 --  	resetin_window <= '0';
--	record_window <= '1';
   --end if;   

   --if freq_table_reset = reset_state then
   --	VSYNC_counter := 0;
   --elsif falling_edge(VSYNC) then
  -- 	if VSYNC_counter = VSYNC_max then
--		VSYNC_counter := VSYNC_max; 
--	else
--   		VSYNC_counter := VSYNC_counter + 1;
--	end if;
   --end if;
   --end process;
   
   	
 
   same_colour <= '0' when (UV_status = V) and 
   				(colour_target = data_UV) and
				(state = locked) 
				else '1';

  


   process(PCLK, VSYNC)
   begin
   if VSYNC = '1' then
   	UV_status <= U;
   elsif falling_edge(PCLK) then
   	if (UV_status = U) then
		UV_status <= V;
	else
		UV_status <= U;
	end if;
    end if;
   end process;



   --draw the cross-hair's vertical line 
   process(pixel_counter, x_cursor, line_counter, y_cursor, quadsize)
      begin
	 --widen the cursor up a bit
      if ((pixel_counter > (x_cursor - 1) AND pixel_counter < (x_cursor + 2)) AND 
	     (line_counter > y_cursor - QUADSIZE) AND (line_counter < y_cursor + QUADSIZE)) then

         VideoA_vert <= '0';
      else
         VideoA_vert <= '1';
      end if;
   end process;

   --draw the cross-hair's horizontal line
	--x_cursor_leftquad <= x_cursor_vector - quadsize_vector;
	--x_cursor_rightquad <= x_cursor_vector + quadsize_vector;

	--x_cursor_vector <= std_logic_vector(CONV_UNSIGNED(x_cursor, 10));
	--y_cursor_vector <= std_logic_vector(CONV_UNSIGNED(y_cursor, 10));

	--pixel_counter_vector <= std_logic_vector(CONV_UNSIGNED(pixel_counter, 10));

   process(pixel_counter, x_cursor, line_counter, y_cursor, quadsize)
      begin
	   --widen the cursor up a bit
      if ((line_counter > (y_cursor-1) AND line_counter < (y_cursor + 2)) AND 
	     (pixel_counter > (x_cursor - QUADSIZE)) AND (pixel_counter < (x_cursor + QUADSIZE))) then
		--(pixel_counter_vector > (x_cursor_leftquad)) AND (pixel_counter_vector < (x_cursor_rightquad))) then
         VideoA_horiz <= '0';
      else
         VideoA_horiz <= '1';
      end if;
   end process;

   --draw the box's horizontal lines
   process(pixel_counter, x_cursor, line_counter, y_cursor, quadsize)
      begin
      if ((line_counter = (y_cursor+QUADSIZE) OR line_counter = (y_cursor - QUADSIZE)) AND 
	    (pixel_counter > x_cursor - QUADSIZE) AND (pixel_counter < x_cursor + QUADSIZE)) then
		--(pixel_counter_vector > (x_cursor_leftquad)) AND (pixel_counter_vector < (x_cursor_rightquad))) then
         VideoA_horizbox <= '0';
      else
         VideoA_horizbox <= '1';
      end if;
   end process;

   --draw the box's vertical lines
   process(pixel_counter, x_cursor, line_counter, y_cursor, quadsize)
      begin
      if ((pixel_counter = (x_cursor+QUADSIZE) OR pixel_counter = (x_cursor - QUADSIZE)) AND 
	     (line_counter > y_cursor - QUADSIZE) AND (line_counter < y_cursor + QUADSIZE)) then
         VideoA_vertbox <= '0';
      else
         VideoA_vertbox <= '1';
      end if;
   end process;


   


   --select normal video if both X and Y counters are currently NOT at the position of where the white cursor should appear
   --otherwise select the video source as a white level  
   VideoA <= VideoA_horiz AND VideoA_vert AND VideoA_horizbox AND VideoA_vertbox AND same_colour when AVID = '1' else '1';

   --Can't select both video types at once or else bad stuff happens!
   VideoB <= not VideoA; 

  track_statemachine : block 

		signal nxt_state: states_type;

		signal modes: states_type;

		signal sy_cursor, sx_cursor: unsigned (9 downto 0);
		signal sfreq_table_reset : freq_table_reset_type;

	begin

   state_machine: process(state, clk_in, y_cursor_autoaim, x_cursor_autoaim)
   begin
   case state is 
  	when unlocked =>
		--the mouse controls the location of the cursor on the screen
		sy_cursor <= unsigned(y_mouse);
		sx_cursor <= unsigned(x_mouse);
		trackOK_OUT <= '0';

		--when left button is held down, object will be locked
		if (leftbut = '1') then
			nxt_state <= locking;
		else
			nxt_state <= unlocked;
		end if;

		sfreq_table_reset <= reset_state;

		colour_rdy <= '0';

		resetin_window <= '1';
   		record_window <= '1';

		resetin_outside <= '1';
   		record_outside <= '1';


	when locking =>
		
		trackOK_OUT <= '0';

		--the mouse controls the location of the cursor on the screen
		sy_cursor <= unsigned(y_mouse);
		sx_cursor <= unsigned(x_mouse);

		resetin_window <= '0';
   		record_window <= '1';

		resetin_outside <= '0';
   		record_outside <= '1';

		--when left button is released we are done locking onto object
		if (leftbut = '0') then
		--if (outrdy_window = '1') then
			nxt_state <= almost_locked;
			colour_rdy <= '1';
		else
			nxt_state <= locking;
			colour_rdy <= '0';
		end if;
		
		sfreq_table_reset <= reset_state;

     when almost_locked =>
		VSYNC_max <= 4;


   		resetin_window <= '0';
   		record_window <= '0';

		resetin_outside <= '0';
   		record_outside <= '0';

	     if outrdy_window = '1' and VSYNC_counter = 4 and sort_addr_outside = "111" then
			nxt_state <= locked;
		else
			nxt_state <= almost_locked;
		end if;

		trackOK_OUT <= '0';

		sfreq_table_reset <= run;

	when locked =>
		VSYNC_max <= 3;
		
		case (VSYNC_counter) is
			when 0 =>
   				resetin_window <= '1';
   				record_window <= '1';
			when 1 =>
				resetin_window <= '0';
   				record_window <= '1';
			when 2 =>
			   	resetin_window <= '0';
   				record_window <= '1';
			when 3 =>
			   	resetin_window <= '0';
   				record_window <= '0';
			when others =>
			   	resetin_window <= '1';
   				record_window <= '1';
				
		end case;
			

		sy_cursor <= y_cursor_autoaim;
		sx_cursor <= x_cursor_autoaim;
		nxt_state <= locked;
		trackOK_OUT <= '1';

		sfreq_table_reset <= run;

		colour_rdy <= '1';
   end case;

      
    --the right mouse button will reset this state machine, releasing the mouse for use
    if (reset = '1' or rightbut = '1' or reset = '1') then
    		state <= unlocked;
    elsif Rising_Edge(clk_in) then

    		state <= nxt_state;

		if state /= almost_locked then
			sort_addr_outside <= "111";
			sort_addr_window <= "000";
		elsif outrdy_outside = '1' then
	   	--	if (sort_addr_outside /= "111") then
		--		if data_window /= data_outside then 
					colour_target <= data_window;
		--			sort_addr_outside <= sort_addr_outside + "001";
		--		else
		--			sort_addr_window <= sort_addr_window + "001";
		--			sort_addr_outside <= sort_addr_outside + "111";
		--		end if;
		--	end if;
		end if;

	

		--if sy_cursor < CONV_UNSIGNED(10, 10) then
		--	y_cursor <= CONV_UNSIGNED(10, 10);
		--elsif sy_cursor > CONV_UNSIGNED(500, 10) then
		--	y_cursor <= CONV_UNSIGNED(500, 10);
		--else
			y_cursor <= sy_cursor;
		--end if;

		--if sx_cursor < CONV_UNSIGNED(10, 10) then
	--		x_cursor <= CONV_UNSIGNED(10, 10);
	--	elsif sx_cursor > CONV_UNSIGNED(700, 10) then
	--		x_cursor <= CONV_UNSIGNED(700, 10);
	--	else
			x_cursor <= sx_cursor;
	--	end if;



		freq_table_reset <= sfreq_table_reset;
    end if;
   end process state_machine;

   end block track_statemachine;


   --VSYNC_COUNTER
   process(VSYNC, VSYNC_max, freq_table_reset)
   begin
   if freq_table_reset = reset_state then
   	VSYNC_counter <= 0;
   elsif falling_edge(VSYNC) then
   	if VSYNC_counter = VSYNC_max then
		--VSYNC_counter := VSYNC_max; 
		VSYNC_counter <= 0;
	else
   		VSYNC_counter <= VSYNC_counter + 1;
	end if;
   end if;
   end process;

   --used to indicate what the status of the video signal is   
   process(slow_clk, video_macro, video_lock)
      begin
      if Rising_edge(slow_clk) then
         if (video_macro = '1') then
            videook_counter <= videook_counter + 1;
         elsif (video_lock = '1') then
            videook_counter <= VIDEOOK_COUNTER_MAX/2;
         else
            videook_counter <= 0;
         end if;
      end if;
   end process;

   process(videook_counter, slow_clk)
      begin
      if falling_edge(slow_clk) then
         if (videook_counter = VIDEOOK_COUNTER_MAX/2) then
            videook_out <= '1';
         elsif (videook_counter = 0) then
            videook_out <= '0';
         end if;
      end if;
   end process;

end Behavioral;
