-- ======================================================================================================
-- ======================================================================================================

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity vga_sync is
	port(
		clk, reset: in std_logic;
		hsync, vsync, comp_sync: out std_logic;
		video_on, p_tick: out std_logic;
		pixel_x, pixel_y: out std_logic_vector(9 downto 0)
	);
end vga_sync;

-- ======================================================================================================
-- ======================================================================================================

architecture arch of vga_sync is

-- 640 X 480 @ 60Hz with a 25.000MHz pixel clock
	constant HD: integer:= 640; -- horizontal display
	constant HF: integer:= 16; -- hsync front porch
	constant HB: integer:= 48; -- hsync back porch
	constant HR: integer:= 96; -- hsync retrace
	constant VD: integer:= 480; -- vertical display
	constant VF: integer:= 11; -- vsync front porch
	constant VB: integer:= 31; -- vsync back porch
	constant VR: integer:= 2; -- vsync retrace

-- 800 X 600 @ 60Hz with a 40.000MHz pixel clock
--	constant HD: integer:= 800;	-- pixels
--	constant HF: integer:= 40;	-- pixels
--	constant HB: integer:= 88;	-- pixels
--	constant HR: integer:= 128;	-- pixels
--	constant VD: integer:= 600;	-- lines
--	constant VF: integer:= 1;	-- lines
--	constant VB: integer:= 23;	-- lines
--	constant VR: integer:= 4;	-- lines

-- mod2 cnter
	signal clk_div2_reg, clk_div2_next: std_logic;
	signal mod2_reg, mod2_next: std_logic;

-- sync counters
	signal v_cnt_reg, v_cnt_next: unsigned(9 downto 0);
	signal h_cnt_reg, h_cnt_next: unsigned(9 downto 0);

-- output buffers
	signal v_sync_reg, h_sync_reg: std_logic;
	signal v_sync_next, h_sync_next: std_logic;
	signal h_sync_delay1, h_sync_delay2: std_logic;
	signal v_sync_delay1, v_sync_delay2: std_logic;

-- status signal
	signal h_end, v_end, pixel_tick: std_logic;

	begin

-- ======================================================================================================
-- System clock is 100 MHz?
	process (clk, reset)
		begin
		if (reset = '1') then
			clk_div2_reg <= '0';
		elsif ( clk'event and clk = '1' ) then
			clk_div2_reg <= clk_div2_next;
		end if;
	end process;

-- mod-2 circuit to generate 50 MHz clock
	clk_div2_next <= not clk_div2_reg;

	process (clk_div2_reg, reset)
		begin
		if (reset = '1') then
			mod2_reg <= '0';
			v_cnt_reg <= (others => '0');
			h_cnt_reg <= (others => '0');
			v_sync_reg <= '0';
			h_sync_reg <= '0';
			v_sync_delay1 <= '0';
			h_sync_delay1 <= '0';
			v_sync_delay2 <= '0';
			h_sync_delay2 <= '0';
		elsif ( clk_div2_reg'event and clk_div2_reg = '1' ) then
			mod2_reg <= mod2_next;
			v_cnt_reg <= v_cnt_next;
			h_cnt_reg <= h_cnt_next;
			v_sync_reg <= v_sync_next;
			h_sync_reg <= h_sync_next;
-- Add to cycles of delay for DAC pipeline. 
			v_sync_delay1 <= v_sync_reg;
			h_sync_delay1 <= h_sync_reg;
			v_sync_delay2 <= v_sync_delay1;
			h_sync_delay2 <= h_sync_delay1;
		end if;
	end process;

-- mod-2 circuit to generate 25 MHz enable tick
	mod2_next <= not mod2_reg;
	
-- 25 MHz pixel tick
	pixel_tick <= '1' when mod2_reg = '1' else '0';

-- status (800 for h_end)
	h_end <= '1' when h_cnt_reg=(HD+HF+HB+HR-1) else '0';
	v_end <= '1' when v_cnt_reg=(VD+VF+VB+VR-1) else '0';

-- ======================================================================================================
-- mod-800 horz sync cnter
-- ======================================================================================================
	process (h_cnt_reg, h_end, pixel_tick)
		begin
		if (pixel_tick = '1') then
			if (h_end = '1') then
				h_cnt_next <= (others => '0');
			else
				h_cnt_next <= h_cnt_reg + 1;
			end if;
		else
			h_cnt_next <= h_cnt_reg;
		end if;
	end process;

-- ======================================================================================================
-- mod-525 horz sync cnter
-- ======================================================================================================
	process (v_cnt_reg, h_end, v_end, pixel_tick)
		begin
		if (pixel_tick = '1' and h_end = '1') then
			if (v_end = '1') then
				v_cnt_next <= (others => '0');
			else
				v_cnt_next <= v_cnt_reg + 1;
			end if;
		else
			v_cnt_next <= v_cnt_reg;
		end if;
	end process;
	
-- horz and vert sync, buffered to avoid glitch -- at 656-751 for h_sync_next
	h_sync_next <= '1' when (h_cnt_reg >= (HD+HF)) and (h_cnt_reg <= (HD+HF+HR-1)) else '0';
	v_sync_next <= '1' when (v_cnt_reg >= (VD+VF)) and (v_cnt_reg <= (VD+VF+VR-1)) else '0';

-- video on/off (640)
	video_on <= '1' when (h_cnt_reg < HD) and (v_cnt_reg < VD) else '0';

-- output signals
	hsync <= h_sync_delay2;
	vsync <= v_sync_delay2;
	pixel_x <= std_logic_vector(h_cnt_reg);
	pixel_y <= std_logic_vector(v_cnt_reg);
	p_tick <= pixel_tick;

-- ======================================================================================================
-- comp sync signal generation
-- ======================================================================================================
	process(reset, h_sync_reg, v_sync_reg)
		begin
		if (reset='1') then
			comp_sync <= '0';
		else
			comp_sync <= h_sync_reg xor v_sync_reg;
		end if;
	end process;

end arch;
